about summary refs log tree commit diff
path: root/converter/other/cameratopam/camera.c
diff options
context:
space:
mode:
Diffstat (limited to 'converter/other/cameratopam/camera.c')
-rw-r--r--converter/other/cameratopam/camera.c1781
1 files changed, 1781 insertions, 0 deletions
diff --git a/converter/other/cameratopam/camera.c b/converter/other/cameratopam/camera.c
new file mode 100644
index 00000000..98d6d37a
--- /dev/null
+++ b/converter/other/cameratopam/camera.c
@@ -0,0 +1,1781 @@
+#define _BSD_SOURCE
+    /* Make sure strcasecmp is in string.h */
+#define _XOPEN_SOURCE
+    /* Make sure putenv is in stdlib.h */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/types.h>
+
+#ifdef HAVE_JPEG
+#include <jpeglib.h>
+#endif
+
+#include "pm.h"
+#include "mallocvar.h"
+
+#include "global_variables.h"
+#include "util.h"
+#include "decode.h"
+#include "bayer.h"
+#include "ljpeg.h"
+#include "dng.h"
+
+#include "camera.h"
+
+#if HAVE_INT64
+   typedef int64_t INT64;
+   static bool const have64BitArithmetic = true;
+#else
+   /* We define INT64 to something that lets the code compile, but we
+      should not execute any INT64 code, because it will get the wrong
+      result.
+   */
+   typedef int INT64;
+   static bool const have64BitArithmetic = false;
+#endif
+
+#ifndef LONG_BIT
+#define LONG_BIT (8 * sizeof (long))
+#endif
+
+#define FORC3 for (c=0; c < 3; c++)
+#define FORC4 for (c=0; c < colors; c++)
+
+static void 
+merror (const void *ptr, const char *where) 
+{
+    if (ptr == NULL)
+        pm_error ("Out of memory in %s", 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)++;
+    }
+  if (fuji_secondary && use_secondary) (*rp)--;
+}
+
+void
+adobe_dng_load_raw_lj()
+{
+  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 (&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;
+    }
+    free (jh.row);
+  }
+}
+
+
+
+void
+adobe_dng_load_raw_nc()
+{
+    unsigned short *pixel, *rp;
+    int row, col;
+
+    pixel = calloc (raw_width * tiff_samples, sizeof *pixel);
+    merror (pixel, "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);
+    }
+    free (pixel);
+}
+
+
+
+static int nikon_curve_offset;
+
+void
+nikon_compressed_load_raw(void)
+{
+    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
+    };
+    int csize, row, col, i, diff;
+    unsigned short vpred[4], hpred[2], *curve;
+
+    init_decoder();
+    make_decoder (nikon_tree, 0);
+
+    fseek (ifp, nikon_curve_offset, SEEK_SET);
+    read_shorts (ifp, vpred, 4);
+    csize = get2(ifp);
+    curve = calloc (csize, sizeof *curve);
+    merror (curve, "nikon_compressed_load_raw()");
+    read_shorts (ifp, curve, csize);
+
+    fseek (ifp, data_offset, SEEK_SET);
+    getbits(ifp, -1);
+
+    for (row=0; row < height; row++)
+        for (col=0; col < raw_width; col++)
+        {
+            diff = ljpeg_diff (first_decode);
+            if (col < 2) {
+                i = 2*(row & 1) + (col & 1);
+                vpred[i] += diff;
+                hpred[col] = vpred[i];
+            } else
+                hpred[col & 1] += diff;
+            if ((unsigned) (col-left_margin) >= width) continue;
+            diff = hpred[col & 1];
+            if (diff >= csize) diff = csize-1;
+            BAYER(row,col-left_margin) = curve[diff];
+        }
+    maximum = curve[csize-1];
+    free (curve);
+}
+
+void
+nikon_load_raw()
+{
+  int irow, row, col, i;
+
+  getbits(ifp, -1);
+  for (irow=0; irow < height; irow++) {
+    row = irow;
+    if (model[0] == 'E') {
+      row = irow * 2 % height + irow / (height/2);
+      if (row == 1 && atoi(model+1) < 5000) {
+    fseek (ifp, 0, SEEK_END);
+    fseek (ifp, ftell(ifp)/2, SEEK_SET);
+    getbits(ifp, -1);
+      }
+    }
+    for (col=0; col < raw_width; col++) {
+      i = getbits(ifp, 12);
+      if ((unsigned) (col-left_margin) < width)
+    BAYER(row,col-left_margin) = i;
+      if (tiff_data_compression == 34713 && (col % 10) == 9)
+    getbits(ifp, 8);
+    }
+  }
+}
+
+/*
+   Figure out if a NEF file is compressed.  These fancy heuristics
+   are only needed for the D100, thanks to a bug in some cameras
+   that tags all images as "compressed".
+ */
+int
+nikon_is_compressed()
+{
+  unsigned char test[256];
+  int i;
+
+  if (tiff_data_compression != 34713)
+    return 0;
+  if (strcmp(model,"D100"))
+    return 1;
+  fseek (ifp, data_offset, SEEK_SET);
+  fread (test, 1, 256, ifp);
+  for (i=15; i < 256; i+=16)
+    if (test[i]) return 1;
+  return 0;
+}
+
+/*
+   Returns 1 for a Coolpix 990, 0 for a Coolpix 995.
+ */
+int
+nikon_e990()
+{
+  int i, histo[256];
+  const unsigned char often[] = { 0x00, 0x55, 0xaa, 0xff };
+
+  memset (histo, 0, sizeof histo);
+  fseek (ifp, 2064*1540*3/4, SEEK_SET);
+  for (i=0; i < 2000; i++)
+    histo[fgetc(ifp)]++;
+  for (i=0; i < 4; i++)
+    if (histo[often[i]] > 400)
+      return 1;
+  return 0;
+}
+
+/*
+   Returns 1 for a Coolpix 2100, 0 for anything else.
+ */
+int
+nikon_e2100()
+{
+  unsigned char t[12];
+  int i;
+
+  fseek (ifp, 0, SEEK_SET);
+  for (i=0; i < 1024; i++) {
+    fread (t, 1, 12, ifp);
+    if (((t[2] & t[4] & t[7] & t[9]) >> 4
+    & t[1] & t[6] & t[8] & t[11] & 3) != 3)
+      return 0;
+  }
+  return 1;
+}
+
+/*
+   Separates a Pentax Optio 33WR from a Nikon E3700.
+ */
+int
+pentax_optio33()
+{
+  int i, sum[] = { 0, 0 };
+  unsigned char tail[952];
+
+  fseek (ifp, -sizeof tail, SEEK_END);
+  fread (tail, 1, sizeof tail, ifp);
+  for (i=0; i < sizeof tail; i++)
+    sum[(i>>2) & 1] += tail[i];
+  return sum[0] < sum[1]*4;
+}
+
+/*
+   Separates a Minolta DiMAGE Z2 from a Nikon E4300.
+ */
+int
+minolta_z2()
+{
+  int i;
+  char tail[424];
+
+  fseek (ifp, -sizeof tail, SEEK_END);
+  fread (tail, 1, sizeof tail, ifp);
+  for (i=0; i < sizeof tail; i++)
+    if (tail[i]) return 1;
+  return 0;
+}
+
+void
+nikon_e2100_load_raw()
+{
+  unsigned char   data[3432], *dp;
+  unsigned short pixel[2288], *pix;
+  int row, col;
+
+  for (row=0; row <= height; row+=2) {
+    if (row == height) {
+      fseek (ifp, ((width==1616) << 13) - (-ftell(ifp) & -2048), SEEK_SET);
+      row = 1;
+    }
+    fread (data, 1, width*3/2, ifp);
+    for (dp=data, pix=pixel; pix < pixel+width; dp+=12, pix+=8) {
+      pix[0] = (dp[2] >> 4) + (dp[ 3] << 4);
+      pix[1] = (dp[2] << 8) +  dp[ 1];
+      pix[2] = (dp[7] >> 4) + (dp[ 0] << 4);
+      pix[3] = (dp[7] << 8) +  dp[ 6];
+      pix[4] = (dp[4] >> 4) + (dp[ 5] << 4);
+      pix[5] = (dp[4] << 8) +  dp[11];
+      pix[6] = (dp[9] >> 4) + (dp[10] << 4);
+      pix[7] = (dp[9] << 8) +  dp[ 8];
+    }
+    for (col=0; col < width; col++)
+      BAYER(row,col) = (pixel[col] & 0xfff);
+  }
+}
+
+void
+nikon_e950_load_raw()
+{
+  int irow, row, col;
+
+  getbits(ifp, -1);
+  for (irow=0; irow < height; irow++) {
+    row = irow * 2 % height;
+    for (col=0; col < width; col++)
+      BAYER(row,col) = getbits(ifp, 10);
+    for (col=28; col--; )
+      getbits(ifp, 8);
+  }
+  maximum = 0x3dd;
+}
+
+/*
+   The Fuji Super CCD is just a Bayer grid rotated 45 degrees.
+ */
+void
+fuji_s2_load_raw()
+{
+  unsigned short pixel[2944];
+  int row, col, r, c;
+
+  fseek (ifp, (2944*24+32)*2, SEEK_CUR);
+  for (row=0; row < 2144; row++) {
+    read_shorts(ifp, pixel, 2944);
+    for (col=0; col < 2880; col++) {
+      r = row + ((col+1) >> 1);
+      c = 2143 - row + (col >> 1);
+      BAYER(r,c) = pixel[col];
+    }
+  }
+}
+
+void
+fuji_s3_load_raw()
+{
+  unsigned short pixel[4352];
+  int row, col, r, c;
+
+  fseek (ifp, (4352*2+32)*2, SEEK_CUR);
+  for (row=0; row < 1440; row++) {
+    read_shorts(ifp, pixel, 4352);
+    for (col=0; col < 4288; col++) {
+      r = 2143 + row - (col >> 1);
+      c = row + ((col+1) >> 1);
+      BAYER(r,c) = pixel[col];
+    }
+  }
+}
+
+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];
+    }
+  }
+}
+
+void
+fuji_s5000_load_raw()
+{
+  fseek (ifp, (1472*4+24)*2, SEEK_CUR);
+  fuji_common_load_raw (1472, 1423, 2152);
+}
+
+void
+fuji_s7000_load_raw()
+{
+  fuji_common_load_raw (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()
+{
+  unsigned short pixel[2944];
+  int row, col, r, c, val;
+
+  for (row=0; row < 2168; row++) {
+    read_shorts(ifp, pixel, 2944);
+    for (col=0; col < 1440; col++) {
+      r = 1439 - col + (row >> 1);
+      c = col + ((row+1) >> 1);
+      val = pixel[col+16 + use_secondary*1472];
+      BAYER(r,c) = val;
+    }
+  }
+}
+
+void
+rollei_load_raw()
+{
+  unsigned char pixel[10];
+  unsigned iten=0, isix, i, buffer=0, row, col, todo[16];
+
+  isix = raw_width * raw_height * 5 / 8;
+  while (fread (pixel, 1, 10, ifp) == 10) {
+    for (i=0; i < 10; i+=2) {
+      todo[i]   = iten++;
+      todo[i+1] = pixel[i] << 8 | pixel[i+1];
+      buffer    = pixel[i] >> 2 | buffer << 6;
+    }
+    for (   ; i < 16; i+=2) {
+      todo[i]   = isix++;
+      todo[i+1] = buffer >> (14-i)*5;
+    }
+    for (i=0; i < 16; i+=2) {
+      row = todo[i] / raw_width - top_margin;
+      col = todo[i] % raw_width - left_margin;
+      if (row < height && col < width)
+    BAYER(row,col) = (todo[i+1] & 0x3ff);
+    }
+  }
+  maximum = 0x3ff;
+}
+
+void
+phase_one_load_raw()
+{
+  int row, col, a, b;
+  unsigned short *pixel, akey, bkey;
+
+  fseek (ifp, 8, SEEK_CUR);
+  fseek (ifp, get4(ifp) + 296, SEEK_CUR);
+  akey = get2(ifp);
+  bkey = get2(ifp);
+  fseek (ifp, data_offset + 12 + top_margin*raw_width*2, SEEK_SET);
+  pixel = calloc (raw_width, sizeof *pixel);
+  merror (pixel, "phase_one_load_raw()");
+  for (row=0; row < height; row++) {
+    read_shorts(ifp, pixel, raw_width);
+    for (col=0; col < raw_width; col+=2) {
+      a = pixel[col+0] ^ akey;
+      b = pixel[col+1] ^ bkey;
+      pixel[col+0] = (b & 0xaaaa) | (a & 0x5555);
+      pixel[col+1] = (a & 0xaaaa) | (b & 0x5555);
+    }
+    for (col=0; col < width; col++)
+      BAYER(row,col) = pixel[col+left_margin];
+  }
+  free (pixel);
+}
+
+void
+ixpress_load_raw()
+{
+  unsigned short pixel[4090];
+  int row, col;
+
+  order = 0x4949;
+  fseek (ifp, 304 + 6*2*4090, SEEK_SET);
+  for (row=height; --row >= 0; ) {
+    read_shorts(ifp, pixel, 4090);
+    for (col=0; col < width; col++)
+      BAYER(row,col) = pixel[width-1-col];
+  }
+}
+
+void
+leaf_load_raw()
+{
+  unsigned short *pixel;
+  int r, c, row, col;
+
+  pixel = calloc (raw_width, sizeof *pixel);
+  merror (pixel, "leaf_load_raw()");
+  for (r=0; r < height-32; r+=32)
+    FORC3 for (row=r; row < r+32; row++) {
+      read_shorts(ifp, pixel, raw_width);
+      for (col=0; col < width; col++)
+    image[row*width+col][c] = pixel[col];
+    }
+  free (pixel);
+}
+
+/*
+   For this function only, raw_width is in bytes, not pixels!
+ */
+void
+packed_12_load_raw()
+{
+  int row, col;
+
+  getbits(ifp, -1);
+  for (row=0; row < height; row++) {
+    for (col=0; col < width; col++)
+      BAYER(row,col) = getbits(ifp, 12);
+    for (col = width*3/2; col < raw_width; col++)
+      getbits(ifp, 8);
+  }
+}
+
+void
+unpacked_load_raw()
+{
+  unsigned short *pixel;
+  int row, col;
+
+  pixel = calloc (raw_width, sizeof *pixel);
+  merror (pixel, "unpacked_load_raw()");
+  for (row=0; row < height; row++) {
+    read_shorts(ifp, pixel, raw_width);
+    for (col=0; col < width; col++)
+      BAYER(row,col) = pixel[col];
+  }
+  free (pixel);
+}
+
+void
+olympus_e300_load_raw()
+{
+  unsigned char  *data,  *dp;
+  unsigned short *pixel, *pix;
+  int dwide, row, col;
+
+  dwide = raw_width * 16 / 10;
+  data = malloc (dwide + raw_width*2);
+  merror (data, "olympus_e300_load_raw()");
+  pixel = (unsigned short *) (data + dwide);
+  for (row=0; row < height; row++) {
+    fread (data, 1, dwide, ifp);
+    for (dp=data, pix=pixel; pix < pixel+raw_width; dp+=3, pix+=2) {
+      if (((dp-data) & 15) == 15) dp++;
+      pix[0] = dp[1] << 8 | dp[0];
+      pix[1] = dp[2] << 4 | dp[1] >> 4;
+    }
+    for (col=0; col < width; col++)
+      BAYER(row,col) = (pixel[col] & 0xfff);
+  }
+  free (data);
+}
+
+void
+olympus_cseries_load_raw()
+{
+  int irow, row, col;
+
+  for (irow=0; irow < height; irow++) {
+    row = irow * 2 % height + irow / (height/2);
+    if (row < 2) {
+      fseek (ifp, data_offset - row*(-width*height*3/4 & -2048), SEEK_SET);
+      getbits(ifp, -1);
+    }
+    for (col=0; col < width; col++)
+      BAYER(row,col) = getbits(ifp, 12);
+  }
+}
+
+void
+eight_bit_load_raw()
+{
+  unsigned char *pixel;
+  int row, col;
+
+  pixel = calloc (raw_width, sizeof *pixel);
+  merror (pixel, "eight_bit_load_raw()");
+  for (row=0; row < height; row++) {
+    fread (pixel, 1, raw_width, ifp);
+    for (col=0; col < width; col++)
+      BAYER(row,col) = pixel[col];
+  }
+  free (pixel);
+  maximum = 0xff;
+}
+
+void
+casio_qv5700_load_raw()
+{
+  unsigned char  data[3232],  *dp;
+  unsigned short pixel[2576], *pix;
+  int row, col;
+
+  for (row=0; row < height; row++) {
+    fread (data, 1, 3232, ifp);
+    for (dp=data, pix=pixel; dp < data+3220; dp+=5, pix+=4) {
+      pix[0] = (dp[0] << 2) + (dp[1] >> 6);
+      pix[1] = (dp[1] << 4) + (dp[2] >> 4);
+      pix[2] = (dp[2] << 6) + (dp[3] >> 2);
+      pix[3] = (dp[3] << 8) + (dp[4]     );
+    }
+    for (col=0; col < width; col++)
+      BAYER(row,col) = (pixel[col] & 0x3ff);
+  }
+  maximum = 0x3fc;
+}
+
+void
+nucore_load_raw()
+{
+  unsigned short *pixel;
+  int irow, row, col;
+
+  pixel = calloc (width, 2);
+  merror (pixel, "nucore_load_raw()");
+  for (irow=0; irow < height; irow++) {
+    read_shorts(ifp, pixel, width);
+    row = irow/2 + height/2 * (irow & 1);
+    for (col=0; col < width; col++)
+      BAYER(row,col) = pixel[col];
+  }
+  free (pixel);
+}
+
+static int  radc_token (int tree)
+{
+  int t;
+  static struct decode *dstart[18], *dindex;
+  static const int *s, source[] = {
+    1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8,
+    1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8,
+    2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8,
+    2,0, 2,1, 2,3, 3,2, 4,4, 5,6, 6,7, 7,5, 7,8,
+    2,1, 2,4, 3,0, 3,2, 3,3, 4,7, 5,5, 6,6, 6,8,
+    2,3, 3,1, 3,2, 3,4, 3,5, 3,6, 4,7, 5,0, 5,8,
+    2,3, 2,6, 3,0, 3,1, 4,4, 4,5, 4,7, 5,2, 5,8,
+    2,4, 2,7, 3,3, 3,6, 4,1, 4,2, 4,5, 5,0, 5,8,
+    2,6, 3,1, 3,3, 3,5, 3,7, 3,8, 4,0, 5,2, 5,4,
+    2,0, 2,1, 3,2, 3,3, 4,4, 4,5, 5,6, 5,7, 4,8,
+    1,0, 2,2, 2,-2,
+    1,-3, 1,3,
+    2,-17, 2,-5, 2,5, 2,17,
+    2,-7, 2,2, 2,9, 2,18,
+    2,-18, 2,-9, 2,-2, 2,7,
+    2,-28, 2,28, 3,-49, 3,-9, 3,9, 4,49, 5,-79, 5,79,
+    2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76,
+    2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37
+  };
+
+  if (free_decode == first_decode)
+    for (s=source, t=0; t < 18; t++) {
+      dstart[t] = free_decode;
+      s = make_decoder_int (s, 0);
+    }
+  if (tree == 18) {
+    if (model[2] == '4')
+      return (getbits(ifp, 5) << 3) + 4; /* DC40 */
+    else
+      return (getbits(ifp, 6) << 2) + 2; /* DC50 */
+  }
+  for (dindex = dstart[tree]; dindex->branch[0]; )
+    dindex = dindex->branch[getbits(ifp, 1)];
+  return dindex->leaf;
+}
+
+#define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--)
+
+#define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \
+: (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];
+
+  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;
+        }
+          }
+        } 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() {}
+#else
+
+static boolean
+fill_input_buffer (j_decompress_ptr cinfo)
+{
+  static char jpeg_buffer[4096];
+  size_t nbytes;
+
+  nbytes = fread (jpeg_buffer, 1, 4096, ifp);
+  swab (jpeg_buffer, jpeg_buffer, nbytes);
+  cinfo->src->next_input_byte = jpeg_buffer;
+  cinfo->src->bytes_in_buffer = nbytes;
+  return TRUE;
+}
+
+void
+kodak_jpeg_load_raw()
+{
+  struct jpeg_decompress_struct cinfo;
+  struct jpeg_error_mgr jerr;
+  JSAMPARRAY buf;
+  JSAMPLE (*pixel)[3];
+  int row, col;
+
+  cinfo.err = jpeg_std_error (&jerr);
+  jpeg_create_decompress (&cinfo);
+  jpeg_stdio_src (&cinfo, ifp);
+  cinfo.src->fill_input_buffer = fill_input_buffer;
+  jpeg_read_header (&cinfo, TRUE);
+  jpeg_start_decompress (&cinfo);
+  if ((cinfo.output_width      != width  ) ||
+      (cinfo.output_height*2   != height ) ||
+      (cinfo.output_components != 3      )) {
+    pm_error ("incorrect JPEG dimensions");
+  }
+  buf = (*cinfo.mem->alloc_sarray)
+        ((j_common_ptr) &cinfo, JPOOL_IMAGE, width*3, 1);
+
+  while (cinfo.output_scanline < cinfo.output_height) {
+    row = cinfo.output_scanline * 2;
+    jpeg_read_scanlines (&cinfo, buf, 1);
+    pixel = (void *) buf[0];
+    for (col=0; col < width; col+=2) {
+      BAYER(row+0,col+0) = pixel[col+0][1] << 1;
+      BAYER(row+1,col+1) = pixel[col+1][1] << 1;
+      BAYER(row+0,col+1) = pixel[col][0] + pixel[col+1][0];
+      BAYER(row+1,col+0) = pixel[col][2] + pixel[col+1][2];
+    }
+  }
+  jpeg_finish_decompress (&cinfo);
+  jpeg_destroy_decompress (&cinfo);
+  maximum = 0xff << 1;
+}
+
+#endif
+
+void
+kodak_dc120_load_raw()
+{
+  static const int mul[4] = { 162, 192, 187,  92 };
+  static const int add[4] = {   0, 636, 424, 212 };
+  unsigned char pixel[848];
+  int row, shift, col;
+
+  for (row=0; row < height; row++) {
+    fread (pixel, 848, 1, ifp);
+    shift = row * mul[row & 3] + add[row & 3];
+    for (col=0; col < width; col++)
+      BAYER(row,col) = (unsigned short) pixel[(col + shift) % 848];
+  }
+  maximum = 0xff;
+}
+
+void
+kodak_dc20_coeff (float const juice)
+{
+  static const float my_coeff[3][4] =
+  { {  2.25,  0.75, -1.75, -0.25 },
+    { -0.25,  0.75,  0.75, -0.25 },
+    { -0.25, -1.75,  0.75,  2.25 } };
+  static const float flat[3][4] =
+  { {  1, 0,   0,   0 },
+    {  0, 0.5, 0.5, 0 },
+    {  0, 0,   0,   1 } };
+  int r, g;
+
+  for (r=0; r < 3; r++)
+    for (g=0; g < 4; g++)
+      coeff[r][g] = my_coeff[r][g] * juice + flat[r][g] * (1-juice);
+  use_coeff = 1;
+}
+
+void
+kodak_easy_load_raw()
+{
+  unsigned char *pixel;
+  unsigned row, col, icol;
+
+  if (raw_width > width)
+    black = 0;
+  pixel = calloc (raw_width, sizeof *pixel);
+  merror (pixel, "kodak_easy_load_raw()");
+  for (row=0; row < height; row++) {
+    fread (pixel, 1, raw_width, ifp);
+    for (col=0; col < raw_width; col++) {
+      icol = col - left_margin;
+      if (icol < width)
+    BAYER(row,icol) = (unsigned short) curve[pixel[col]];
+      else
+    black += curve[pixel[col]];
+    }
+  }
+  free (pixel);
+  if (raw_width > width)
+    black /= (raw_width - width) * height;
+  if (!strncmp(model,"DC2",3))
+    black = 0;
+  maximum = curve[0xff];
+}
+
+void
+kodak_compressed_load_raw()
+{
+  unsigned char c, blen[256];
+  unsigned short raw[6];
+  unsigned row, col, len, save, i, israw=0, bits=0, pred[2];
+  INT64 bitbuf=0;
+  int diff;
+
+  assert(have64BitArithmetic);
+
+  for (row=0; row < height; row++)
+    for (col=0; col < width; col++)
+    {
+      if ((col & 255) == 0) {       /* Get the bit-lengths of the */
+    len = width - col;      /* next 256 pixel values      */
+    if (len > 256) len = 256;
+    save = ftell(ifp);
+    for (israw=i=0; i < len; i+=2) {
+      c = fgetc(ifp);
+      if ((blen[i+0] = c & 15) > 12 ||
+          (blen[i+1] = c >> 4) > 12 )
+        israw = 1;
+    }
+    bitbuf = bits = pred[0] = pred[1] = 0;
+    if (len % 8 == 4) {
+      bitbuf  = fgetc(ifp) << 8;
+      bitbuf += fgetc(ifp);
+      bits = 16;
+    }
+    if (israw)
+      fseek (ifp, save, SEEK_SET);
+      }
+      if (israw) {          /* If the data is not compressed */
+    switch (col & 7) {
+      case 0:
+        read_shorts(ifp, raw, 6);
+        diff = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12;
+        break;
+      case 1:
+        diff = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12;
+        break;
+      default:
+        diff = raw[(col & 7) - 2] & 0xfff;
+    }
+      } else {              /* If the data is compressed */
+    len = blen[col & 255];      /* Number of bits for this pixel */
+    if (bits < len) {       /* Got enough bits in the buffer? */
+      for (i=0; i < 32; i+=8)
+        bitbuf += (INT64) fgetc(ifp) << (bits+(i^8));
+      bits += 32;
+    }
+    diff = bitbuf & (0xffff >> (16-len));  /* Pull bits from buffer */
+    bitbuf >>= len;
+    bits -= len;
+    if ((diff & (1 << (len-1))) == 0)
+      diff -= (1 << len) - 1;
+    pred[col & 1] += diff;
+    diff = pred[col & 1];
+      }
+      BAYER(row,col) = curve[diff];
+    }
+}
+
+void
+kodak_yuv_load_raw()
+{
+  unsigned char c, blen[384];
+  unsigned row, col, len, bits=0;
+  INT64 bitbuf=0;
+  int i, li=0, si, diff, six[6], y[4], cb=0, cr=0, rgb[3];
+  unsigned short *ip;
+
+  assert(have64BitArithmetic);
+
+  for (row=0; row < height; row+=2)
+    for (col=0; col < width; col+=2) {
+      if ((col & 127) == 0) {
+    len = (width - col + 1) * 3 & -4;
+    if (len > 384) len = 384;
+    for (i=0; i < len; ) {
+      c = fgetc(ifp);
+      blen[i++] = c & 15;
+      blen[i++] = c >> 4;
+    }
+    li = bitbuf = bits = y[1] = y[3] = cb = cr = 0;
+    if (len % 8 == 4) {
+      bitbuf  = fgetc(ifp) << 8;
+      bitbuf += fgetc(ifp);
+      bits = 16;
+    }
+      }
+      for (si=0; si < 6; si++) {
+    len = blen[li++];
+    if (bits < len) {
+      for (i=0; i < 32; i+=8)
+        bitbuf += (INT64) fgetc(ifp) << (bits+(i^8));
+      bits += 32;
+    }
+    diff = bitbuf & (0xffff >> (16-len));
+    bitbuf >>= len;
+    bits -= len;
+    if ((diff & (1 << (len-1))) == 0)
+      diff -= (1 << len) - 1;
+    six[si] = diff;
+      }
+      y[0] = six[0] + y[1];
+      y[1] = six[1] + y[0];
+      y[2] = six[2] + y[3];
+      y[3] = six[3] + y[2];
+      cb  += six[4];
+      cr  += six[5];
+      for (i=0; i < 4; i++) {
+    ip = image[(row+(i >> 1))*width + col+(i & 1)];
+    rgb[0] = y[i] + cr;
+    rgb[1] = y[i];
+    rgb[2] = y[i] + cb;
+    FORC3 if (rgb[c] > 0) ip[c] = curve[rgb[c]];
+      }
+    }
+  maximum = 0xe74;
+}
+
+static void  sony_decrypt (unsigned *data, int len, int start, int key)
+{
+  static uint32_t pad[128];
+  unsigned int p;
+
+  if (start) {
+    for (p=0; p < 4; p++)
+      pad[p] = key = key * 48828125 + 1;
+    pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31;
+    for (p=4; p < 127; p++)
+      pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31;
+
+    /* Convert to big-endian */
+
+    for (p=0; p < 127; p++) {
+        union {
+            unsigned char bytes[4];
+            uint32_t word;
+        } u;
+
+        u.bytes[0] = pad[p] >> 24;
+        u.bytes[1] = pad[p] >> 16;
+        u.bytes[2] = pad[p] >>  8;
+        u.bytes[3] = pad[p] >>  0;
+        
+        pad[p] = u.word;
+    }
+  }
+  while (len--)
+    *data++ ^= pad[p++ & 0x7f] = pad[(p+1) & 0x7f] ^ pad[(p+65) & 0x7f];
+}
+
+void
+sony_load_raw()
+{
+  unsigned char head[40];
+  struct pixel {
+      unsigned char bytes[2];
+  };
+  struct pixel * pixelrow;
+  unsigned i, key, row, col;
+
+  fseek (ifp, 200896, SEEK_SET);
+  fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR);
+  order = 0x4d4d;
+  key = get4(ifp);
+  fseek (ifp, 164600, SEEK_SET);
+  fread (head, 1, 40, ifp);
+  sony_decrypt ((void *) head, 10, 1, key);
+  for (i=26; i-- > 22; )
+    key = key << 8 | head[i];
+  fseek (ifp, data_offset, SEEK_SET);
+  MALLOCARRAY(pixelrow, raw_width);
+  merror (pixelrow, "sony_load_raw()");
+  for (row=0; row < height; row++) {
+    fread (pixelrow, 2, raw_width, ifp);
+    sony_decrypt ((void *) pixelrow, raw_width/2, !row, key);
+    for (col=9; col < left_margin; col++)
+      black += pixelrow[col].bytes[0] * 256 + pixelrow[col].bytes[1];
+    for (col=0; col < width; col++)
+      BAYER(row,col) =
+          pixelrow[col+left_margin].bytes[0] * 256 +
+          pixelrow[col+left_margin].bytes[1];
+  }
+  free (pixelrow);
+  if (left_margin > 9)
+    black /= (left_margin-9) * height;
+  maximum = 0x3ff0;
+}
+
+void
+parse_minolta(FILE * const ifp)
+{
+  int save, tag, len, offset, high=0, wide=0;
+
+  fseek (ifp, 4, SEEK_SET);
+  offset = get4(ifp) + 8;
+  while ((save=ftell(ifp)) < offset) {
+    tag = get4(ifp);
+    len = get4(ifp);
+    switch (tag) {
+      case 0x505244:                /* PRD */
+    fseek (ifp, 8, SEEK_CUR);
+    high = get2(ifp);
+    wide = get2(ifp);
+    break;
+      case 0x574247:                /* WBG */
+    get4(ifp);
+    camera_red  = get2(ifp);
+    camera_red /= get2(ifp);
+    camera_blue = get2(ifp);
+    camera_blue = get2(ifp) / camera_blue;
+    break;
+      case 0x545457:                /* TTW */
+    parse_tiff(ifp, ftell(ifp));
+    }
+    fseek (ifp, save+len+8, SEEK_SET);
+  }
+  raw_height = high;
+  raw_width  = wide;
+  data_offset = offset;
+}
+
+/*
+   CIFF block 0x1030 contains an 8x8 white sample.
+   Load this into white[][] for use in scale_colors().
+ */
+static void  ciff_block_1030()
+{
+  static const unsigned short key[] = { 0x410, 0x45f3 };
+  int i, bpp, row, col, vbits=0;
+  unsigned long bitbuf=0;
+
+  get2(ifp);
+  if (get4(ifp) != 0x80008) return;
+  if (get4(ifp) == 0) return;
+  bpp = get2(ifp);
+  if (bpp != 10 && bpp != 12) return;
+  for (i=row=0; row < 8; row++)
+    for (col=0; col < 8; col++) {
+      if (vbits < bpp) {
+    bitbuf = bitbuf << 16 | (get2(ifp) ^ key[i++ & 1]);
+    vbits += 16;
+      }
+      white[row][col] =
+    bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp);
+      vbits -= bpp;
+    }
+}
+
+/*
+   Parse a CIFF file, better known as Canon CRW format.
+ */
+void 
+parse_ciff(FILE * const ifp, 
+           int    const offset, 
+           int    const length)
+{
+  int tboff, nrecs, i, type, len, roff, aoff, save, wbi=-1;
+  static const int remap[] = { 1,2,3,4,5,1 };
+  static const int remap_10d[] = { 0,1,3,4,5,6,0,0,2,8 };
+  static const int remap_s70[] = { 0,1,2,9,4,3,6,7,8,9,10,0,0,0,7,0,0,8 };
+  unsigned short key[] = { 0x410, 0x45f3 };
+
+  if (strcmp(model,"Canon PowerShot G6") &&
+      strcmp(model,"Canon PowerShot S70") &&
+      strcmp(model,"Canon PowerShot Pro1"))
+    key[0] = key[1] = 0;
+  fseek (ifp, offset+length-4, SEEK_SET);
+  tboff = get4(ifp) + offset;
+  fseek (ifp, tboff, SEEK_SET);
+  nrecs = get2(ifp);
+  for (i = 0; i < nrecs; i++) {
+    type = get2(ifp);
+    len  = get4(ifp);
+    roff = get4(ifp);
+    aoff = offset + roff;
+    save = ftell(ifp);
+    if (type == 0x080a) {       /* Get the camera make and model */
+      fseek (ifp, aoff, SEEK_SET);
+      fread (make, 64, 1, ifp);
+      fseek (ifp, aoff+strlen(make)+1, SEEK_SET);
+      fread (model, 64, 1, ifp);
+    }
+    if (type == 0x102a) {       /* Find the White Balance index */
+      fseek (ifp, aoff+14, SEEK_SET);   /* 0=auto, 1=daylight, 2=cloudy ... */
+      wbi = get2(ifp);
+      if (((!strcmp(model,"Canon EOS DIGITAL REBEL") ||
+        !strcmp(model,"Canon EOS 300D DIGITAL"))) && wbi == 6)
+    wbi++;
+    }
+    if (type == 0x102c) {       /* Get white balance (G2) */
+      if (!strcmp(model,"Canon PowerShot G1") ||
+      !strcmp(model,"Canon PowerShot Pro90 IS")) {
+    fseek (ifp, aoff+120, SEEK_SET);
+    white[0][1] = get2(ifp);
+    white[0][0] = get2(ifp);
+    white[1][0] = get2(ifp);
+    white[1][1] = get2(ifp);
+      } else {
+    fseek (ifp, aoff+100, SEEK_SET);
+    goto common;
+      }
+    }
+    if (type == 0x0032) {       /* Get white balance (D30 & G3) */
+      if (!strcmp(model,"Canon EOS D30")) {
+    fseek (ifp, aoff+72, SEEK_SET);
+common:
+    camera_red   = get2(ifp) ^ key[0];
+    camera_red   =(get2(ifp) ^ key[1]) / camera_red;
+    camera_blue  = get2(ifp) ^ key[0];
+    camera_blue /= get2(ifp) ^ key[1];
+      } else if (!strcmp(model,"Canon PowerShot G6") ||
+         !strcmp(model,"Canon PowerShot S70")) {
+    fseek (ifp, aoff+96 + remap_s70[wbi]*8, SEEK_SET);
+    goto common;
+      } else if (!strcmp(model,"Canon PowerShot Pro1")) {
+    fseek (ifp, aoff+96 + wbi*8, SEEK_SET);
+    goto common;
+      } else {
+    fseek (ifp, aoff+80 + (wbi < 6 ? remap[wbi]*8 : 0), SEEK_SET);
+    if (!camera_red)
+      goto common;
+      }
+    }
+    if (type == 0x10a9) {       /* Get white balance (D60) */
+      if (!strcmp(model,"Canon EOS 10D"))
+    wbi = remap_10d[wbi];
+      fseek (ifp, aoff+2 + wbi*8, SEEK_SET);
+      camera_red  = get2(ifp);
+      camera_red /= get2(ifp);
+      camera_blue = get2(ifp);
+      camera_blue = get2(ifp) / camera_blue;
+    }
+    if (type == 0x1030 && (wbi == 6 || wbi == 15)) {
+      fseek (ifp, aoff, SEEK_SET);  /* Get white sample */
+      ciff_block_1030();
+    }
+    if (type == 0x1031) {       /* Get the raw width and height */
+      fseek (ifp, aoff+2, SEEK_SET);
+      raw_width  = get2(ifp);
+      raw_height = get2(ifp);
+    }
+    if (type == 0x180e) {       /* Get the timestamp */
+      fseek (ifp, aoff, SEEK_SET);
+      timestamp = get4(ifp);
+    }
+    if (type == 0x580e)
+      timestamp = len;
+    if (type == 0x1810) {       /* Get the rotation */
+      fseek (ifp, aoff+12, SEEK_SET);
+      flip = get4(ifp);
+    }
+    if (type == 0x1835) {       /* Get the decoder table */
+      fseek (ifp, aoff, SEEK_SET);
+      crw_init_tables (get4(ifp));
+    }
+    if (type >> 8 == 0x28 || type >> 8 == 0x30) /* Get sub-tables */
+      parse_ciff(ifp, aoff, len);
+    fseek (ifp, save, SEEK_SET);
+  }
+  if (wbi == 0 && !strcmp(model,"Canon EOS D30"))
+    camera_red = -1;            /* Use my auto WB for this photo */
+}
+
+void
+parse_rollei(FILE * const ifp)
+{
+  char line[128], *val;
+  int tx=0, ty=0;
+  struct tm t;
+  time_t ts;
+
+  fseek (ifp, 0, SEEK_SET);
+  do {
+    fgets (line, 128, ifp);
+    if ((val = strchr(line,'=')))
+      *val++ = 0;
+    else
+      val = line + strlen(line);
+    if (!strcmp(line,"DAT"))
+      sscanf (val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year);
+    if (!strcmp(line,"TIM"))
+      sscanf (val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec);
+    if (!strcmp(line,"HDR"))
+      data_offset = atoi(val);
+    if (!strcmp(line,"X  "))
+      raw_width = atoi(val);
+    if (!strcmp(line,"Y  "))
+      raw_height = atoi(val);
+    if (!strcmp(line,"TX "))
+      tx = atoi(val);
+    if (!strcmp(line,"TY "))
+      ty = atoi(val);
+  } while (strncmp(line,"EOHD",4));
+  t.tm_year -= 1900;
+  t.tm_mon -= 1;
+  putenv((char*)"TZ=");
+  if ((ts = mktime(&t)) > 0)
+    timestamp = ts;
+  data_offset += tx * ty * 2;
+  strcpy (make, "Rollei");
+  strcpy (model,"d530flex");
+}
+
+
+
+void
+parse_mos(FILE * const ifp, 
+          int    const offset)
+{
+    char data[40];
+    int skip, from, i, neut[4];
+
+    fseek (ifp, offset, SEEK_SET);
+    while (1) {
+        fread (data, 1, 8, ifp);
+        if (strcmp(data,"PKTS")) break;
+        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);
+            camera_red  = (float) neut[2] / neut[1];
+            camera_blue = (float) neut[2] / neut[3];
+        }
+        parse_mos(ifp, from);
+        fseek (ifp, skip+from, SEEK_SET);
+    }
+}
+
+void
+nikon_e950_coeff()
+{
+  int r, g;
+  static const float my_coeff[3][4] =
+  { { -1.936280,  1.800443, -1.448486,  2.584324 },
+    {  1.405365, -0.524955, -0.289090,  0.408680 },
+    { -1.204965,  1.082304,  2.941367, -1.818705 } };
+
+  for (r=0; r < 3; r++)
+    for (g=0; g < 4; g++)
+      coeff[r][g] = my_coeff[r][g];
+  use_coeff = 1;
+}
+
+
+
+static double getrat()
+{
+  double num = get4(ifp);
+  return num / get4(ifp);
+}
+
+
+
+static void 
+parse_makernote(FILE * const ifp)
+{
+  unsigned base=0, offset=0, entries, tag, type, len, save;
+  static const int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 };
+  short sorder;
+  char buf[10];
+/*
+   The MakerNote might have its own TIFF header (possibly with
+   its own byte-order!), or it might just be a table.
+ */
+  sorder = order;
+  fread (buf, 1, 10, ifp);
+  if (!strncmp (buf,"KC" ,2) ||     /* these aren't TIFF format */
+      !strncmp (buf,"MLY",3)) return;
+  if (!strcmp (buf,"Nikon")) {
+    base = ftell(ifp);
+    order = get2(ifp);
+    if (get2(ifp) != 42) goto quit;
+    offset = get4(ifp);
+    fseek (ifp, offset-8, SEEK_CUR);
+  } else if (!strncmp (buf,"FUJIFILM",8) ||
+         !strcmp  (buf,"Panasonic")) {
+    order = 0x4949;
+    fseek (ifp,  2, SEEK_CUR);
+  } else if (!strcmp (buf,"OLYMP") ||
+         !strcmp (buf,"LEICA") ||
+         !strcmp (buf,"EPSON"))
+    fseek (ifp, -2, SEEK_CUR);
+  else if (!strcmp (buf,"AOC") ||
+       !strcmp (buf,"QVC"))
+    fseek (ifp, -4, SEEK_CUR);
+  else fseek (ifp, -10, SEEK_CUR);
+
+  entries = get2(ifp);
+  while (entries--) {
+    tag  = get2(ifp);
+    type = get2(ifp);
+    len  = get4(ifp);
+    save = ftell(ifp);
+    if (len * size[type < 13 ? type:0] > 4)
+      fseek (ifp, get4(ifp)+base, SEEK_SET);
+
+    if (tag == 0xc && len == 4) {
+      camera_red  = getrat();
+      camera_blue = getrat();
+    }
+    if (tag == 0x14 && len == 2560 && type == 7) {
+      fseek (ifp, 1248, SEEK_CUR);
+      goto get2_256;
+    }
+    if (strstr(make,"PENTAX")) {
+      if (tag == 0x1b) tag = 0x1018;
+      if (tag == 0x1c) tag = 0x1017;
+    }
+    if (tag == 0x8c)
+      nikon_curve_offset = ftell(ifp) + 2112;
+    if (tag == 0x96)
+      nikon_curve_offset = ftell(ifp) + 2;
+    if (tag == 0x97) {
+      if (!strcmp(model,"NIKON D100 ")) {
+    fseek (ifp, 72, SEEK_CUR);
+    camera_red  = get2(ifp) / 256.0;
+    camera_blue = get2(ifp) / 256.0;
+      } else if (!strcmp(model,"NIKON D2H")) {
+    fseek (ifp, 10, SEEK_CUR);
+    goto get2_rggb;
+      } else if (!strcmp(model,"NIKON D70")) {
+    fseek (ifp, 20, SEEK_CUR);
+    camera_red  = get2(ifp);
+    camera_red /= get2(ifp);
+    camera_blue = get2(ifp);
+    camera_blue/= get2(ifp);
+      }
+    }
+    if (tag == 0xe0 && len == 17) {
+      get2(ifp);
+      raw_width  = get2(ifp);
+      raw_height = get2(ifp);
+    }
+    if (tag == 0x200 && len == 4)
+      black = (get2(ifp)+get2(ifp)+get2(ifp)+get2(ifp))/4;
+    if (tag == 0x201 && len == 4) {
+      camera_red  = get2(ifp);
+      camera_red /= get2(ifp);
+      camera_blue = get2(ifp);
+      camera_blue = get2(ifp) / camera_blue;
+    }
+    if (tag == 0x401 && len == 4) {
+      black = (get4(ifp)+get4(ifp)+get4(ifp)+get4(ifp))/4;
+    }
+    if (tag == 0xe80 && len == 256 && type == 7) {
+      fseek (ifp, 48, SEEK_CUR);
+      camera_red  = get2(ifp) * 508 * 1.078 / 0x10000;
+      camera_blue = get2(ifp) * 382 * 1.173 / 0x10000;
+    }
+    if (tag == 0xf00 && len == 614 && type == 7) {
+      fseek (ifp, 188, SEEK_CUR);
+      goto get2_256;
+    }
+    if (tag == 0x1017)
+      camera_red  = get2(ifp) / 256.0;
+    if (tag == 0x1018)
+      camera_blue = get2(ifp) / 256.0;
+    if (tag == 0x2011 && len == 2) {
+get2_256:
+      order = 0x4d4d;
+      camera_red  = get2(ifp) / 256.0;
+      camera_blue = get2(ifp) / 256.0;
+    }
+    if (tag == 0x4001) {
+      fseek (ifp, strstr(model,"EOS-1D") ? 68:50, SEEK_CUR);
+get2_rggb:
+      camera_red  = get2(ifp);
+      camera_red /= get2(ifp);
+      camera_blue = get2(ifp);
+      camera_blue = get2(ifp) / camera_blue;
+    }
+    fseek (ifp, save+4, SEEK_SET);
+  }
+quit:
+  order = sorder;
+}
+
+
+
+static void
+get_timestamp(FILE * const ifp)
+{
+/*
+   Since the TIFF DateTime string has no timezone information,
+   assume that the camera's clock was set to Universal Time.
+ */
+  struct tm t;
+  time_t ts;
+
+  if (fscanf (ifp, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon,
+    &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6)
+    return;
+  t.tm_year -= 1900;
+  t.tm_mon -= 1;
+  putenv((char*)"TZ=UTC");   /* Remove this to assume local time */
+  if ((ts = mktime(&t)) > 0)
+    timestamp = ts;
+}
+
+static void 
+parse_exif(FILE * const ifp, int base)
+{
+  int entries, tag, type, len, val, save;
+
+  entries = get2(ifp);
+  while (entries--) {
+    tag  = get2(ifp);
+    type = get2(ifp);
+    len  = get4(ifp);
+    val  = get4(ifp);
+    save = ftell(ifp);
+    fseek (ifp, base+val, SEEK_SET);
+    if (tag == 0x9003 || tag == 0x9004)
+      get_timestamp(ifp);
+    if (tag == 0x927c) {
+      if (!strncmp(make,"SONY",4))
+    data_offset = base+val+len;
+      else
+    parse_makernote(ifp);
+    }
+    fseek (ifp, save, SEEK_SET);
+  }
+}
+
+static int 
+parse_tiff_ifd(FILE * const ifp, int base, int level)
+{
+  unsigned entries, tag, type, len, plen=16, save;
+  int done=0, use_cm=0, cfa, i, j, c;
+  static const int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 };
+  char software[64];
+  static const int flip_map[] = { 0,1,3,2,4,6,7,5 };
+  unsigned char cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256];
+  unsigned short scale[4];
+  double dblack, cc[4][4], cm[4][3];
+  double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 };
+
+  for (j=0; j < 4; j++)
+    for (i=0; i < 4; i++)
+      cc[j][i] = i == j;
+  entries = get2(ifp);
+  if (entries > 512) return 1;
+  while (entries--) {
+    tag  = get2(ifp);
+    type = get2(ifp);
+    len  = get4(ifp);
+    save = ftell(ifp);
+    if (tag > 50700 && tag < 50800) done = 1;
+    if (len * size[type < 13 ? type:0] > 4)
+      fseek (ifp, get4(ifp)+base, SEEK_SET);
+    switch (tag) {
+      case 0x11:
+    camera_red  = get4(ifp) / 256.0;
+    break;
+      case 0x12:
+    camera_blue = get4(ifp) / 256.0;
+    break;
+      case 0x100:           /* ImageWidth */
+    if (strcmp(make,"Canon") || level)
+      raw_width = type==3 ? get2(ifp) : get4(ifp);
+    break;
+      case 0x101:           /* ImageHeight */
+    if (strcmp(make,"Canon") || level)
+      raw_height = type==3 ? get2(ifp) : get4(ifp);
+    break;
+      case 0x102:           /* Bits per sample */
+    fuji_secondary = len == 2;
+    if (level) maximum = (1 << get2(ifp)) - 1;
+    break;
+      case 0x103:           /* Compression */
+    tiff_data_compression = get2(ifp);
+    break;
+      case 0x106:           /* Kodak color format */
+    kodak_data_compression = get2(ifp);
+    break;
+      case 0x10f:           /* Make */
+    fgets (make, 64, ifp);
+    break;
+      case 0x110:           /* Model */
+    fgets (model, 64, ifp);
+    break;
+      case 0x111:           /* StripOffset */
+    data_offset = get4(ifp);
+    break;
+      case 0x112:           /* Orientation */
+    flip = flip_map[(get2(ifp)-1) & 7];
+    break;
+      case 0x115:           /* SamplesPerPixel */
+    tiff_samples = get2(ifp);
+    break;
+      case 0x131:           /* Software tag */
+    fgets (software, 64, ifp);
+    if (!strncmp(software,"Adobe",5))
+      make[0] = 0;
+    break;
+      case 0x132:           /* DateTime tag */
+    get_timestamp(ifp);
+    break;
+      case 0x144:           /* TileOffsets */
+    if (level) {
+      data_offset = ftell(ifp);
+    } else {
+      strcpy (make, "Leaf");
+      data_offset = get4(ifp);
+    }
+    break;
+      case 0x14a:           /* SubIFD tag */
+    if (len > 2 && !is_dng && !strcmp(make,"Kodak"))
+        len = 2;
+    while (len--) {
+      i = ftell(ifp);
+      fseek (ifp, get4(ifp)+base, SEEK_SET);
+      if (parse_tiff_ifd(ifp, base, level+1)) break;
+      fseek (ifp, i+4, SEEK_SET);
+    }
+    break;
+      case 33405:           /* Model2 */
+    fgets (model2, 64, ifp);
+    break;
+      case 33422:           /* CFAPattern */
+    if ((plen=len) > 16) plen = 16;
+    fread (cfa_pat, 1, plen, ifp);
+    for (colors=cfa=i=0; i < plen; i++) {
+      colors += !(cfa & (1 << cfa_pat[i]));
+      cfa |= 1 << cfa_pat[i];
+    }
+    if (cfa == 070) memcpy (cfa_pc,"\003\004\005",3);   /* CMY */
+    if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4);   /* GMCY */
+    goto guess_cfa_pc;
+      case 34665:           /* EXIF tag */
+    fseek (ifp, get4(ifp)+base, SEEK_SET);
+    parse_exif(ifp, base);
+    break;
+      case 50706:           /* DNGVersion */
+    is_dng = 1;
+    if (flip == 7) flip = 4;    /* Adobe didn't read the TIFF spec. */
+    break;
+      case 50710:           /* CFAPlaneColor */
+    if (len > 4) len = 4;
+    colors = len;
+    fread (cfa_pc, 1, colors, ifp);
+guess_cfa_pc:
+    FORC4 tab[cfa_pc[c]] = c;
+    for (i=16; i--; )
+      filters = filters << 2 | tab[cfa_pat[i % plen]];
+    break;
+      case 50711:           /* CFALayout */
+    if (get2(ifp) == 2) {
+      fuji_width = (raw_width+1)/2;
+      filters = 0x49494949;
+    }
+    break;
+      case 0x123:
+      case 0x90d:
+      case 50712:           /* LinearizationTable */
+    if (len > 0x1000)
+        len = 0x1000;
+    read_shorts(ifp, curve, len);
+    for (i=len; i < 0x1000; i++)
+      maximum = curve[i] = curve[i-1];
+    break;
+      case 50714:           /* BlackLevel */
+      case 50715:           /* BlackLevelDeltaH */
+      case 50716:           /* BlackLevelDeltaV */
+    for (dblack=i=0; i < len; i++)
+      dblack += getrat();
+    black += dblack/len + 0.5;
+    break;
+      case 50717:           /* WhiteLevel */
+    maximum = get2(ifp);
+    break;
+      case 50718:           /* DefaultScale */
+    for (i=0; i < 4; i++)
+      scale[i] = get4(ifp);
+    if (scale[1]*scale[2] == 2*scale[0]*scale[3]) ymag = 2;
+    break;
+      case 50721:           /* ColorMatrix1 */
+      case 50722:           /* ColorMatrix2 */
+    FORC4 for (j=0; j < 3; j++)
+      cm[c][j] = getrat();
+    use_cm = 1;
+    break;
+      case 50723:           /* CameraCalibration1 */
+      case 50724:           /* CameraCalibration2 */
+    for (i=0; i < colors; i++)
+      FORC4 cc[i][c] = getrat();    
+      case 50727:           /* AnalogBalance */
+    FORC4 ab[c] = getrat();
+    break;
+      case 50728:           /* AsShotNeutral */
+    FORC4 asn[c] = getrat();
+    break;
+      case 50729:           /* AsShotWhiteXY */
+    xyz[0] = getrat();
+    xyz[1] = getrat();
+    xyz[2] = 1 - xyz[0] - xyz[1];
+    }
+    fseek (ifp, save+4, SEEK_SET);
+  }
+  for (i=0; i < colors; i++)
+    FORC4 cc[i][c] *= ab[i];
+  if (use_cm)
+    dng_coeff (cc, cm, xyz);
+  if (asn[0])
+    FORC4 pre_mul[c] = 1 / asn[c];
+  if (!use_cm)
+    FORC4 pre_mul[c] /= cc[c][c];
+
+  if (is_dng || level) return done;
+
+  if ((raw_height & 1) && !strncmp (make,"OLYMPUS",7))
+       raw_height++;
+
+  if (make[0] == 0 && raw_width == 680 && raw_height == 680) {
+    strcpy (make, "Imacon");
+    strcpy (model,"Ixpress");
+  }
+  return done;
+}
+
+void
+parse_tiff(FILE * const ifp, int base)
+{
+  int doff;
+
+  fseek (ifp, base, SEEK_SET);
+  order = get2(ifp);
+  if (order != 0x4949 && order != 0x4d4d) return;
+  get2(ifp);
+  while ((doff = get4(ifp))) {
+    fseek (ifp, doff+base, SEEK_SET);
+    if (parse_tiff_ifd(ifp, base, 0)) break;
+  }
+  if (!is_dng && !strncmp(make,"Kodak",5)) {
+    fseek (ifp, 12+base, SEEK_SET);
+    parse_tiff_ifd(ifp, base, 2);
+  }
+}
+
+
+
+/*
+   Many cameras have a "debug mode" that writes JPEG and raw
+   at the same time.  The raw file has no header, so try to
+   to open the matching JPEG file and read its metadata.
+ */
+void
+parse_external_jpeg(const char * const ifname)
+{
+    const char *file, *ext;
+    char * jfile;
+    char * jext;
+    char * jname;
+
+    ext  = strrchr (ifname, '.');
+    file = strrchr (ifname, '/');
+    if (!file) file = strrchr (ifname, '\\');
+    if (!file) file = ifname-1;
+    file++;
+    if (strlen(ext) != 4 || ext-file != 8) return;
+    jname = malloc (strlen(ifname) + 1);
+    merror (jname, "parse_external()");
+    strcpy (jname, ifname);
+    jfile = jname + (file - ifname);
+    jext  = jname + (ext  - ifname);
+    if (strcasecmp (ext, ".jpg")) {
+        strcpy (jext, isupper(ext[1]) ? ".JPG":".jpg");
+        memcpy (jfile, file+4, 4);
+        memcpy (jfile+4, file, 4);
+    } else
+        while (isdigit(*--jext)) {
+            if (*jext != '9') {
+                (*jext)++;
+                break;
+            }
+            *jext = '0';
+        }
+    if (strcmp (jname, ifname)) {
+        FILE * ifP;
+        ifP = fopen (jname, "rb");
+        if (ifP) {
+            if (verbose)
+                pm_message ("Reading metadata from %s...", jname);
+            parse_tiff(ifP, 12);
+            fclose (ifP);
+        }
+    }
+    if (!timestamp)
+        pm_message ( "Failed to read metadata from %s", jname);
+    free (jname);
+}
+