fuji_green.c

00001 /*
00002   fuji_green -- read Fuji green pixels
00003  */
00004 
00005 #define _GNU_SOURCE
00006 #include <ctype.h>
00007 #include <errno.h>
00008 #include <fcntl.h>
00009 #include <float.h>
00010 #include <limits.h>
00011 #include <math.h>
00012 #include <setjmp.h>
00013 #include <stdio.h>
00014 #include <stdlib.h>
00015 #include <string.h>
00016 #include <time.h>
00017 
00018 #ifdef WIN32
00019 #include <winsock2.h>
00020 #pragma comment(lib, "ws2_32.lib")
00021 #define strcasecmp stricmp
00022 typedef __int64 INT64;
00023 #else
00024 #include <unistd.h>
00025 #include <netinet/in.h>
00026 typedef long long INT64;
00027 #endif
00028 
00029 #define ushort UshORt
00030 typedef unsigned char uchar;
00031 typedef unsigned short ushort;
00032 
00033 /*
00034    All global variables are defined here, and all functions that
00035    access them are prefixed with "CLASS".  Note that a thread-safe
00036    C++ class cannot have non-const static local variables.
00037  */
00038 FILE *ifp;
00039 short order;
00040 char *ifname, make[64], model[64];
00041 int data_offset;
00042 int height, width, trim;
00043 ushort *image;
00044 void (*load_raw)();
00045 float bright=1.0;
00046 int verbose=0;
00047 void write_ppm(FILE *);
00048 void (*write_fun)(FILE *) = write_ppm;
00049 jmp_buf failure;
00050 
00051 #define CLASS
00052 
00053 void CLASS merror (void *ptr, char *where)
00054 {
00055   if (ptr) return;
00056   fprintf (stderr, "%s: Out of memory in %s\n", ifname, where);
00057   longjmp (failure, 1);
00058 }
00059 
00060 /*
00061    Get a 2-byte integer, making no assumptions about CPU byte order.
00062    Nor should we assume that the compiler evaluates left-to-right.
00063  */
00064 ushort CLASS fget2 (FILE *f)
00065 {
00066   uchar a, b;
00067 
00068   a = fgetc(f);
00069   b = fgetc(f);
00070   if (order == 0x4949)      /* "II" means little-endian */
00071     return a + (b << 8);
00072   else              /* "MM" means big-endian */
00073     return (a << 8) + b;
00074 }
00075 
00076 /*
00077    Same for a 4-byte integer.
00078  */
00079 int CLASS fget4 (FILE *f)
00080 {
00081   uchar a, b, c, d;
00082 
00083   a = fgetc(f);
00084   b = fgetc(f);
00085   c = fgetc(f);
00086   d = fgetc(f);
00087   if (order == 0x4949)
00088     return a + (b << 8) + (c << 16) + (d << 24);
00089   else
00090     return (a << 24) + (b << 16) + (c << 8) + d;
00091 }
00092 
00093 /*
00094    Faster than calling fget2() multiple times.
00095  */
00096 void CLASS read_shorts (ushort *pixel, int count)
00097 {
00098   fread (pixel, 2, count, ifp);
00099   if ((order == 0x4949) == (ntohs(0x1234) == 0x1234))
00100     swab (pixel, pixel, count*2);
00101 }
00102 
00103 void CLASS fuji_s2_load_raw()
00104 {
00105   ushort pixel[2944];
00106   int row, col;
00107 
00108   fseek (ifp, (2944*24+32)*2, SEEK_CUR);
00109   for (col=width; col--; ) {
00110     read_shorts (pixel, 2944);
00111     for (row=0; row < height; row++)
00112       image[row*width+col] = pixel[row*2+1];
00113   }
00114 }
00115 
00116 void CLASS fuji_s3_load_raw()
00117 {
00118   ushort pixel[4352];
00119   int row, col;
00120 
00121   for (row=0; row < height; row++) {
00122     read_shorts (pixel, width*2);
00123     for (col=0; col < width; col++)
00124       image[row*width+col] = pixel[col*2+1];
00125   }
00126 }
00127 
00128 void CLASS fuji_load_raw()
00129 {
00130   ushort pixel[2944];
00131   int row, col;
00132 
00133   for (row=0; row < height; row++) {
00134     read_shorts (pixel, width);
00135     read_shorts (pixel, width);
00136     for (col=0; col < width; col++) {
00137       image[row*width+col] = pixel[col];
00138     }
00139   }
00140 }
00141 
00142 /*
00143    Parse a TIFF file looking for camera model and decompress offsets.
00144  */
00145 void CLASS parse_tiff (int base)
00146 {
00147   int doff, entries, tag, type, len, val, save;
00148 
00149   fseek (ifp, base, SEEK_SET);
00150   order = fget2(ifp);
00151   val = fget2(ifp);     /* Should be 42 for standard TIFF */
00152   while ((doff = fget4(ifp))) {
00153     fseek (ifp, doff+base, SEEK_SET);
00154     entries = fget2(ifp);
00155     while (entries--) {
00156       tag  = fget2(ifp);
00157       type = fget2(ifp);
00158       len  = fget4(ifp);
00159       if (type == 3 && len < 3) {
00160     val = fget2(ifp);  fget2(ifp);
00161       } else
00162     val = fget4(ifp);
00163       save = ftell(ifp);
00164       fseek (ifp, base+val, SEEK_SET);
00165       switch (tag) {
00166     case 0x10f:         /* Make tag */
00167       fgets (make, 64, ifp);
00168       break;
00169     case 0x110:         /* Model tag */
00170       fgets (model, 64, ifp);
00171       }
00172       fseek (ifp, save, SEEK_SET);
00173     }
00174   }
00175 }
00176 
00177 int fgetint (int offset)
00178 {
00179   fseek (ifp, offset, SEEK_SET);
00180   fread (&offset, 4, 1, ifp);
00181   return ntohl(offset);
00182 }
00183 
00184 /*
00185    Identify which camera created this file, and set global variables
00186    accordingly.  Return nonzero if the file cannot be decoded.
00187  */
00188 int CLASS identify()
00189 {
00190   char head[32], *c;
00191   unsigned i;
00192 
00193 /*  What format is this file?  Set make[] if we recognize it. */
00194 
00195   make[0] = model[0] = 0;
00196   data_offset = 0;
00197 
00198   fread (head, 1, 32, ifp);
00199   if (!memcmp (head, "FUJIFILM", 8)) {
00200     parse_tiff (fgetint(84)+12);
00201     data_offset = fgetint(100);
00202   }
00203   c = make + strlen(make);      /* Remove trailing spaces */
00204   while (*--c == ' ') *c = 0;
00205   c = model + strlen(model);
00206   while (*--c == ' ') *c = 0;
00207   i = strlen(make);         /* Remove make from model */
00208   if (!strncmp (model, make, i++))
00209     memmove (model, model+i, 64-i);
00210 
00211   if (make[0] == 0) {
00212     fprintf (stderr, "%s: unsupported file format.\n", ifname);
00213     return 1;
00214   }
00215 
00216 /*  File format is OK.  Do we support this camera? */
00217 /*  Start with some useful defaults:           */
00218   height = width = 0;
00219   load_raw = fuji_load_raw;
00220 
00221   if (!strcmp(model,"FinePixS2Pro")) {
00222     height = 2880;
00223     width = 2144;
00224     load_raw = fuji_s2_load_raw;
00225   } else if (!strcmp(model,"FinePix S3Pro")) {
00226     fseek (ifp, 0, SEEK_END);
00227     height = (ftell(ifp) - data_offset) / 4352;
00228     width  = 4352/2;
00229     load_raw = fuji_s3_load_raw;
00230   } else if (!strcmp(model,"FinePix S5000")) {
00231     height = 2156;
00232     width  = 1472;
00233   } else if (!strcmp(model,"FinePix S7000") ||
00234          !strcmp(model,"FinePix E550") ||
00235          !strcmp(model,"FinePix F810")) {
00236     height = 3080;
00237     width  = 2048;
00238   } else if (!strcmp(model,"FinePix F700") ||
00239          !strcmp(model,"FinePix S20Pro")) {
00240     height = 2168;
00241     width  = 2944;
00242   }
00243   if (!height) {
00244     fprintf (stderr, "%s: %s %s is not supported.\n",
00245     ifname, make, model);
00246     return 1;
00247   }
00248   height /= 2;
00249   fseek (ifp, data_offset, SEEK_SET);
00250   return 0;
00251 }
00252 
00253 /*
00254    Write the image to a 24-bpp PPM file.
00255  */
00256 void CLASS write_ppm (FILE *ofp)
00257 {
00258   int row, col, i, val, total, histogram[0x2000];
00259   float white, r;
00260   uchar lut[0x10000];
00261 
00262 /*  Set the white point to the 99th percentile  */
00263   memset (histogram, 0, sizeof histogram);
00264   for (row = trim; row < height-trim; row++)
00265     for (col = trim; col < width-trim; col++)
00266       histogram[image[row*width+col] >> 4]++;
00267   i = width * height * 0.01;
00268   for (val=0x2000, total=0; --val; )
00269     if ((total += histogram[val]) > i) break;
00270   white = (val << 4) / bright;
00271 
00272   for (i=0; i < 0x10000; i++) {
00273     r = i / white;
00274     val = (r <= 0.018 ? r*4.5 : pow(r,0.45)*1.099-0.099) * 256;
00275     if (val > 255) val = 255;
00276     lut[i] = val;
00277   }
00278   fprintf (ofp, "P5\n%d %d\n255\n",
00279     width-trim*2, height-trim*2);
00280   for (row=trim; row < height-trim; row++)
00281     for (col=trim; col < width-trim; col++)
00282       fputc (lut[image[row*width+col]], ofp);
00283 }
00284 
00285 /*
00286    Write the image to a 48-bpp Photoshop file.
00287  */
00288 void CLASS write_psd (FILE *ofp)
00289 {
00290   char head[] = {
00291     '8','B','P','S',        /* signature */
00292     0,1,0,0,0,0,0,0,        /* version and reserved */
00293     0,1,            /* number of channels */
00294     0,0,0,0,            /* height, big-endian */
00295     0,0,0,0,            /* width, big-endian */
00296     0,16,           /* 16-bit color */
00297     0,1,            /* mode (1=grey, 3=rgb) */
00298     0,0,0,0,            /* color mode data */
00299     0,0,0,0,            /* image resources */
00300     0,0,0,0,            /* layer/mask info */
00301     0,0             /* no compression */
00302   };
00303   int hw[2], psize, row, col, val;
00304   ushort *buffer, *pred;
00305 
00306   hw[0] = htonl(height-trim*2); /* write the header */
00307   hw[1] = htonl(width-trim*2);
00308   memcpy (head+14, hw, sizeof hw);
00309   fwrite (head, 40, 1, ofp);
00310 
00311   psize = (height-trim*2) * (width-trim*2);
00312   buffer = calloc (2, psize);
00313   merror (buffer, "write_psd()");
00314   pred = buffer;
00315 
00316   for (row = trim; row < height-trim; row++) {
00317     for (col = trim; col < width-trim; col++) {
00318       val = image[row*width+col] * bright;
00319       if (val > 0xffff)
00320       val = 0xffff;
00321       *pred++ = htons(val);
00322     }
00323   }
00324   fwrite(buffer, psize, 2, ofp);
00325   free(buffer);
00326 }
00327 
00328 /*
00329    Write the image to a 48-bpp PPM file.
00330  */
00331 void CLASS write_ppm16 (FILE *ofp)
00332 {
00333   int row, col, val;
00334 
00335   fprintf (ofp, "P5\n%d %d\n%d\n",
00336     width-trim*2, height-trim*2, 65535);
00337 
00338   for (row = trim; row < height-trim; row++) {
00339     for (col = trim; col < width-trim; col++) {
00340       val = image[row*width+col] * bright;
00341       if (val > 0xffff)
00342       val = 0xffff;
00343       fputc (val >> 8, ofp);
00344       fputc (val & 255, ofp);
00345     }
00346   }
00347 }
00348 
00349 int CLASS main (int argc, char **argv)
00350 {
00351   int arg, status=0;
00352   int identify_only=0, write_to_stdout=0;
00353   char opt, *ofname, *cp;
00354   const char *write_ext = ".pgm";
00355   FILE *ofp = stdout;
00356 
00357   if (argc == 1)
00358   {
00359     fprintf (stderr,
00360     "\nFuji Green channel output"
00361     "\nby Dave Coffin, dcoffin a cybercom o net"
00362     "\n\nUsage:  %s [options] file1 file2 ...\n"
00363     "\nValid options:"
00364     "\n-i        Identify files but don't decode them"
00365     "\n-c        Write to standard output"
00366     "\n-v        Print verbose messages while decoding"
00367     "\n-b <num>  Set brightness (1.0 by default)"
00368     "\n-2        Write  8-bit PGM (default)"
00369     "\n-3        Write 16-bit PSD (Adobe Photoshop)"
00370     "\n-4        Write 16-bit PGM"
00371     "\n\n", argv[0]);
00372     return 1;
00373   }
00374 
00375   argv[argc] = "";
00376   for (arg=1; argv[arg][0] == '-'; ) {
00377     opt = argv[arg++][1];
00378     if (strchr ("b", opt) && !isdigit(argv[arg][0])) {
00379       fprintf (stderr, "\"-%c\" requires a numeric argument.\n", opt);
00380       return 1;
00381     }
00382     switch (opt)
00383     {
00384       case 'b':  bright      = atof(argv[arg++]);  break;
00385 
00386       case 'i':  identify_only     = 1;  break;
00387       case 'c':  write_to_stdout   = 1;  break;
00388       case 'v':  verbose           = 1;  break;
00389 
00390       case '2':  write_fun = write_ppm;   write_ext = ".pgm";  break;
00391       case '3':  write_fun = write_psd;   write_ext = ".psd";  break;
00392       case '4':  write_fun = write_ppm16; write_ext = ".pgm";  break;
00393 
00394       default:
00395     fprintf (stderr, "Unknown option \"-%c\".\n", opt);
00396     return 1;
00397     }
00398   }
00399   if (arg == argc) {
00400     fprintf (stderr, "No files to process.\n");
00401     return 1;
00402   }
00403   if (write_to_stdout) {
00404     if (isatty(1)) {
00405       fprintf (stderr, "Will not write an image to the terminal!\n");
00406       return 1;
00407     }
00408 #if defined(WIN32) || defined(DJGPP)
00409     if (setmode(1,O_BINARY) < 0) {
00410       perror("setmode()");
00411       return 1;
00412     }
00413 #endif
00414   }
00415 
00416   for ( ; arg < argc; arg++)
00417   {
00418     status = 1;
00419     image = NULL;
00420     if (setjmp (failure)) {
00421       if (fileno(ifp) > 2) fclose(ifp);
00422       if (fileno(ofp) > 2) fclose(ofp);
00423       if (image) free(image);
00424       status = 1;
00425       continue;
00426     }
00427     ifname = argv[arg];
00428     if (!(ifp = fopen (ifname, "rb"))) {
00429       perror (ifname);
00430       continue;
00431     }
00432     if ((status = identify())) {
00433       fclose(ifp);
00434       continue;
00435     }
00436     if (identify_only) {
00437       fprintf (stderr, "%s is a %s %s image.\n", ifname, make, model);
00438       fclose(ifp);
00439       continue;
00440     }
00441     image = calloc (height * width, sizeof *image);
00442     merror (image, "main()");
00443     if (verbose)
00444       fprintf (stderr,
00445     "Loading %s %s image from %s...\n", make, model, ifname);
00446     (*load_raw)();
00447     fclose(ifp);
00448     trim = 0;
00449     ofname = malloc (strlen(ifname) + 16);
00450     merror (ofname, "main()");
00451     if (write_to_stdout)
00452       strcpy (ofname, "standard output");
00453     else {
00454       strcpy (ofname, ifname);
00455       if ((cp = strrchr (ofname, '.'))) *cp = 0;
00456       strcat (ofname, write_ext);
00457       ofp = fopen (ofname, "wb");
00458       if (!ofp) {
00459     status = 1;
00460     perror(ofname);
00461     goto cleanup;
00462       }
00463     }
00464     if (verbose)
00465       fprintf (stderr, "Writing data to %s...\n", ofname);
00466     (*write_fun)(ofp);
00467     if (ofp != stdout)
00468       fclose(ofp);
00469 cleanup:
00470     free(ofname);
00471     free(image);
00472   }
00473   return status;
00474 }

Generated on Sat Jan 27 11:36:13 2007 for libopenraw by  doxygen 1.4.7