about summary refs log tree commit diff
path: root/converter/other/cameratopam
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other/cameratopam')
-rw-r--r--converter/other/cameratopam/Makefile22
-rw-r--r--converter/other/cameratopam/camera.c375
-rw-r--r--converter/other/cameratopam/camera.h95
-rw-r--r--converter/other/cameratopam/cameratopam.c1237
-rw-r--r--converter/other/cameratopam/cameratopam.h6
-rw-r--r--converter/other/cameratopam/canon.c6
-rw-r--r--converter/other/cameratopam/canon.h11
-rw-r--r--converter/other/cameratopam/dng.c151
-rw-r--r--converter/other/cameratopam/dng.h4
-rw-r--r--converter/other/cameratopam/foveon.c37
-rw-r--r--converter/other/cameratopam/foveon.h13
-rw-r--r--converter/other/cameratopam/global_variables.h1
-rw-r--r--converter/other/cameratopam/identify.c2256
-rw-r--r--converter/other/cameratopam/identify.h4
-rw-r--r--converter/other/cameratopam/ljpeg.c238
-rw-r--r--converter/other/cameratopam/ljpeg.h14
16 files changed, 2322 insertions, 2148 deletions
diff --git a/converter/other/cameratopam/Makefile b/converter/other/cameratopam/Makefile
index 20a95aa2..d6207aea 100644
--- a/converter/other/cameratopam/Makefile
+++ b/converter/other/cameratopam/Makefile
@@ -9,7 +9,7 @@ EXTERN_INCLUDES =
 ifneq ($(JPEGLIB),NONE)
   ifneq ($(JPEGHDR_DIR)x,x)
     EXTERN_INCLUDES += -I$(JPEGHDR_DIR)
-    CFLAGS += -DHAVE_JPEG
+    HAVE_JPEG_DEFINE = -DHAVE_JPEG
   endif
 endif
 
@@ -19,20 +19,20 @@ include $(BUILDDIR)/config.mk
 .PHONY: all
 all: cameratopam
 
-OBJECTS = util.o identify.o cameratopam.o camera.o foveon.o decode.o \
+ADDL_OBJECTS = util.o identify.o camera.o foveon.o decode.o \
 	canon.o ljpeg.o dng.o
 
-MERGE_OBJECTS =
+OBJECTS = cameratopam.o $(ADDL_OBJECTS)
 
-BINARIES = cameratopam
-MERGEBINARIES = 
+camera.o camera.o2: CFLAGS_TARGET = $(HAVE_JPEG_DEFINE)
+
+MERGE_OBJECTS = cameratopam.o2 $(ADDL_OBJECTS)
+
+PORTBINARIES = cameratopam
+BINARIES = $(PORTBINARIES)
+MERGEBINARIES = cameratopam
 SCRIPTS = 
 
 include $(SRCDIR)/common.mk
 
-cameratopam: $(OBJECTS) $(NETPBMLIB) $(LIBOPT)
-	$(LD) -o $@ \
-          $(OBJECTS) $(shell $(LIBOPT) $(NETPBMLIB) $(LIBOPTR)) \
-	  $(MATHLIB) $(LDFLAGS) $(LDLIBS) \
-	  $(RPATH) $(LADD)
-
+cameratopam: $(ADDL_OBJECTS)
diff --git a/converter/other/cameratopam/camera.c b/converter/other/cameratopam/camera.c
index 98d6d37a..a1adba95 100644
--- a/converter/other/cameratopam/camera.c
+++ b/converter/other/cameratopam/camera.c
@@ -12,10 +12,13 @@
 #include <jpeglib.h>
 #endif
 
+#include "pm_config.h"
 #include "pm.h"
 #include "mallocvar.h"
+#include "pm_c_util.h"
 
 #include "global_variables.h"
+#include "cameratopam.h"
 #include "util.h"
 #include "decode.h"
 #include "bayer.h"
@@ -54,67 +57,76 @@ merror (const void *ptr, const char *where)
 
 
 static void  
-adobe_copy_pixel (int row, int col, unsigned short **rp, bool use_secondary)
-{
-  unsigned r=row, c=col;
-
-  if (fuji_secondary && use_secondary) (*rp)++;
-  if (filters) {
-    if (fuji_width) {
-      r = row + fuji_width - 1 - (col >> 1);
-      c = row + ((col+1) >> 1);
-    }
-    if (r < height && c < width)
-      BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp;
-    *rp += 1 + fuji_secondary;
-  } else
-    for (c=0; c < tiff_samples; c++) {
-      image[row*width+col][c] = **rp < 0x1000 ? curve[**rp] : **rp;
-      (*rp)++;
+adobeCopyPixel(Image             const image,
+               unsigned int      const row,
+               unsigned int      const col,
+               unsigned short ** const rp,
+               bool              const useSecondary) {
+
+    unsigned r=row, c=col;
+
+    if (fuji_secondary && useSecondary)
+        ++(*rp);
+    if (filters) {
+        if (fuji_width) {
+            r = row + fuji_width - 1 - (col >> 1);
+            c = row + ((col+1) >> 1);
+        }
+        if (r < height && c < width)
+            BAYER(r,c) = **rp < 0x1000 ? curve[**rp] : **rp;
+        *rp += 1 + fuji_secondary;
+    } else {
+        unsigned int c;
+        for (c = 0; c < tiff_samples; ++c) {
+            image[row*width+col][c] = **rp < 0x1000 ? curve[**rp] : **rp;
+            ++(*rp);
+        }
     }
-  if (fuji_secondary && use_secondary) (*rp)--;
+    if (fuji_secondary && useSecondary)
+        --(*rp);
 }
 
 void
-adobe_dng_load_raw_lj()
-{
-  int save, twide, trow=0, tcol=0, jrow, jcol;
-  struct jhead jh;
-  unsigned short *rp;
+adobe_dng_load_raw_lj(Image const image) {
 
-  while (1) {
-    save = ftell(ifp);
-    fseek (ifp, get4(ifp), SEEK_SET);
-    if (!ljpeg_start (ifp, &jh)) break;
-    if (trow >= raw_height) break;
-    if (jh.high > raw_height-trow)
-    jh.high = raw_height-trow;
-    twide = jh.wide;
-    if (filters) twide *= jh.clrs;
-    else         colors = jh.clrs;
-    if (fuji_secondary) twide /= 2;
-    if (twide > raw_width-tcol)
-    twide = raw_width-tcol;
-
-    for (jrow=0; jrow < jh.high; jrow++) {
-      ljpeg_row (&jh);
-      for (rp=jh.row, jcol=0; jcol < twide; jcol++)
-    adobe_copy_pixel (trow+jrow, tcol+jcol, &rp, use_secondary);
-    }
-    fseek (ifp, save+4, SEEK_SET);
-    if ((tcol += twide) >= raw_width) {
-      tcol = 0;
-      trow += jh.high;
+    int save, twide, trow=0, tcol=0, jrow, jcol;
+    struct jhead jh;
+    unsigned short *rp;
+
+    while (1) {
+        save = ftell(ifp);
+        fseek (ifp, get4(ifp), SEEK_SET);
+        if (!ljpeg_start (ifp, &jh)) break;
+        if (trow >= raw_height) break;
+        if (jh.high > raw_height-trow)
+            jh.high = raw_height-trow;
+        twide = jh.wide;
+        if (filters) twide *= jh.clrs;
+        else         colors = jh.clrs;
+        if (fuji_secondary) twide /= 2;
+        if (twide > raw_width-tcol)
+            twide = raw_width-tcol;
+
+        for (jrow=0; jrow < jh.high; jrow++) {
+            ljpeg_row(ifp, &jh);
+            for (rp=jh.row, jcol=0; jcol < twide; jcol++)
+                adobeCopyPixel(image,
+                               trow+jrow, tcol+jcol, &rp, use_secondary);
+        }
+        fseek (ifp, save+4, SEEK_SET);
+        if ((tcol += twide) >= raw_width) {
+            tcol = 0;
+            trow += jh.high;
+        }
+        free (jh.row);
     }
-    free (jh.row);
-  }
 }
 
 
 
 void
-adobe_dng_load_raw_nc()
-{
+adobe_dng_load_raw_nc(Image const image) {
+
     unsigned short *pixel, *rp;
     int row, col;
 
@@ -123,7 +135,7 @@ adobe_dng_load_raw_nc()
     for (row=0; row < raw_height; row++) {
         read_shorts (ifp, pixel, raw_width * tiff_samples);
         for (rp=pixel, col=0; col < raw_width; col++)
-            adobe_copy_pixel (row, col, &rp, use_secondary);
+            adobeCopyPixel(image, row, col, &rp, use_secondary);
     }
     free (pixel);
 }
@@ -133,8 +145,8 @@ adobe_dng_load_raw_nc()
 static int nikon_curve_offset;
 
 void
-nikon_compressed_load_raw(void)
-{
+nikon_compressed_load_raw(Image const image) {
+
     static const unsigned char nikon_tree[] = {
         0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0,
         5,4,3,6,2,7,1,0,8,9,11,10,12
@@ -158,7 +170,7 @@ nikon_compressed_load_raw(void)
     for (row=0; row < height; row++)
         for (col=0; col < raw_width; col++)
         {
-            diff = ljpeg_diff (first_decode);
+            diff = ljpeg_diff (ifp, first_decode);
             if (col < 2) {
                 i = 2*(row & 1) + (col & 1);
                 vpred[i] += diff;
@@ -175,8 +187,8 @@ nikon_compressed_load_raw(void)
 }
 
 void
-nikon_load_raw()
-{
+nikon_load_raw(Image const image) {
+
   int irow, row, col, i;
 
   getbits(ifp, -1);
@@ -293,8 +305,8 @@ minolta_z2()
 }
 
 void
-nikon_e2100_load_raw()
-{
+nikon_e2100_load_raw(Image const image) {
+        
   unsigned char   data[3432], *dp;
   unsigned short pixel[2288], *pix;
   int row, col;
@@ -321,8 +333,8 @@ nikon_e2100_load_raw()
 }
 
 void
-nikon_e950_load_raw()
-{
+nikon_e950_load_raw(Image const image) {
+
   int irow, row, col;
 
   getbits(ifp, -1);
@@ -340,8 +352,7 @@ nikon_e950_load_raw()
    The Fuji Super CCD is just a Bayer grid rotated 45 degrees.
  */
 void
-fuji_s2_load_raw()
-{
+fuji_s2_load_raw(Image const image) {
   unsigned short pixel[2944];
   int row, col, r, c;
 
@@ -357,8 +368,7 @@ fuji_s2_load_raw()
 }
 
 void
-fuji_s3_load_raw()
-{
+fuji_s3_load_raw(Image const image) {
   unsigned short pixel[4352];
   int row, col, r, c;
 
@@ -373,42 +383,52 @@ fuji_s3_load_raw()
   }
 }
 
-static void  fuji_common_load_raw (int ncol, int icol, int nrow)
-{
-  unsigned short pixel[2048];
-  int row, col, r, c;
-
-  for (row=0; row < nrow; row++) {
-    read_shorts(ifp, pixel, ncol);
-    for (col=0; col <= icol; col++) {
-      r = icol - col + (row >> 1);
-      c = col + ((row+1) >> 1);
-      BAYER(r,c) = pixel[col];
+static void 
+fuji_common_load_raw(Image        const image,
+                     unsigned int const ncol,
+                     unsigned int const icol,
+                     unsigned int const nrow) {
+
+    unsigned short pixel[2048];
+    unsigned int row;
+
+    for (row = 0; row < nrow; ++row) {
+        unsigned int col;
+        read_shorts(ifp, pixel, ncol);
+        for (col = 0; col <= icol; ++col) {
+            int const r = icol - col + (row >> 1);
+            int const c = col + ((row+1) >> 1);
+            BAYER(r,c) = pixel[col];
+        }
     }
-  }
 }
 
+
+
 void
-fuji_s5000_load_raw()
-{
+fuji_s5000_load_raw(Image const image) {
+
   fseek (ifp, (1472*4+24)*2, SEEK_CUR);
-  fuji_common_load_raw (1472, 1423, 2152);
+  fuji_common_load_raw(image, 1472, 1423, 2152);
 }
 
+
+
 void
-fuji_s7000_load_raw()
-{
-  fuji_common_load_raw (2048, 2047, 3080);
+fuji_s7000_load_raw(Image const image) {
+
+    fuji_common_load_raw(image, 2048, 2047, 3080);
 }
 
+
+
 /*
    The Fuji Super CCD SR has two photodiodes for each pixel.
    The secondary has about 1/16 the sensitivity of the primary,
    but this ratio may vary.
  */
 void
-fuji_f700_load_raw()
-{
+fuji_f700_load_raw(Image const image) {
   unsigned short pixel[2944];
   int row, col, r, c, val;
 
@@ -424,8 +444,7 @@ fuji_f700_load_raw()
 }
 
 void
-rollei_load_raw()
-{
+rollei_load_raw(Image const image) {
   unsigned char pixel[10];
   unsigned iten=0, isix, i, buffer=0, row, col, todo[16];
 
@@ -451,8 +470,7 @@ rollei_load_raw()
 }
 
 void
-phase_one_load_raw()
-{
+phase_one_load_raw(Image const image) {
   int row, col, a, b;
   unsigned short *pixel, akey, bkey;
 
@@ -478,8 +496,7 @@ phase_one_load_raw()
 }
 
 void
-ixpress_load_raw()
-{
+ixpress_load_raw(Image const image) {
   unsigned short pixel[4090];
   int row, col;
 
@@ -493,8 +510,7 @@ ixpress_load_raw()
 }
 
 void
-leaf_load_raw()
-{
+leaf_load_raw(Image const image) {
   unsigned short *pixel;
   int r, c, row, col;
 
@@ -513,8 +529,7 @@ leaf_load_raw()
    For this function only, raw_width is in bytes, not pixels!
  */
 void
-packed_12_load_raw()
-{
+packed_12_load_raw(Image const image) {
   int row, col;
 
   getbits(ifp, -1);
@@ -527,8 +542,7 @@ packed_12_load_raw()
 }
 
 void
-unpacked_load_raw()
-{
+unpacked_load_raw(Image const image) {
   unsigned short *pixel;
   int row, col;
 
@@ -543,8 +557,7 @@ unpacked_load_raw()
 }
 
 void
-olympus_e300_load_raw()
-{
+olympus_e300_load_raw(Image const image) {
   unsigned char  *data,  *dp;
   unsigned short *pixel, *pix;
   int dwide, row, col;
@@ -567,8 +580,7 @@ olympus_e300_load_raw()
 }
 
 void
-olympus_cseries_load_raw()
-{
+olympus_cseries_load_raw(Image const image) {
   int irow, row, col;
 
   for (irow=0; irow < height; irow++) {
@@ -583,8 +595,7 @@ olympus_cseries_load_raw()
 }
 
 void
-eight_bit_load_raw()
-{
+eight_bit_load_raw(Image const image) {
   unsigned char *pixel;
   int row, col;
 
@@ -600,8 +611,7 @@ eight_bit_load_raw()
 }
 
 void
-casio_qv5700_load_raw()
-{
+casio_qv5700_load_raw(Image const image) {
   unsigned char  data[3232],  *dp;
   unsigned short pixel[2576], *pix;
   int row, col;
@@ -621,8 +631,7 @@ casio_qv5700_load_raw()
 }
 
 void
-nucore_load_raw()
-{
+nucore_load_raw(Image const image) {
   unsigned short *pixel;
   int irow, row, col;
 
@@ -684,79 +693,91 @@ static int  radc_token (int tree)
 : (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4)
 
 void
-kodak_radc_load_raw()
-{
-  int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val;
-  short last[3] = { 16,16,16 }, mul[3], buf[3][3][386];
+kodak_radc_load_raw(Image const image) {
+    int row, col, tree, nreps, rep, step, c, s, r, x, y, val;
+    unsigned int i;
+    short last[3] = { 16,16,16 }, mul[3], buf[3][3][386];
 
-  init_decoder();
-  getbits(ifp, -1);
-  for (i=0; i < sizeof(buf)/sizeof(short); i++)
-    buf[0][0][i] = 2048;
-  for (row=0; row < height; row+=4) {
-    for (i=0; i < 3; i++)
-      mul[i] = getbits(ifp, 6);
-    FORC3 {
-      val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c];
-      s = val > 65564 ? 10:12;
-      x = ~(-1 << (s-1));
-      val <<= 12-s;
-      for (i=0; i < sizeof(buf[0])/sizeof(short); i++)
-    buf[c][0][i] = (buf[c][0][i] * val + x) >> s;
-      last[c] = mul[c];
-      for (r=0; r <= !c; r++) {
-    buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7;
-    for (tree=1, col=width/2; col > 0; ) {
-      if ((tree = radc_token(tree))) {
-        col -= 2;
-        if (tree == 8)
-          FORYX buf[c][y][x] = radc_token(tree+10) * mul[c];
-        else
-          FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR;
-      } else
-        do {
-          nreps = (col > 2) ? radc_token(9) + 1 : 1;
-          for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) {
-        col -= 2;
-        FORYX buf[c][y][x] = PREDICTOR;
-        if (rep & 1) {
-          step = radc_token(10) << 4;
-          FORYX buf[c][y][x] += step;
+    init_decoder();
+    getbits(ifp, -1);
+    for (i = 0; i < ARRAY_SIZE(buf); ++i) {
+        unsigned int j;
+        for (j = 0; j < ARRAY_SIZE(buf[0]); ++j) {
+            unsigned int k;
+            for (k = 0; k < ARRAY_SIZE(buf[0][0]); ++k)
+                buf[i][j][k] = 2048;
         }
-          }
-        } while (nreps == 9);
-    }
-    for (y=0; y < 2; y++)
-      for (x=0; x < width/2; x++) {
-        val = (buf[c][y+1][x] << 4) / mul[c];
-        if (val < 0) val = 0;
-        if (c)
-          BAYER(row+y*2+c-1,x*2+2-c) = val;
-        else
-          BAYER(row+r*2+y,x*2+y) = val;
-      }
-    memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c);
-      }
-    }
-    for (y=row; y < row+4; y++)
-      for (x=0; x < width; x++)
-    if ((x+y) & 1) {
-      val = (BAYER(y,x)-2048)*2 + (BAYER(y,x-1)+BAYER(y,x+1))/2;
-      if (val < 0) val = 0;
-      BAYER(y,x) = val;
     }
-  }
-  maximum = 0x1fff;     /* wild guess */
+    for (row=0; row < height; row+=4) {
+        unsigned int i;
+        for (i = 0; i < 3; ++i)
+            mul[i] = getbits(ifp, 6);
+        FORC3 {
+            val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c];
+            s = val > 65564 ? 10:12;
+            x = ~(-1 << (s-1));
+            val <<= 12-s;
+            for (i=0; i < ARRAY_SIZE(buf[c][0]); i++)
+                buf[c][0][i] = (buf[c][0][i] * val + x) >> s;
+            last[c] = mul[c];
+            for (r=0; r <= !c; r++) {
+                buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7;
+                for (tree=1, col=width/2; col > 0; ) {
+                    if ((tree = radc_token(tree))) {
+                        col -= 2;
+                        if (tree == 8)
+                            FORYX buf[c][y][x] =
+                                radc_token(tree+10) * mul[c];
+                        else
+                            FORYX buf[c][y][x] =
+                                radc_token(tree+10) * 16 + PREDICTOR;
+                    } else
+                        do {
+                            nreps = (col > 2) ? radc_token(9) + 1 : 1;
+                            for (rep=0;
+                                 rep < 8 && rep < nreps && col > 0;
+                                 rep++) {
+                                col -= 2;
+                                FORYX buf[c][y][x] = PREDICTOR;
+                                if (rep & 1) {
+                                    step = radc_token(10) << 4;
+                                    FORYX buf[c][y][x] += step;
+                                }
+                            }
+                        } while (nreps == 9);
+                }
+                for (y=0; y < 2; y++)
+                    for (x=0; x < width/2; x++) {
+                        val = (buf[c][y+1][x] << 4) / mul[c];
+                        if (val < 0) val = 0;
+                        if (c)
+                            BAYER(row+y*2+c-1,x*2+2-c) = val;
+                        else
+                            BAYER(row+r*2+y,x*2+y) = val;
+                    }
+                memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c);
+            }
+        }
+        for (y=row; y < row+4; y++)
+            for (x=0; x < width; x++)
+                if ((x+y) & 1) {
+                    val = (BAYER(y,x)-2048)*2 + (BAYER(y,x-1)+BAYER(y,x+1))/2;
+                    if (val < 0) val = 0;
+                    BAYER(y,x) = val;
+                }
+    }
+    maximum = 0x1fff;     /* wild guess */
 }
 
 #undef FORYX
 #undef PREDICTOR
 
 #ifndef HAVE_JPEG
-void kodak_jpeg_load_raw() {}
+void
+kodak_jpeg_load_raw(Image const Image) {}
 #else
 
-static boolean
+static bool
 fill_input_buffer (j_decompress_ptr cinfo)
 {
   static char jpeg_buffer[4096];
@@ -770,7 +791,7 @@ fill_input_buffer (j_decompress_ptr cinfo)
 }
 
 void
-kodak_jpeg_load_raw()
+kodak_jpeg_load_raw(Image const image)
 {
   struct jpeg_decompress_struct cinfo;
   struct jpeg_error_mgr jerr;
@@ -811,7 +832,7 @@ kodak_jpeg_load_raw()
 #endif
 
 void
-kodak_dc120_load_raw()
+kodak_dc120_load_raw(Image const image)
 {
   static const int mul[4] = { 162, 192, 187,  92 };
   static const int add[4] = {   0, 636, 424, 212 };
@@ -847,7 +868,7 @@ kodak_dc20_coeff (float const juice)
 }
 
 void
-kodak_easy_load_raw()
+kodak_easy_load_raw(Image const image)
 {
   unsigned char *pixel;
   unsigned row, col, icol;
@@ -875,7 +896,7 @@ kodak_easy_load_raw()
 }
 
 void
-kodak_compressed_load_raw()
+kodak_compressed_load_raw(Image const image)
 {
   unsigned char c, blen[256];
   unsigned short raw[6];
@@ -939,7 +960,7 @@ kodak_compressed_load_raw()
 }
 
 void
-kodak_yuv_load_raw()
+kodak_yuv_load_raw(Image const image)
 {
   unsigned char c, blen[384];
   unsigned row, col, len, bits=0;
@@ -1030,7 +1051,7 @@ static void  sony_decrypt (unsigned *data, int len, int start, int key)
 }
 
 void
-sony_load_raw()
+sony_load_raw(Image const image)
 {
   unsigned char head[40];
   struct pixel {
@@ -1298,12 +1319,6 @@ parse_mos(FILE * const ifp,
         fread (data, 1, 40, ifp);
         skip = get4(ifp);
         from = ftell(ifp);
-#ifdef USE_LCMS
-        if (!strcmp(data,"icc_camera_profile")) {
-            profile_length = skip;
-            profile_offset = from;
-        }
-#endif
         if (!strcmp(data,"NeutObj_neutrals")) {
             for (i=0; i < 4; i++)
                 fscanf (ifp, "%d", neut+i);
diff --git a/converter/other/cameratopam/camera.h b/converter/other/cameratopam/camera.h
index a1e884cf..02c3f2af 100644
--- a/converter/other/cameratopam/camera.h
+++ b/converter/other/cameratopam/camera.h
@@ -1,5 +1,10 @@
+#ifndef CAMERA_H_INCLUDED
+#define CAMERA_H_INCLUDED
+
 #include <stdio.h>
 
+#include "cameratopam.h"
+
 void 
 parse_ciff(FILE * const ifp,
            int    const offset,
@@ -21,20 +26,18 @@ void
 parse_mos(FILE * const ifp,
           int    const offset);
 
-void
-adobe_dng_load_raw_lj(void);
+typedef void LoadRawFn(Image const image);
 
-void
-adobe_dng_load_raw_nc(void);
+LoadRawFn adobe_dng_load_raw_lj;
+
+LoadRawFn adobe_dng_load_raw_nc;
 
 int
 nikon_is_compressed(void);
 
-void
-nikon_compressed_load_raw(void);
+LoadRawFn nikon_compressed_load_raw;
 
-void
-nikon_e950_load_raw(void);
+LoadRawFn nikon_e950_load_raw;
 
 void
 nikon_e950_coeff(void);
@@ -45,87 +48,63 @@ nikon_e990(void);
 int
 nikon_e2100(void);
 
-void
-nikon_e2100_load_raw(void);
+LoadRawFn nikon_e2100_load_raw;
 
 int
 minolta_z2(void);
 
-void
-fuji_s2_load_raw(void);
+LoadRawFn fuji_s2_load_raw;
 
-void
-fuji_s3_load_raw(void);
+LoadRawFn fuji_s3_load_raw;
 
-void
-fuji_s5000_load_raw(void);
+LoadRawFn fuji_s5000_load_raw;
 
-void
-unpacked_load_raw(void);
+LoadRawFn unpacked_load_raw;
 
-void
-fuji_s7000_load_raw(void);
+LoadRawFn fuji_s7000_load_raw;
 
-void
-fuji_f700_load_raw(void);
+LoadRawFn fuji_f700_load_raw;
 
-void
-packed_12_load_raw(void);
+LoadRawFn packed_12_load_raw;
 
-void
-eight_bit_load_raw(void);
+LoadRawFn eight_bit_load_raw;
 
-void
-phase_one_load_raw(void);
+LoadRawFn phase_one_load_raw;
 
-void
-ixpress_load_raw(void);
+LoadRawFn ixpress_load_raw;
 
-void
-leaf_load_raw(void);
+LoadRawFn leaf_load_raw;
 
-void
-olympus_e300_load_raw(void);
+LoadRawFn olympus_e300_load_raw;
 
-void
-olympus_cseries_load_raw(void);
+LoadRawFn olympus_cseries_load_raw;
 
-void
-sony_load_raw(void);
+LoadRawFn sony_load_raw;
 
-void
-kodak_easy_load_raw(void);
+LoadRawFn kodak_easy_load_raw;
 
-void
-kodak_compressed_load_raw(void);
+LoadRawFn kodak_compressed_load_raw;
 
-void
-kodak_yuv_load_raw(void);
+LoadRawFn kodak_yuv_load_raw;
 
 void
 kodak_dc20_coeff (float const juice);
 
-void
-kodak_radc_load_raw(void);
+LoadRawFn kodak_radc_load_raw;
 
-void
-kodak_jpeg_load_raw(void);
+LoadRawFn kodak_jpeg_load_raw;
 
-void
-kodak_dc120_load_raw(void);
+LoadRawFn kodak_dc120_load_raw;
 
-void
-rollei_load_raw(void);
+LoadRawFn rollei_load_raw;
 
-void
-casio_qv5700_load_raw(void);
+LoadRawFn casio_qv5700_load_raw;
 
-void
-nucore_load_raw(void);
+LoadRawFn nucore_load_raw;
 
-void
-nikon_load_raw(void);
+LoadRawFn nikon_load_raw;
 
 int
 pentax_optio33(void);
 
+#endif
diff --git a/converter/other/cameratopam/cameratopam.c b/converter/other/cameratopam/cameratopam.c
index b2d6da9b..ec33dd31 100644
--- a/converter/other/cameratopam/cameratopam.c
+++ b/converter/other/cameratopam/cameratopam.c
@@ -7,8 +7,11 @@
  */
 
 
-#define _BSD_SOURCE 1   /* Make sure string.h contains strcasecmp() */
-#define _XOPEN_SOURCE  /* Make sure unistd.h contains swab() */
+#define _BSD_SOURCE 1   /* Make sure string.h contains strdup() */
+#define _XOPEN_SOURCE 500
+   /* Make sure unistd.h contains swab(), string.h constains strdup() */
+
+#include "pm_config.h"
 
 #include <ctype.h>
 #include <unistd.h>
@@ -23,10 +26,10 @@
 #include <stdlib.h>
 #include <string.h>
 
-#ifdef __CYGWIN__
+#ifdef HAVE_IO_H
   #include <io.h>
 #endif
-#if !defined(WIN32) || defined(__CYGWIN__)
+#if !MSVCRT
   #include <unistd.h>
 #endif
 
@@ -36,6 +39,7 @@
 #include "pam.h"
 
 #include "global_variables.h"
+#include "cameratopam.h"
 #include "util.h"
 #include "decode.h"
 #include "identify.h"
@@ -59,22 +63,19 @@ int height, width, fuji_width, colors, tiff_samples;
 int black, maximum, clip_max;
 int iheight, iwidth, shrink;
 int is_dng, is_canon, is_foveon, use_coeff, use_gamma;
-int trim, flip, xmag, ymag;
+int flip, xmag, ymag;
 int zero_after_ff;
 unsigned filters;
-unsigned short (*image)[4], white[8][8], curve[0x1000];
+unsigned short  white[8][8];
+unsigned short  curve[0x1000];
 int fuji_secondary;
-float cam_mul[4], pre_mul[4], coeff[3][4];
+float cam_mul[4], coeff[3][4];
+float pre_mul[4];
 int histogram[3][0x2000];
 jmp_buf failure;
-bool use_secondary;
+int use_secondary;
 bool verbose;
 
-#ifdef USE_LCMS
-#include <lcms.h>
-int profile_offset, profile_length;
-#endif
-
 #define CLASS
 
 #define FORC3 for (c=0; c < 3; c++)
@@ -86,7 +87,7 @@ static void CLASS merror (const void *ptr, const char *where)
         pm_error ("Out of memory in %s", where);
 }
 
-struct cmdlineInfo {
+struct CmdlineInfo {
     /* All the information the user supplied in the command line,
        in a form easy for the program to use.
     */
@@ -110,11 +111,11 @@ struct cmdlineInfo {
 };
 
 
-static struct cmdlineInfo cmdline;
+static struct CmdlineInfo cmdline;
 
 static void
 parseCommandLine(int argc, char ** argv,
-                 struct cmdlineInfo *cmdlineP) {
+                 struct CmdlineInfo *cmdlineP) {
 /*----------------------------------------------------------------------------
    Note that many of the strings that this function returns in the
    *cmdlineP structure are actually in the supplied argv array.  And
@@ -167,7 +168,7 @@ parseCommandLine(int argc, char ** argv,
     OPTENT3(0,   "linear",   
             OPT_FLAG,    NULL, &cmdlineP->linear, 0);
 
-    optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
+    pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
 
     if (!brightSpec)
         cmdlineP->bright = 1.0;
@@ -189,615 +190,694 @@ parseCommandLine(int argc, char ** argv,
 }
 
   
-/*
-   Seach from the current directory up to the root looking for
-   a ".badpixels" file, and fix those pixels now.
- */
-static void CLASS bad_pixels()
-{
-  FILE *fp=NULL;
-  char *fname, *cp, line[128];
-  int len, time, row, col, r, c, rad, tot, n, fixed=0;
-
-  if (!filters) return;
-  for (len=16 ; ; len *= 2) {
-    fname = malloc (len);
-    if (!fname) return;
-    if (getcwd (fname, len-12)) break;
-    free (fname);
-    if (errno != ERANGE) return;
-  }
-#ifdef WIN32
-  if (fname[1] == ':')
-    memmove (fname, fname+2, len-2);
-  for (cp=fname; *cp; cp++)
-    if (*cp == '\\') *cp = '/';
+
+static void CLASS
+fixBadPixels(Image const image) {
+/*----------------------------------------------------------------------------
+  Search from the current directory up to the root looking for
+  a ".badpixels" file, and fix those pixels now.
+-----------------------------------------------------------------------------*/
+    if (filters) {
+        FILE *fp;
+        char *fname, *cp, line[128];
+        int len, time, row, col, rad, tot, n, fixed=0;
+
+        for (len=16 ; ; len *= 2) {
+            fname = malloc (len);
+            if (!fname) return;
+            if (getcwd (fname, len-12))
+                break;
+            free (fname);
+            if (errno != ERANGE)
+                return;
+        }
+#if MSVCRT
+        if (fname[1] == ':')
+            memmove (fname, fname+2, len-2);
+        for (cp=fname; *cp; cp++)
+            if (*cp == '\\') *cp = '/';
 #endif
-  cp = fname + strlen(fname);
-  if (cp[-1] == '/') cp--;
-  while (*fname == '/') {
-    strcpy (cp, "/.badpixels");
-    if ((fp = fopen (fname, "r"))) break;
-    if (cp == fname) break;
-    while (*--cp != '/');
-  }
-  free (fname);
-  if (!fp) return;
-  while (fgets (line, 128, fp)) {
-    cp = strchr (line, '#');
-    if (cp) *cp = 0;
-    if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue;
-    if ((unsigned) col >= width || (unsigned) row >= height) continue;
-    if (time > timestamp) continue;
-    for (tot=n=0, rad=1; rad < 3 && n==0; rad++)
-      for (r = row-rad; r <= row+rad; r++)
-    for (c = col-rad; c <= col+rad; c++)
-      if ((unsigned) r < height && (unsigned) c < width &&
-        (r != row || c != col) && FC(r,c) == FC(row,col)) {
-        tot += BAYER(r,c);
-        n++;
-      }
-    BAYER(row,col) = tot/n;
-    if (cmdline.verbose) {
-      if (!fixed++)
-          pm_message ("Fixed bad pixels at: %d,%d", col, row);
+        cp = fname + strlen(fname);
+        if (cp[-1] == '/')
+            --cp;
+        fp = NULL; /* initial value */
+        while (*fname == '/') {
+            strcpy (cp, "/.badpixels");
+            fp = fopen (fname, "r");
+            if (fp)
+                break;
+            if (cp == fname)
+                break;
+            while (*--cp != '/');
+        }
+        free (fname);
+        if (fp) {
+            while (fgets (line, 128, fp)) {
+                char * cp;
+                cp = strchr (line, '#');
+                if (cp) *cp = 0;
+                if (sscanf (line, "%d %d %d", &col, &row, &time) != 3)
+                    continue;
+                if ((unsigned) col >= width || (unsigned) row >= height)
+                    continue;
+                if (time > timestamp) continue;
+                for (tot=n=0, rad=1; rad < 3 && n==0; rad++) {
+                    unsigned int r;
+                    for (r = row-rad; r <= row+rad; ++r) {
+                        unsigned int c;
+                        for (c = col-rad; c <= col+rad; ++c) {
+                            if ((unsigned) r < height &&
+                                (unsigned) c < width  &&
+                                (r != row || c != col) &&
+                                FC(r,c) == FC(row,col)) {
+                                tot += BAYER(r,c);
+                                ++n;
+                            }
+                        }
+                    }
+                }
+                BAYER(row,col) = tot/n;
+                if (cmdline.verbose) {
+                    if (!fixed++)
+                        pm_message ("Fixed bad pixels at: %d,%d", col, row);
+                }
+            }
+            fclose (fp);
+        }
     }
-  }
-  fclose (fp);
 }
 
-static void CLASS scale_colors()
-{
-  int row, col, c, val, shift=0;
-  int min[4], max[4], count[4];
-  double sum[4], dmin;
-
-  maximum -= black;
-  if (cmdline.use_auto_wb || (cmdline.use_camera_wb && camera_red == -1)) {
-    FORC4 min[c] = INT_MAX;
-    FORC4 max[c] = count[c] = sum[c] = 0;
-    for (row=0; row < height; row++)
-      for (col=0; col < width; col++)
-    FORC4 {
-      val = image[row*width+col][c];
-      if (!val) continue;
-      if (min[c] > val) min[c] = val;
-      if (max[c] < val) max[c] = val;
-      val -= black;
-      if (val > maximum-25) continue;
-      if (val < 0) val = 0;
-      sum[c] += val;
-      count[c]++;
+
+
+static void CLASS
+scaleColors(Image const image) {
+
+    int row;
+    int c;
+    int val;
+    int shift;
+    int min[4], max[4], count[4];
+    double sum[4], dmin;
+    int scaleMax;
+
+    scaleMax = maximum - black;  /* initial value */
+    if (cmdline.use_auto_wb || (cmdline.use_camera_wb && camera_red == -1)) {
+        unsigned int row;
+        FORC4 min  [c] = INT_MAX;
+        FORC4 max  [c] = 0;
+        FORC4 count[c] = 0;
+        FORC4 sum  [c] = 0;
+        for (row = 0; row < height; ++row) {
+            unsigned int col;
+            for (col = 0; col < width; ++col) {
+                FORC4 {
+                    int val;
+                    val = image[row*width+col][c];
+                    if (val != 0) {
+                        if (min[c] > val)
+                            min[c] = val;
+                        if (max[c] < val)
+                            max[c] = val;
+                        val -= black;
+                        if (val <= scaleMax-25) {
+                            sum  [c] += MAX(0, val);
+                            count[c] += 1;
+                        }
+                    }
+                }
+            }
+        }
+        FORC4 pre_mul[c] = count[c] / sum[c];
     }
-    FORC4 pre_mul[c] = count[c] / sum[c];
-  }
-  if (cmdline.use_camera_wb && camera_red != -1) {
-    FORC4 count[c] = sum[c] = 0;
-    for (row=0; row < 8; row++)
-      for (col=0; col < 8; col++) {
-    c = FC(row,col);
-    if ((val = white[row][col] - black) > 0)
-      sum[c] += val;
-    count[c]++;
-      }
-    val = 1;
-    FORC4 if (sum[c] == 0) val = 0;
-    if (val)
-      FORC4 pre_mul[c] = count[c] / sum[c];
-    else if (camera_red && camera_blue)
-      memcpy (pre_mul, cam_mul, sizeof pre_mul);
-    else
-      pm_message ("Cannot use camera white balance.");
-  }
-  if (!use_coeff) {
-    pre_mul[0] *= cmdline.red_scale;
-    pre_mul[2] *= cmdline.blue_scale;
-  }
-  dmin = DBL_MAX;
-  FORC4 if (dmin > pre_mul[c])
+    if (cmdline.use_camera_wb && camera_red != -1) {
+        unsigned int row;
+        FORC4 count[c] = sum[c] = 0;
+        for (row = 0; row < 8; ++row) {
+            unsigned int col;
+            for (col = 0; col < 8; ++col) {
+                c = FC(row,col);
+                if ((val = white[row][col] - black) > 0)
+                    sum[c] += val;
+                ++count[c];
+            }
+        }
+        val = 1;
+        FORC4 if (sum[c] == 0) val = 0;
+        if (val)
+            FORC4 pre_mul[c] = count[c] / sum[c];
+        else if (camera_red && camera_blue)
+            memcpy(pre_mul, cam_mul, sizeof pre_mul);
+        else
+            pm_message ("Cannot use camera white balance.");
+    }
+    if (!use_coeff) {
+        pre_mul[0] *= cmdline.red_scale;
+        pre_mul[2] *= cmdline.blue_scale;
+    }
+    dmin = DBL_MAX;
+    FORC4 if (dmin > pre_mul[c])
         dmin = pre_mul[c];
-  FORC4 pre_mul[c] /= dmin;
-
-  while (maximum << shift < 0x8000) shift++;
-  FORC4 pre_mul[c] *= 1 << shift;
-  maximum <<= shift;
-
-  if (cmdline.linear || cmdline.bright < 1) {
-      maximum *= cmdline.bright;
-      if (maximum > 0xffff)
-          maximum = 0xffff;
-      FORC4 pre_mul[c] *= cmdline.bright;
-  }
-  if (cmdline.verbose) {
-    fprintf (stderr, "Scaling with black=%d, pre_mul[] =", black);
-    FORC4 fprintf (stderr, " %f", pre_mul[c]);
-    fputc ('\n', stderr);
-  }
-  clip_max = cmdline.no_clip_color ? 0xffff : maximum;
-  for (row=0; row < height; row++)
-    for (col=0; col < width; col++)
-      FORC4 {
-    val = image[row*width+col][c];
-    if (!val) continue;
-    val -= black;
-    val *= pre_mul[c];
-    if (val < 0) val = 0;
-    if (val > clip_max) val = clip_max;
-    image[row*width+col][c] = val;
-      }
-}
-
-/*
-   This algorithm is officially called:
+    FORC4 pre_mul[c] /= dmin;
 
-   "Interpolation using a Threshold-based variable number of gradients"
+    for (shift = 0; scaleMax << shift < 0x8000; ++shift);
 
-   described in http://www-ise.stanford.edu/~tingchen/algodep/vargra.html
+    FORC4 pre_mul[c] *= 1 << shift;
+    scaleMax <<= shift;
 
-   I've extended the basic idea to work with non-Bayer filter arrays.
-   Gradients are numbered clockwise from NW=0 to W=7.
- */
-static void CLASS vng_interpolate()
-{
-  static const signed char *cp, terms[] = {
-    -2,-2,+0,-1,0,(char)0x01, -2,-2,+0,+0,1,(char)0x01, -2,-1,-1,+0,0,(char)0x01,
-    -2,-1,+0,-1,0,(char)0x02, -2,-1,+0,+0,0,(char)0x03, -2,-1,+0,+1,1,(char)0x01,
-    -2,+0,+0,-1,0,(char)0x06, -2,+0,+0,+0,1,(char)0x02, -2,+0,+0,+1,0,(char)0x03,
-    -2,+1,-1,+0,0,(char)0x04, -2,+1,+0,-1,1,(char)0x04, -2,+1,+0,+0,0,(char)0x06,
-    -2,+1,+0,+1,0,(char)0x02, -2,+2,+0,+0,1,(char)0x04, -2,+2,+0,+1,0,(char)0x04,
-    -1,-2,-1,+0,0,(char)0x80, -1,-2,+0,-1,0,(char)0x01, -1,-2,+1,-1,0,(char)0x01,
-    -1,-2,+1,+0,1,(char)0x01, -1,-1,-1,+1,0,(char)0x88, -1,-1,+1,-2,0,(char)0x40,
-    -1,-1,+1,-1,0,(char)0x22, -1,-1,+1,+0,0,(char)0x33, -1,-1,+1,+1,1,(char)0x11,
-    -1,+0,-1,+2,0,(char)0x08, -1,+0,+0,-1,0,(char)0x44, -1,+0,+0,+1,0,(char)0x11,
-    -1,+0,+1,-2,1,(char)0x40, -1,+0,+1,-1,0,(char)0x66, -1,+0,+1,+0,1,(char)0x22,
-    -1,+0,+1,+1,0,(char)0x33, -1,+0,+1,+2,1,(char)0x10, -1,+1,+1,-1,1,(char)0x44,
-    -1,+1,+1,+0,0,(char)0x66, -1,+1,+1,+1,0,(char)0x22, -1,+1,+1,+2,0,(char)0x10,
-    -1,+2,+0,+1,0,(char)0x04, -1,+2,+1,+0,1,(char)0x04, -1,+2,+1,+1,0,(char)0x04,
-    +0,-2,+0,+0,1,(char)0x80, +0,-1,+0,+1,1,(char)0x88, +0,-1,+1,-2,0,(char)0x40,
-    +0,-1,+1,+0,0,(char)0x11, +0,-1,+2,-2,0,(char)0x40, +0,-1,+2,-1,0,(char)0x20,
-    +0,-1,+2,+0,0,(char)0x30, +0,-1,+2,+1,1,(char)0x10, +0,+0,+0,+2,1,(char)0x08,
-    +0,+0,+2,-2,1,(char)0x40, +0,+0,+2,-1,0,(char)0x60, +0,+0,+2,+0,1,(char)0x20,
-    +0,+0,+2,+1,0,(char)0x30, +0,+0,+2,+2,1,(char)0x10, +0,+1,+1,+0,0,(char)0x44,
-    +0,+1,+1,+2,0,(char)0x10, +0,+1,+2,-1,1,(char)0x40, +0,+1,+2,+0,0,(char)0x60,
-    +0,+1,+2,+1,0,(char)0x20, +0,+1,+2,+2,0,(char)0x10, +1,-2,+1,+0,0,(char)0x80,
-    +1,-1,+1,+1,0,(char)0x88, +1,+0,+1,+2,0,(char)0x08, +1,+0,+2,-1,0,(char)0x40,
-    +1,+0,+2,+1,0,(char)0x10
-  }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 };
-  unsigned short (*brow[5])[4], *pix;
-  int code[8][2][320], *ip, gval[8], gmin, gmax, sum[4];
-  int row, col, shift, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
-  int g, diff, thold, num, c;
-
-  for (row=0; row < 8; row++) {     /* Precalculate for bilinear */
-    for (col=1; col < 3; col++) {
-      ip = code[row][col & 1];
-      memset (sum, 0, sizeof sum);
-      for (y=-1; y <= 1; y++)
-    for (x=-1; x <= 1; x++) {
-      shift = (y==0) + (x==0);
-      if (shift == 2) continue;
-      color = FC(row+y,col+x);
-      *ip++ = (width*y + x)*4 + color;
-      *ip++ = shift;
-      *ip++ = color;
-      sum[color] += 1 << shift;
-    }
-      FORC4
-    if (c != FC(row,col)) {
-      *ip++ = c;
-      *ip++ = sum[c];
+    if (cmdline.linear || cmdline.bright < 1) {
+        scaleMax = MIN(0xffff, scaleMax * cmdline.bright);
+        FORC4 pre_mul[c] *= cmdline.bright;
     }
+    if (cmdline.verbose) {
+        fprintf(stderr, "Scaling with black=%d, ", black);
+        fprintf(stderr, "pre_mul[] = ");
+        FORC4 fprintf (stderr, " %f", pre_mul[c]);
+        fprintf(stderr, "\n");
     }
-  }
-  for (row=1; row < height-1; row++) {  /* Do bilinear interpolation */
-    for (col=1; col < width-1; col++) {
-      pix = image[row*width+col];
-      ip = code[row & 7][col & 1];
-      memset (sum, 0, sizeof sum);
-      for (g=8; g--; ) {
-    diff = pix[*ip++];
-    diff <<= *ip++;
-    sum[*ip++] += diff;
-      }
-      for (g=colors; --g; ) {
-    c = *ip++;
-    pix[c] = sum[c] / *ip++;
-      }
+    clip_max = cmdline.no_clip_color ? 0xffff : scaleMax;
+    for (row = 0; row < height; ++row) {
+        unsigned int col;
+        for (col = 0; col < width; ++col) {
+            unsigned int c;
+            for (c = 0; c < colors; ++c) {
+                int val;
+                val = image[row*width+col][c];
+                if (val != 0) {
+                    val -= black;
+                    val *= pre_mul[c];
+                    image[row*width+col][c] = MAX(0, MIN(clip_max, val));
+                }
+            }
+        }
     }
-  }
-  if (cmdline.quick_interpolate)
-    return;
-
-  for (row=0; row < 8; row++) {     /* Precalculate for VNG */
-    for (col=0; col < 2; col++) {
-      ip = code[row][col];
-      for (cp=terms, t=0; t < 64; t++) {
-    y1 = *cp++;  x1 = *cp++;
-    y2 = *cp++;  x2 = *cp++;
-    weight = *cp++;
-    grads = *cp++;
-    color = FC(row+y1,col+x1);
-    if (FC(row+y2,col+x2) != color) continue;
-    diag = (FC(row,col+1) == color && FC(row+1,col) == color) ? 2:1;
-    if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue;
-    *ip++ = (y1*width + x1)*4 + color;
-    *ip++ = (y2*width + x2)*4 + color;
-    *ip++ = weight;
-    for (g=0; g < 8; g++)
-      if (grads & 1<<g) *ip++ = g;
-    *ip++ = -1;
-      }
-      *ip++ = INT_MAX;
-      for (cp=chood, g=0; g < 8; g++) {
-    y = *cp++;  x = *cp++;
-    *ip++ = (y*width + x) * 4;
-    color = FC(row,col);
-    if (FC(row+y,col+x) != color && FC(row+y*2,col+x*2) == color)
-      *ip++ = (y*width + x) * 8 + color;
-    else
-      *ip++ = 0;
-      }
+}
+
+
+
+static void CLASS
+vngInterpolate(Image const image) {
+
+    /*
+      This algorithm is officially called "Interpolation using a
+      Threshold-based variable number of gradients," described in
+      http://www-ise.stanford.edu/~tingchen/algodep/vargra.html
+
+      I've extended the basic idea to work with non-Bayer filter arrays.
+      Gradients are numbered clockwise from NW=0 to W=7.
+    */
+
+    static const signed char *cp, terms[] = {
+  -2,-2,+0,-1,0,(char)0x01, -2,-2,+0,+0,1,(char)0x01, -2,-1,-1,+0,0,(char)0x01,
+  -2,-1,+0,-1,0,(char)0x02, -2,-1,+0,+0,0,(char)0x03, -2,-1,+0,+1,1,(char)0x01,
+  -2,+0,+0,-1,0,(char)0x06, -2,+0,+0,+0,1,(char)0x02, -2,+0,+0,+1,0,(char)0x03,
+  -2,+1,-1,+0,0,(char)0x04, -2,+1,+0,-1,1,(char)0x04, -2,+1,+0,+0,0,(char)0x06,
+  -2,+1,+0,+1,0,(char)0x02, -2,+2,+0,+0,1,(char)0x04, -2,+2,+0,+1,0,(char)0x04,
+  -1,-2,-1,+0,0,(char)0x80, -1,-2,+0,-1,0,(char)0x01, -1,-2,+1,-1,0,(char)0x01,
+  -1,-2,+1,+0,1,(char)0x01, -1,-1,-1,+1,0,(char)0x88, -1,-1,+1,-2,0,(char)0x40,
+  -1,-1,+1,-1,0,(char)0x22, -1,-1,+1,+0,0,(char)0x33, -1,-1,+1,+1,1,(char)0x11,
+  -1,+0,-1,+2,0,(char)0x08, -1,+0,+0,-1,0,(char)0x44, -1,+0,+0,+1,0,(char)0x11,
+  -1,+0,+1,-2,1,(char)0x40, -1,+0,+1,-1,0,(char)0x66, -1,+0,+1,+0,1,(char)0x22,
+  -1,+0,+1,+1,0,(char)0x33, -1,+0,+1,+2,1,(char)0x10, -1,+1,+1,-1,1,(char)0x44,
+  -1,+1,+1,+0,0,(char)0x66, -1,+1,+1,+1,0,(char)0x22, -1,+1,+1,+2,0,(char)0x10,
+  -1,+2,+0,+1,0,(char)0x04, -1,+2,+1,+0,1,(char)0x04, -1,+2,+1,+1,0,(char)0x04,
+  +0,-2,+0,+0,1,(char)0x80, +0,-1,+0,+1,1,(char)0x88, +0,-1,+1,-2,0,(char)0x40,
+  +0,-1,+1,+0,0,(char)0x11, +0,-1,+2,-2,0,(char)0x40, +0,-1,+2,-1,0,(char)0x20,
+  +0,-1,+2,+0,0,(char)0x30, +0,-1,+2,+1,1,(char)0x10, +0,+0,+0,+2,1,(char)0x08,
+  +0,+0,+2,-2,1,(char)0x40, +0,+0,+2,-1,0,(char)0x60, +0,+0,+2,+0,1,(char)0x20,
+  +0,+0,+2,+1,0,(char)0x30, +0,+0,+2,+2,1,(char)0x10, +0,+1,+1,+0,0,(char)0x44,
+  +0,+1,+1,+2,0,(char)0x10, +0,+1,+2,-1,1,(char)0x40, +0,+1,+2,+0,0,(char)0x60,
+  +0,+1,+2,+1,0,(char)0x20, +0,+1,+2,+2,0,(char)0x10, +1,-2,+1,+0,0,(char)0x80,
+  +1,-1,+1,+1,0,(char)0x88, +1,+0,+1,+2,0,(char)0x08, +1,+0,+2,-1,0,(char)0x40,
+  +1,+0,+2,+1,0,(char)0x10
+    }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 };
+    unsigned short (*brow[5])[4], *pix;
+    int code[8][2][320], *ip, gval[8], gmin, gmax, sum[4];
+    int row, col, shift, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
+    int g, diff, thold, num, c;
+
+    for (row=0; row < 8; row++) {     /* Precalculate for bilinear */
+        for (col=1; col < 3; col++) {
+            ip = code[row][col & 1];
+            memset (sum, 0, sizeof sum);
+            for (y=-1; y <= 1; y++)
+                for (x=-1; x <= 1; x++) {
+                    shift = (y==0) + (x==0);
+                    if (shift == 2) continue;
+                    color = FC(row+y,col+x);
+                    *ip++ = (width*y + x)*4 + color;
+                    *ip++ = shift;
+                    *ip++ = color;
+                    sum[color] += 1 << shift;
+                }
+            FORC4
+                if (c != FC(row,col)) {
+                    *ip++ = c;
+                    *ip++ = sum[c];
+                }
+        }
     }
-  }
-  brow[4] = calloc (width*3, sizeof **brow);
-  merror (brow[4], "vng_interpolate()");
-  for (row=0; row < 3; row++)
-    brow[row] = brow[4] + row*width;
-  for (row=2; row < height-2; row++) {      /* Do VNG interpolation */
-    for (col=2; col < width-2; col++) {
-      pix = image[row*width+col];
-      ip = code[row & 7][col & 1];
-      memset (gval, 0, sizeof gval);
-      while ((g = ip[0]) != INT_MAX) {      /* Calculate gradients */
-    num = (diff = pix[g] - pix[ip[1]]) >> 31;
-    gval[ip[3]] += (diff = ((diff ^ num) - num) << ip[2]);
-    ip += 5;
-    if ((g = ip[-1]) == -1) continue;
-    gval[g] += diff;
-    while ((g = *ip++) != -1)
-      gval[g] += diff;
-      }
-      ip++;
-      gmin = gmax = gval[0];            /* Choose a threshold */
-      for (g=1; g < 8; g++) {
-    if (gmin > gval[g]) gmin = gval[g];
-    if (gmax < gval[g]) gmax = gval[g];
-      }
-      if (gmax == 0) {
-    memcpy (brow[2][col], pix, sizeof *image);
-    continue;
-      }
-      thold = gmin + (gmax >> 1);
-      memset (sum, 0, sizeof sum);
-      color = FC(row,col);
-      for (num=g=0; g < 8; g++,ip+=2) {     /* Average the neighbors */
-    if (gval[g] <= thold) {
-      FORC4
-        if (c == color && ip[1])
-          sum[c] += (pix[c] + pix[ip[1]]) >> 1;
-        else
-          sum[c] += pix[ip[0] + c];
-      num++;
+    for (row=1; row < height-1; row++) {  /* Do bilinear interpolation */
+        for (col=1; col < width-1; col++) {
+            pix = image[row*width+col];
+            ip = code[row & 7][col & 1];
+            memset (sum, 0, sizeof sum);
+            for (g=8; g--; ) {
+                diff = pix[*ip++];
+                diff <<= *ip++;
+                sum[*ip++] += diff;
+            }
+            for (g=colors; --g; ) {
+                c = *ip++;
+                pix[c] = sum[c] / *ip++;
+            }
+        }
     }
-      }
-      FORC4 {                   /* Save to buffer */
-    t = pix[color];
-    if (c != color) {
-      t += (sum[c] - sum[color])/num;
-      if (t < 0) t = 0;
-      if (t > clip_max) t = clip_max;
+    if (cmdline.quick_interpolate)
+        return;
+
+    for (row=0; row < 8; row++) {     /* Precalculate for VNG */
+        for (col=0; col < 2; col++) {
+            ip = code[row][col];
+            for (cp=terms, t=0; t < 64; t++) {
+                y1 = *cp++;  x1 = *cp++;
+                y2 = *cp++;  x2 = *cp++;
+                weight = *cp++;
+                grads = *cp++;
+                color = FC(row+y1,col+x1);
+                if (FC(row+y2,col+x2) != color) continue;
+                diag =
+                    (FC(row,col+1) == color && FC(row+1,col) == color) ? 2:1;
+                if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue;
+                *ip++ = (y1*width + x1)*4 + color;
+                *ip++ = (y2*width + x2)*4 + color;
+                *ip++ = weight;
+                for (g=0; g < 8; g++)
+                    if (grads & 1<<g) *ip++ = g;
+                *ip++ = -1;
+            }
+            *ip++ = INT_MAX;
+            for (cp=chood, g=0; g < 8; g++) {
+                y = *cp++;  x = *cp++;
+                *ip++ = (y*width + x) * 4;
+                color = FC(row,col);
+                if (FC(row+y,col+x) != color && FC(row+y*2,col+x*2) == color)
+                    *ip++ = (y*width + x) * 8 + color;
+                else
+                    *ip++ = 0;
+            }
+        }
     }
-    brow[2][col][c] = t;
-      }
+    brow[4] = calloc (width*3, sizeof **brow);
+    merror (brow[4], "vngInterpolate()");
+    for (row=0; row < 3; row++)
+        brow[row] = brow[4] + row*width;
+    for (row=2; row < height-2; row++) {      /* Do VNG interpolation */
+        for (col=2; col < width-2; col++) {
+            pix = image[row*width+col];
+            ip = code[row & 7][col & 1];
+            memset (gval, 0, sizeof gval);
+            while ((g = ip[0]) != INT_MAX) {      /* Calculate gradients */
+                num = (diff = pix[g] - pix[ip[1]]) >> 31;
+                gval[ip[3]] += (diff = ((diff ^ num) - num) << ip[2]);
+                ip += 5;
+                if ((g = ip[-1]) == -1) continue;
+                gval[g] += diff;
+                while ((g = *ip++) != -1)
+                    gval[g] += diff;
+            }
+            ip++;
+            gmin = gmax = gval[0];            /* Choose a threshold */
+            for (g=1; g < 8; g++) {
+                if (gmin > gval[g]) gmin = gval[g];
+                if (gmax < gval[g]) gmax = gval[g];
+            }
+            if (gmax == 0) {
+                memcpy (brow[2][col], pix, sizeof *image);
+                continue;
+            }
+            thold = gmin + (gmax >> 1);
+            memset (sum, 0, sizeof sum);
+            color = FC(row,col);
+            for (num=g=0; g < 8; g++,ip+=2) {     /* Average the neighbors */
+                if (gval[g] <= thold) {
+                    FORC4
+                        if (c == color && ip[1])
+                            sum[c] += (pix[c] + pix[ip[1]]) >> 1;
+                        else
+                            sum[c] += pix[ip[0] + c];
+                    num++;
+                }
+            }
+            FORC4 {                   /* Save to buffer */
+                t = pix[color];
+                if (c != color) {
+                    t += (sum[c] - sum[color])/num;
+                    if (t < 0) t = 0;
+                    if (t > clip_max) t = clip_max;
+                }
+                brow[2][col][c] = t;
+            }
+        }
+        if (row > 3)                /* Write buffer to image */
+            memcpy(image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
+        for (g=0; g < 4; g++)
+            brow[(g-1) & 3] = brow[g];
     }
-    if (row > 3)                /* Write buffer to image */
-      memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
-    for (g=0; g < 4; g++)
-      brow[(g-1) & 3] = brow[g];
-  }
-  memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
-  memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image);
-  free (brow[4]);
+    memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image);
+    memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image);
+    free (brow[4]);
 }
 
-#ifdef USE_LCMS
-static void 
-apply_profile(FILE *       const ifP,
-              const char * const pfname)
-{
-  char *prof;
-  cmsHPROFILE hInProfile=NULL, hOutProfile;
-  cmsHTRANSFORM hTransform;
-
-  if (pfname)
-    hInProfile = cmsOpenProfileFromFile (pfname, "r");
-  else if (profile_length) {
-    prof = malloc (profile_length);
-    merror (prof, "apply_profile()");
-    fseek (ifP, profile_offset, SEEK_SET);
-    fread (prof, 1, profile_length, ifP);
-    hInProfile = cmsOpenProfileFromMem (prof, profile_length);
-    free (prof);
-  }
-  if (!hInProfile) return;
-  if (cmdline.verbose)
-      pm_message( "Applying color profile...");
-  maximum = 0xffff;
-  use_gamma = use_coeff = 0;
-
-  hOutProfile = cmsCreate_sRGBProfile();
-  hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16,
-    hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0);
-  cmsDoTransform (hTransform, image, image, width*height);
-
-  cmsDeleteTransform (hTransform);
-  cmsCloseProfile (hInProfile);
-  cmsCloseProfile (hOutProfile);
-}
-#else
-static void 
-apply_profile(FILE *       const ifP,
-              const char * const pfname)
-{
-}
-#endif
 
-/*
+
+static void CLASS
+convertToRgb(Image        const image,
+             unsigned int const trim) {
+/*----------------------------------------------------------------------------
    Convert the entire image to RGB colorspace and build a histogram.
- */
-static void CLASS convert_to_rgb()
-{
-  int row, col, r, g, c=0;
-  unsigned short *img;
-  float rgb[3];
-
-  if (cmdline.document_mode)
-    colors = 1;
-  memset (histogram, 0, sizeof histogram);
-  for (row = trim; row < height-trim; row++)
-    for (col = trim; col < width-trim; col++) {
-      img = image[row*width+col];
-      if (cmdline.document_mode)
-    c = FC(row,col);
-      if (colors == 4 && !use_coeff)    /* Recombine the greens */
-    img[1] = (img[1] + img[3]) >> 1;
-      if (colors == 1)          /* RGB from grayscale */
-    for (r=0; r < 3; r++)
-      rgb[r] = img[c];
-      else if (use_coeff) {     /* RGB via coeff[][] */
-    for (r=0; r < 3; r++)
-      for (rgb[r]=g=0; g < colors; g++)
-        rgb[r] += img[g] * coeff[r][g];
-      } else                /* RGB from RGB (easy) */
-    goto norgb;
-      for (r=0; r < 3; r++) {
-    if (rgb[r] < 0)        rgb[r] = 0;
-    if (rgb[r] > clip_max) rgb[r] = clip_max;
-    img[r] = rgb[r];
-      }
-norgb:
-      for (r=0; r < 3; r++)
-    histogram[r][img[r] >> 3]++;
+
+   We modify 'image' to change it from whatever it is now to RGB.
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+    unsigned int c;
+    float rgb[3];  /* { red, green, blue } */
+
+    c = 0;  /* initial value */
+
+    if (cmdline.document_mode)
+        colors = 1;
+
+    memset(histogram, 0, sizeof histogram);
+
+    for (row = 0 + trim; row < height - trim; ++row) {
+        unsigned int col;
+        for (col = 0 + trim; col < width - trim; ++col) {
+            unsigned short * const img = image[row*width+col];
+
+            if (cmdline.document_mode)
+                c = FC(row,col);
+
+            if (colors == 4 && !use_coeff)
+                /* Recombine the greens */
+                img[1] = (img[1] + img[3]) / 2;
+
+            if (colors == 1) {
+                /* RGB from grayscale */
+                unsigned int i;
+                for (i = 0; i < 3; ++i)
+                    rgb[i] = img[c];
+            } else if (use_coeff) {
+                /* RGB via coeff[][] */
+                unsigned int i;
+                for (i = 0; i < 3; ++i) {
+                    unsigned int j;
+                    for (j = 0, rgb[i]= 0; j < colors; ++j)
+                        rgb[i] += img[j] * coeff[i][j];
+                }
+            } else {
+                /* RGB from RGB (easy) */
+                unsigned int i;
+                for (i = 0; i < 3; ++i)
+                    rgb[i] = img[i];
+            }
+            {
+                unsigned int i;
+                for (i = 0; i < 3; ++i)
+                    img[i] = MIN(clip_max, MAX(0, rgb[i]));
+            }
+            {
+                unsigned int i;
+                for (i = 0; i < 3; ++i)
+                    ++histogram[i][img[i] >> 3];
+            }
+        }
     }
 }
 
-static void CLASS fuji_rotate()
-{
-  int i, wide, high, row, col;
-  double step;
-  float r, c, fr, fc;
-  unsigned ur, uc;
-  unsigned short (*img)[4], (*pix)[4];
-
-  if (!fuji_width) return;
-  if (cmdline.verbose)
-    pm_message ("Rotating image 45 degrees...");
-  fuji_width = (fuji_width + shrink) >> shrink;
-  step = sqrt(0.5);
-  wide = fuji_width / step;
-  high = (height - fuji_width) / step;
-  img = calloc (wide*high, sizeof *img);
-  merror (img, "fuji_rotate()");
-
-  for (row=0; row < high; row++)
-    for (col=0; col < wide; col++) {
-      ur = r = fuji_width + (row-col)*step;
-      uc = c = (row+col)*step;
-      if (ur > height-2 || uc > width-2) continue;
-      fr = r - ur;
-      fc = c - uc;
-      pix = image + ur*width + uc;
-      for (i=0; i < colors; i++)
-    img[row*wide+col][i] =
-      (pix[    0][i]*(1-fc) + pix[      1][i]*fc) * (1-fr) +
-      (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr;
+
+
+static void CLASS
+fujiRotate(Image * const imageP) {
+
+    int wide;
+    int high;
+    unsigned int row;
+    double step;
+    float r, c, fr, fc;
+    unsigned short (*newImage)[4];
+    unsigned short (*pix)[4];
+
+    if (fuji_width > 0) {
+        if (cmdline.verbose)
+            pm_message ("Rotating image 45 degrees...");
+
+        fuji_width = (fuji_width + shrink) >> shrink;
+        step = sqrt(0.5);
+        wide = fuji_width / step;
+        high = (height - fuji_width) / step;
+        newImage = calloc (wide*high, sizeof *newImage);
+        merror (newImage, "fujiRotate()");
+
+        for (row = 0; row < high; ++row) {
+            unsigned int col;
+            for (col = 0; col < wide; ++col) {
+                unsigned int ur = r = fuji_width + (row-col)*step;
+                unsigned int uc = c = (row+col)*step;
+
+                unsigned int i;
+
+                if (ur > height-2 || uc > width-2)
+                    continue;
+
+                fr = r - ur;
+                fc = c - uc;
+                pix = (*imageP) + ur * width + uc;
+
+                for (i = 0; i < colors; ++i) {
+                    newImage[row*wide+col][i] =
+                        (pix[    0][i]*(1-fc) + pix[      1][i]*fc) * (1-fr) +
+                        (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr;
+                } 
+            }
+        }        
+        free(*imageP);
+        width  = wide;
+        height = high;
+        *imageP  = newImage;
+        fuji_width = 0;
     }
-  free (image);
-  width  = wide;
-  height = high;
-  image  = img;
-  fuji_width = 0;
 }
 
-static void CLASS flip_image()
-{
+
+
+static void CLASS
+flipImage(Image const image) {
+
     unsigned *flag;
-    int size, base, dest, next, row, col, temp;
+    int size, base, dest;
 
     struct imageCell {
         unsigned char contents[8];
     };
     struct imageCell * img;
-    struct imageCell hold;
 
     switch ((flip+3600) % 360) {
-    case 270:  flip = 5;  break;
-    case 180:  flip = 3;  break;
-    case  90:  flip = 6;
+    case 270:  flip = 0x5;  break;
+    case 180:  flip = 0x3;  break;
+    case  90:  flip = 0x6;
     }
     img = (struct imageCell *) image;
     size = height * width;
     flag = calloc ((size+31) >> 5, sizeof *flag);
-    merror (flag, "flip_image()");
-    for (base = 0; base < size; base++) {
-        if (flag[base >> 5] & (1 << (base & 31)))
-            continue;
-        dest = base;
-        hold = img[base];
-        while (1) {
-            if (flip & 4) {
-                row = dest % height;
-                col = dest / height;
-            } else {
-                row = dest / width;
-                col = dest % width;
+    merror (flag, "flipImage()");
+    for (base = 0; base < size; ++base) {
+        if (flag[base >> 5] & (1 << (base & 31))) {
+            /* nothing */
+        } else {
+            struct imageCell const hold = img[base];
+            dest = base;
+            while (true) {
+                unsigned int col;
+                unsigned int row;
+                int next;
+                if (flip & 0x4) {
+                    row = dest % height;
+                    col = dest / height;
+                } else {
+                    row = dest / width;
+                    col = dest % width;
+                }
+                if (flip & 0x2)
+                    row = height - 1 - row;
+                if (flip & 1)
+                    col = width - 1 - col;
+                next = row * width + col;
+                if (next == base)
+                    break;
+                flag[next >> 5] |= 1 << (next & 31);
+                img[dest] = img[next];
+                dest = next;
             }
-            if (flip & 2)
-                row = height - 1 - row;
-            if (flip & 1)
-                col = width - 1 - col;
-            next = row * width + col;
-            if (next == base) break;
-            flag[next >> 5] |= 1 << (next & 31);
-            img[dest] = img[next];
-            dest = next;
+            img[dest] = hold;
         }
-        img[dest] = hold;
     }
     free (flag);
-    if (flip & 4) {
-        temp = height;
+    if (flip & 0x4) {
+        int const oldHeight = height;
+        int const oldYmag = ymag;
+
         height = width;
-        width = temp;
-        temp = ymag;
+        width = oldHeight;
         ymag = xmag;
-        xmag = temp;
+        xmag = oldYmag;
     }
 }
 
-/*
-   Write the image as an RGB PAM image
- */
-static void CLASS write_pam_nonlinear (FILE *ofp)
-{
-  unsigned char lut[0x10000];
-  int perc, c, val, total, i, row, col;
-  float white=0, r;
-  struct pam pam;
-  tuple * tuplerow;
-
-  pam.size   = sizeof(pam);
-  pam.len    = PAM_STRUCT_SIZE(tuple_type);
-  pam.file   = ofp;
-  pam.width  = xmag*(width-trim*2);
-  pam.height = ymag*(height-trim*2);
-  pam.depth  = 3;
-  pam.format = PAM_FORMAT;
-  pam.maxval = 255;
-  strcpy(pam.tuple_type, "RGB");
-
-  pnm_writepaminit(&pam);
-
-  tuplerow = pnm_allocpamrow(&pam);
-
-  perc = width * height * 0.01;     /* 99th percentile white point */
-  if (fuji_width) perc /= 2;
-  FORC3 {
-    for (val=0x2000, total=0; --val > 32; )
-      if ((total += histogram[c][val]) > perc) break;
-    if (white < val) white = val;
-  }
-  white *= 8 / cmdline.bright;
-  for (i=0; i < 0x10000; i++) {
-    r = i / white;
-    val = 256 * ( !use_gamma ? r :
-    r <= 0.018 ? r*4.5 : pow(r,0.45)*1.099-0.099 );
-    if (val > 255) val = 255;
-    lut[i] = val;
-  }
-  for (row=trim; row < height-trim; row++) {
-      for (col=trim; col < width-trim; col++) {
-          unsigned int plane;
-          for (plane=0; plane < pam.depth; ++plane) {
-              unsigned int copy;
-              for (copy=0; copy < xmag; ++copy) {
-                  unsigned int const pamcol = xmag*(col-trim)+copy;
-                  tuplerow[pamcol][plane] = lut[image[row*width+col][plane]];
-              }
-          }
-      }
-      {
-          unsigned int copy;
-          for (copy=0; copy < ymag; ++copy)
-              pnm_writepamrow(&pam, tuplerow);
-      }
-  }
-  pnm_freepamrow(tuplerow);
+
+
+static void CLASS
+writePamLinear(FILE *       const ofP,
+               Image        const image,
+               unsigned int const trim) {
+/*----------------------------------------------------------------------------
+   Write the image 'image' to a 16-bit PAM file with linear color space
+-----------------------------------------------------------------------------*/
+    unsigned int row;
+
+    struct pam pam;
+    tuple * tuplerow;
+
+    pam.size   = sizeof(pam);
+    pam.len    = PAM_STRUCT_SIZE(tuple_type);
+    pam.file   = ofP;
+    pam.width  = width - trim - trim;
+    pam.height = height - trim - trim;
+    pam.depth  = 3;
+    pam.format = PAM_FORMAT;
+    pam.maxval = MAX(maximum, 256);
+    strcpy(pam.tuple_type, "RGB");
+
+    pnm_writepaminit(&pam);
+
+    tuplerow = pnm_allocpamrow(&pam);
+
+    for (row = 0 + trim; row < height - trim; ++row) {
+        unsigned int col;
+        for (col = 0 + trim; col < width - trim; ++col) {
+            unsigned int const pamCol = col - trim;
+            unsigned int plane;
+            for (plane = 0; plane < 3; ++plane)
+                tuplerow[pamCol][plane] = image[row*width+col][plane];
+        }
+        pnm_writepamrow(&pam, tuplerow);
+    }
+    pnm_freepamrow(tuplerow);
 }
 
-/*
-   Write the image to a 16-bit PAM file with linear color space
- */
-static void CLASS write_pam_linear (FILE *ofp)
-{
-  int row;
-
-  struct pam pam;
-  tuple * tuplerow;
-
-  if (maximum < 256) maximum = 256;
-
-  pam.size   = sizeof(pam);
-  pam.len    = PAM_STRUCT_SIZE(tuple_type);
-  pam.file   = ofp;
-  pam.width  = width-trim*2;
-  pam.height = height-trim*2;
-  pam.depth  = 3;
-  pam.format = PAM_FORMAT;
-  pam.maxval = MAX(maximum, 256);
-  strcpy(pam.tuple_type, "RGB");
-
-  pnm_writepaminit(&pam);
-
-  tuplerow = pnm_allocpamrow(&pam);
-
-  for (row = trim; row < height-trim; row++) {
-      unsigned int col;
-      for (col = trim; col < width-trim; col++) {
-          unsigned int const pamCol = col - trim;
-          unsigned int plane;
-          for (plane = 0; plane < 3; ++plane)
-              tuplerow[pamCol][plane] = image[row*width+col][plane];
-      }
-      pnm_writepamrow(&pam, tuplerow);
-  }
-  pnm_freepamrow(tuplerow);
+
+
+static void CLASS
+writePamNonlinear(FILE *       const ofP,
+                  Image        const image,
+                  unsigned int const trim) {
+/*----------------------------------------------------------------------------
+  Write the image 'image' as an RGB PAM image
+-----------------------------------------------------------------------------*/
+    unsigned char lut[0x10000];
+    int perc;
+    int c;
+    int total;
+    int i;
+    unsigned int row;
+    float white;
+    float r;
+    struct pam pam;
+    tuple * tuplerow;
+
+    white = 0;  /* initial value */
+
+    pam.size   = sizeof(pam);
+    pam.len    = PAM_STRUCT_SIZE(tuple_type);
+    pam.file   = ofP;
+    pam.width  = xmag*(width-trim*2);
+    pam.height = ymag*(height-trim*2);
+    pam.depth  = 3;
+    pam.format = PAM_FORMAT;
+    pam.maxval = 255;
+    strcpy(pam.tuple_type, "RGB");
+
+    pnm_writepaminit(&pam);
+
+    tuplerow = pnm_allocpamrow(&pam);
+
+    perc = width * height * 0.01;     /* 99th percentile white point */
+    if (fuji_width) perc /= 2;
+    FORC3 {
+        int val;
+        for (val=0x2000, total=0; --val > 32; )
+            if ((total += histogram[c][val]) > perc) break;
+        if (white < val)
+            white = val;
+    }
+    white *= 8 / cmdline.bright;
+    for (i=0; i < 0x10000; ++i) {
+        int val;
+        r = i / white;
+        val = 256 * ( !use_gamma ? r :
+                      r <= 0.018 ? r*4.5 : pow(r,0.45)*1.099-0.099 );
+        lut[i] = MIN(255, val);
+    }
+
+    for (row = 0 + trim; row < height - trim; ++row) {
+        unsigned int col;
+        for (col = 0 + trim; col < width - trim; ++col) {
+            unsigned int plane;
+            for (plane = 0; plane < pam.depth; ++plane) {
+                sample const value = lut[image[row*width+col][plane]];
+                unsigned int copy;
+                for (copy = 0; copy < xmag; ++copy) {
+                    unsigned int const pamcol = xmag*(col-trim)+copy;
+                    tuplerow[pamcol][plane] = value;
+                }
+            }
+        }
+        {
+            unsigned int copy;
+            for (copy = 0; copy < ymag; ++copy)
+                pnm_writepamrow(&pam, tuplerow);
+        }
+    }
+    pnm_freepamrow(tuplerow);
 }
 
 
 
 static void CLASS
-writePam(FILE * const ofP,
-         bool   const linear) {
+writePam(FILE *       const ofP,
+         Image        const image,
+         bool         const linear,
+         unsigned int const trim) {
 
     if (linear)
-        write_pam_linear(ofP);
+        writePamLinear(ofP, image, trim);
     else
-        write_pam_nonlinear(ofP);
+        writePamNonlinear(ofP, image, trim);
 }
 
 
 
-
 static void CLASS
-convertIt(FILE *    const ifP,
-          FILE *    const ofP,
-          loadRawFn const load_raw) {
+convertIt(FILE *       const ifP,
+          FILE *       const ofP,
+          LoadRawFn *  const load_raw) {
+
+    Image image;
+    unsigned int trim;
 
     shrink = cmdline.half_size && filters;
     iheight = (height + shrink) >> shrink;
     iwidth  = (width  + shrink) >> shrink;
-    image = calloc (iheight*iwidth*sizeof *image + meta_length, 1);
+    image = calloc (iheight*iwidth*sizeof(*image) + meta_length, 1);
     merror (image, "main()");
     meta_data = (char *) (image + iheight*iwidth);
     if (cmdline.verbose)
@@ -807,43 +887,49 @@ convertIt(FILE *    const ifP,
 
     ifp = ifP;  /* Set global variable for (*load_raw)() */
 
-    load_raw();
-    bad_pixels();
+    load_raw(image);
+    fixBadPixels(image);
     height = iheight;
     width  = iwidth;
     if (is_foveon) {
         if (cmdline.verbose)
             pm_message ("Foveon interpolation...");
-        foveon_interpolate(coeff);
+        foveon_interpolate(image, coeff);
     } else {
-        scale_colors();
+        scaleColors(image);
     }
-    if (shrink) filters = 0;
-    trim = 0;
+    if (shrink)
+        filters = 0;
+
     if (filters && !cmdline.document_mode) {
         trim = 1;
         if (cmdline.verbose)
             pm_message ("%s interpolation...",
                         cmdline.quick_interpolate ? "Bilinear":"VNG");
-        vng_interpolate();
-    }
-    fuji_rotate();
-    apply_profile(ifP, cmdline.profile);
+        vngInterpolate(image);
+    } else
+        trim = 0;
+
+    fujiRotate(&image);
+
     if (cmdline.verbose)
         pm_message ("Converting to RGB colorspace...");
-    convert_to_rgb();
+    convertToRgb(image, trim);
 
     if (flip) {
         if (cmdline.verbose)
             pm_message ("Flipping image %c:%c:%c...",
                         flip & 1 ? 'H':'0', flip & 2 ? 'V':'0', 
                         flip & 4 ? 'T':'0');
-        flip_image();
+        flipImage(image);
     }
-    writePam(ofP, cmdline.linear);
+    writePam(ofP, image, cmdline.linear, trim);
+
+    free(image);
 }
 
 
+
 int 
 main (int argc, char **argv) {
 
@@ -851,7 +937,7 @@ main (int argc, char **argv) {
 
     FILE * ifP;
     int rc;
-    loadRawFn load_raw;
+    LoadRawFn * load_raw;
 
     pnm_init(&argc, argv);
 
@@ -861,8 +947,6 @@ main (int argc, char **argv) {
 
     ifP = pm_openr(cmdline.inputFileName);
 
-    image = NULL;
-    
     rc = identify(ifP,
                   cmdline.use_secondary, cmdline.use_camera_rgb,
                   cmdline.red_scale, cmdline.blue_scale,
@@ -881,7 +965,6 @@ main (int argc, char **argv) {
     }
     pm_close(ifP);
     pm_close(ofP);
-    free(image);
 
     return 0;
 }
diff --git a/converter/other/cameratopam/cameratopam.h b/converter/other/cameratopam/cameratopam.h
new file mode 100644
index 00000000..9ff33cb3
--- /dev/null
+++ b/converter/other/cameratopam/cameratopam.h
@@ -0,0 +1,6 @@
+#ifndef CAMERATOPAM_H_INCLUDED
+#define CAMERATOPAM_H_INCLUDED
+
+typedef unsigned short (*Image)[4];
+
+#endif
diff --git a/converter/other/cameratopam/canon.c b/converter/other/cameratopam/canon.c
index a34771d0..96a6210b 100644
--- a/converter/other/cameratopam/canon.c
+++ b/converter/other/cameratopam/canon.c
@@ -9,7 +9,7 @@
 
 
 void 
-canon_600_load_raw(void) {
+canon_600_load_raw(Image const image) {
     unsigned char  data[1120], *dp;
     unsigned short pixel[896], *pix;
     int irow, orow, col;
@@ -42,7 +42,7 @@ canon_600_load_raw(void) {
 
 
 void
-canon_a5_load_raw(void) {
+canon_a5_load_raw(Image const image) {
     unsigned char  data[1940], *dp;
     unsigned short pixel[1552], *pix;
     int row, col;
@@ -97,7 +97,7 @@ canon_has_lowbits()
 
 
 void 
-canon_compressed_load_raw(void) {
+canon_compressed_load_raw(Image const image) {
     unsigned short *pixel, *prow;
     int lowbits, i, row, r, col, save, val;
     unsigned irow, icol;
diff --git a/converter/other/cameratopam/canon.h b/converter/other/cameratopam/canon.h
index 041cdc4d..fe6a5a08 100644
--- a/converter/other/cameratopam/canon.h
+++ b/converter/other/cameratopam/canon.h
@@ -1,13 +1,12 @@
 #ifndef CANON_H_INCLUDED
 #define CANON_H_INCLUDED
 
-void 
-canon_600_load_raw(void);
+#include "camera.h"
 
-void
-canon_a5_load_raw(void);
+LoadRawFn canon_600_load_raw;
 
-void 
-canon_compressed_load_raw(void);
+LoadRawFn canon_a5_load_raw;
+
+LoadRawFn canon_compressed_load_raw;
 
 #endif
diff --git a/converter/other/cameratopam/dng.c b/converter/other/cameratopam/dng.c
index 44d45b02..bddfd9f4 100644
--- a/converter/other/cameratopam/dng.c
+++ b/converter/other/cameratopam/dng.c
@@ -4,70 +4,105 @@
 #include "dng.h"
 
 void 
-dng_coeff (double cc[4][4], double cm[4][3], double xyz[3])
-{
-  static const double rgb_xyz[3][3] = {     /* RGB from XYZ */
-    {  3.240479, -1.537150, -0.498535 },
-    { -0.969256,  1.875992,  0.041556 },
-    {  0.055648, -0.204043,  1.057311 } };
+dng_coeff (double cc[4][4],
+           double cm[4][3],
+           double xyz[3]) {
+    static const double rgb_xyz[3][3] = {     /* RGB from XYZ */
+        {  3.240479, -1.537150, -0.498535 },
+        { -0.969256,  1.875992,  0.041556 },
+        {  0.055648, -0.204043,  1.057311 } };
 #if 0
-  static const double xyz_rgb[3][3] = {     /* XYZ from RGB */
-    { 0.412453, 0.357580, 0.180423 },
-    { 0.212671, 0.715160, 0.072169 },
-    { 0.019334, 0.119193, 0.950227 } };
+    static const double xyz_rgb[3][3] = {     /* XYZ from RGB */
+        { 0.412453, 0.357580, 0.180423 },
+        { 0.212671, 0.715160, 0.072169 },
+        { 0.019334, 0.119193, 0.950227 } };
 #endif
-  double cam_xyz[4][3], xyz_cam[3][4], invert[3][6], num;
-  int i, j, k;
+    double cam_xyz[4][3], xyz_cam[3][4], invert[3][6];
+    unsigned int i;
 
-  memset (cam_xyz, 0, sizeof cam_xyz);
-  for (i=0; i < colors; i++)
-    for (j=0; j < 3; j++)
-      for (k=0; k < colors; k++)
-    cam_xyz[i][j] += cc[i][k] * cm[k][j] * xyz[j];
+    for (i = 0; i < colors; ++i) {
+        unsigned int j;
+        for (j = 0; j < 3; ++j) {
+            unsigned int k;
+            for (k = 0, cam_xyz[i][j] = 0.0; k < colors; ++k) {
+                cam_xyz[i][j] += cc[i][k] * cm[k][j] * xyz[j];
+            }
+        }
+    }
+    for (i = 0; i < colors; ++i) {
+        unsigned int j;
+        double camXyzSum;
+
+        for (j = 0, camXyzSum = 0.0; j < 3; ++j)
+            camXyzSum += cam_xyz[i][j];
 
-  for (i=0; i < colors; i++) {
-    for (num=j=0; j < 3; j++)
-      num += cam_xyz[i][j];
-    for (j=0; j < 3; j++)
-      cam_xyz[i][j] /= num;
-    pre_mul[i] = 1 / num;
-  }
-  for (i=0; i < 3; i++) {
-    for (j=0; j < 6; j++)
-      invert[i][j] = j == i+3;
-    for (j=0; j < 3; j++)
-      for (k=0; k < colors; k++)
-    invert[i][j] += cam_xyz[k][i] * cam_xyz[k][j];
-  }
-  for (i=0; i < 3; i++) {
-    num = invert[i][i];
-    for (j=0; j < 6; j++)       /* Normalize row i */
-      invert[i][j] /= num;
-    for (k=0; k < 3; k++) {     /* Subtract it from other rows */
-      if (k==i) continue;
-      num = invert[k][i];
-      for (j=0; j < 6; j++)
-    invert[k][j] -= invert[i][j] * num;
+        for (j = 0; j < 3; ++j)
+            cam_xyz[i][j] /= camXyzSum;
+
+        pre_mul[i] = 1 / camXyzSum;
+    }
+    for (i = 0; i < 3; ++i) {
+        unsigned int j;
+        for (j = 0; j < 6; ++j)
+            invert[i][j] = j == i+3;
+        for (j = 0; j < 3; ++j) {
+            unsigned int k;
+            for (k = 0; k < colors; ++k)
+                invert[i][j] += cam_xyz[k][i] * cam_xyz[k][j];
+        }
     }
-  }
-  memset (xyz_cam, 0, sizeof xyz_cam);
-  for (i=0; i < 3; i++)
-    for (j=0; j < colors; j++)
-      for (k=0; k < 3; k++)
-    xyz_cam[i][j] += invert[i][k+3] * cam_xyz[j][k];
+    for (i = 0; i < 3; ++i) {
+        double const num = invert[i][i];
+        unsigned int j;
+        unsigned int k;
+        for (j = 0; j < 6; ++j)       /* Normalize row i */
+            invert[i][j] /= num;
+        for (k = 0; k < 3; ++k) {     /* Subtract it from other rows */
+            if (k != i) {
+                double const num = invert[k][i];
+                unsigned int j;
+                for (j = 0; j < 6; ++j)
+                    invert[k][j] -= invert[i][j] * num;
+            }
+        }
+    }
+
+    memset(xyz_cam, 0, sizeof xyz_cam);
 
-  memset (coeff, 0, sizeof coeff);
-  for (i=0; i < 3; i++)
-    for (j=0; j < colors; j++)
-      for (k=0; k < 3; k++)
-    coeff[i][j] += rgb_xyz[i][k] * xyz_cam[k][j];
+    for (i = 0; i < 3; ++i) {
+        unsigned int j;
+        for (j = 0; j < colors; ++j) {
+            unsigned int k;
+            for (k = 0; k < 3; ++k)
+                xyz_cam[i][j] += invert[i][k+3] * cam_xyz[j][k];
+        }
+    }
+    memset (coeff, 0, sizeof coeff);
 
-  for (num=j=0; j < colors; j++)
-    num += coeff[1][j];
-  for (i=0; i < 3; i++) {
-    for (j=0; j < colors; j++)
-      coeff[i][j] /= num;
-  }
-  use_coeff = 1;
+    for (i = 0; i < 3; ++i) {
+        unsigned int j;
+        for (j = 0; j < colors; ++j) {
+            unsigned int k;
+            for (k = 0; k < 3; ++k)
+                coeff[i][j] += rgb_xyz[i][k] * xyz_cam[k][j];
+        }
+    }
+    {
+        double greenSum;
+        unsigned int j;
+        unsigned int i;
+
+        for (j = 0, greenSum = 0.0; j < colors; ++j)
+            greenSum += coeff[1][j];
+
+        for (i = 0; i < 3; ++i) {
+            unsigned int j;
+            for (j = 0; j < colors; ++j)
+                coeff[i][j] /= greenSum;
+        }
+    }
+    use_coeff = 1;
 }
 
+
+
diff --git a/converter/other/cameratopam/dng.h b/converter/other/cameratopam/dng.h
index 01e7e0a5..56293563 100644
--- a/converter/other/cameratopam/dng.h
+++ b/converter/other/cameratopam/dng.h
@@ -1,2 +1,4 @@
 void 
-dng_coeff (double cc[4][4], double cm[4][3], double xyz[3]);
+dng_coeff(double cc[4][4],
+          double cm[4][3],
+          double xyz[3]);
diff --git a/converter/other/cameratopam/foveon.c b/converter/other/cameratopam/foveon.c
index a8d62bee..a3e5449a 100644
--- a/converter/other/cameratopam/foveon.c
+++ b/converter/other/cameratopam/foveon.c
@@ -141,8 +141,8 @@ parse_foveon(FILE * const ifp) {
 
 
 void  
-foveon_coeff(bool * const useCoeffP,
-             float        coeff[3][4]) {
+foveon_coeff(int * const useCoeffP,
+             float       coeff[3][4]) {
 
     static const float foveon[3][3] =
     { {  1.4032, -0.2231, -0.1016 },
@@ -211,7 +211,7 @@ foveon_load_camf() {
 
 
 void  
-foveon_load_raw() {
+foveon_load_raw(Image const image) {
 
     struct decode *dindex;
     short diff[1024], pred[3];
@@ -391,7 +391,8 @@ static int  foveon_apply_curve (short *curve, int i)
 }
 
 void  
-foveon_interpolate(float coeff[3][4]) {
+foveon_interpolate(Image const image,
+                   float coeff[3][4]) {
 
     static const short hood[] = { 
         -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 };
@@ -472,18 +473,22 @@ foveon_interpolate(float coeff[3][4]) {
     sgrow = calloc (dim[1], sizeof *sgrow);
     sgx = (width + dim[1]-2) / (dim[1]-1);
 
-    black = calloc (height, sizeof *black);
-    for (row=0; row < height; row++) {
-        for (i=0; i < 6; i++)
-            ddft[0][0][i] = ddft[1][0][i] +
-                row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]);
+    black = calloc (height, sizeof(black[0]));
+    for (row=0; row < height; ++row) {
+        unsigned int i;
+        for (i=0; i < 3; ++i) {
+            unsigned int j;
+            for (j = 0; j < 2; ++j)
+                ddft[0][i][j] = ddft[1][i][j] +
+                    row / (height-1.0) * (ddft[2][i][j] - ddft[1][i][j]);
+        }
         FORC3 black[row][c] =
             ( foveon_avg (image[row*width]+c, dscr[0], cfilt) +
               foveon_avg (image[row*width]+c, dscr[1], cfilt) * 3
               - ddft[0][c][0] ) / 4 - ddft[0][c][1];
     }
-    memcpy (black, black+8, sizeof (*black)*8);
-    memcpy (black+height-11, black+height-22, 11*sizeof *black);
+    memcpy (black, black+8, 8 * sizeof(black[0]));
+    memcpy (black+height-11, black+height-22, 11*(sizeof black[0]));
     memcpy (last, black, sizeof last);
 
     for (row=1; row < height-1; row++) {
@@ -522,9 +527,13 @@ foveon_interpolate(float coeff[3][4]) {
         FORC3 black[row][c] += fsum[c]/2 + total[c]/(total[3]*100.0);
 
     for (row=0; row < height; row++) {
-        for (i=0; i < 6; i++)
-            ddft[0][0][i] = ddft[1][0][i] +
-                row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]);
+        unsigned int i;
+        for (i = 0; i < 3; ++i) {
+            unsigned int j;
+            for (j = 0; j < 2; ++j)
+                ddft[0][i][j] = ddft[1][i][j] +
+                    row / (height-1.0) * (ddft[2][i][j] - ddft[1][i][j]);
+        }
         pix = (short*)image[row*width];
         memcpy (prev, pix, sizeof prev);
         frow = row / (height-1.0) * (dim[2]-1);
diff --git a/converter/other/cameratopam/foveon.h b/converter/other/cameratopam/foveon.h
index 57be2244..c9bf48a8 100644
--- a/converter/other/cameratopam/foveon.h
+++ b/converter/other/cameratopam/foveon.h
@@ -1,14 +1,17 @@
 #include "pm.h"
 
+#include "cameratopam.h"
+#include "camera.h"
+
 void 
 parse_foveon(FILE * const ifp);
 
 void  
-foveon_interpolate(float coeff[3][4]);
+foveon_interpolate(Image const image,
+                   float coeff[3][4]);
 
-void 
-foveon_load_raw(void);
+LoadRawFn foveon_load_raw;
 
 void  
-foveon_coeff(bool * const useCoeffP,
-             float        coeff[3][4]);
+foveon_coeff(int * const useCoeffP,
+             float       coeff[3][4]);
diff --git a/converter/other/cameratopam/global_variables.h b/converter/other/cameratopam/global_variables.h
index c8732d5a..2bfc08c9 100644
--- a/converter/other/cameratopam/global_variables.h
+++ b/converter/other/cameratopam/global_variables.h
@@ -23,7 +23,6 @@ extern time_t timestamp;
 extern int is_foveon;
 extern int is_dng;
 extern int is_canon;
-extern unsigned short (*image)[4];
 extern int maximum;
 extern int clip_max;
 extern short order;
diff --git a/converter/other/cameratopam/identify.c b/converter/other/cameratopam/identify.c
index a101c8ad..02208be6 100644
--- a/converter/other/cameratopam/identify.c
+++ b/converter/other/cameratopam/identify.c
@@ -2,6 +2,8 @@
 #include <string.h>
 
 #include "pm.h"
+#include "pm_c_util.h"
+#include "nstring.h"
 
 #include "global_variables.h"
 #include "util.h"
@@ -15,235 +17,250 @@
 
 
 #if HAVE_INT64
-   static bool const have64BitArithmetic = true;
+static bool const have64BitArithmetic = true;
 #else
-   static bool const have64BitArithmetic = false;
+static bool const have64BitArithmetic = false;
 #endif
 
 
-static loadRawFn load_raw;
 
 /* This does the same as the function of the same name in the GNU C library */
 static const char *memmem_internal (const char *haystack, size_t haystacklen,
-                     const char *needle, size_t needlelen)
+                                    const char *needle, size_t needlelen)
 {
-  const char *c;
-  for (c = haystack; c <= haystack + haystacklen - needlelen; c++)
-    if (!memcmp (c, needle, needlelen))
-      return c;
-  return NULL;
+    const char *c;
+    for (c = haystack; c <= haystack + haystacklen - needlelen; c++)
+        if (!memcmp (c, needle, needlelen))
+            return c;
+    return NULL;
 }
 
-/*
-   Thanks to Adobe for providing these excellent CAM -> XYZ matrices!
- */
+
+
 static void 
-adobe_coeff()
-{
-  static const struct {
-    const char *prefix;
-    short trans[12];
-  } table[] = {
-    { "Canon EOS D2000C",
-    { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } },
-    { "Canon EOS D30",
-    { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } },
-    { "Canon EOS D60",
-    { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } },
-    { "Canon EOS 10D",
-    { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
-    { "Canon EOS 20D",
-    { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } },
-    { "Canon EOS-1Ds Mark II",
-    { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } },
-    { "Canon EOS-1D Mark II",
-    { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } },
-    { "Canon EOS-1DS",
-    { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } },
-    { "Canon EOS-1D",
-    { 6906,-278,-1017,-6649,15074,1621,-2848,3897,7611 } },
-    { "Canon EOS",
-    { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
-    { "Canon PowerShot 600",
-    { -3822,10019,1311,4085,-157,3386,-5341,10829,4812,-1969,10969,1126 } },
-    { "Canon PowerShot A50",
-    { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } },
-    { "Canon PowerShot A5",
-    { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } },
-    { "Canon PowerShot G1",
-    { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } },
-    { "Canon PowerShot G2",
-    { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } },
-    { "Canon PowerShot G3",
-    { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } },
-    { "Canon PowerShot G5",
-    { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } },
-    { "Canon PowerShot G6",
-    { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } },
-    { "Canon PowerShot Pro1",
-    { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } },
-    { "Canon PowerShot Pro70",
-    { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } },
-    { "Canon PowerShot Pro90",
-    { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } },
-    { "Canon PowerShot S30",
-    { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } },
-    { "Canon PowerShot S40",
-    { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } },
-    { "Canon PowerShot S45",
-    { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } },
-    { "Canon PowerShot S50",
-    { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } },
-    { "Canon PowerShot S70",
-    { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } },
-    { "Contax N Digital",
-    { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } },
-    { "EPSON R-D1",
-    { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } },
-    { "FUJIFILM FinePix E550",
-    { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } },
-    { "FUJIFILM FinePix F700",
-    { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
-    { "FUJIFILM FinePix S20Pro",
-    { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
-    { "FUJIFILM FinePix S2Pro",
-    { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } },
-    { "FUJIFILM FinePix S3Pro",
-    { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } },
-    { "FUJIFILM FinePix S5000",
-    { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } },
-    { "FUJIFILM FinePix S5100",
-    { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } },
-    { "FUJIFILM FinePix S7000",
-    { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } },
-    { "Kodak DCS315C",
-    { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } },
-    { "Kodak DCS330C",
-    { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } },
-    { "KODAK DCS420",
-    { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } },
-    { "KODAK DCS460",
-    { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
-    { "KODAK EOSDCS1",
-    { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
-    { "KODAK EOSDCS3B",
-    { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } },
-    { "Kodak DCS520C",
-    { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } },
-    { "Kodak DCS560C",
-    { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } },
-    { "Kodak DCS620C",
-    { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } },
-    { "Kodak DCS620X",
-    { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } },
-    { "Kodak DCS660C",
-    { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } },
-    { "Kodak DCS720X",
-    { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } },
-    { "Kodak DCS760C",
-    { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } },
-    { "Kodak DCS Pro SLR",
-    { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } },
-    { "Kodak DCS Pro 14nx",
-    { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } },
-    { "Kodak DCS Pro 14",
-    { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } },
-    { "Kodak ProBack645",
-    { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } },
-    { "Kodak ProBack",
-    { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } },
-    { "LEICA DIGILUX 2",
-    { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } },
-    { "Leaf Valeo",
-    { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } },
-    { "Minolta DiMAGE 5",
-    { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } },
-    { "Minolta DiMAGE 7",
-    { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } },
-    { "Minolta DiMAGE A1",
-    { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } },
-    { "MINOLTA DiMAGE A200",
-    { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } },
-    { "Minolta DiMAGE A2",
-    { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } },
-    { "MINOLTA DYNAX 7D",
-    { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } },
-    { "NIKON D100",
-    { 5915,-949,-778,-7516,15364,2282,-1228,1337,6404 } },
-    { "NIKON D1H",
-    { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } },
-    { "NIKON D1X",
-    { 7620,-2173,-966,-7604,15843,1805,-2356,2811,8439 } },
-    { "NIKON D1",
-    { 7559,-2130,-965,-7611,15713,1972,-2478,3042,8290 } },
-    { "NIKON D2H",
-    { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } },
-    { "NIKON D70",
-    { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } },
-    { "NIKON E995", /* copied from E5000 */
-    { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
-    { "NIKON E2500",
-    { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
-    { "NIKON E4500",
-    { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
-    { "NIKON E5000",
-    { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
-    { "NIKON E5400",
-    { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } },
-    { "NIKON E5700",
-    { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } },
-    { "NIKON E8400",
-    { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } },
-    { "NIKON E8700",
-    { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } },
-    { "NIKON E8800",
-    { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } },
-    { "OLYMPUS C5050",
-    { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } },
-    { "OLYMPUS C5060",
-    { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } },
-    { "OLYMPUS C70",
-    { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } },
-    { "OLYMPUS C80",
-    { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } },
-    { "OLYMPUS E-10",
-    { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } },
-    { "OLYMPUS E-1",
-    { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } },
-    { "OLYMPUS E-20",
-    { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } },
-    { "OLYMPUS E-300",
-    { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } },
-    { "PENTAX *ist D",
-    { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } },
-    { "Panasonic DMC-LC1",
-    { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } },
-    { "SONY DSC-F828",
-    { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } },
-    { "SONY DSC-V3",
-    { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }
-  };
-  double cc[4][4], cm[4][3], xyz[] = { 1,1,1 };
-  char name[130];
-  int i, j;
+adobeCoeff(const char * const make,
+           const char * const model) {
+    /*
+      Thanks to Adobe for providing these excellent CAM -> XYZ matrices!
+    */
+    struct CoeffTableEntry {
+        const char * prefix;
+        short trans[12];
+    }; 
+
+    static struct CoeffTableEntry const table[] = {
+        { "Canon EOS D2000C",
+          { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } },
+        { "Canon EOS D30",
+          { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } },
+        { "Canon EOS D60",
+          { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } },
+        { "Canon EOS 10D",
+          { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
+        { "Canon EOS 20D",
+          { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } },
+        { "Canon EOS-1Ds Mark II",
+          { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } },
+        { "Canon EOS-1D Mark II",
+          { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } },
+        { "Canon EOS-1DS",
+          { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } },
+        { "Canon EOS-1D",
+          { 6906,-278,-1017,-6649,15074,1621,-2848,3897,7611 } },
+        { "Canon EOS",
+          { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
+        { "Canon PowerShot 600",
+          { -3822,10019,1311,4085,-157,3386,-5341,10829,4812,-1969,10969,
+            1126} },
+        { "Canon PowerShot A50",
+          { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } },
+        { "Canon PowerShot A5",
+          { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547} },
+        { "Canon PowerShot G1",
+          { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557} },
+        { "Canon PowerShot G2",
+          { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } },
+        { "Canon PowerShot G3",
+          { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } },
+        { "Canon PowerShot G5",
+          { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } },
+        { "Canon PowerShot G6",
+          { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } },
+        { "Canon PowerShot Pro1",
+          { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } },
+        { "Canon PowerShot Pro70",
+          { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } },
+        { "Canon PowerShot Pro90",
+          { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577} },
+        { "Canon PowerShot S30",
+          { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } },
+        { "Canon PowerShot S40",
+          { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } },
+        { "Canon PowerShot S45",
+          { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } },
+        { "Canon PowerShot S50",
+          { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } },
+        { "Canon PowerShot S70",
+          { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } },
+        { "Contax N Digital",
+          { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } },
+        { "EPSON R-D1",
+          { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } },
+        { "FUJIFILM FinePix E550",
+          { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } },
+        { "FUJIFILM FinePix F700",
+          { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
+        { "FUJIFILM FinePix S20Pro",
+          { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
+        { "FUJIFILM FinePix S2Pro",
+          { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } },
+        { "FUJIFILM FinePix S3Pro",
+          { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } },
+        { "FUJIFILM FinePix S5000",
+          { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } },
+        { "FUJIFILM FinePix S5100",
+          { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } },
+        { "FUJIFILM FinePix S7000",
+          { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } },
+        { "Kodak DCS315C",
+          { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } },
+        { "Kodak DCS330C",
+          { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } },
+        { "KODAK DCS420",
+          { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } },
+        { "KODAK DCS460",
+          { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
+        { "KODAK EOSDCS1",
+          { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
+        { "KODAK EOSDCS3B",
+          { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } },
+        { "Kodak DCS520C",
+          { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } },
+        { "Kodak DCS560C",
+          { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } },
+        { "Kodak DCS620C",
+          { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } },
+        { "Kodak DCS620X",
+          { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } },
+        { "Kodak DCS660C",
+          { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } },
+        { "Kodak DCS720X",
+          { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } },
+        { "Kodak DCS760C",
+          { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } },
+        { "Kodak DCS Pro SLR",
+          { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } },
+        { "Kodak DCS Pro 14nx",
+          { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } },
+        { "Kodak DCS Pro 14",
+          { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } },
+        { "Kodak ProBack645",
+          { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } },
+        { "Kodak ProBack",
+          { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } },
+        { "LEICA DIGILUX 2",
+          { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } },
+        { "Leaf Valeo",
+          { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } },
+        { "Minolta DiMAGE 5",
+          { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } },
+        { "Minolta DiMAGE 7",
+          { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } },
+        { "Minolta DiMAGE A1",
+          { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } },
+        { "MINOLTA DiMAGE A200",
+          { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } },
+        { "Minolta DiMAGE A2",
+          { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } },
+        { "MINOLTA DYNAX 7D",
+          { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } },
+        { "NIKON D100",
+          { 5915,-949,-778,-7516,15364,2282,-1228,1337,6404 } },
+        { "NIKON D1H",
+          { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } },
+        { "NIKON D1X",
+          { 7620,-2173,-966,-7604,15843,1805,-2356,2811,8439 } },
+        { "NIKON D1",
+          { 7559,-2130,-965,-7611,15713,1972,-2478,3042,8290 } },
+        { "NIKON D2H",
+          { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } },
+        { "NIKON D70",
+          { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } },
+        { "NIKON E995", /* copied from E5000 */
+          { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+        { "NIKON E2500",
+          { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+        { "NIKON E4500",
+          { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+        { "NIKON E5000",
+          { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
+        { "NIKON E5400",
+          { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } },
+        { "NIKON E5700",
+          { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } },
+        { "NIKON E8400",
+          { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } },
+        { "NIKON E8700",
+          { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } },
+        { "NIKON E8800",
+          { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } },
+        { "OLYMPUS C5050",
+          { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } },
+        { "OLYMPUS C5060",
+          { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } },
+        { "OLYMPUS C70",
+          { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } },
+        { "OLYMPUS C80",
+          { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } },
+        { "OLYMPUS E-10",
+          { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } },
+        { "OLYMPUS E-1",
+          { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } },
+        { "OLYMPUS E-20",
+          { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } },
+        { "OLYMPUS E-300",
+          { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } },
+        { "PENTAX *ist D",
+          { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } },
+        { "Panasonic DMC-LC1",
+          { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } },
+        { "SONY DSC-F828",
+          { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,
+            3481} },
+        { "SONY DSC-V3",
+          { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }
+    };
+    double cc[4][4];
+    double cm[4][3];
+    double xyz[] = { 1,1,1 };
+    char name[130];
+    unsigned int i;
 
-  for (i=0; i < 4; i++)
-    for (j=0; j < 4; j++)
-      cc[i][j] = i == j;
-  sprintf (name, "%s %s", make, model);
-  for (i=0; i < sizeof table / sizeof *table; i++)
-    if (!strncmp (name, table[i].prefix, strlen(table[i].prefix))) {
-      for (j=0; j < 12; j++)
-    cm[0][j] = table[i].trans[j];
-      dng_coeff (cc, cm, xyz);
-      break;
+    /* Make an identity matrix (1's on the diagonal) */
+    for (i = 0; i < 4; ++i) {
+        unsigned int j;
+        for (j = 0; j < 4; ++j)
+            cc[i][j] = (i == j);
+    }
+    sprintf (name, "%s %s", make, model);
+
+    for (i = 0; i < ARRAY_SIZE(table); ++i) {
+        const struct CoeffTableEntry * const entryP = &table[i];
+
+        if (strneq(name, entryP->prefix, strlen(entryP->prefix))) {
+            unsigned int j;
+            for (j = 0; j < 12; ++j)
+                cm[j/3][j%3] = entryP->trans[j];
+            dng_coeff(cc, cm, xyz);
+
+            break;
+        }
     }
 }
 
-/*
-   Identify which camera created this file, and set global variables
-   accordingly.  Return nonzero if the file cannot be decoded.
- */
+
+
+
 int
 identify(FILE *       const ifp,
          bool         const use_secondary,
@@ -252,932 +269,937 @@ identify(FILE *       const ifp,
          float        const blue_scale,
          unsigned int const four_color_rgb,
          const char * const inputFileName,
-         loadRawFn *  const loadRawFnP)
-{
-  char head[32];
-  char * c;
-  unsigned hlen, fsize, i;
-  static const struct {
-    int fsize;
-    char make[12], model[15], withjpeg;
-  } table[] = {
-    {    62464, "Kodak",    "DC20"       ,0 },
-    {   124928, "Kodak",    "DC20"       ,0 },
-    {   311696, "ST Micro", "STV680 VGA" ,0 },  /* SPYz */
-    {   787456, "Creative", "PC-CAM 600" ,0 },
-    {  2465792, "NIKON",    "E950"       ,1 },  /* or E800,E700 */
-    {  2940928, "NIKON",    "E2100"      ,1 },  /* or E2500 */
-    {  4771840, "NIKON",    "E990"       ,1 },  /* or E995 */
-    {  4775936, "NIKON",    "E3700"      ,1 },  /* or Optio 33WR */
-    {  5869568, "NIKON",    "E4300"      ,1 },  /* or DiMAGE Z2 */
-    {  5865472, "NIKON",    "E4500"      ,0 },
-    {  1976352, "CASIO",    "QV-2000UX"  ,0 },
-    {  3217760, "CASIO",    "QV-3*00EX"  ,0 },
-    {  6218368, "CASIO",    "QV-5700"    ,0 },
-    {  7530816, "CASIO",    "QV-R51"     ,1 },
-    {  7684000, "CASIO",    "QV-4000"    ,0 },
-    {  7753344, "CASIO",    "EX-Z55"     ,1 },
-    {  9313536, "CASIO",    "EX-P600"    ,1 },
-    { 10979200, "CASIO",    "EX-P700"    ,1 },
-    {  3178560, "PENTAX",   "Optio S"    ,1 },  /*  8-bit */
-    {  4841984, "PENTAX",   "Optio S"    ,1 },  /* 12-bit */
-    {  6114240, "PENTAX",   "Optio S4"   ,1 },  /* or S4i */
-    { 12582980, "Sinar",    ""           ,0 } };
-  static const char *corp[] =
-    { "Canon", "NIKON", "EPSON", "Kodak", "OLYMPUS", "PENTAX",
-      "MINOLTA", "Minolta", "Konica", "CASIO" };
-  float tmp;
-
-  /*  What format is this file?  Set make[] if we recognize it. */
+         LoadRawFn ** const loadRawFnP) {
+/*----------------------------------------------------------------------------
+  Identify which camera created this file, and set global variables
+  accordingly.  Return nonzero if the file cannot be decoded.
+-----------------------------------------------------------------------------*/
+    char head[32];
+    char * c;
+    unsigned hlen, fsize, i;
+    static const struct {
+        int fsize;
+        char make[12], model[15], withjpeg;
+    } table[] = {
+        {    62464, "Kodak",    "DC20"       ,0 },
+        {   124928, "Kodak",    "DC20"       ,0 },
+        {   311696, "ST Micro", "STV680 VGA" ,0 },  /* SPYz */
+        {   787456, "Creative", "PC-CAM 600" ,0 },
+        {  2465792, "NIKON",    "E950"       ,1 },  /* or E800,E700 */
+        {  2940928, "NIKON",    "E2100"      ,1 },  /* or E2500 */
+        {  4771840, "NIKON",    "E990"       ,1 },  /* or E995 */
+        {  4775936, "NIKON",    "E3700"      ,1 },  /* or Optio 33WR */
+        {  5869568, "NIKON",    "E4300"      ,1 },  /* or DiMAGE Z2 */
+        {  5865472, "NIKON",    "E4500"      ,0 },
+        {  1976352, "CASIO",    "QV-2000UX"  ,0 },
+        {  3217760, "CASIO",    "QV-3*00EX"  ,0 },
+        {  6218368, "CASIO",    "QV-5700"    ,0 },
+        {  7530816, "CASIO",    "QV-R51"     ,1 },
+        {  7684000, "CASIO",    "QV-4000"    ,0 },
+        {  7753344, "CASIO",    "EX-Z55"     ,1 },
+        {  9313536, "CASIO",    "EX-P600"    ,1 },
+        { 10979200, "CASIO",    "EX-P700"    ,1 },
+        {  3178560, "PENTAX",   "Optio S"    ,1 },  /*  8-bit */
+        {  4841984, "PENTAX",   "Optio S"    ,1 },  /* 12-bit */
+        {  6114240, "PENTAX",   "Optio S4"   ,1 },  /* or S4i */
+        { 12582980, "Sinar",    ""           ,0 } };
+    static const char *corp[] =
+        { "Canon", "NIKON", "EPSON", "Kodak", "OLYMPUS", "PENTAX",
+          "MINOLTA", "Minolta", "Konica", "CASIO" };
+    float tmp;
+    LoadRawFn * load_raw;
 
-  raw_height = raw_width = fuji_width = flip = 0;
-  make[0] = model[0] = model2[0] = 0;
-  memset (white, 0, sizeof white);
-  timestamp = tiff_samples = 0;
-  data_offset = meta_length = tiff_data_compression = 0;
-  zero_after_ff = is_dng = fuji_secondary = filters = 0;
-  black = is_foveon = use_coeff = 0;
-  use_gamma = xmag = ymag = 1;
-  for (i=0; i < 4; i++) {
-    cam_mul[i] = 1 & i;
-    pre_mul[i] = 1;
-  }
-  colors = 3;
-  for (i=0; i < 0x1000; i++) curve[i] = i;
-  maximum = 0xfff;
-#ifdef USE_LCMS
-  profile_length = 0;
-#endif
+    /*  What format is this file?  Set make[] if we recognize it. */
 
-  order = get2(ifp);
-  hlen = get4(ifp);
-  fseek (ifp, 0, SEEK_SET);
-  fread (head, 1, 32, ifp);
-  fseek (ifp, 0, SEEK_END);
-  fsize = ftell(ifp);
-  if ((c = (char*)memmem_internal(head, 32, "MMMMRawT", 8))) {
-    strcpy (make, "Phase One");
-    data_offset = c - head;
-    fseek (ifp, data_offset + 8, SEEK_SET);
-    fseek (ifp, get4(ifp) + 136, SEEK_CUR);
-    raw_width = get4(ifp);
-    fseek (ifp, 12, SEEK_CUR);
-    raw_height = get4(ifp);
-  } else if (order == 0x4949 || order == 0x4d4d) {
-    if (!memcmp (head+6, "HEAPCCDR", 8)) {
-      data_offset = hlen;
-      parse_ciff(ifp, hlen, fsize - hlen);
-    } else {
-      parse_tiff(ifp, 0);
-      if (!strncmp(make,"NIKON",5) && filters == 0)
-    make[0] = 0;
+    raw_height = raw_width = fuji_width = flip = 0;
+    make[0] = model[0] = model2[0] = 0;
+    memset (white, 0, sizeof white);
+    timestamp = tiff_samples = 0;
+    data_offset = meta_length = tiff_data_compression = 0;
+    zero_after_ff = is_dng = fuji_secondary = filters = 0;
+    black = is_foveon = use_coeff = 0;
+    use_gamma = xmag = ymag = 1;
+    for (i=0; i < 4; i++) {
+        cam_mul[i] = 1 & i;
+        pre_mul[i] = 1;
     }
-  } else if (!memcmp (head, "\0MRM", 4))
-    parse_minolta(ifp);
+    colors = 3;
+    for (i=0; i < 0x1000; i++) curve[i] = i;
+    maximum = 0xfff;
+
+    order = get2(ifp);
+    hlen = get4(ifp);
+    fseek (ifp, 0, SEEK_SET);
+    fread (head, 1, 32, ifp);
+    fseek (ifp, 0, SEEK_END);
+    fsize = ftell(ifp);
+    if ((c = (char*)memmem_internal(head, 32, "MMMMRawT", 8))) {
+        strcpy (make, "Phase One");
+        data_offset = c - head;
+        fseek (ifp, data_offset + 8, SEEK_SET);
+        fseek (ifp, get4(ifp) + 136, SEEK_CUR);
+        raw_width = get4(ifp);
+        fseek (ifp, 12, SEEK_CUR);
+        raw_height = get4(ifp);
+    } else if (order == 0x4949 || order == 0x4d4d) {
+        if (!memcmp (head+6, "HEAPCCDR", 8)) {
+            data_offset = hlen;
+            parse_ciff(ifp, hlen, fsize - hlen);
+        } else {
+            parse_tiff(ifp, 0);
+            if (!strncmp(make,"NIKON",5) && filters == 0)
+                make[0] = 0;
+        }
+    } else if (!memcmp (head, "\0MRM", 4))
+        parse_minolta(ifp);
     else if (!memcmp (head, "\xff\xd8\xff\xe1", 4) &&
-         !memcmp (head+6, "Exif", 4)) {
-    fseek (ifp, 4, SEEK_SET);
-    fseek (ifp, 4 + get2(ifp), SEEK_SET);
-    if (fgetc(ifp) != 0xff)
-      parse_tiff(ifp, 12);
-  } else if (!memcmp (head, "BM", 2)) {
-    data_offset = 0x1000;
-    order = 0x4949;
-    fseek (ifp, 38, SEEK_SET);
-    if (get4(ifp) == 2834 && get4(ifp) == 2834) {
-      strcpy (model, "BMQ");
-      flip = 3;
-      goto nucore;
-    }
-  } else if (!memcmp (head, "BR", 2)) {
-    strcpy (model, "RAW");
-nucore:
-    strcpy (make, "Nucore");
-    order = 0x4949;
-    fseek (ifp, 10, SEEK_SET);
-    data_offset += get4(ifp);
-    get4(ifp);
-    raw_width  = get4(ifp);
-    raw_height = get4(ifp);
-    if (model[0] == 'B' && raw_width == 2597) {
-      raw_width++;
-      data_offset -= 0x1000;
-    }
-  } else if (!memcmp (head+25, "ARECOYK", 7)) {
-    strcpy (make, "Contax");
-    strcpy (model,"N Digital");
-    fseek (ifp, 60, SEEK_SET);
-    camera_red  = get4(ifp);
-    camera_red /= get4(ifp);
-    camera_blue = get4(ifp);
-    camera_blue = get4(ifp) / camera_blue;
-  } else if (!memcmp (head, "FUJIFILM", 8)) {
-    long data_offset_long;
-    fseek (ifp, 84, SEEK_SET);
-    parse_tiff(ifp, get4(ifp)+12);
-    fseek (ifp, 100, SEEK_SET);
-    pm_readbiglong(ifp, &data_offset_long);
-    data_offset = data_offset_long;
-  } else if (!memcmp (head, "DSC-Image", 9))
-    parse_rollei(ifp);
-  else if (!memcmp (head, "FOVb", 4))
-    parse_foveon(ifp);
-  else
-      for (i=0; i < sizeof table / sizeof *table; i++)
-          if (fsize == table[i].fsize) {
-              strcpy (make,  table[i].make );
-              strcpy (model, table[i].model);
-              if (table[i].withjpeg)
-                  parse_external_jpeg(inputFileName);
-          }
-  parse_mos(ifp, 8);
-  parse_mos(ifp, 3472);
+             !memcmp (head+6, "Exif", 4)) {
+        fseek (ifp, 4, SEEK_SET);
+        fseek (ifp, 4 + get2(ifp), SEEK_SET);
+        if (fgetc(ifp) != 0xff)
+            parse_tiff(ifp, 12);
+    } else if (!memcmp (head, "BM", 2)) {
+        data_offset = 0x1000;
+        order = 0x4949;
+        fseek (ifp, 38, SEEK_SET);
+        if (get4(ifp) == 2834 && get4(ifp) == 2834) {
+            strcpy (model, "BMQ");
+            flip = 3;
+            goto nucore;
+        }
+    } else if (!memcmp (head, "BR", 2)) {
+        strcpy (model, "RAW");
+    nucore:
+        strcpy (make, "Nucore");
+        order = 0x4949;
+        fseek (ifp, 10, SEEK_SET);
+        data_offset += get4(ifp);
+        get4(ifp);
+        raw_width  = get4(ifp);
+        raw_height = get4(ifp);
+        if (model[0] == 'B' && raw_width == 2597) {
+            raw_width++;
+            data_offset -= 0x1000;
+        }
+    } else if (!memcmp (head+25, "ARECOYK", 7)) {
+        strcpy (make, "Contax");
+        strcpy (model,"N Digital");
+        fseek (ifp, 60, SEEK_SET);
+        camera_red  = get4(ifp);
+        camera_red /= get4(ifp);
+        camera_blue = get4(ifp);
+        camera_blue = get4(ifp) / camera_blue;
+    } else if (!memcmp (head, "FUJIFILM", 8)) {
+        long data_offset_long;
+        fseek (ifp, 84, SEEK_SET);
+        parse_tiff(ifp, get4(ifp)+12);
+        fseek (ifp, 100, SEEK_SET);
+        pm_readbiglong(ifp, &data_offset_long);
+        data_offset = data_offset_long;
+    } else if (!memcmp (head, "DSC-Image", 9))
+        parse_rollei(ifp);
+    else if (!memcmp (head, "FOVb", 4))
+        parse_foveon(ifp);
+    else
+        for (i=0; i < sizeof table / sizeof *table; i++)
+            if (fsize == table[i].fsize) {
+                strcpy (make,  table[i].make );
+                strcpy (model, table[i].model);
+                if (table[i].withjpeg)
+                    parse_external_jpeg(inputFileName);
+            }
+    parse_mos(ifp, 8);
+    parse_mos(ifp, 3472);
+
+    for (i=0; i < sizeof corp / sizeof *corp; i++)
+        if (strstr (make, corp[i]))     /* Simplify company names */
+            strcpy (make, corp[i]);
+    if (!strncmp (make, "KODAK", 5))
+        make[16] = model[16] = 0;
+    c = make + strlen(make);      /* Remove trailing spaces */
+    while (*--c == ' ') *c = 0;
+    c = model + strlen(model);
+    while (*--c == ' ') *c = 0;
+    i = strlen(make);         /* Remove make from model */
+    if (!strncmp (model, make, i++))
+        memmove (model, model+i, 64-i);
+    make[63] = model[63] = model2[63] = 0;
 
-  for (i=0; i < sizeof corp / sizeof *corp; i++)
-    if (strstr (make, corp[i]))     /* Simplify company names */
-    strcpy (make, corp[i]);
-  if (!strncmp (make, "KODAK", 5))
-    make[16] = model[16] = 0;
-  c = make + strlen(make);      /* Remove trailing spaces */
-  while (*--c == ' ') *c = 0;
-  c = model + strlen(model);
-  while (*--c == ' ') *c = 0;
-  i = strlen(make);         /* Remove make from model */
-  if (!strncmp (model, make, i++))
-    memmove (model, model+i, 64-i);
-  make[63] = model[63] = model2[63] = 0;
+    if (verbose)
+        fprintf(stderr, "Make = '%s', Model = '%s'\n", make, model);
 
-  if (make[0] == 0) {
-    pm_message ("unrecognized file format.");
-    return 1;
-  }
+    if (make[0] == 0) {
+        pm_message ("unrecognized file format.");
+        return 1;
+    }
 
 /*  File format is OK.  Do we know this camera? */
 /*  Start with some useful defaults:           */
 
-  top_margin = left_margin = 0;
-  if ((raw_height | raw_width) < 0)
-       raw_height = raw_width  = 0;
-  height = raw_height;
-  width  = raw_width;
-  if (fuji_width) {
-    width = height + fuji_width;
-    height = width - 1;
-    ymag = 1;
-  }
-  load_raw = NULL;
-  if (is_dng) {
-    strcat (model, " DNG");
-    if (!filters)
-      colors = tiff_samples;
-    if (tiff_data_compression == 1)
-      load_raw = adobe_dng_load_raw_nc;
-    if (tiff_data_compression == 7)
-      load_raw = adobe_dng_load_raw_lj;
-    goto dng_skip;
-  }
+    top_margin = left_margin = 0;
+    if ((raw_height | raw_width) < 0)
+        raw_height = raw_width  = 0;
+    height = raw_height;
+    width  = raw_width;
+    if (fuji_width) {
+        width = height + fuji_width;
+        height = width - 1;
+        ymag = 1;
+    }
+    load_raw = NULL;
+    if (is_dng) {
+        strcat (model, " DNG");
+        if (!filters)
+            colors = tiff_samples;
+        if (tiff_data_compression == 1)
+            load_raw = adobe_dng_load_raw_nc;
+        if (tiff_data_compression == 7)
+            load_raw = adobe_dng_load_raw_lj;
+        goto dng_skip;
+    }
 
-/*  We'll try to decode anything from Canon or Nikon. */
+    /*  We'll try to decode anything from Canon or Nikon. */
 
-  if (!filters) filters = 0x94949494;
-  if ((is_canon = !strcmp(make,"Canon")))
-    load_raw = memcmp (head+6,"HEAPCCDR",8) ?
-        lossless_jpeg_load_raw : canon_compressed_load_raw;
-  if (!strcmp(make,"NIKON"))
-    load_raw = nikon_is_compressed() ?
-    nikon_compressed_load_raw : nikon_load_raw;
+    if (!filters) filters = 0x94949494;
+    if ((is_canon = !strcmp(make,"Canon")))
+        load_raw = memcmp (head+6,"HEAPCCDR",8) ?
+            lossless_jpeg_load_raw : canon_compressed_load_raw;
+    if (!strcmp(make,"NIKON"))
+        load_raw = nikon_is_compressed() ?
+            nikon_compressed_load_raw : nikon_load_raw;
 
-/* Set parameters based on camera name (for non-DNG files). */
+    /* Set parameters based on camera name (for non-DNG files). */
 
-  if (is_foveon) {
-    if (!have64BitArithmetic)
-      pm_error("This program was built without 64 bit arithmetic "
-               "capability and the Foveon format requires it.");
-    if (height*2 < width) ymag = 2;
-    if (width < height) xmag = 2;
-    filters = 0;
-    load_raw = foveon_load_raw;
-    foveon_coeff(&use_coeff, coeff);
-  } else if (!strcmp(model,"PowerShot 600")) {
-    height = 613;
-    width  = 854;
-    colors = 4;
-    filters = 0xe1e4e1e4;
-    load_raw = canon_600_load_raw;
-  } else if (!strcmp(model,"PowerShot A5") ||
-         !strcmp(model,"PowerShot A5 Zoom")) {
-    height = 773;
-    width  = 960;
-    raw_width = 992;
-    colors = 4;
-    filters = 0x1e4e1e4e;
-    load_raw = canon_a5_load_raw;
-  } else if (!strcmp(model,"PowerShot A50")) {
-    height =  968;
-    width  = 1290;
-    raw_width = 1320;
-    colors = 4;
-    filters = 0x1b4e4b1e;
-    load_raw = canon_a5_load_raw;
-  } else if (!strcmp(model,"PowerShot Pro70")) {
-    height = 1024;
-    width  = 1552;
-    colors = 4;
-    filters = 0x1e4b4e1b;
-    load_raw = canon_a5_load_raw;
-    black = 34;
-  } else if (!strcmp(model,"PowerShot Pro90 IS")) {
-    width  = 1896;
-    colors = 4;
-    filters = 0xb4b4b4b4;
-  } else if (is_canon && raw_width == 2144) {
-    height = 1550;
-    width  = 2088;
-    top_margin  = 8;
-    left_margin = 4;
-    if (!strcmp(model,"PowerShot G1")) {
-      colors = 4;
-      filters = 0xb4b4b4b4;
-    }
-  } else if (is_canon && raw_width == 2224) {
-    height = 1448;
-    width  = 2176;
-    top_margin  = 6;
-    left_margin = 48;
-  } else if (is_canon && raw_width == 2376) {
-    height = 1720;
-    width  = 2312;
-    top_margin  = 6;
-    left_margin = 12;
-  } else if (is_canon && raw_width == 2672) {
-    height = 1960;
-    width  = 2616;
-    top_margin  = 6;
-    left_margin = 12;
-  } else if (is_canon && raw_width == 3152) {
-    height = 2056;
-    width  = 3088;
-    top_margin  = 12;
-    left_margin = 64;
-    maximum = 0xfa0;
-  } else if (is_canon && raw_width == 3160) {
-    height = 2328;
-    width  = 3112;
-    top_margin  = 12;
-    left_margin = 44;
-  } else if (is_canon && raw_width == 3344) {
-    height = 2472;
-    width  = 3288;
-    top_margin  = 6;
-    left_margin = 4;
-  } else if (!strcmp(model,"EOS D2000C")) {
-    filters = 0x61616161;
-    black = curve[200];
-  } else if (!strcmp(model,"EOS-1D")) {
-    raw_height = height = 1662;
-    raw_width  = width  = 2496;
-    data_offset = 288912;
-    filters = 0x61616161;
-  } else if (!strcmp(model,"EOS-1DS")) {
-    raw_height = height = 2718;
-    raw_width  = width  = 4082;
-    data_offset = 289168;
-    filters = 0x61616161;
-  } else if (is_canon && raw_width == 3516) {
-    top_margin  = 14;
-    left_margin = 42;
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 3596) {
-    top_margin  = 12;
-    left_margin = 74;
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 5108) {
-    top_margin  = 13;
-    left_margin = 98;
-    maximum = 0xe80;
-canon_cr2:
-    height = raw_height - top_margin;
-    width  = raw_width - left_margin;
-  } else if (!strcmp(model,"D1")) {
-    camera_red  *= 256/527.0;
-    camera_blue *= 256/317.0;
-  } else if (!strcmp(model,"D1X")) {
-    width  = 4024;
-    ymag = 2;
-  } else if (!strcmp(model,"D100")) {
-    if (tiff_data_compression == 34713 && load_raw == nikon_load_raw)
-      raw_width = (width += 3) + 3;
-  } else if (!strcmp(model,"D2H")) {
-    width  = 2482;
-    left_margin = 6;
-  } else if (!strcmp(model,"D2X")) {
-    width  = 4312;
-    pre_mul[0] = 1.514;
-    pre_mul[2] = 1.727;
-  } else if (fsize == 2465792) {
-    height = 1203;
-    width  = 1616;
-    filters = 0x4b4b4b4b;
-    colors = 4;
-    load_raw = nikon_e950_load_raw;
-    nikon_e950_coeff();
-    pre_mul[0] = 1.18193;
-    pre_mul[2] = 1.16452;
-    pre_mul[3] = 1.17250;
-  } else if (!strcmp(model,"E990")) {
-    if (!timestamp && !nikon_e990()) goto cp_e995;
-    height = 1540;
-    width  = 2064;
-    colors = 4;
-    filters = 0xb4b4b4b4;
-    nikon_e950_coeff();
-    pre_mul[0] = 1.196;
-    pre_mul[1] = 1.246;
-    pre_mul[2] = 1.018;
-  } else if (!strcmp(model,"E995")) {
-cp_e995:
-    strcpy (model, "E995");
-    height = 1540;
-    width  = 2064;
-    colors = 4;
-    filters = 0xe1e1e1e1;
-  } else if (!strcmp(model,"E2100")) {
-    if (!timestamp && !nikon_e2100()) goto cp_e2500;
-    width = 1616;
-    height = 1206;
-    load_raw = nikon_e2100_load_raw;
-    pre_mul[0] = 1.945;
-    pre_mul[2] = 1.040;
-  } else if (!strcmp(model,"E2500")) {
-cp_e2500:
-    strcpy (model, "E2500");
-    width = 1616;
-    height = 1204;
-    colors = 4;
-    filters = 0x4b4b4b4b;
-  } else if (!strcmp(model,"E3700")) {
-    if (!timestamp && pentax_optio33()) goto optio_33wr;
-    height = 1542;
-    width  = 2064;
-    load_raw = nikon_e2100_load_raw;
-    pre_mul[0] = 1.818;
-    pre_mul[2] = 1.618;
-  } else if (!strcmp(model,"Optio 33WR")) {
-optio_33wr:
-    strcpy (make, "PENTAX");
-    strcpy (model,"Optio 33WR");
-    height = 1542;
-    width  = 2064;
-    load_raw = nikon_e2100_load_raw;
-    flip = 1;
-    filters = 0x16161616;
-    pre_mul[0] = 1.331;
-    pre_mul[2] = 1.820;
-  } else if (!strcmp(model,"E4300")) {
-    if (!timestamp && minolta_z2()) goto dimage_z2;
-    height = 1710;
-    width  = 2288;
-    filters = 0x16161616;
-    pre_mul[0] = 508;
-    pre_mul[1] = 256;
-    pre_mul[2] = 322;
-  } else if (!strcmp(model,"DiMAGE Z2")) {
-dimage_z2:
-    strcpy (make, "MINOLTA");
-    strcpy (model,"DiMAGE Z2");
-    height = 1710;
-    width  = 2288;
-    filters = 0x16161616;
-    load_raw = nikon_e2100_load_raw;
-    pre_mul[0] = 508;
-    pre_mul[1] = 256;
-    pre_mul[2] = 450;
-  } else if (!strcmp(model,"E4500")) {
-    height = 1708;
-    width  = 2288;
-    colors = 4;
-    filters = 0xb4b4b4b4;
-  } else if (!strcmp(model,"R-D1")) {
-    tiff_data_compression = 34713;
-    load_raw = nikon_load_raw;
-  } else if (!strcmp(model,"FinePixS2Pro")) {
-    height = 3584;
-    width  = 3583;
-    fuji_width = 2144;
-    filters = 0x61616161;
-    load_raw = fuji_s2_load_raw;
-    black = 128;
-    strcpy (model+7, " S2Pro");
-  } else if (!strcmp(model,"FinePix S3Pro")) {
-    height = 3583;
-    width  = 3584;
-    fuji_width = 2144;
-    if (fsize > 18000000 && use_secondary)
-      data_offset += 4352*2*1444;
-    filters = 0x49494949;
-    load_raw = fuji_s3_load_raw;
-    maximum = 0xffff;
-  } else if (!strcmp(model,"FinePix S5000")) {
-    height = 2499;
-    width  = 2500;
-    fuji_width = 1423;
-    filters = 0x49494949;
-    load_raw = fuji_s5000_load_raw;
-    maximum = 0x3e00;
-  } else if (!strcmp(model,"FinePix S5100") ||
-         !strcmp(model,"FinePix S5500")) {
-    height = 1735;
-    width  = 2304;
-    data_offset += width*10;
-    filters = 0x49494949;
-    load_raw = unpacked_load_raw;
-    maximum = 0xffff;
-  } else if (!strcmp(model,"FinePix E550") ||
-         !strcmp(model,"FinePix F810") ||
-         !strcmp(model,"FinePix S7000")) {
-    height = 3587;
-    width  = 3588;
-    fuji_width = 2047;
-    filters = 0x49494949;
-    load_raw = fuji_s7000_load_raw;
-    maximum = 0x3e00;
-  } else if (!strcmp(model,"FinePix F700") ||
-         !strcmp(model,"FinePix S20Pro")) {
-    height = 2523;
-    width  = 2524;
-    fuji_width = 1440;
-    filters = 0x49494949;
-    load_raw = fuji_f700_load_raw;
-    maximum = 0x3e00;
-  } else if (!strcmp(model,"Digital Camera KD-400Z")) {
-    height = 1712;
-    width  = 2312;
-    raw_width = 2336;
-    data_offset = 4034;
-    fseek (ifp, 2032, SEEK_SET);
-    goto konica_400z;
-  } else if (!strcmp(model,"Digital Camera KD-510Z")) {
-    data_offset = 4032;
-    pre_mul[0] = 1.297;
-    pre_mul[2] = 1.438;
-    fseek (ifp, 2032, SEEK_SET);
-    goto konica_510z;
-  } else if (!strcasecmp(make,"MINOLTA")) {
-    load_raw = unpacked_load_raw;
-    maximum = 0xf7d;
-    if (!strncmp(model,"DiMAGE A",8)) {
-      if (!strcmp(model,"DiMAGE A200")) {
-    filters = 0x49494949;
-    tmp = camera_red;
-    camera_red  = 1 / camera_blue;
-    camera_blue = 1 / tmp;
-      }
-      load_raw = packed_12_load_raw;
-      maximum = model[8] == '1' ? 0xf8b : 0xfff;
-    } else if (!strncmp(model,"ALPHA",5) ||
-           !strncmp(model,"DYNAX",5) ||
-           !strncmp(model,"MAXXUM",6)) {
-      load_raw = packed_12_load_raw;
-      maximum = 0xffb;
-    } else if (!strncmp(model,"DiMAGE G",8)) {
-      if (model[8] == '4') {
-    data_offset = 5056;
-    pre_mul[0] = 1.602;
-    pre_mul[2] = 1.441;
-    fseek (ifp, 2078, SEEK_SET);
-    height = 1716;
-    width  = 2304;
-      } else if (model[8] == '5') {
-    data_offset = 4016;
-    fseek (ifp, 1936, SEEK_SET);
-konica_510z:
-    height = 1956;
-    width  = 2607;
-    raw_width = 2624;
-      } else if (model[8] == '6') {
-    data_offset = 4032;
-    fseek (ifp, 2030, SEEK_SET);
-    height = 2136;
-    width  = 2848;
-      }
-      filters = 0x61616161;
-konica_400z:
-      load_raw = unpacked_load_raw;
-      maximum = 0x3df;
-      order = 0x4d4d;
-      camera_red   = get2(ifp);
-      camera_blue  = get2(ifp);
-      camera_red  /= get2(ifp);
-      camera_blue /= get2(ifp);
-    }
-    if (pre_mul[0] == 1 && pre_mul[2] == 1) {
-      pre_mul[0] = 1.42;
-      pre_mul[2] = 1.25;
-    }
-  } else if (!strcmp(model,"*ist D")) {
-    load_raw = unpacked_load_raw;
-  } else if (!strcmp(model,"*ist DS")) {
-    height--;
-    load_raw = packed_12_load_raw;
-  } else if (!strcmp(model,"Optio S")) {
-    if (fsize == 3178560) {
-      height = 1540;
-      width  = 2064;
-      load_raw = eight_bit_load_raw;
-      camera_red  *= 4;
-      camera_blue *= 4;
-      pre_mul[0] = 1.391;
-      pre_mul[2] = 1.188;
-    } else {
-      height = 1544;
-      width  = 2068;
-      raw_width = 3136;
-      load_raw = packed_12_load_raw;
-      maximum = 0xf7c;
-      pre_mul[0] = 1.137;
-      pre_mul[2] = 1.453;
-    }
-  } else if (!strncmp(model,"Optio S4",8)) {
-    height = 1737;
-    width  = 2324;
-    raw_width = 3520;
-    load_raw = packed_12_load_raw;
-    maximum = 0xf7a;
-    pre_mul[0] = 1.980;
-    pre_mul[2] = 1.570;
-  } else if (!strcmp(model,"STV680 VGA")) {
-    height = 484;
-    width  = 644;
-    load_raw = eight_bit_load_raw;
-    flip = 2;
-    filters = 0x16161616;
-    black = 16;
-    pre_mul[0] = 1.097;
-    pre_mul[2] = 1.128;
-  } else if (!strcmp(make,"Phase One")) {
-    switch (raw_height) {
-      case 2060:
-    strcpy (model, "LightPhase");
-    height = 2048;
-    width  = 3080;
-    top_margin  = 5;
-    left_margin = 22;
-    pre_mul[0] = 1.331;
-    pre_mul[2] = 1.154;
-    break;
-      case 2682:
-    strcpy (model, "H10");
-    height = 2672;
-    width  = 4012;
-    top_margin  = 5;
-    left_margin = 26;
-    break;
-      case 4128:
-    strcpy (model, "H20");
-    height = 4098;
-    width  = 4098;
-    top_margin  = 20;
-    left_margin = 26;
-    pre_mul[0] = 1.963;
-    pre_mul[2] = 1.430;
-    break;
-      case 5488:
-    strcpy (model, "H25");
-    height = 5458;
-    width  = 4098;
-    top_margin  = 20;
-    left_margin = 26;
-    pre_mul[0] = 2.80;
-    pre_mul[2] = 1.20;
-    }
-    filters = top_margin & 1 ? 0x94949494 : 0x49494949;
-    load_raw = phase_one_load_raw;
-    maximum = 0xffff;
-  } else if (!strcmp(model,"Ixpress")) {
-    height = 4084;
-    width  = 4080;
-    filters = 0x49494949;
-    load_raw = ixpress_load_raw;
-    maximum = 0xffff;
-    pre_mul[0] = 1.963;
-    pre_mul[2] = 1.430;
-  } else if (!strcmp(make,"Sinar") && !memcmp(head,"8BPS",4)) {
-    fseek (ifp, 14, SEEK_SET);
-    height = get4(ifp);
-    width  = get4(ifp);
-    filters = 0x61616161;
-    data_offset = 68;
-    load_raw = unpacked_load_raw;
-    maximum = 0xffff;
-  } else if (!strcmp(make,"Leaf")) {
-    if (height > width)
-      filters = 0x16161616;
-    load_raw = unpacked_load_raw;
-    maximum = 0x3fff;
-    strcpy (model, "Valeo");
-    if (raw_width == 2060) {
-      filters = 0;
-      load_raw = leaf_load_raw;
-      maximum = 0xffff;
-      strcpy (model, "Volare");
-    }
-  } else if (!strcmp(model,"DIGILUX 2") || !strcmp(model,"DMC-LC1")) {
-    height = 1928;
-    width  = 2568;
-    data_offset = 1024;
-    load_raw = unpacked_load_raw;
-    maximum = 0xfff0;
-  } else if (!strcmp(model,"E-1")) {
-    filters = 0x61616161;
-    load_raw = unpacked_load_raw;
-    maximum = 0xfff0;
-    black = 1024;
-  } else if (!strcmp(model,"E-10")) {
-    load_raw = unpacked_load_raw;
-    maximum = 0xfff0;
-    black = 2048;
-  } else if (!strncmp(model,"E-20",4)) {
-    load_raw = unpacked_load_raw;
-    maximum = 0xffc0;
-    black = 2560;
-  } else if (!strcmp(model,"E-300")) {
-    width -= 21;
-    load_raw = olympus_e300_load_raw;
-    if (fsize > 15728640) {
-      load_raw = unpacked_load_raw;
-      maximum = 0xfc30;
-    } else
-      black = 62;
-  } else if (!strcmp(make,"OLYMPUS")) {
-    load_raw = olympus_cseries_load_raw;
-    if (!strcmp(model,"C5050Z") ||
-    !strcmp(model,"C8080WZ"))
-      filters = 0x16161616;
-  } else if (!strcmp(model,"N Digital")) {
-    height = 2047;
-    width  = 3072;
-    filters = 0x61616161;
-    data_offset = 0x1a00;
-    load_raw = packed_12_load_raw;
-    maximum = 0xf1e;
-  } else if (!strcmp(model,"DSC-F828")) {
-    width = 3288;
-    left_margin = 5;
-    load_raw = sony_load_raw;
-    filters = 0x9c9c9c9c;
-    colors = 4;
-    black = 491;
-  } else if (!strcmp(model,"DSC-V3")) {
-    width = 3109;
-    left_margin = 59;
-    load_raw = sony_load_raw;
-  } else if (!strcasecmp(make,"KODAK")) {
-    filters = 0x61616161;
-    if (!strcmp(model,"NC2000F")) {
-      width -= 4;
-      left_margin = 1;
-      for (i=176; i < 0x1000; i++)
-    curve[i] = curve[i-1];
-      pre_mul[0] = 1.509;
-      pre_mul[2] = 2.686;
-    } else if (!strcmp(model,"EOSDCS3B")) {
-      width -= 4;
-      left_margin = 2;
-    } else if (!strcmp(model,"EOSDCS1")) {
-      width -= 4;
-      left_margin = 2;
-    } else if (!strcmp(model,"DCS315C")) {
-      black = 8;
-    } else if (!strcmp(model,"DCS330C")) {
-      black = 8;
-    } else if (!strcmp(model,"DCS420")) {
-      width -= 4;
-      left_margin = 2;
-    } else if (!strcmp(model,"DCS460")) {
-      width -= 4;
-      left_margin = 2;
-    } else if (!strcmp(model,"DCS460A")) {
-      width -= 4;
-      left_margin = 2;
-      colors = 1;
-      filters = 0;
-    } else if (!strcmp(model,"DCS520C")) {
-      black = 180;
-    } else if (!strcmp(model,"DCS560C")) {
-      black = 188;
-    } else if (!strcmp(model,"DCS620C")) {
-      black = 180;
-    } else if (!strcmp(model,"DCS620X")) {
-      black = 185;
-    } else if (!strcmp(model,"DCS660C")) {
-      black = 214;
-    } else if (!strcmp(model,"DCS660M")) {
-      black = 214;
-      colors = 1;
-      filters = 0;
-    } else if (!strcmp(model,"DCS760M")) {
-      colors = 1;
-      filters = 0;
-    }
-    switch (tiff_data_compression) {
-    case 0:               /* No compression */
-    case 1:
-        load_raw = kodak_easy_load_raw;
-        break;
-    case 7:               /* Lossless JPEG */
-        load_raw = lossless_jpeg_load_raw;
-    case 32867:
-        break;
-    case 65000:           /* Kodak DCR compression */
+    if (is_foveon) {
         if (!have64BitArithmetic)
             pm_error("This program was built without 64 bit arithmetic "
-                     "capability, and Kodak DCR compression requires it.");
-        if (kodak_data_compression == 32803)
-            load_raw = kodak_compressed_load_raw;
-        else {
-            load_raw = kodak_yuv_load_raw;
-            height = (height+1) & -2;
-            width  = (width +1) & -2;
+                     "capability and the Foveon format requires it.");
+        if (height*2 < width) ymag = 2;
+        if (width < height) xmag = 2;
+        filters = 0;
+        load_raw = foveon_load_raw;
+        foveon_coeff(&use_coeff, coeff);
+    } else if (!strcmp(model,"PowerShot 600")) {
+        height = 613;
+        width  = 854;
+        colors = 4;
+        filters = 0xe1e4e1e4;
+        load_raw = canon_600_load_raw;
+    } else if (!strcmp(model,"PowerShot A5") ||
+               !strcmp(model,"PowerShot A5 Zoom")) {
+        height = 773;
+        width  = 960;
+        raw_width = 992;
+        colors = 4;
+        filters = 0x1e4e1e4e;
+        load_raw = canon_a5_load_raw;
+    } else if (!strcmp(model,"PowerShot A50")) {
+        height =  968;
+        width  = 1290;
+        raw_width = 1320;
+        colors = 4;
+        filters = 0x1b4e4b1e;
+        load_raw = canon_a5_load_raw;
+    } else if (!strcmp(model,"PowerShot Pro70")) {
+        height = 1024;
+        width  = 1552;
+        colors = 4;
+        filters = 0x1e4b4e1b;
+        load_raw = canon_a5_load_raw;
+        black = 34;
+    } else if (!strcmp(model,"PowerShot Pro90 IS")) {
+        width  = 1896;
+        colors = 4;
+        filters = 0xb4b4b4b4;
+    } else if (is_canon && raw_width == 2144) {
+        height = 1550;
+        width  = 2088;
+        top_margin  = 8;
+        left_margin = 4;
+        if (!strcmp(model,"PowerShot G1")) {
+            colors = 4;
+            filters = 0xb4b4b4b4;
+        }
+    } else if (is_canon && raw_width == 2224) {
+        height = 1448;
+        width  = 2176;
+        top_margin  = 6;
+        left_margin = 48;
+    } else if (is_canon && raw_width == 2376) {
+        height = 1720;
+        width  = 2312;
+        top_margin  = 6;
+        left_margin = 12;
+    } else if (is_canon && raw_width == 2672) {
+        height = 1960;
+        width  = 2616;
+        top_margin  = 6;
+        left_margin = 12;
+    } else if (is_canon && raw_width == 3152) {
+        height = 2056;
+        width  = 3088;
+        top_margin  = 12;
+        left_margin = 64;
+        maximum = 0xfa0;
+    } else if (is_canon && raw_width == 3160) {
+        height = 2328;
+        width  = 3112;
+        top_margin  = 12;
+        left_margin = 44;
+    } else if (is_canon && raw_width == 3344) {
+        height = 2472;
+        width  = 3288;
+        top_margin  = 6;
+        left_margin = 4;
+    } else if (!strcmp(model,"EOS D2000C")) {
+        filters = 0x61616161;
+        black = curve[200];
+    } else if (!strcmp(model,"EOS-1D")) {
+        raw_height = height = 1662;
+        raw_width  = width  = 2496;
+        data_offset = 288912;
+        filters = 0x61616161;
+    } else if (!strcmp(model,"EOS-1DS")) {
+        raw_height = height = 2718;
+        raw_width  = width  = 4082;
+        data_offset = 289168;
+        filters = 0x61616161;
+    } else if (is_canon && raw_width == 3516) {
+        top_margin  = 14;
+        left_margin = 42;
+        goto canon_cr2;
+    } else if (is_canon && raw_width == 3596) {
+        top_margin  = 12;
+        left_margin = 74;
+        goto canon_cr2;
+    } else if (is_canon && raw_width == 5108) {
+        top_margin  = 13;
+        left_margin = 98;
+        maximum = 0xe80;
+    canon_cr2:
+        height = raw_height - top_margin;
+        width  = raw_width - left_margin;
+    } else if (!strcmp(model,"D1")) {
+        camera_red  *= 256/527.0;
+        camera_blue *= 256/317.0;
+    } else if (!strcmp(model,"D1X")) {
+        width  = 4024;
+        ymag = 2;
+    } else if (!strcmp(model,"D100")) {
+        if (tiff_data_compression == 34713 && load_raw == nikon_load_raw)
+            raw_width = (width += 3) + 3;
+    } else if (!strcmp(model,"D2H")) {
+        width  = 2482;
+        left_margin = 6;
+    } else if (!strcmp(model,"D2X")) {
+        width  = 4312;
+        pre_mul[0] = 1.514;
+        pre_mul[2] = 1.727;
+    } else if (fsize == 2465792) {
+        height = 1203;
+        width  = 1616;
+        filters = 0x4b4b4b4b;
+        colors = 4;
+        load_raw = nikon_e950_load_raw;
+        nikon_e950_coeff();
+        pre_mul[0] = 1.18193;
+        pre_mul[2] = 1.16452;
+        pre_mul[3] = 1.17250;
+    } else if (!strcmp(model,"E990")) {
+        if (!timestamp && !nikon_e990()) goto cp_e995;
+        height = 1540;
+        width  = 2064;
+        colors = 4;
+        filters = 0xb4b4b4b4;
+        nikon_e950_coeff();
+        pre_mul[0] = 1.196;
+        pre_mul[1] = 1.246;
+        pre_mul[2] = 1.018;
+    } else if (!strcmp(model,"E995")) {
+    cp_e995:
+        strcpy (model, "E995");
+        height = 1540;
+        width  = 2064;
+        colors = 4;
+        filters = 0xe1e1e1e1;
+    } else if (!strcmp(model,"E2100")) {
+        if (!timestamp && !nikon_e2100()) goto cp_e2500;
+        width = 1616;
+        height = 1206;
+        load_raw = nikon_e2100_load_raw;
+        pre_mul[0] = 1.945;
+        pre_mul[2] = 1.040;
+    } else if (!strcmp(model,"E2500")) {
+    cp_e2500:
+        strcpy (model, "E2500");
+        width = 1616;
+        height = 1204;
+        colors = 4;
+        filters = 0x4b4b4b4b;
+    } else if (!strcmp(model,"E3700")) {
+        if (!timestamp && pentax_optio33()) goto optio_33wr;
+        height = 1542;
+        width  = 2064;
+        load_raw = nikon_e2100_load_raw;
+        pre_mul[0] = 1.818;
+        pre_mul[2] = 1.618;
+    } else if (!strcmp(model,"Optio 33WR")) {
+    optio_33wr:
+        strcpy (make, "PENTAX");
+        strcpy (model,"Optio 33WR");
+        height = 1542;
+        width  = 2064;
+        load_raw = nikon_e2100_load_raw;
+        flip = 1;
+        filters = 0x16161616;
+        pre_mul[0] = 1.331;
+        pre_mul[2] = 1.820;
+    } else if (!strcmp(model,"E4300")) {
+        if (!timestamp && minolta_z2()) goto dimage_z2;
+        height = 1710;
+        width  = 2288;
+        filters = 0x16161616;
+        pre_mul[0] = 508;
+        pre_mul[1] = 256;
+        pre_mul[2] = 322;
+    } else if (!strcmp(model,"DiMAGE Z2")) {
+    dimage_z2:
+        strcpy (make, "MINOLTA");
+        strcpy (model,"DiMAGE Z2");
+        height = 1710;
+        width  = 2288;
+        filters = 0x16161616;
+        load_raw = nikon_e2100_load_raw;
+        pre_mul[0] = 508;
+        pre_mul[1] = 256;
+        pre_mul[2] = 450;
+    } else if (!strcmp(model,"E4500")) {
+        height = 1708;
+        width  = 2288;
+        colors = 4;
+        filters = 0xb4b4b4b4;
+    } else if (!strcmp(model,"R-D1")) {
+        tiff_data_compression = 34713;
+        load_raw = nikon_load_raw;
+    } else if (!strcmp(model,"FinePixS2Pro")) {
+        height = 3584;
+        width  = 3583;
+        fuji_width = 2144;
+        filters = 0x61616161;
+        load_raw = fuji_s2_load_raw;
+        black = 128;
+        strcpy (model+7, " S2Pro");
+    } else if (!strcmp(model,"FinePix S3Pro")) {
+        height = 3583;
+        width  = 3584;
+        fuji_width = 2144;
+        if (fsize > 18000000 && use_secondary)
+            data_offset += 4352*2*1444;
+        filters = 0x49494949;
+        load_raw = fuji_s3_load_raw;
+        maximum = 0xffff;
+    } else if (!strcmp(model,"FinePix S5000")) {
+        height = 2499;
+        width  = 2500;
+        fuji_width = 1423;
+        filters = 0x49494949;
+        load_raw = fuji_s5000_load_raw;
+        maximum = 0x3e00;
+    } else if (!strcmp(model,"FinePix S5100") ||
+               !strcmp(model,"FinePix S5500")) {
+        height = 1735;
+        width  = 2304;
+        data_offset += width*10;
+        filters = 0x49494949;
+        load_raw = unpacked_load_raw;
+        maximum = 0xffff;
+    } else if (!strcmp(model,"FinePix E550") ||
+               !strcmp(model,"FinePix F810") ||
+               !strcmp(model,"FinePix S7000")) {
+        height = 3587;
+        width  = 3588;
+        fuji_width = 2047;
+        filters = 0x49494949;
+        load_raw = fuji_s7000_load_raw;
+        maximum = 0x3e00;
+    } else if (!strcmp(model,"FinePix F700") ||
+               !strcmp(model,"FinePix S20Pro")) {
+        height = 2523;
+        width  = 2524;
+        fuji_width = 1440;
+        filters = 0x49494949;
+        load_raw = fuji_f700_load_raw;
+        maximum = 0x3e00;
+    } else if (!strcmp(model,"Digital Camera KD-400Z")) {
+        height = 1712;
+        width  = 2312;
+        raw_width = 2336;
+        data_offset = 4034;
+        fseek (ifp, 2032, SEEK_SET);
+        goto konica_400z;
+    } else if (!strcmp(model,"Digital Camera KD-510Z")) {
+        data_offset = 4032;
+        pre_mul[0] = 1.297;
+        pre_mul[2] = 1.438;
+        fseek (ifp, 2032, SEEK_SET);
+        goto konica_510z;
+    } else if (!strcasecmp(make,"MINOLTA")) {
+        load_raw = unpacked_load_raw;
+        maximum = 0xf7d;
+        if (!strncmp(model,"DiMAGE A",8)) {
+            if (!strcmp(model,"DiMAGE A200")) {
+                filters = 0x49494949;
+                tmp = camera_red;
+                camera_red  = 1 / camera_blue;
+                camera_blue = 1 / tmp;
+            }
+            load_raw = packed_12_load_raw;
+            maximum = model[8] == '1' ? 0xf8b : 0xfff;
+        } else if (!strncmp(model,"ALPHA",5) ||
+                   !strncmp(model,"DYNAX",5) ||
+                   !strncmp(model,"MAXXUM",6)) {
+            load_raw = packed_12_load_raw;
+            maximum = 0xffb;
+        } else if (!strncmp(model,"DiMAGE G",8)) {
+            if (model[8] == '4') {
+                data_offset = 5056;
+                pre_mul[0] = 1.602;
+                pre_mul[2] = 1.441;
+                fseek (ifp, 2078, SEEK_SET);
+                height = 1716;
+                width  = 2304;
+            } else if (model[8] == '5') {
+                data_offset = 4016;
+                fseek (ifp, 1936, SEEK_SET);
+            konica_510z:
+                height = 1956;
+                width  = 2607;
+                raw_width = 2624;
+            } else if (model[8] == '6') {
+                data_offset = 4032;
+                fseek (ifp, 2030, SEEK_SET);
+                height = 2136;
+                width  = 2848;
+            }
+            filters = 0x61616161;
+        konica_400z:
+            load_raw = unpacked_load_raw;
+            maximum = 0x3df;
+            order = 0x4d4d;
+            camera_red   = get2(ifp);
+            camera_blue  = get2(ifp);
+            camera_red  /= get2(ifp);
+            camera_blue /= get2(ifp);
+        }
+        if (pre_mul[0] == 1 && pre_mul[2] == 1) {
+            pre_mul[0] = 1.42;
+            pre_mul[2] = 1.25;
+        }
+    } else if (!strcmp(model,"*ist D")) {
+        load_raw = unpacked_load_raw;
+    } else if (!strcmp(model,"*ist DS")) {
+        height--;
+        load_raw = packed_12_load_raw;
+    } else if (!strcmp(model,"Optio S")) {
+        if (fsize == 3178560) {
+            height = 1540;
+            width  = 2064;
+            load_raw = eight_bit_load_raw;
+            camera_red  *= 4;
+            camera_blue *= 4;
+            pre_mul[0] = 1.391;
+            pre_mul[2] = 1.188;
+        } else {
+            height = 1544;
+            width  = 2068;
+            raw_width = 3136;
+            load_raw = packed_12_load_raw;
+            maximum = 0xf7c;
+            pre_mul[0] = 1.137;
+            pre_mul[2] = 1.453;
+        }
+    } else if (!strncmp(model,"Optio S4",8)) {
+        height = 1737;
+        width  = 2324;
+        raw_width = 3520;
+        load_raw = packed_12_load_raw;
+        maximum = 0xf7a;
+        pre_mul[0] = 1.980;
+        pre_mul[2] = 1.570;
+    } else if (!strcmp(model,"STV680 VGA")) {
+        height = 484;
+        width  = 644;
+        load_raw = eight_bit_load_raw;
+        flip = 2;
+        filters = 0x16161616;
+        black = 16;
+        pre_mul[0] = 1.097;
+        pre_mul[2] = 1.128;
+    } else if (!strcmp(make,"Phase One")) {
+        switch (raw_height) {
+        case 2060:
+            strcpy (model, "LightPhase");
+            height = 2048;
+            width  = 3080;
+            top_margin  = 5;
+            left_margin = 22;
+            pre_mul[0] = 1.331;
+            pre_mul[2] = 1.154;
+            break;
+        case 2682:
+            strcpy (model, "H10");
+            height = 2672;
+            width  = 4012;
+            top_margin  = 5;
+            left_margin = 26;
+            break;
+        case 4128:
+            strcpy (model, "H20");
+            height = 4098;
+            width  = 4098;
+            top_margin  = 20;
+            left_margin = 26;
+            pre_mul[0] = 1.963;
+            pre_mul[2] = 1.430;
+            break;
+        case 5488:
+            strcpy (model, "H25");
+            height = 5458;
+            width  = 4098;
+            top_margin  = 20;
+            left_margin = 26;
+            pre_mul[0] = 2.80;
+            pre_mul[2] = 1.20;
+        }
+        filters = top_margin & 1 ? 0x94949494 : 0x49494949;
+        load_raw = phase_one_load_raw;
+        maximum = 0xffff;
+    } else if (!strcmp(model,"Ixpress")) {
+        height = 4084;
+        width  = 4080;
+        filters = 0x49494949;
+        load_raw = ixpress_load_raw;
+        maximum = 0xffff;
+        pre_mul[0] = 1.963;
+        pre_mul[2] = 1.430;
+    } else if (!strcmp(make,"Sinar") && !memcmp(head,"8BPS",4)) {
+        fseek (ifp, 14, SEEK_SET);
+        height = get4(ifp);
+        width  = get4(ifp);
+        filters = 0x61616161;
+        data_offset = 68;
+        load_raw = unpacked_load_raw;
+        maximum = 0xffff;
+    } else if (!strcmp(make,"Leaf")) {
+        if (height > width)
+            filters = 0x16161616;
+        load_raw = unpacked_load_raw;
+        maximum = 0x3fff;
+        strcpy (model, "Valeo");
+        if (raw_width == 2060) {
             filters = 0;
+            load_raw = leaf_load_raw;
+            maximum = 0xffff;
+            strcpy (model, "Volare");
+        }
+    } else if (!strcmp(model,"DIGILUX 2") || !strcmp(model,"DMC-LC1")) {
+        height = 1928;
+        width  = 2568;
+        data_offset = 1024;
+        load_raw = unpacked_load_raw;
+        maximum = 0xfff0;
+    } else if (!strcmp(model,"E-1")) {
+        filters = 0x61616161;
+        load_raw = unpacked_load_raw;
+        maximum = 0xfff0;
+        black = 1024;
+    } else if (!strcmp(model,"E-10")) {
+        load_raw = unpacked_load_raw;
+        maximum = 0xfff0;
+        black = 2048;
+    } else if (!strncmp(model,"E-20",4)) {
+        load_raw = unpacked_load_raw;
+        maximum = 0xffc0;
+        black = 2560;
+    } else if (!strcmp(model,"E-300")) {
+        width -= 21;
+        load_raw = olympus_e300_load_raw;
+        if (fsize > 15728640) {
+            load_raw = unpacked_load_raw;
+            maximum = 0xfc30;
+        } else
+            black = 62;
+    } else if (!strcmp(make,"OLYMPUS")) {
+        load_raw = olympus_cseries_load_raw;
+        if (!strcmp(model,"C5050Z") ||
+            !strcmp(model,"C8080WZ"))
+            filters = 0x16161616;
+    } else if (!strcmp(model,"N Digital")) {
+        height = 2047;
+        width  = 3072;
+        filters = 0x61616161;
+        data_offset = 0x1a00;
+        load_raw = packed_12_load_raw;
+        maximum = 0xf1e;
+    } else if (!strcmp(model,"DSC-F828")) {
+        width = 3288;
+        left_margin = 5;
+        load_raw = sony_load_raw;
+        filters = 0x9c9c9c9c;
+        colors = 4;
+        black = 491;
+    } else if (!strcmp(model,"DSC-V3")) {
+        width = 3109;
+        left_margin = 59;
+        load_raw = sony_load_raw;
+    } else if (!strcasecmp(make,"KODAK")) {
+        filters = 0x61616161;
+        if (!strcmp(model,"NC2000F")) {
+            width -= 4;
+            left_margin = 1;
+            for (i=176; i < 0x1000; i++)
+                curve[i] = curve[i-1];
+            pre_mul[0] = 1.509;
+            pre_mul[2] = 2.686;
+        } else if (!strcmp(model,"EOSDCS3B")) {
+            width -= 4;
+            left_margin = 2;
+        } else if (!strcmp(model,"EOSDCS1")) {
+            width -= 4;
+            left_margin = 2;
+        } else if (!strcmp(model,"DCS315C")) {
+            black = 8;
+        } else if (!strcmp(model,"DCS330C")) {
+            black = 8;
+        } else if (!strcmp(model,"DCS420")) {
+            width -= 4;
+            left_margin = 2;
+        } else if (!strcmp(model,"DCS460")) {
+            width -= 4;
+            left_margin = 2;
+        } else if (!strcmp(model,"DCS460A")) {
+            width -= 4;
+            left_margin = 2;
+            colors = 1;
+            filters = 0;
+        } else if (!strcmp(model,"DCS520C")) {
+            black = 180;
+        } else if (!strcmp(model,"DCS560C")) {
+            black = 188;
+        } else if (!strcmp(model,"DCS620C")) {
+            black = 180;
+        } else if (!strcmp(model,"DCS620X")) {
+            black = 185;
+        } else if (!strcmp(model,"DCS660C")) {
+            black = 214;
+        } else if (!strcmp(model,"DCS660M")) {
+            black = 214;
+            colors = 1;
+            filters = 0;
+        } else if (!strcmp(model,"DCS760M")) {
+            colors = 1;
+            filters = 0;
+        }
+        switch (tiff_data_compression) {
+        case 0:               /* No compression */
+        case 1:
+            load_raw = kodak_easy_load_raw;
+            break;
+        case 7:               /* Lossless JPEG */
+            load_raw = lossless_jpeg_load_raw;
+        case 32867:
+            break;
+        case 65000:           /* Kodak DCR compression */
+            if (!have64BitArithmetic)
+                pm_error("This program was built without 64 bit arithmetic "
+                         "capability, and Kodak DCR compression requires it.");
+            if (kodak_data_compression == 32803)
+                load_raw = kodak_compressed_load_raw;
+            else {
+                load_raw = kodak_yuv_load_raw;
+                height = (height+1) & -2;
+                width  = (width +1) & -2;
+                filters = 0;
+            }
+            break;
+        default:
+            pm_message ("%s %s uses unrecognized compression method %d.",
+                        make, model, tiff_data_compression);
+            return 1;
+        }
+        if (!strcmp(model,"DC20")) {
+            height = 242;
+            if (fsize < 100000) {
+                width = 249;
+                raw_width = 256;
+            } else {
+                width = 501;
+                raw_width = 512;
+            }
+            data_offset = raw_width + 1;
+            colors = 4;
+            filters = 0x8d8d8d8d;
+            kodak_dc20_coeff (1.0);
+            pre_mul[1] = 1.179;
+            pre_mul[2] = 1.209;
+            pre_mul[3] = 1.036;
+            load_raw = kodak_easy_load_raw;
+        } else if (strstr(model,"DC25")) {
+            strcpy (model, "DC25");
+            height = 242;
+            if (fsize < 100000) {
+                width = 249;
+                raw_width = 256;
+                data_offset = 15681;
+            } else {
+                width = 501;
+                raw_width = 512;
+                data_offset = 15937;
+            }
+            colors = 4;
+            filters = 0xb4b4b4b4;
+            load_raw = kodak_easy_load_raw;
+        } else if (!strcmp(model,"Digital Camera 40")) {
+            strcpy (model, "DC40");
+            height = 512;
+            width = 768;
+            data_offset = 1152;
+            load_raw = kodak_radc_load_raw;
+        } else if (strstr(model,"DC50")) {
+            strcpy (model, "DC50");
+            height = 512;
+            width = 768;
+            data_offset = 19712;
+            load_raw = kodak_radc_load_raw;
+        } else if (strstr(model,"DC120")) {
+            strcpy (model, "DC120");
+            height = 976;
+            width = 848;
+            if (tiff_data_compression == 7)
+                load_raw = kodak_jpeg_load_raw;
+            else
+                load_raw = kodak_dc120_load_raw;
+        }
+    } else if (!strcmp(make,"Rollei")) {
+        switch (raw_width) {
+        case 1316:
+            height = 1030;
+            width  = 1300;
+            top_margin  = 1;
+            left_margin = 6;
+            break;
+        case 2568:
+            height = 1960;
+            width  = 2560;
+            top_margin  = 2;
+            left_margin = 8;
+        }
+        filters = 0x16161616;
+        load_raw = rollei_load_raw;
+        pre_mul[0] = 1.8;
+        pre_mul[2] = 1.3;
+    } else if (!strcmp(model,"PC-CAM 600")) {
+        height = 768;
+        data_offset = width = 1024;
+        filters = 0x49494949;
+        load_raw = eight_bit_load_raw;
+        pre_mul[0] = 1.14;
+        pre_mul[2] = 2.73;
+    } else if (!strcmp(model,"QV-2000UX")) {
+        height = 1208;
+        width  = 1632;
+        data_offset = width * 2;
+        load_raw = eight_bit_load_raw;
+    } else if (!strcmp(model,"QV-3*00EX")) {
+        height = 1546;
+        width  = 2070;
+        raw_width = 2080;
+        load_raw = eight_bit_load_raw;
+    } else if (!strcmp(model,"QV-4000")) {
+        height = 1700;
+        width  = 2260;
+        load_raw = unpacked_load_raw;
+        maximum = 0xffff;
+    } else if (!strcmp(model,"QV-5700")) {
+        height = 1924;
+        width  = 2576;
+        load_raw = casio_qv5700_load_raw;
+    } else if (!strcmp(model,"QV-R51")) {
+        height = 1926;
+        width  = 2576;
+        raw_width = 3904;
+        load_raw = packed_12_load_raw;
+        pre_mul[0] = 1.340;
+        pre_mul[2] = 1.672;
+    } else if (!strcmp(model,"EX-Z55")) {
+        height = 1960;
+        width  = 2570;
+        raw_width = 3904;
+        load_raw = packed_12_load_raw;
+        pre_mul[0] = 1.520;
+        pre_mul[2] = 1.316;
+    } else if (!strcmp(model,"EX-P600")) {
+        height = 2142;
+        width  = 2844;
+        raw_width = 4288;
+        load_raw = packed_12_load_raw;
+        pre_mul[0] = 1.797;
+        pre_mul[2] = 1.219;
+    } else if (!strcmp(model,"EX-P700")) {
+        height = 2318;
+        width  = 3082;
+        raw_width = 4672;
+        load_raw = packed_12_load_raw;
+        pre_mul[0] = 1.758;
+        pre_mul[2] = 1.504;
+    } else if (!strcmp(make,"Nucore")) {
+        filters = 0x61616161;
+        load_raw = unpacked_load_raw;
+        if (width == 2598) {
+            filters = 0x16161616;
+            load_raw = nucore_load_raw;
+            flip = 2;
         }
-        break;
-    default:
-        pm_message ("%s %s uses unrecognized compression method %d.",
-                    make, model, tiff_data_compression);
-        return 1;
-    }
-    if (!strcmp(model,"DC20")) {
-      height = 242;
-      if (fsize < 100000) {
-    width = 249;
-    raw_width = 256;
-      } else {
-    width = 501;
-    raw_width = 512;
-      }
-      data_offset = raw_width + 1;
-      colors = 4;
-      filters = 0x8d8d8d8d;
-      kodak_dc20_coeff (1.0);
-      pre_mul[1] = 1.179;
-      pre_mul[2] = 1.209;
-      pre_mul[3] = 1.036;
-      load_raw = kodak_easy_load_raw;
-    } else if (strstr(model,"DC25")) {
-      strcpy (model, "DC25");
-      height = 242;
-      if (fsize < 100000) {
-    width = 249;
-    raw_width = 256;
-    data_offset = 15681;
-      } else {
-    width = 501;
-    raw_width = 512;
-    data_offset = 15937;
-      }
-      colors = 4;
-      filters = 0xb4b4b4b4;
-      load_raw = kodak_easy_load_raw;
-    } else if (!strcmp(model,"Digital Camera 40")) {
-      strcpy (model, "DC40");
-      height = 512;
-      width = 768;
-      data_offset = 1152;
-      load_raw = kodak_radc_load_raw;
-    } else if (strstr(model,"DC50")) {
-      strcpy (model, "DC50");
-      height = 512;
-      width = 768;
-      data_offset = 19712;
-      load_raw = kodak_radc_load_raw;
-    } else if (strstr(model,"DC120")) {
-      strcpy (model, "DC120");
-      height = 976;
-      width = 848;
-      if (tiff_data_compression == 7)
-    load_raw = kodak_jpeg_load_raw;
-      else
-    load_raw = kodak_dc120_load_raw;
-    }
-  } else if (!strcmp(make,"Rollei")) {
-    switch (raw_width) {
-      case 1316:
-    height = 1030;
-    width  = 1300;
-    top_margin  = 1;
-    left_margin = 6;
-    break;
-      case 2568:
-    height = 1960;
-    width  = 2560;
-    top_margin  = 2;
-    left_margin = 8;
-    }
-    filters = 0x16161616;
-    load_raw = rollei_load_raw;
-    pre_mul[0] = 1.8;
-    pre_mul[2] = 1.3;
-  } else if (!strcmp(model,"PC-CAM 600")) {
-    height = 768;
-    data_offset = width = 1024;
-    filters = 0x49494949;
-    load_raw = eight_bit_load_raw;
-    pre_mul[0] = 1.14;
-    pre_mul[2] = 2.73;
-  } else if (!strcmp(model,"QV-2000UX")) {
-    height = 1208;
-    width  = 1632;
-    data_offset = width * 2;
-    load_raw = eight_bit_load_raw;
-  } else if (!strcmp(model,"QV-3*00EX")) {
-    height = 1546;
-    width  = 2070;
-    raw_width = 2080;
-    load_raw = eight_bit_load_raw;
-  } else if (!strcmp(model,"QV-4000")) {
-    height = 1700;
-    width  = 2260;
-    load_raw = unpacked_load_raw;
-    maximum = 0xffff;
-  } else if (!strcmp(model,"QV-5700")) {
-    height = 1924;
-    width  = 2576;
-    load_raw = casio_qv5700_load_raw;
-  } else if (!strcmp(model,"QV-R51")) {
-    height = 1926;
-    width  = 2576;
-    raw_width = 3904;
-    load_raw = packed_12_load_raw;
-    pre_mul[0] = 1.340;
-    pre_mul[2] = 1.672;
-  } else if (!strcmp(model,"EX-Z55")) {
-    height = 1960;
-    width  = 2570;
-    raw_width = 3904;
-    load_raw = packed_12_load_raw;
-    pre_mul[0] = 1.520;
-    pre_mul[2] = 1.316;
-  } else if (!strcmp(model,"EX-P600")) {
-    height = 2142;
-    width  = 2844;
-    raw_width = 4288;
-    load_raw = packed_12_load_raw;
-    pre_mul[0] = 1.797;
-    pre_mul[2] = 1.219;
-  } else if (!strcmp(model,"EX-P700")) {
-    height = 2318;
-    width  = 3082;
-    raw_width = 4672;
-    load_raw = packed_12_load_raw;
-    pre_mul[0] = 1.758;
-    pre_mul[2] = 1.504;
-  } else if (!strcmp(make,"Nucore")) {
-    filters = 0x61616161;
-    load_raw = unpacked_load_raw;
-    if (width == 2598) {
-      filters = 0x16161616;
-      load_raw = nucore_load_raw;
-      flip = 2;
     }
-  }
-  if (!use_coeff) adobe_coeff();
+    if (!use_coeff)
+        adobeCoeff(make, model);
 dng_skip:
-  if (!load_raw || !height) {
-    pm_message ("This program cannot handle data from %s %s.",
-                make, model);
-    return 1;
-  }
+    if (!load_raw || !height) {
+        pm_message ("This program cannot handle data from %s %s.",
+                    make, model);
+        return 1;
+    }
 #ifdef NO_JPEG
-  if (load_raw == kodak_jpeg_load_raw) {
-    pm_message ("decoder was not linked with libjpeg.");
-    return 1;
-  }
-#endif
-  if (!raw_height) raw_height = height;
-  if (!raw_width ) raw_width  = width;
-  if (use_camera_rgb && colors == 3)
-      use_coeff = 0;
-  if (use_coeff)         /* Apply user-selected color balance */
-    for (i=0; i < colors; i++) {
-      coeff[0][i] *= red_scale;
-      coeff[2][i] *= blue_scale;
+    if (load_raw == kodak_jpeg_load_raw) {
+        pm_message ("decoder was not linked with libjpeg.");
+        return 1;
     }
-  if (four_color_rgb && filters && colors == 3) {
-    for (i=0; i < 32; i+=4) {
-      if ((filters >> i & 15) == 9)
-    filters |= 2 << i;
-      if ((filters >> i & 15) == 6)
-    filters |= 8 << i;
+#endif
+    if (!raw_height) raw_height = height;
+    if (!raw_width ) raw_width  = width;
+    if (use_camera_rgb && colors == 3)
+        use_coeff = 0;
+    if (use_coeff)         /* Apply user-selected color balance */
+        for (i=0; i < colors; i++) {
+            coeff[0][i] *= red_scale;
+            coeff[2][i] *= blue_scale;
+        }
+    if (four_color_rgb && filters && colors == 3) {
+        for (i=0; i < 32; i+=4) {
+            if ((filters >> i & 15) == 9)
+                filters |= 2 << i;
+            if ((filters >> i & 15) == 6)
+                filters |= 8 << i;
+        }
+        colors++;
+        pre_mul[3] = pre_mul[1];
+        if (use_coeff)
+            for (i=0; i < 3; i++)
+                coeff[i][3] = coeff[i][1] /= 2;
     }
-    colors++;
-    pre_mul[3] = pre_mul[1];
-    if (use_coeff)
-      for (i=0; i < 3; i++)
-    coeff[i][3] = coeff[i][1] /= 2;
-  }
-  fseek (ifp, data_offset, SEEK_SET);
+    fseek (ifp, data_offset, SEEK_SET);
 
-  *loadRawFnP = load_raw;
+    *loadRawFnP = load_raw;
 
-  return 0;
+    return 0;
 }
diff --git a/converter/other/cameratopam/identify.h b/converter/other/cameratopam/identify.h
index 012b807c..62c9aae5 100644
--- a/converter/other/cameratopam/identify.h
+++ b/converter/other/cameratopam/identify.h
@@ -1,4 +1,4 @@
-typedef void (*loadRawFn)();
+#include "camera.h"
 
 int
 identify(FILE *       const ifp,
@@ -8,4 +8,4 @@ identify(FILE *       const ifp,
          float        const blue_scale,
          unsigned int const four_color_rgb,
          const char * const inputFileName,
-         loadRawFn *  const loadRawFnP);
+         LoadRawFn ** const loadRawFnP);
diff --git a/converter/other/cameratopam/ljpeg.c b/converter/other/cameratopam/ljpeg.c
index 4b092933..07791e25 100644
--- a/converter/other/cameratopam/ljpeg.c
+++ b/converter/other/cameratopam/ljpeg.c
@@ -20,127 +20,145 @@
  */
 
 int  
-ljpeg_start (FILE * ifp, struct jhead *jh)
-{
-  int i, tag, len;
-  unsigned char data[256], *dp;
-
-  init_decoder();
-  for (i=0; i < 4; i++)
-    jh->huff[i] = free_decode;
-  fread (data, 2, 1, ifp);
-  if (data[0] != 0xff || data[1] != 0xd8) return 0;
-  do {
-    fread (data, 2, 2, ifp);
-    tag =  data[0] << 8 | data[1];
-    len = (data[2] << 8 | data[3]);
-    if (len < 2)
-      pm_error("Length field is %u; must be at least 2", len);
-    else {
-      unsigned int const dataLen = len - 2;
-      if (tag <= 0xff00 || dataLen > 255) return 0;
-      fread (data, 1, dataLen, ifp);
-      switch (tag) {
-      case 0xffc3:
-        jh->bits = data[0];
-        jh->high = data[1] << 8 | data[2];
-        jh->wide = data[3] << 8 | data[4];
-        jh->clrs = data[5];
-        break;
-      case 0xffc4:
-        for (dp = data; dp < data+dataLen && *dp < 4; ) {
-          jh->huff[*dp] = free_decode;
-          dp = make_decoder (++dp, 0);
+ljpeg_start(FILE *         const ifP,
+            struct jhead * const jhP) {
+
+    int i, tag;
+    unsigned char data[256], *dp;
+
+    init_decoder();
+    for (i=0; i < 4; i++)
+        jhP->huff[i] = free_decode;
+    fread (data, 2, 1, ifP);
+    if (data[0] != 0xff || data[1] != 0xd8) return 0;
+    do {
+        unsigned int len;
+
+        fread (data, 2, 2, ifP);
+        tag =  data[0] << 8 | data[1];
+        len = data[2] << 8 | data[3];
+
+        if (len < 2)
+            pm_error("Length field is %u; must be at least 2", len);
+        else {
+            unsigned int const dataLen = len - 2;
+
+            if (tag <= 0xff00 || dataLen > 255) return 0;
+            fread (data, 1, dataLen, ifP);
+            switch (tag) {
+            case 0xffc3:
+                jhP->bits = data[0];
+                jhP->high = data[1] << 8 | data[2];
+                jhP->wide = data[3] << 8 | data[4];
+                jhP->clrs = data[5];
+                break;
+            case 0xffc4:
+                for (dp = data; dp < data + dataLen && *dp < 4; ) {
+                    jhP->huff[*dp] = free_decode;
+                    dp = make_decoder (++dp, 0);
+                }
+            }
         }
-      }
-    }
-  } while (tag != 0xffda);
-  jh->row = calloc (jh->wide*jh->clrs, 2);
-  if (jh->row == NULL)
-      pm_error("Out of memory in ljpeg_start()");
-  for (i=0; i < 4; i++)
-    jh->vpred[i] = 1 << (jh->bits-1);
-  zero_after_ff = 1;
-  getbits(ifp, -1);
-  return 1;
+    } while (tag != 0xffda);
+    jhP->row = calloc (jhP->wide*jhP->clrs, 2);
+    if (jhP->row == NULL)
+        pm_error("Out of memory in ljpeg_start()");
+    for (i=0; i < 4; i++)
+        jhP->vpred[i] = 1 << (jhP->bits-1);
+    zero_after_ff = 1;
+    getbits(ifP, -1);
+    return 1;
 }
 
+
+
 int 
-ljpeg_diff (struct decode *dindex)
-{
-  int len, diff;
-
-  while (dindex->branch[0])
-    dindex = dindex->branch[getbits(ifp, 1)];
-  diff = getbits(ifp, len = dindex->leaf);
-  if ((diff & (1 << (len-1))) == 0)
-    diff -= (1 << len) - 1;
-  return diff;
+ljpeg_diff(FILE *          const ifP,
+           struct decode * const dindexHeadP) {
+
+    int len;
+    int diff;
+    struct decode * dindexP;
+
+    for (dindexP = dindexHeadP; dindexP->branch[0]; )
+        dindexP = dindexP->branch[getbits(ifP, 1)];
+
+    diff = getbits(ifP, len = dindexP->leaf);
+
+    if ((diff & (1 << (len-1))) == 0)
+        diff -= (1 << len) - 1;
+
+    return diff;
 }
 
+
+
 void
-ljpeg_row (struct jhead *jh)
-{
-  int col, c, diff;
-  unsigned short *outp=jh->row;
-
-  for (col=0; col < jh->wide; col++)
-    for (c=0; c < jh->clrs; c++) {
-      diff = ljpeg_diff (jh->huff[c]);
-      *outp = col ? outp[-jh->clrs]+diff : (jh->vpred[c] += diff);
-      outp++;
-    }
+ljpeg_row(FILE *         const ifP,
+          struct jhead * const jhP) {
+
+    int col, c, diff;
+    unsigned short *outp=jhP->row;
+
+    for (col=0; col < jhP->wide; col++)
+        for (c=0; c < jhP->clrs; c++) {
+            diff = ljpeg_diff(ifP, jhP->huff[c]);
+            *outp = col ? outp[-jhP->clrs]+diff : (jhP->vpred[c] += diff);
+            outp++;
+        }
 }
 
+
+
 void  
-lossless_jpeg_load_raw(void)
-{
-  int jwide, jrow, jcol, val, jidx, i, row, col;
-  struct jhead jh;
-  int min=INT_MAX;
-
-  if (!ljpeg_start (ifp, &jh)) return;
-  jwide = jh.wide * jh.clrs;
-
-  for (jrow=0; jrow < jh.high; jrow++) {
-    ljpeg_row (&jh);
-    for (jcol=0; jcol < jwide; jcol++) {
-      val = curve[jh.row[jcol]];
-      jidx = jrow*jwide + jcol;
-      if (raw_width == 5108) {
-    i = jidx / (1680*jh.high);
-    if (i < 2) {
-      row = jidx / 1680 % jh.high;
-      col = jidx % 1680 + i*1680;
-    } else {
-      jidx -= 2*1680*jh.high;
-      row = jidx / 1748;
-      col = jidx % 1748 + 2*1680;
-    }
-      } else if (raw_width == 3516) {
-    row = jidx / 1758;
-    col = jidx % 1758;
-    if (row >= raw_height) {
-      row -= raw_height;
-      col += 1758;
-    }
-      } else {
-    row = jidx / raw_width;
-    col = jidx % raw_width;
-      }
-      if ((unsigned) (row-top_margin) >= height) continue;
-      if ((unsigned) (col-left_margin) < width) {
-    BAYER(row-top_margin,col-left_margin) = val;
-    if (min > val) min = val;
-      } else
-    black += val;
+lossless_jpeg_load_raw(Image  const image) {
+
+    int jwide, jrow, jcol, val, jidx, i, row, col;
+    struct jhead jh;
+    int min=INT_MAX;
+
+    if (!ljpeg_start (ifp, &jh)) return;
+    jwide = jh.wide * jh.clrs;
+
+    for (jrow=0; jrow < jh.high; jrow++) {
+        ljpeg_row (ifp, &jh);
+        for (jcol=0; jcol < jwide; jcol++) {
+            val = curve[jh.row[jcol]];
+            jidx = jrow*jwide + jcol;
+            if (raw_width == 5108) {
+                i = jidx / (1680*jh.high);
+                if (i < 2) {
+                    row = jidx / 1680 % jh.high;
+                    col = jidx % 1680 + i*1680;
+                } else {
+                    jidx -= 2*1680*jh.high;
+                    row = jidx / 1748;
+                    col = jidx % 1748 + 2*1680;
+                }
+            } else if (raw_width == 3516) {
+                row = jidx / 1758;
+                col = jidx % 1758;
+                if (row >= raw_height) {
+                    row -= raw_height;
+                    col += 1758;
+                }
+            } else {
+                row = jidx / raw_width;
+                col = jidx % raw_width;
+            }
+            if ((unsigned) (row-top_margin) >= height) continue;
+            if ((unsigned) (col-left_margin) < width) {
+                BAYER(row-top_margin,col-left_margin) = val;
+                if (min > val) min = val;
+            } else
+                black += val;
+        }
     }
-  }
-  free (jh.row);
-  if (raw_width > width)
-    black /= (raw_width - width) * height;
-  if (!strcasecmp(make,"KODAK"))
-    black = min;
+    free (jh.row);
+    if (raw_width > width)
+        black /= (raw_width - width) * height;
+    if (!strcasecmp(make,"KODAK"))
+        black = min;
 }
 
 
diff --git a/converter/other/cameratopam/ljpeg.h b/converter/other/cameratopam/ljpeg.h
index 60832a3d..9d9d8ee9 100644
--- a/converter/other/cameratopam/ljpeg.h
+++ b/converter/other/cameratopam/ljpeg.h
@@ -1,17 +1,21 @@
+#include "camera.h"
+
 struct jhead {
   int bits, high, wide, clrs, vpred[4];
   struct decode *huff[4];
   unsigned short *row;
 };
 
-void  
-lossless_jpeg_load_raw(void);
+LoadRawFn lossless_jpeg_load_raw;
 
 int  
-ljpeg_start (FILE * ifp, struct jhead *jh);
+ljpeg_start (FILE *         const ifP,
+             struct jhead * const jhP);
 
 int 
-ljpeg_diff (struct decode *dindex);
+ljpeg_diff (FILE *          const ifP,
+            struct decode * const dindexP);
 
 void
-ljpeg_row (struct jhead *jh);
+ljpeg_row(FILE *         const ifP,
+          struct jhead * const jhP);