file probe prefs, updated dcraw, bugs - garbage, accel, ffmpeg/giphy.gif
authorGood Guy <[email protected]>
Sun, 21 May 2017 00:35:21 +0000 (18:35 -0600)
committerGood Guy <[email protected]>
Sun, 21 May 2017 00:35:21 +0000 (18:35 -0600)
24 files changed:
cinelerra-5.1/cinelerra/Makefile
cinelerra-5.1/cinelerra/dcraw.c
cinelerra-5.1/cinelerra/dcraw.h [new file with mode: 0644]
cinelerra-5.1/cinelerra/ffmpeg.C
cinelerra-5.1/cinelerra/file.C
cinelerra-5.1/cinelerra/file.h
cinelerra-5.1/cinelerra/filecr2.C
cinelerra-5.1/cinelerra/fileffmpeg.C
cinelerra-5.1/cinelerra/garbage.h
cinelerra-5.1/cinelerra/interfaceprefs.C
cinelerra-5.1/cinelerra/interfaceprefs.h
cinelerra-5.1/cinelerra/mainmenu.C
cinelerra-5.1/cinelerra/mwindow.C
cinelerra-5.1/cinelerra/mwindowgui.C
cinelerra-5.1/cinelerra/performanceprefs.C
cinelerra-5.1/cinelerra/performanceprefs.h
cinelerra-5.1/cinelerra/performanceprefs.inc
cinelerra-5.1/cinelerra/preferences.C
cinelerra-5.1/cinelerra/preferences.h
cinelerra-5.1/cinelerra/preferencesthread.C
cinelerra-5.1/cinelerra/probeprefs.C [new file with mode: 0644]
cinelerra-5.1/cinelerra/probeprefs.h [new file with mode: 0644]
cinelerra-5.1/cinelerra/probeprefs.inc [new file with mode: 0644]
cinelerra-5.1/thirdparty/downloads.txt

index 562908604a28272a615722b8fac0f5909b89e172..93fd8b61ec392d06693c604dce3e720e8ef26347 100644 (file)
@@ -226,6 +226,7 @@ OBJS = \
        $(OBJDIR)/pluginvclient.o \
        $(OBJDIR)/preferences.o \
        $(OBJDIR)/preferencesthread.o \
+       $(OBJDIR)/probeprefs.o \
        $(OBJDIR)/question.o \
        $(OBJDIR)/quit.o \
        $(OBJDIR)/recconfirmdelete.o \
@@ -445,7 +446,7 @@ $(OBJDIR)/sha1.o:   sha1.C sha1.h
        $(CXX) `cat $(OBJDIR)/c_flags` -O3 -c $< -o $@
 
 $(DCRAW): dcraw.c
-       $(GCC) `cat $(OBJDIR)/c_flags` -Wno-misleading-indentation dcraw.c -c -o $*.o
+       $(GCC) `cat $(OBJDIR)/c_flags` -O4 -Wno-misleading-indentation dcraw.c -c -o $*.o
 
 $(THEME_DATA):
        cd $(OBJDIR) && \
index 4d0e3826f6b8e8a58eb651c141f2b8b6f03cd128..52c3f920d22804d0f4678ede066c0535759eb4ad 100644 (file)
@@ -1,6 +1,6 @@
 /*
    dcraw.c -- Dave Coffin's raw photo decoder
-   Copyright 1997-2012 by Dave Coffin, dcoffin a cybercom o net
+   Copyright 1997-2016 by Dave Coffin, dcoffin a cybercom o net
 
    This is a command-line ANSI C program to convert raw photos from
    any digital camera on any computer running any operating system.
    *If you have not modified dcraw.c in any way, a link to my
    homepage qualifies as "full source code".
 
-   $Revision: 1.454 $
-   $Date: 2012/12/23 19:25:36 $
+   $Revision: 1.477 $
+   $Date: 2016/05/10 21:30:43 $
  */
 
-#define DCRAW_VERSION "9.17"
-#define LOCALTIME
+#define DCRAW_VERSION "9.27"
 
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #include <time.h>
 #include <sys/types.h>
 
-
 // CINELERRA
 #define NODEPS
-
-
-#ifdef NODEPS
-#define NO_JASPER
-#define NO_JPEG
-#define NO_LCMS
-#endif
-#ifndef NO_JASPER
-#include <jasper/jasper.h>     /* Decode RED camera movies */
-#endif
-#ifndef NO_JPEG
-#include <jpeglib.h>           /* Decode compressed Kodak DC120 photos */
-#endif                         /* and Adobe Lossy DNGs */
-#ifndef NO_LCMS
-#include <lcms.h>              /* Support color profiles */
-#endif
-#ifdef LOCALEDIR
-#include <libintl.h>
-#define _(String) gettext(String)
-#else
-#define _(String) (String)
-#endif
+#define LOCALTIME
 
 #if defined(DJGPP) || defined(__MINGW32__)
 #define fseeko fseek
@@ -95,13 +72,25 @@ typedef long long INT64;
 typedef unsigned long long UINT64;
 #endif
 
-#ifdef LJPEG_DECODE
-#error Please compile dcraw.c by itself.
-#error Do not link it with ljpeg_decode.
+#ifdef NODEPS
+#define NO_JASPER
+#define NO_JPEG
+#define NO_LCMS
 #endif
-
-#ifndef LONG_BIT
-#define LONG_BIT (8 * sizeof (long))
+#ifndef NO_JASPER
+#include <jasper/jasper.h>     /* Decode Red camera movies */
+#endif
+#ifndef NO_JPEG
+#include <jpeglib.h>           /* Decode compressed Kodak DC120 photos */
+#endif                         /* and Adobe Lossy DNGs */
+#ifndef NO_LCMS
+#include <lcms2.h>             /* Support color profiles */
+#endif
+#ifdef LOCALEDIR
+#include <libintl.h>
+#define _(String) gettext(String)
+#else
+#define _(String) (String)
 #endif
 
 #if !defined(uchar)
@@ -123,71 +112,74 @@ float **dcraw_data;
 int dcraw_alpha;
 float dcraw_matrix[9];
 
+// CINELERRA
+#define CLASS
+struct jhead;
+struct tiff_tag;
+struct tiff_hdr;
 
-
-
-
-
-FILE *ifp, *ofp;
-short order;
-const char *ifname;
-char *meta_data;
-char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64];
-float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len;
-time_t timestamp;
-unsigned shot_order, kodak_cbpp, filters, exif_cfa, unique_id;
-off_t    strip_offset, data_offset;
-off_t    thumb_offset, meta_offset, profile_offset;
-unsigned thumb_length, meta_length, profile_length;
-unsigned thumb_misc, *oprof, fuji_layout, shot_select=0, multi_out=0;
-unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress;
-unsigned black, cblack[4], maximum, mix_green, raw_color, zero_is_bad;
-unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error;
-unsigned tile_width, tile_length, gpsdata[32], load_flags;
-ushort raw_height, raw_width, height, width, top_margin, left_margin;
-ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height;
-ushort *raw_image, (*image)[4];
-ushort white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4];
+#include "dcraw.h"
 
 // CINELERRA
-static int mask[8][4], flip, tiff_flip, colors;
-
-
-double pixel_aspect, aber[4]={1,1,1,1}, gamm[6]={ 0.45,4.5,0,0,0,0 };
-float bright=1, user_mul[4]={0,0,0,0}, threshold=0;
-int half_size=0, four_color_rgb=0, document_mode=0, highlight=0;
-int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=-1;
-int output_color=1, output_bps=8, output_tiff=0, med_passes=0;
-int no_auto_bright=0;
-unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX };
-float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4];
-const double xyz_rgb[3][3] = {                 /* XYZ from RGB */
+static FILE *ifp, *ofp;
+static short order;
+static const char *ifname;
+static char *meta_data, xtrans[6][6], xtrans_abs[6][6];
+static char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64];
+static float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len;
+static time_t timestamp;
+static off_t strip_offset, data_offset;
+static off_t thumb_offset, meta_offset, profile_offset;
+static unsigned shot_order, kodak_cbpp, exif_cfa, unique_id;
+static unsigned thumb_length, meta_length, profile_length;
+static unsigned thumb_misc, *oprof, fuji_layout;
+static unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress;
+static unsigned black, maximum, mix_green, raw_color, zero_is_bad;
+static unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error;
+static unsigned tile_width, tile_length, gpsdata[32], load_flags;
+static unsigned flip, tiff_flip, filters, colors;
+static ushort raw_height, raw_width, height, width, top_margin, left_margin;
+static ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height;
+static ushort *raw_image, (*image)[4], cblack[4102];
+static ushort white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4];
+
+static unsigned shot_select=0, multi_out=0;
+static double pixel_aspect, aber[4]={1,1,1,1}, gamm[6]={ 0.45,4.5,0,0,0,0 };
+static float bright=1, user_mul[4]={0,0,0,0}, threshold=0;
+static int mask[8][4];
+static int half_size=0, four_color_rgb=0, document_mode=0, highlight=0;
+static int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=1;
+static int output_color=1, output_bps=8, output_tiff=0, med_passes=0;
+static int no_auto_bright=0;
+static unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX };
+static float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4];
+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 } };
-const float d65_white[3] = { 0.950456, 1, 1.088754 };
-int histogram[4][0x2000];
-void (*write_thumb)(), (*write_fun)();
-void (*load_raw)(), (*thumb_load_raw)();
-jmp_buf failure;
+static const float d65_white[3] = { 0.950456, 1, 1.088754 };
+static int histogram[4][0x2000];
+static void (*write_thumb)(), (*write_fun)();
+static void (*load_raw)(), (*thumb_load_raw)();
+static jmp_buf failure;
 
-struct decode {
+static struct decode {
   struct decode *branch[2];
   int leaf;
-} first_decode[2048], *second_decode, *free_decode;
+} first_decode[2048], /* *second_decode, CINELERRA */ *free_decode;
 
-struct tiff_ifd {
+static struct tiff_ifd {
   int width, height, bps, comp, phint, offset, flip, samples, bytes;
   int tile_width, tile_length;
+  float shutter;
 } tiff_ifd[10];
 
-struct ph1 {
-  int format, key_off, black, black_off, split_col, tag_21a;
+static struct ph1 {
+  int format, key_off, tag_21a;
+  int black, split_col, black_col, split_row, black_row;
   float tag_210;
 } ph1;
 
-#define CLASS
-
 #define FORC(cnt) for (c=0; c < cnt; c++)
 #define FORC3 FORC(3)
 #define FORC4 FORC(4)
@@ -199,7 +191,7 @@ struct ph1 {
 #define MAX(a,b) ((a) > (b) ? (a) : (b))
 #define LIM(x,min,max) MAX(min,MIN(x,max))
 #define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y))
-#define CLIP(x) LIM(x,0,65535)
+#define CLIP(x) LIM((int)(x),0,65535)
 #define SWAP(a,b) { a=a+b; b=a-b; a=a-b; }
 
 /*
@@ -272,20 +264,39 @@ int CLASS fcol (int row, int col)
     { 0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1 },
     { 2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2 },
     { 0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3 } };
-  static const char filter2[6][6] =
-  { { 1,1,0,1,1,2 },
-    { 1,1,2,1,1,0 },
-    { 2,0,1,0,2,1 },
-    { 1,1,2,1,1,0 },
-    { 1,1,0,1,1,2 },
-    { 0,2,1,2,0,1 } };
 
   if (filters == 1) return filter[(row+top_margin)&15][(col+left_margin)&15];
-  if (filters == 2) return filter2[(row+6) % 6][(col+6) % 6];
+  if (filters == 9) return xtrans[(row+6) % 6][(col+6) % 6];
   return FC(row,col);
 }
 
-#ifndef __GLIBC__
+// CINELERRA
+static void reset()
+{
+       shot_select=0;
+       multi_out=0;
+       aber[0]=1; aber[1]=1; aber[2]=1; aber[3]=1;
+       gamm[0]=0.45; gamm[1]=4.5; gamm[2]=0; gamm[3]=0; gamm[4]=0; gamm[5]=0;
+       bright=1;
+       user_mul[0]=0; user_mul[1]=0; user_mul[2]=0; user_mul[3]=0;
+       threshold=0;
+       half_size=0;
+       four_color_rgb=0;
+       document_mode=0;
+       highlight=0;
+       verbose=0;
+       use_auto_wb=0;
+       use_camera_wb=0;
+       use_camera_matrix=1;
+       output_color=1;
+       output_bps=8;
+       output_tiff=0;
+       med_passes=0;
+       no_auto_bright=0;
+       greybox[0]=0; greybox[1]=0; greybox[2]=UINT_MAX; greybox[3]=UINT_MAX;
+}
+
+#if 0
 char *my_memmem (char *haystack, size_t haystacklen,
              char *needle, size_t needlelen)
 {
@@ -296,6 +307,15 @@ char *my_memmem (char *haystack, size_t haystacklen,
   return 0;
 }
 #define memmem my_memmem
+char *my_strcasestr (char *haystack, const char *needle)
+{
+  char *c;
+  for (c = haystack; *c; c++)
+    if (!strncasecmp(c, needle, strlen(needle)))
+      return c;
+  return 0;
+}
+#define strcasestr my_strcasestr
 #endif
 
 void CLASS merror (void *ptr, const char *where)
@@ -391,6 +411,61 @@ void CLASS read_shorts (ushort *pixel, int count)
     swab (pixel, pixel, count*2);
 }
 
+void CLASS cubic_spline (const int *x_, const int *y_, const int len)
+{
+  float **A, *b, *c, *d, *x, *y;
+  int i, j;
+
+  A = (float **) calloc (((2*len + 4)*sizeof **A + sizeof *A), 2*len);
+  if (!A) return;
+  A[0] = (float *) (A + 2*len);
+  for (i = 1; i < 2*len; i++)
+    A[i] = A[0] + 2*len*i;
+  y = len + (x = i + (d = i + (c = i + (b = A[0] + i*i))));
+  for (i = 0; i < len; i++) {
+    x[i] = x_[i] / 65535.0;
+    y[i] = y_[i] / 65535.0;
+  }
+  for (i = len-1; i > 0; i--) {
+    b[i] = (y[i] - y[i-1]) / (x[i] - x[i-1]);
+    d[i-1] = x[i] - x[i-1];
+  }
+  for (i = 1; i < len-1; i++) {
+    A[i][i] = 2 * (d[i-1] + d[i]);
+    if (i > 1) {
+      A[i][i-1] = d[i-1];
+      A[i-1][i] = d[i-1];
+    }
+    A[i][len-1] = 6 * (b[i+1] - b[i]);
+  }
+  for(i = 1; i < len-2; i++) {
+    float v = A[i+1][i] / A[i][i];
+    for(j = 1; j <= len-1; j++)
+      A[i+1][j] -= v * A[i][j];
+  }
+  for(i = len-2; i > 0; i--) {
+    float acc = 0;
+    for(j = i; j <= len-2; j++)
+      acc += A[i][j]*c[j];
+    c[i] = (A[i][len-1] - acc) / A[i][i];
+  }
+  for (i = 0; i < 0x10000; i++) {
+    float x_out = (float)(i / 65535.0);
+    float y_out = 0;
+    for (j = 0; j < len-1; j++) {
+      if (x[j] <= x_out && x_out <= x[j+1]) {
+       float v = x_out - x[j];
+       y_out = y[j] +
+         ((y[j+1] - y[j]) / d[j] - (2 * d[j] * c[j] + c[j+1] * d[j])/6) * v
+          + (c[j] * 0.5) * v*v + ((c[j+1] - c[j]) / (6 * d[j])) * v*v*v;
+      }
+    }
+    curve[i] = y_out < 0.0 ? 0 : (y_out >= 1.0 ? 65535 :
+               (ushort)(y_out * 65535.0 + 0.5));
+  }
+  free (A);
+}
+
 void CLASS canon_600_fixed_wb (int temp)
 {
   static const short mul[4][5] = {
@@ -560,17 +635,14 @@ int CLASS canon_s2is()
   return 0;
 }
 
-/*
-   getbits(-1) initializes the buffer
-   getbits(n) where 0 <= n <= 25 returns an n-bit integer
- */
 unsigned CLASS getbithuff (int nbits, ushort *huff)
 {
   static unsigned bitbuf=0;
   static int vbits=0, reset=0;
   unsigned c;
 
-  if (nbits == -1)
+  if (nbits > 25) return 0;
+  if (nbits < 0)
     return bitbuf = vbits = reset = 0;
   if (nbits == 0 || vbits < 0) return 0;
   while (!reset && vbits < nbits && (c = fgetc(ifp)) != EOF &&
@@ -779,27 +851,22 @@ void CLASS canon_load_raw()
   FORC(2) free (huff[c]);
 }
 
-/*
-   Not a full implementation of Lossless JPEG, just
-   enough to decode Canon, Kodak and Adobe DNG images.
- */
 struct jhead {
-  int bits, high, wide, clrs, sraw, psv, restart, vpred[6];
-  ushort *huff[6], *free[4], *row;
+  int algo, bits, high, wide, clrs, sraw, psv, restart, vpred[6];
+  ushort quant[64], idct[64], *huff[20], *free[20], *row;
 };
 
 int CLASS ljpeg_start (struct jhead *jh, int info_only)
 {
-  int c, tag, len;
+  ushort c, tag, len;
   uchar data[0x10000];
   const uchar *dp;
 
   memset (jh, 0, sizeof *jh);
   jh->restart = INT_MAX;
-  fread (data, 2, 1, ifp);
-  if (data[1] != 0xd8) return 0;
+  if ((fgetc(ifp),fgetc(ifp)) != 0xd8) return 0;
   do {
-    fread (data, 2, 2, ifp);
+    if (!fread (data, 2, 2, ifp)) return 0;
     tag =  data[0] << 8 | data[1];
     len = (data[2] << 8 | data[3]) - 2;
     if (tag <= 0xff00) return 0;
@@ -807,7 +874,9 @@ int CLASS ljpeg_start (struct jhead *jh, int info_only)
     switch (tag) {
       case 0xffc3:
        jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3;
+      case 0xffc1:
       case 0xffc0:
+       jh->algo = tag & 0xff;
        jh->bits = data[0];
        jh->high = data[1] << 8 | data[2];
        jh->wide = data[3] << 8 | data[4];
@@ -816,19 +885,25 @@ int CLASS ljpeg_start (struct jhead *jh, int info_only)
        break;
       case 0xffc4:
        if (info_only) break;
-       for (dp = data; dp < data+len && (c = *dp++) < 4; )
+       for (dp = data; dp < data+len && !((c = *dp++) & -20); )
          jh->free[c] = jh->huff[c] = make_decoder_ref (&dp);
        break;
       case 0xffda:
        jh->psv = data[1+data[0]*2];
        jh->bits -= data[3+data[0]*2] & 15;
        break;
+      case 0xffdb:
+       FORC(64) jh->quant[c] = data[c*2+1] << 8 | data[c*2+2];
+       break;
       case 0xffdd:
        jh->restart = data[0] << 8 | data[1];
     }
   } while (tag != 0xffda);
+  if (jh->bits > 16 || jh->clrs > 6 ||
+     !jh->bits || !jh->high || !jh->wide || !jh->clrs) return 0;
   if (info_only) return 1;
-  FORC(5) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c];
+  if (!jh->huff[0]) return 0;
+  FORC(19) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c];
   if (jh->sraw) {
     FORC(4)        jh->huff[2+c] = jh->huff[1];
     FORC(jh->sraw) jh->huff[1+c] = jh->huff[0];
@@ -914,16 +989,16 @@ void CLASS lossless_jpeg_load_raw()
       val = curve[*rp++];
       if (cr2_slice[0]) {
        jidx = jrow*jwide + jcol;
-       i = jidx / (cr2_slice[1]*jh.high);
+       i = jidx / (cr2_slice[1]*raw_height);
        if ((j = i >= cr2_slice[0]))
                 i  = cr2_slice[0];
-       jidx -= i * (cr2_slice[1]*jh.high);
+       jidx -= i * (cr2_slice[1]*raw_height);
        row = jidx / cr2_slice[1+j];
        col = jidx % cr2_slice[1+j] + i*cr2_slice[1];
       }
       if (raw_width == 3984 && (col -= 2) < 0)
        col += (row--,raw_width);
-      if (row >= 0) RAW(row,col) = val;
+      if ((unsigned) row < raw_height) RAW(row,col) = val;
       if (++col >= raw_width)
        col = (row++,0);
     }
@@ -939,7 +1014,7 @@ void CLASS canon_sraw_load_raw()
   int v[3]={0,0,0}, ver, hue;
   char *cp;
 
-  if (!ljpeg_start (&jh, 0)) return;
+  if (!ljpeg_start (&jh, 0) || jh.clrs < 4) return;
   jwide = (jh.wide >>= 1) * jh.clrs;
 
   for (ecol=slice=0; slice <= cr2_slice[0]; slice++) {
@@ -968,7 +1043,7 @@ void CLASS canon_sraw_load_raw()
   ip = (short (*)[4]) image;
   rp = ip[0];
   for (row=0; row < height; row++, ip+=width) {
-    if (row & (jh.sraw >> 1)) {
+    if (row & (jh.sraw >> 1)) { //CINELERRA
       for (col=0; col < width; col+=2)
        for (c=1; c < 3; c++)
          if (row == height-1)
@@ -1008,23 +1083,59 @@ void CLASS adobe_copy_pixel (unsigned row, unsigned col, ushort **rp)
 {
   int c;
 
-  if (is_raw == 2 && shot_select) (*rp)++;
+  if (tiff_samples == 2 && shot_select) (*rp)++;
   if (raw_image) {
     if (row < raw_height && col < raw_width)
       RAW(row,col) = curve[**rp];
-    *rp += is_raw;
+    *rp += tiff_samples;
   } else {
     if (row < height && col < width)
       FORC(tiff_samples)
        image[row*width+col][c] = curve[(*rp)[c]];
     *rp += tiff_samples;
   }
-  if (is_raw == 2 && shot_select) (*rp)--;
+  if (tiff_samples == 2 && shot_select) (*rp)--;
+}
+
+void CLASS ljpeg_idct (struct jhead *jh)
+{
+  int c, i, j, len, skip, coef;
+  float work[3][8][8];
+  static float cs[106] = { 0 };
+  static const uchar zigzag[80] =
+  {  0, 1, 8,16, 9, 2, 3,10,17,24,32,25,18,11, 4, 5,12,19,26,33,
+    40,48,41,34,27,20,13, 6, 7,14,21,28,35,42,49,56,57,50,43,36,
+    29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,
+    47,55,62,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63 };
+
+  if (!cs[0])
+    FORC(106) cs[c] = cos((c & 31)*M_PI/16)/2;
+  memset (work, 0, sizeof work);
+  work[0][0][0] = jh->vpred[0] += ljpeg_diff (jh->huff[0]) * jh->quant[0];
+  for (i=1; i < 64; i++ ) {
+    len = gethuff (jh->huff[16]);
+    i += skip = len >> 4;
+    if (!(len &= 15) && skip < 15) break;
+    coef = getbits(len);
+    if ((coef & (1 << (len-1))) == 0)
+      coef -= (1 << len) - 1;
+    ((float *)work)[zigzag[i]] = coef * jh->quant[i];
+  }
+  FORC(8) work[0][0][c] *= M_SQRT1_2;
+  FORC(8) work[0][c][0] *= M_SQRT1_2;
+  for (i=0; i < 8; i++)
+    for (j=0; j < 8; j++)
+      FORC(8) work[1][i][j] += work[0][i][c] * cs[(j*2+1)*c];
+  for (i=0; i < 8; i++)
+    for (j=0; j < 8; j++)
+      FORC(8) work[2][i][j] += work[1][c][j] * cs[(i*2+1)*c];
+
+  FORC(64) jh->idct[c] = CLIP(((float *)work[2])[c]+0.5);
 }
 
 void CLASS lossless_dng_load_raw()
 {
-  unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col;
+  unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col, i, j;
   struct jhead jh;
   ushort *rp;
 
@@ -1035,14 +1146,32 @@ void CLASS lossless_dng_load_raw()
     if (!ljpeg_start (&jh, 0)) break;
     jwide = jh.wide;
     if (filters) jwide *= jh.clrs;
-    jwide /= is_raw;
-    for (row=col=jrow=0; jrow < jh.high; jrow++) {
-      rp = ljpeg_row (jrow, &jh);
-      for (jcol=0; jcol < jwide; jcol++) {
-       adobe_copy_pixel (trow+row, tcol+col, &rp);
-       if (++col >= tile_width || col >= raw_width)
-         row += 1 + (col = 0);
-      }
+    jwide /= MIN (is_raw, tiff_samples);
+    switch (jh.algo) {
+      case 0xc1:
+       jh.vpred[0] = 16384;
+       getbits(-1);
+       for (jrow=0; jrow+7 < jh.high; jrow += 8) {
+         for (jcol=0; jcol+7 < jh.wide; jcol += 8) {
+           ljpeg_idct (&jh);
+           rp = jh.idct;
+           row = trow + jcol/tile_width + jrow*2;
+           col = tcol + jcol%tile_width;
+           for (i=0; i < 16; i+=2)
+             for (j=0; j < 8; j++)
+               adobe_copy_pixel (row+i, col+j, &rp);
+         }
+       }
+       break;
+      case 0xc3:
+       for (row=col=jrow=0; jrow < jh.high; jrow++) {
+         rp = ljpeg_row (jrow, &jh);
+         for (jcol=0; jcol < jwide; jcol++) {
+           adobe_copy_pixel (trow+row, tcol+col, &rp);
+           if (++col >= tile_width || col >= raw_width)
+             row += 1 + (col = 0);
+         }
+       }
     }
     fseek (ifp, save+4, SEEK_SET);
     if ((tcol += tile_width) >= raw_width)
@@ -1056,7 +1185,7 @@ void CLASS packed_dng_load_raw()
   ushort *pixel, *rp;
   int row, col;
 
-  pixel = (ushort *) calloc (raw_width * tiff_samples, sizeof *pixel);
+  pixel = (ushort *) calloc (raw_width, tiff_samples*sizeof *pixel);
   merror (pixel, "packed_dng_load_raw()");
   for (row=0; row < raw_height; row++) {
     if (tiff_bps == 16)
@@ -1164,6 +1293,25 @@ void CLASS nikon_load_raw()
   free (huff);
 }
 
+void CLASS nikon_yuv_load_raw()
+{
+  int row, col, yuv[4], rgb[3], b, c;
+  UINT64 bitbuf=0;
+
+  for (row=0; row < raw_height; row++)
+    for (col=0; col < raw_width; col++) {
+      if (!(b = col & 1)) {
+       bitbuf = 0;
+       FORC(6) bitbuf |= (UINT64) fgetc(ifp) << c*8;
+       FORC(4) yuv[c] = (bitbuf >> c*12 & 0xfff) - (c >> 1 << 11);
+      }
+      rgb[0] = yuv[b] + 1.370705*yuv[3];
+      rgb[1] = yuv[b] - 0.337633*yuv[2] - 0.698001*yuv[3];
+      rgb[2] = yuv[b] + 1.732446*yuv[2];
+      FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,0xfff)] / cam_mul[c];
+    }
+}
+
 /*
    Returns 1 for a Coolpix 995, 0 for anything else.
  */
@@ -1208,10 +1356,10 @@ void CLASS nikon_3700()
     int bits;
     char make[12], model[15];
   } table[] = {
-    { 0x00, "PENTAX",  "Optio 33WR" },
-    { 0x03, "NIKON",   "E3200" },
-    { 0x32, "NIKON",   "E3700" },
-    { 0x33, "OLYMPUS", "C740UZ" } };
+    { 0x00, "Pentax",  "Optio 33WR" },
+    { 0x03, "Nikon",   "E3200" },
+    { 0x32, "Nikon",   "E3700" },
+    { 0x33, "Olympus", "C740UZ" } };
 
   fseek (ifp, 3072, SEEK_SET);
   fread (dp, 1, 24, ifp);
@@ -1257,7 +1405,7 @@ void CLASS ppm16_thumb()
   int i;
   char *thumb;
   thumb_length = thumb_width*thumb_height*3;
-  thumb = (char *) calloc (thumb_length,2);
+  thumb = (char *) calloc (thumb_length, 2);
   merror (thumb, "ppm16_thumb()");
   read_shorts ((ushort *) thumb, thumb_length);
   for (i=0; i < thumb_length; i++)
@@ -1332,14 +1480,16 @@ int CLASS raw (unsigned row, unsigned col)
 void CLASS phase_one_flat_field (int is_float, int nc)
 {
   ushort head[8];
-  unsigned wide, y, x, c, rend, cend, row, col;
+  unsigned wide, high, y, x, c, rend, cend, row, col;
   float *mrow, num, mult[4];
 
   read_shorts (head, 8);
-  wide = head[2] / head[4];
+  if (head[2] * head[3] * head[4] * head[5] == 0) return;
+  wide = head[2] / head[4] + (head[2] % head[4] != 0);
+  high = head[3] / head[5] + (head[3] % head[5] != 0);
   mrow = (float *) calloc (nc*wide, sizeof *mrow);
   merror (mrow, "phase_one_flat_field()");
-  for (y=0; y < head[3] / head[5]; y++) {
+  for (y=0; y < high; y++) {
     for (x=0; x < wide; x++)
       for (c=0; c < nc; c+=2) {
        num = is_float ? getreal(11) : get2()/32768.0;
@@ -1348,14 +1498,18 @@ void CLASS phase_one_flat_field (int is_float, int nc)
       }
     if (y==0) continue;
     rend = head[1] + y*head[5];
-    for (row = rend-head[5]; row < raw_height && row < rend; row++) {
+    for (row = rend-head[5];
+        row < raw_height && row < rend &&
+        row < head[1]+head[3]-head[5]; row++) {
       for (x=1; x < wide; x++) {
        for (c=0; c < nc; c+=2) {
          mult[c] = mrow[c*wide+x-1];
          mult[c+1] = (mrow[c*wide+x] - mult[c]) / head[4];
        }
        cend = head[0] + x*head[4];
-       for (col = cend-head[4]; col < raw_width && col < cend; col++) {
+       for (col = cend-head[4];
+            col < raw_width &&
+            col < cend && col < head[0]+head[2]-head[4]; col++) {
          c = nc > 2 ? FC(row-top_margin,col-left_margin) : 0;
          if (!(c & 1)) {
            c = RAW(row,col) * mult[c];
@@ -1383,6 +1537,7 @@ void CLASS phase_one_correct()
       {-2,-2}, {-2,2}, {2,-2}, {2,2} };
   float poly[8], num, cfrac, frac, mult[2], *yval[2];
   ushort *xval[2];
+  int qmult_applied = 0, qlin_applied = 0;
 
   if (half_size || !meta_length) return;
   if (verbose) fprintf (stderr,_("Phase One correction...\n"));
@@ -1422,7 +1577,7 @@ void CLASS phase_one_correct()
        row  = get2();
        type = get2(); get2();
        if (col >= raw_width) continue;
-       if (type == 131)                        /* Bad column */
+       if (type == 131 || type == 137)         /* Bad column */
          for (row=0; row < raw_height; row++)
            if (FC(row-top_margin,col-left_margin) == 1) {
              for (sum=i=0; i < 4; i++)
@@ -1459,6 +1614,83 @@ void CLASS phase_one_correct()
        mindiff = diff;
        off_412 = ftell(ifp) - 38;
       }
+    } else if (tag == 0x41f && !qlin_applied) { /* Quadrant linearization */
+      ushort lc[2][2][16], ref[16];
+      int qr, qc;
+      for (qr = 0; qr < 2; qr++)
+       for (qc = 0; qc < 2; qc++)
+         for (i = 0; i < 16; i++)
+           lc[qr][qc][i] = get4();
+      for (i = 0; i < 16; i++) {
+       int v = 0;
+       for (qr = 0; qr < 2; qr++)
+         for (qc = 0; qc < 2; qc++)
+           v += lc[qr][qc][i];
+       ref[i] = (v + 2) >> 2;
+      }
+      for (qr = 0; qr < 2; qr++) {
+       for (qc = 0; qc < 2; qc++) {
+         int cx[19], cf[19];
+         for (i = 0; i < 16; i++) {
+           cx[1+i] = lc[qr][qc][i];
+           cf[1+i] = ref[i];
+         }
+         cx[0] = cf[0] = 0;
+         cx[17] = cf[17] = ((unsigned) ref[15] * 65535) / lc[qr][qc][15];
+         cx[18] = cf[18] = 65535;
+         cubic_spline(cx, cf, 19);
+         for (row = (qr ? ph1.split_row : 0);
+              row < (qr ? raw_height : ph1.split_row); row++)
+           for (col = (qc ? ph1.split_col : 0);
+                col < (qc ? raw_width : ph1.split_col); col++)
+             RAW(row,col) = curve[RAW(row,col)];
+       }
+      }
+      qlin_applied = 1;
+    } else if (tag == 0x41e && !qmult_applied) { /* Quadrant multipliers */
+      float qmult[2][2] = { { 1, 1 }, { 1, 1 } };
+      get4(); get4(); get4(); get4();
+      qmult[0][0] = 1.0 + getreal(11);
+      get4(); get4(); get4(); get4(); get4();
+      qmult[0][1] = 1.0 + getreal(11);
+      get4(); get4(); get4();
+      qmult[1][0] = 1.0 + getreal(11);
+      get4(); get4(); get4();
+      qmult[1][1] = 1.0 + getreal(11);
+      for (row=0; row < raw_height; row++)
+       for (col=0; col < raw_width; col++) {
+         i = qmult[row >= ph1.split_row][col >= ph1.split_col] * RAW(row,col);
+         RAW(row,col) = LIM(i,0,65535);
+       }
+      qmult_applied = 1;
+    } else if (tag == 0x431 && !qmult_applied) { /* Quadrant combined */
+      ushort lc[2][2][7], ref[7];
+      int qr, qc;
+      for (i = 0; i < 7; i++)
+       ref[i] = get4();
+      for (qr = 0; qr < 2; qr++)
+       for (qc = 0; qc < 2; qc++)
+         for (i = 0; i < 7; i++)
+           lc[qr][qc][i] = get4();
+      for (qr = 0; qr < 2; qr++) {
+       for (qc = 0; qc < 2; qc++) {
+         int cx[9], cf[9];
+         for (i = 0; i < 7; i++) {
+           cx[1+i] = ref[i];
+           cf[1+i] = ((unsigned) ref[i] * lc[qr][qc][i]) / 10000;
+         }
+         cx[0] = cf[0] = 0;
+         cx[8] = cf[8] = 65535;
+         cubic_spline(cx, cf, 9);
+         for (row = (qr ? ph1.split_row : 0);
+              row < (qr ? raw_height : ph1.split_row); row++)
+           for (col = (qc ? ph1.split_col : 0);
+                col < (qc ? raw_width : ph1.split_col); col++)
+             RAW(row,col) = curve[RAW(row,col)];
+        }
+      }
+      qmult_applied = 1;
+      qlin_applied = 1;
     }
     fseek (ifp, save, SEEK_SET);
   }
@@ -1545,18 +1777,22 @@ void CLASS phase_one_load_raw_c()
   static const int length[] = { 8,7,6,9,11,10,5,12,14,13 };
   int *offset, len[2], pred[2], row, col, i, j;
   ushort *pixel;
-  short (*black)[2];
+  short (*cblack)[2], (*rblack)[2];
 
-  pixel = (ushort *) calloc (raw_width + raw_height*4, 2);
+  pixel = (ushort *) calloc (raw_width*3 + raw_height*4, 2);
   merror (pixel, "phase_one_load_raw_c()");
   offset = (int *) (pixel + raw_width);
   fseek (ifp, strip_offset, SEEK_SET);
   for (row=0; row < raw_height; row++)
     offset[row] = get4();
-  black = (short (*)[2]) offset + raw_height;
-  fseek (ifp, ph1.black_off, SEEK_SET);
-  if (ph1.black_off)
-    read_shorts ((ushort *) black[0], raw_height*2);
+  cblack = (short (*)[2]) (offset + raw_height);
+  fseek (ifp, ph1.black_col, SEEK_SET);
+  if (ph1.black_col)
+    read_shorts ((ushort *) cblack[0], raw_height*2);
+  rblack = cblack + raw_height;
+  fseek (ifp, ph1.black_row, SEEK_SET);
+  if (ph1.black_row)
+    read_shorts ((ushort *) rblack[0], raw_width*2);
   for (i=0; i < 256; i++)
     curve[i] = i*i / 3.969 + 0.5;
   for (row=0; row < raw_height; row++) {
@@ -1580,8 +1816,10 @@ void CLASS phase_one_load_raw_c()
        pixel[col] = curve[pixel[col]];
     }
     for (col=0; col < raw_width; col++) {
-      i = (pixel[col] << 2) - ph1.black + black[row][col >= ph1.split_col];
-       if (i > 0) RAW(row,col) = i;
+      i = (pixel[col] << 2*(ph1.format != 8)) - ph1.black
+       + cblack[row][col >= ph1.split_col]
+       + rblack[col][row >= ph1.split_row];
+      if (i > 0) RAW(row,col) = i;
     }
   }
   free (pixel);
@@ -1591,26 +1829,57 @@ void CLASS phase_one_load_raw_c()
 void CLASS hasselblad_load_raw()
 {
   struct jhead jh;
-  int row, col, pred[2], len[2], diff, c;
+  int shot, row, col, *back[5], len[2], diff[12], pred, sh, f, s, c;
+  unsigned upix, urow, ucol;
+  ushort *ip;
 
   if (!ljpeg_start (&jh, 0)) return;
   order = 0x4949;
   ph1_bits(-1);
+  back[4] = (int *) calloc (raw_width, 3*sizeof **back);
+  merror (back[4], "hasselblad_load_raw()");
+  FORC3 back[c] = back[4] + c*raw_width;
+  cblack[6] >>= sh = tiff_samples > 1;
+  shot = LIM(shot_select, 1, tiff_samples) - 1;
   for (row=0; row < raw_height; row++) {
-    pred[0] = pred[1] = 0x8000 + load_flags;
+    FORC4 back[(c+3) & 3] = back[c];
     for (col=0; col < raw_width; col+=2) {
-      FORC(2) len[c] = ph1_huff(jh.huff[0]);
-      FORC(2) {
-       diff = ph1_bits(len[c]);
-       if ((diff & (1 << (len[c]-1))) == 0)
-         diff -= (1 << len[c]) - 1;
-       if (diff == 65535) diff = -32768;
-       RAW(row,col+c) = pred[c] += diff;
+      for (s=0; s < tiff_samples*2; s+=2) {
+       FORC(2) len[c] = ph1_huff(jh.huff[0]);
+       FORC(2) {
+         diff[s+c] = ph1_bits(len[c]);
+         if ((diff[s+c] & (1 << (len[c]-1))) == 0)
+           diff[s+c] -= (1 << len[c]) - 1;
+         if (diff[s+c] == 65535) diff[s+c] = -32768;
+       }
+      }
+      for (s=col; s < col+2; s++) {
+       pred = 0x8000 + load_flags;
+       if (col) pred = back[2][s-2];
+       if (col && row > 1) switch (jh.psv) {
+         case 11: pred += back[0][s]/2 - back[0][s-2]/2;  break;
+       }
+       f = (row & 1)*3 ^ ((col+s) & 1);
+       FORC (tiff_samples) {
+         pred += diff[(s & 1)*tiff_samples+c];
+         upix = pred >> sh & 0xffff;
+         if (raw_image && c == shot)
+           RAW(row,s) = upix;
+         if (image) {
+           urow = row-top_margin  + (c & 1);
+           ucol = col-left_margin - ((c >> 1) & 1);
+           ip = &image[urow*width+ucol][f];
+           if (urow < height && ucol < width)
+             *ip = c < 4 ? upix : (*ip + upix) >> 1;
+         }
+       }
+       back[2][s] = pred;
       }
     }
   }
+  free (back[4]);
   ljpeg_end (&jh);
-  maximum = 0xffff;
+  if (image) mix_green = 1;
 }
 
 void CLASS leaf_hdr_load_raw()
@@ -1660,20 +1929,13 @@ void CLASS sinar_4shot_load_raw()
   ushort *pixel;
   unsigned shot, row, col, r, c;
 
-  if ((shot = shot_select) || half_size) {
-    if (shot) shot--;
-    if (shot > 3) shot = 3;
+  if (raw_image) {
+    shot = LIM (shot_select, 1, 4) - 1;
     fseek (ifp, data_offset + shot*4, SEEK_SET);
     fseek (ifp, get4(), SEEK_SET);
     unpacked_load_raw();
     return;
   }
-  free (raw_image);
-  raw_image = 0;
-  free (image);
-  image = (ushort (*)[4])
-       calloc ((iheight=height)*(iwidth=width), sizeof *image);
-  merror (image, "sinar_4shot_load_raw()");
   pixel = (ushort *) calloc (raw_width, sizeof *pixel);
   merror (pixel, "sinar_4shot_load_raw()");
   for (shot=0; shot < 4; shot++) {
@@ -1684,18 +1946,19 @@ void CLASS sinar_4shot_load_raw()
       if ((r = row-top_margin - (shot >> 1 & 1)) >= height) continue;
       for (col=0; col < raw_width; col++) {
        if ((c = col-left_margin - (shot & 1)) >= width) continue;
-       image[r*width+c][FC(row,col)] = pixel[col];
+       image[r*width+c][(row & 1)*3 ^ (~col & 1)] = pixel[col];
       }
     }
   }
   free (pixel);
-  shrink = filters = 0;
+  mix_green = 1;
 }
 
 void CLASS imacon_full_load_raw()
 {
   int row, col;
 
+  if (!image) return;
   for (row=0; row < height; row++)
     for (col=0; col < width; col++)
       read_shorts (image[row*width+col], 3);
@@ -1703,13 +1966,12 @@ void CLASS imacon_full_load_raw()
 
 void CLASS packed_load_raw()
 {
-  int vbits=0, bwide, pwide, rbits, bite, half, irow, row, col, val, i;
+  int vbits=0, bwide, rbits, bite, half, irow, row, col, val, i;
   UINT64 bitbuf=0;
 
-  if (raw_width * 8 >= width * tiff_bps)       /* Is raw_width in bytes? */
-       pwide = (bwide = raw_width) * 8 / tiff_bps;
-  else bwide = (pwide = raw_width) * tiff_bps / 8;
-  rbits = bwide * 8 - pwide * tiff_bps;
+  bwide = raw_width * tiff_bps / 8;
+  bwide += bwide & load_flags >> 7;
+  rbits = bwide * 8 - raw_width * tiff_bps;
   if (load_flags & 1) bwide = bwide * 16 / 15;
   bite = 8 + (load_flags & 24);
   half = (raw_height+1) >> 1;
@@ -1725,16 +1987,16 @@ void CLASS packed_load_raw()
        fseek (ifp, ftell(ifp) >> 3 << 2, SEEK_SET);
       }
     }
-    for (col=0; col < pwide; col++) {
+    for (col=0; col < raw_width; col++) {
       for (vbits -= tiff_bps; vbits < 0; vbits += bite) {
        bitbuf <<= bite;
        for (i=0; i < bite; i+=8)
          bitbuf |= (unsigned) (fgetc(ifp) << i);
       }
       val = bitbuf << (64-tiff_bps-vbits) >> (64-tiff_bps);
-      RAW(row,col ^ (load_flags >> 6)) = val;
-      if (load_flags & 1 && (col % 10) == 9 &&
-       fgetc(ifp) && col < width+left_margin) derror();
+      RAW(row,col ^ (load_flags >> 6 & 1)) = val;
+      if (load_flags & 1 && (col % 10) == 9 && fgetc(ifp) &&
+       row < height+top_margin && col < width+left_margin) derror();
     }
     vbits -= rbits;
   }
@@ -1744,9 +2006,10 @@ void CLASS nokia_load_raw()
 {
   uchar  *data,  *dp;
   int rev, dwide, row, col, c;
+  double sum[]={0,0};
 
   rev = 3 * (order == 0x4949);
-  dwide = raw_width * 5 / 4;
+  dwide = (raw_width * 5 + 1) / 4;
   data = (uchar *) malloc (dwide*2);
   merror (data, "nokia_load_raw()");
   for (row=0; row < raw_height; row++) {
@@ -1757,6 +2020,33 @@ void CLASS nokia_load_raw()
   }
   free (data);
   maximum = 0x3ff;
+  if (strcmp(make,"OmniVision")) return;
+  row = raw_height/2;
+  FORC(width-1) {
+    sum[ c & 1] += SQR(RAW(row,c)-RAW(row+1,c+1));
+    sum[~c & 1] += SQR(RAW(row+1,c)-RAW(row,c+1));
+  }
+  if (sum[1] > sum[0]) filters = 0x4b4b4b4b;
+}
+
+void CLASS canon_rmf_load_raw()
+{
+  int row, col, bits, orow, ocol, c;
+
+  for (row=0; row < raw_height; row++)
+    for (col=0; col < raw_width-2; col+=3) {
+      bits = get4();
+      FORC3 {
+       orow = row;
+       if ((ocol = col+c-4) < 0) {
+         ocol += raw_width;
+         if ((orow -= 2) < 0)
+           orow += raw_height;
+       }
+       RAW(orow,ocol) = curve[bits >> (10*c+2) & 0x3ff];
+      }
+    }
+  maximum = curve[0x3ff];
 }
 
 unsigned CLASS pana_bits (int nbits)
@@ -1967,7 +2257,7 @@ void CLASS kodak_radc_load_raw()
   };
   ushort huff[19][256];
   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], *bp;
+  short last[3] = { 16,16,16 }, mul[3], buf[3][3][386];
   static const ushort pt[] =
     { 0,0, 1280,1344, 2320,3616, 3328,8000, 4095,16383, 65535,16383 };
 
@@ -1977,12 +2267,12 @@ void CLASS kodak_radc_load_raw()
        (c-pt[i-2]) / (pt[i]-pt[i-2]) * (pt[i+1]-pt[i-1]) + pt[i-1] + 0.5;
   for (s=i=0; i < sizeof src; i+=2)
     FORC(256 >> src[i])
-      huff[0][s++] = src[i] << 8 | (uchar) src[i+1];
+      ((ushort *)huff)[s++] = src[i] << 8 | (uchar) src[i+1];
   s = kodak_cbpp == 243 ? 2 : 3;
   FORC(256) huff[18][c] = (8-s) << 8 | c >> s << s | 1 << (s-1);
   getbits(-1);
-  for ( bp=&buf[0][0][0],i=sizeof(buf)/sizeof(*bp); --i>=0; ++bp )
-    *bp = 2048;
+  for (i=0; i < sizeof(buf)/sizeof(short); i++)
+    ((short *)buf)[i] = 2048;
   for (row=0; row < height; row+=4) {
     FORC3 mul[c] = getbits(6);
     FORC3 {
@@ -1991,8 +2281,7 @@ void CLASS kodak_radc_load_raw()
       x = ~(-1 << (s-1));
       val <<= 12-s;
       for (i=0; i < sizeof(buf[0])/sizeof(short); i++)
-      for ( bp=&buf[c][0][0],i=sizeof(buf[0])/sizeof(*bp); --i>=0; ++bp )
-       *bp = (*bp * val + x) >> s;
+       ((short *)buf[c])[i] = (((short *)buf[c])[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;
@@ -2102,6 +2391,8 @@ void CLASS kodak_jpeg_load_raw()
   maximum = 0xff << 1;
 }
 
+void CLASS gamma_curve (double pwr, double ts, int mode, int imax);
+
 void CLASS lossy_dng_load_raw()
 {
   struct jpeg_decompress_struct cinfo;
@@ -2110,29 +2401,34 @@ void CLASS lossy_dng_load_raw()
   JSAMPLE (*pixel)[3];
   unsigned sorder=order, ntags, opcode, deg, i, j, c;
   unsigned save=data_offset-4, trow=0, tcol=0, row, col;
-  ushort curve[3][256];
+  ushort cur[3][256];
   double coeff[9], tot;
 
-  fseek (ifp, meta_offset, SEEK_SET);
-  order = 0x4d4d;
-  ntags = get4();
-  while (ntags--) {
-    opcode = get4(); get4(); get4();
-    if (opcode != 8)
-    { fseek (ifp, get4(), SEEK_CUR); continue; }
-    fseek (ifp, 20, SEEK_CUR);
-    if ((c = get4()) > 2) break;
-    fseek (ifp, 12, SEEK_CUR);
-    if ((deg = get4()) > 8) break;
-    for (i=0; i <= deg && i < 9; i++)
-      coeff[i] = getreal(12);
-    for (i=0; i < 256; i++) {
-      for (tot=j=0; j <= deg; j++)
-       tot += coeff[j] * pow(i/255.0, j);
-      curve[c][i] = tot*0xffff;
+  if (meta_offset) {
+    fseek (ifp, meta_offset, SEEK_SET);
+    order = 0x4d4d;
+    ntags = get4();
+    while (ntags--) {
+      opcode = get4(); get4(); get4();
+      if (opcode != 8)
+      { fseek (ifp, get4(), SEEK_CUR); continue; }
+      fseek (ifp, 20, SEEK_CUR);
+      if ((c = get4()) > 2) break;
+      fseek (ifp, 12, SEEK_CUR);
+      if ((deg = get4()) > 8) break;
+      for (i=0; i <= deg && i < 9; i++)
+       coeff[i] = getreal(12);
+      for (i=0; i < 256; i++) {
+       for (tot=j=0; j <= deg; j++)
+         tot += coeff[j] * pow(i/255.0, j);
+       cur[c][i] = tot*0xffff;
+      }
     }
+    order = sorder;
+  } else {
+    gamma_curve (1/2.4, 12.92, 1, 255);
+    FORC3 memcpy (cur[c], curve, sizeof cur[0]);
   }
-  order = sorder;
   cinfo.err = jpeg_std_error (&jerr);
   jpeg_create_decompress (&cinfo);
   while (trow < raw_height) {
@@ -2149,7 +2445,7 @@ void CLASS lossy_dng_load_raw()
       jpeg_read_scanlines (&cinfo, buf, 1);
       pixel = (JSAMPLE (*)[3]) buf[0];
       for (col=0; col < cinfo.output_width && tcol+col < width; col++) {
-       FORC3 image[row*width+tcol+col][c] = curve[c][pixel[col][c]];
+       FORC3 image[row*width+tcol+col][c] = cur[c][pixel[col][c]];
       }
     }
     jpeg_abort_decompress (&cinfo);
@@ -2193,21 +2489,46 @@ void CLASS eight_bit_load_raw()
   maximum = curve[0xff];
 }
 
-void CLASS kodak_yrgb_load_raw()
+void CLASS kodak_c330_load_raw()
+{
+  uchar *pixel;
+  int row, col, y, cb, cr, rgb[3], c;
+
+  pixel = (uchar *) calloc (raw_width, 2*sizeof *pixel);
+  merror (pixel, "kodak_c330_load_raw()");
+  for (row=0; row < height; row++) {
+    if (fread (pixel, raw_width, 2, ifp) < 2) derror();
+    if (load_flags && (row & 31) == 31)
+      fseek (ifp, raw_width*32, SEEK_CUR);
+    for (col=0; col < width; col++) {
+      y  = pixel[col*2];
+      cb = pixel[(col*2 & -4) | 1] - 128;
+      cr = pixel[(col*2 & -4) | 3] - 128;
+      rgb[1] = y - ((cb + cr + 2) >> 2);
+      rgb[2] = rgb[1] + cb;
+      rgb[0] = rgb[1] + cr;
+      FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,255)];
+    }
+  }
+  free (pixel);
+  maximum = curve[0xff];
+}
+
+void CLASS kodak_c603_load_raw()
 {
   uchar *pixel;
   int row, col, y, cb, cr, rgb[3], c;
 
   pixel = (uchar *) calloc (raw_width, 3*sizeof *pixel);
-  merror (pixel, "kodak_yrgb_load_raw()");
+  merror (pixel, "kodak_c603_load_raw()");
   for (row=0; row < height; row++) {
     if (~row & 1)
       if (fread (pixel, raw_width, 3, ifp) < 3) derror();
-    for (col=0; col < raw_width; col++) {
+    for (col=0; col < width; col++) {
       y  = pixel[width*2*(row & 1) + col];
       cb = pixel[width + (col & -2)]   - 128;
       cr = pixel[width + (col & -2)+1] - 128;
-      rgb[1] = y-((cb + cr + 2) >> 2);
+      rgb[1] = y - ((cb + cr + 2) >> 2);
       rgb[2] = rgb[1] + cb;
       rgb[0] = rgb[1] + cr;
       FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,255)];
@@ -2326,6 +2647,7 @@ void CLASS kodak_ycbcr_load_raw()
   int row, col, len, c, i, j, k, y[2][2], cb, cr, rgb[3];
   ushort *ip;
 
+  if (!image) return;
   for (row=0; row < height; row+=2)
     for (col=0; col < width; col+=128) {
       len = MIN (128, width-col);
@@ -2353,8 +2675,6 @@ void CLASS kodak_rgb_load_raw()
   int row, col, len, c, i, rgb[3];
   ushort *ip=image[0];
 
-  if (raw_image) free (raw_image);
-  raw_image = 0;
   for (row=0; row < height; row++)
     for (col=0; col < width; col+=256) {
       len = MIN (256, width-col);
@@ -2377,7 +2697,7 @@ void CLASS kodak_thumb_load_raw()
 
 void CLASS sony_decrypt (unsigned *data, int len, int start, int key)
 {
-  static unsigned pad[128], p = 0;
+  static unsigned pad[128], p;
 
   if (start) {
     for (p=0; p < 4; p++)
@@ -2388,10 +2708,8 @@ void CLASS sony_decrypt (unsigned *data, int len, int start, int key)
     for (p=0; p < 127; p++)
       pad[p] = htonl(pad[p]);
   }
-  while (len--) {
-    *data++ ^= pad[p & 127] = pad[(p+1) & 127] ^ pad[(p+65) & 127];
-    p++;
-  }
+  while (len-- && p++)
+    *data++ ^= pad[(p-1) & 127] = pad[p & 127] ^ pad[(p+64) & 127];
 }
 
 void CLASS sony_load_raw()
@@ -2406,14 +2724,14 @@ void CLASS sony_load_raw()
   key = get4();
   fseek (ifp, 164600, SEEK_SET);
   fread (head, 1, 40, ifp);
-  sony_decrypt ((unsigned int *) head, 10, 1, key);
+  sony_decrypt ((unsigned *) head, 10, 1, key);
   for (i=26; i-- > 22; )
     key = key << 8 | head[i];
   fseek (ifp, data_offset, SEEK_SET);
   for (row=0; row < raw_height; row++) {
     pixel = raw_image + row*raw_width;
     if (fread (pixel, 2, raw_width, ifp) < raw_width) derror();
-    sony_decrypt ((unsigned int *) pixel, raw_width/2, !row, key);
+    sony_decrypt ((unsigned *) pixel, raw_width/2, !row, key);
     for (col=0; col < raw_width; col++)
       if ((pixel[col] = ntohs(pixel[col])) >> 14) derror();
   }
@@ -2422,23 +2740,20 @@ void CLASS sony_load_raw()
 
 void CLASS sony_arw_load_raw()
 {
-  ushort huff[32768];
+  ushort huff[32770];
   static const ushort tab[18] =
   { 0xf11,0xf10,0xe0f,0xd0e,0xc0d,0xb0c,0xa0b,0x90a,0x809,
     0x708,0x607,0x506,0x405,0x304,0x303,0x300,0x202,0x201 };
-  int i, c, n, col, row, len, diff, sum=0;
+  int i, c, n, col, row, sum=0;
 
+  huff[0] = 15;
   for (n=i=0; i < 18; i++)
-    FORC(32768 >> (tab[i] >> 8)) huff[n++] = tab[i];
+    FORC(32768 >> (tab[i] >> 8)) huff[++n] = tab[i];
   getbits(-1);
   for (col = raw_width; col--; )
     for (row=0; row < raw_height+1; row+=2) {
       if (row == raw_height) row = 1;
-      len = getbithuff(15,huff);
-      diff = getbits(len);
-      if ((diff & (1 << (len-1))) == 0)
-       diff -= (1 << len) - 1;
-      if ((sum += diff) >> 12) derror();
+      if ((sum += ljpeg_diff(huff)) >> 12) derror();
       if (row < height) RAW(row,col) = sum;
     }
 }
@@ -2449,7 +2764,7 @@ void CLASS sony_arw2_load_raw()
   ushort pix[16];
   int row, col, val, max, min, imax, imin, sh, bit, i;
 
-  data = (uchar *) malloc (raw_width);
+  data = (uchar *) malloc (raw_width+1);
   merror (data, "sony_arw2_load_raw()");
   for (row=0; row < height; row++) {
     fread (data, 1, raw_width, ifp);
@@ -2475,12 +2790,115 @@ void CLASS sony_arw2_load_raw()
   free (data);
 }
 
+void CLASS samsung_load_raw()
+{
+  int row, col, c, i, dir, op[4], len[4];
+
+  order = 0x4949;
+  for (row=0; row < raw_height; row++) {
+    fseek (ifp, strip_offset+row*4, SEEK_SET);
+    fseek (ifp, data_offset+get4(), SEEK_SET);
+    ph1_bits(-1);
+    FORC4 len[c] = row < 2 ? 7:4;
+    for (col=0; col < raw_width; col+=16) {
+      dir = ph1_bits(1);
+      FORC4 op[c] = ph1_bits(2);
+      FORC4 switch (op[c]) {
+       case 3: len[c] = ph1_bits(4);   break;
+       case 2: len[c]--;               break;
+       case 1: len[c]++;
+      }
+      for (c=0; c < 16; c+=2) {
+       i = len[((c & 1) << 1) | (c >> 3)];
+        RAW(row,col+c) = ((signed) ph1_bits(i) << (32-i) >> (32-i)) +
+         (dir ? RAW(row+(~c | -2),col+c) : col ? RAW(row,col+(c | -2)) : 128);
+       if (c == 14) c = -1;
+      }
+    }
+  }
+  for (row=0; row < raw_height-1; row+=2)
+    for (col=0; col < raw_width-1; col+=2)
+      SWAP (RAW(row,col+1), RAW(row+1,col));
+}
+
+void CLASS samsung2_load_raw()
+{
+  static const ushort tab[14] =
+  { 0x304,0x307,0x206,0x205,0x403,0x600,0x709,
+    0x80a,0x90b,0xa0c,0xa0d,0x501,0x408,0x402 };
+  ushort huff[1026], vpred[2][2] = {{0,0},{0,0}}, hpred[2];
+  int i, c, n, row, col, diff;
+
+  huff[0] = 10;
+  for (n=i=0; i < 14; i++)
+    FORC(1024 >> (tab[i] >> 8)) huff[++n] = tab[i];
+  getbits(-1);
+  for (row=0; row < raw_height; row++)
+    for (col=0; col < raw_width; col++) {
+      diff = ljpeg_diff (huff);
+      if (col < 2) hpred[col] = vpred[row & 1][col] += diff;
+      else        hpred[col & 1] += diff;
+      RAW(row,col) = hpred[col & 1];
+      if (hpred[col & 1] >> tiff_bps) derror();
+    }
+}
+
+void CLASS samsung3_load_raw()
+{
+  int opt, init, mag, pmode, row, tab, col, pred, diff, i, c;
+  ushort lent[3][2], len[4], *prow[2];
+
+  order = 0x4949;
+  fseek (ifp, 9, SEEK_CUR);
+  opt = fgetc(ifp);
+  init = (get2(),get2());
+  for (row=0; row < raw_height; row++) {
+    fseek (ifp, (data_offset-ftell(ifp)) & 15, SEEK_CUR);
+    ph1_bits(-1);
+    mag = 0; pmode = 7;
+    FORC(6) ((ushort *)lent)[c] = row < 2 ? 7:4;
+    prow[ row & 1] = &RAW(row-1,1-((row & 1) << 1));   // green
+    prow[~row & 1] = &RAW(row-2,0);                    // red and blue
+    for (tab=0; tab+15 < raw_width; tab+=16) {
+      if (~opt & 4 && !(tab & 63)) {
+       i = ph1_bits(2);
+       mag = i < 3 ? mag-'2'+"204"[i] : ph1_bits(12);
+      }
+      if (opt & 2)
+       pmode = 7 - 4*ph1_bits(1);
+      else if (!ph1_bits(1))
+       pmode = ph1_bits(3);
+      if (opt & 1 || !ph1_bits(1)) {
+       FORC4 len[c] = ph1_bits(2);
+       FORC4 {
+         i = ((row & 1) << 1 | (c & 1)) % 3;
+         len[c] = len[c] < 3 ? lent[i][0]-'1'+"120"[len[c]] : ph1_bits(4);
+         lent[i][0] = lent[i][1];
+         lent[i][1] = len[c];
+       }
+      }
+      FORC(16) {
+       col = tab + (((c & 7) << 1)^(c >> 3)^(row & 1));
+       pred = (pmode == 7 || row < 2)
+            ? (tab ? RAW(row,tab-2+(col & 1)) : init)
+            : (prow[col & 1][col-'4'+"0224468"[pmode]] +
+               prow[col & 1][col-'4'+"0244668"[pmode]] + 1) >> 1;
+       diff = ph1_bits (i = len[c >> 2]);
+       if (diff >> (i-1)) diff -= 1 << i;
+       diff = diff * (mag*2+1) + mag;
+       RAW(row,col) = pred + diff;
+      }
+    }
+  }
+}
+
 #define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1)
 
 /* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */
 void CLASS smal_decode_segment (unsigned seg[2][2], int holes)
 {
-  uchar hist[3][13] = {
+// CINELERRA
+  uchar hist[3][18] = {
     { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 },
     { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 },
     { 3, 3, 0, 0, 63,     47,     31,     15,    0 } };
@@ -2491,6 +2909,8 @@ void CLASS smal_decode_segment (unsigned seg[2][2], int holes)
 
   fseek (ifp, seg[0][1]+1, SEEK_SET);
   getbits(-1);
+  if (seg[1][0] > raw_width*raw_height)
+      seg[1][0] = raw_width*raw_height;
   for (pix=seg[0][0]; pix < seg[1][0]; pix++) {
     for (s=0; s < 3; s++) {
       data = data << nbits | getbits(nbits);
@@ -2596,10 +3016,10 @@ void CLASS smal_v9_load_raw()
 
   fseek (ifp, 67, SEEK_SET);
   offset = get4();
-  nseg = fgetc(ifp);
+  nseg = (uchar) fgetc(ifp);
   fseek (ifp, offset, SEEK_SET);
   for (i=0; i < nseg*2; i++)
-    seg[0][i] = get4() + data_offset*(i & 1);
+    ((unsigned *)seg)[i] = get4() + data_offset*(i & 1);
   fseek (ifp, 78, SEEK_SET);
   holes = fgetc(ifp);
   fseek (ifp, 88, SEEK_SET);
@@ -2627,7 +3047,7 @@ void CLASS redcine_load_raw()
   if (!jimg) longjmp (failure, 3);
   jmat = jas_matrix_create (height/2, width/2);
   merror (jmat, "redcine_load_raw()");
-  img = (ushort *) calloc ((height+2)*(width+2), 2);
+  img = (ushort *) calloc ((height+2), (width+2)*2);
   merror (img, "redcine_load_raw()");
   FORC4 {
     jas_image_readcmpt (jimg, c, 0, 0, width/2, height/2, jmat);
@@ -2785,7 +3205,7 @@ void CLASS foveon_huff (ushort *huff)
 void CLASS foveon_dp_load_raw()
 {
   unsigned c, roff[4], row, col, diff;
-  ushort huff[258], vpred[2][2], hpred[2];
+  ushort huff[512], vpred[2][2], hpred[2];
 
   fseek (ifp, 8, SEEK_CUR);
   foveon_huff (huff);
@@ -2838,7 +3258,7 @@ void CLASS foveon_load_camf()
          meta_data[j++] = hpred[0] >> 4;
          meta_data[j++] = hpred[0] << 4 | hpred[1] >> 8;
          meta_data[j++] = hpred[1];
-        }
+       }
       }
     }
   } else
@@ -2998,7 +3418,7 @@ void CLASS foveon_interpolate()
        foveon_camf_param ("IncludeBlocks", "ColorDQ") ?
                "ColorDQ" : "ColorDQCamRGB");
   if (foveon_camf_param ("IncludeBlocks", "ColumnFilter"))
-                foveon_fixed (&cfilt, 1, "ColumnFilter");
+                foveon_fixed (&cfilt, 1, "ColumnFilter");
 
   memset (ddft, 0, sizeof ddft);
   if (!foveon_camf_param ("IncludeBlocks", "DarkDrift")
@@ -3061,14 +3481,11 @@ void CLASS foveon_interpolate()
 
   black = (float (*)[3]) calloc (height, sizeof *black);
   for (row=0; row < height; row++) {
-    float *dp0 = &ddft[0][0][0];
-    float *dp1 = &ddft[1][0][0];
-    float *dp2 = &ddft[2][0][0];
-    for( i=6; --i>=0; ++dp0,++dp1,++dp2 )
-      *dp0 = *dp1 + row / (height-1.0) * (*dp2 - *dp1);
-    pix = image[row*width];
+    for (i=0; i < 6; i++)
+      ((float *)ddft[0])[i] = ((float *)ddft[1])[i] +
+       row / (height-1.0) * (((float *)ddft[2])[i] - ((float *)ddft[1])[i]);
     FORC3 black[row][c] =
-       ( foveon_avg (image[row*width]+c, dscr[0], cfilt) +
+       ( 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];
   }
@@ -3110,11 +3527,9 @@ void CLASS foveon_interpolate()
     FORC3 black[row][c] += fsum[c]/2 + total[c]/(total[3]*100.0);
 
   for (row=0; row < height; row++) {
-    float *dp0 = &ddft[0][0][0];
-    float *dp1 = &ddft[1][0][0];
-    float *dp2 = &ddft[2][0][0];
-    for( i=6; --i>=0; ++dp0,++dp1,++dp2 )
-      *dp0 = *dp1 + row / (height-1.0) * (*dp2 - *dp1);
+    for (i=0; i < 6; i++)
+      ((float *)ddft[0])[i] = ((float *)ddft[1])[i] +
+       row / (height-1.0) * (((float *)ddft[2])[i] - ((float *)ddft[1])[i]);
     pix = image[row*width];
     memcpy (prev, pix, sizeof prev);
     frow = row / (height-1.0) * (dim[2]-1);
@@ -3153,7 +3568,7 @@ void CLASS foveon_interpolate()
   free (sgrow);
   free (sgain);
 
-  if ((badpix = (unsigned int *) foveon_camf_matrix (dim, "BadPixels"))) {
+  if ((badpix = (unsigned *) foveon_camf_matrix (dim, "BadPixels"))) {
     for (i=0; i < dim[0]; i++) {
       col = (badpix[i] >> 8 & 0xfff) - keep[0];
       row = (badpix[i] >> 20       ) - keep[1];
@@ -3295,7 +3710,7 @@ void CLASS foveon_interpolate()
   }
 
   /* Smooth the image bottom-to-top and save at 1/4 scale */
-  shrink = (short (*)[3]) calloc ((width/4) * (height/4), sizeof *shrink);
+  shrink = (short (*)[3]) calloc ((height/4), (width/4)*sizeof *shrink);
   merror (shrink, "foveon_interpolate()");
   for (row = height/4; row--; )
     for (col=0; col < width/4; col++) {
@@ -3398,11 +3813,11 @@ void CLASS crop_masked_pixels()
       for (col=0; col < width; col++)
        BAYER2(row,col) = RAW(row+top_margin,col+left_margin);
   }
-  if (mask[0][3]) goto mask_set;
+  if (mask[0][3] > 0) goto mask_set;
   if (load_raw == &CLASS canon_load_raw ||
       load_raw == &CLASS lossless_jpeg_load_raw) {
-    mask[0][1] = mask[1][1] = 2;
-    mask[0][3] = -2;
+    mask[0][1] = mask[1][1] += 2;
+    mask[0][3] -= 2;
     goto sides;
   }
   if (load_raw == &CLASS canon_600_load_raw ||
@@ -3424,8 +3839,8 @@ sides:
 mask_set:
   memset (mblack, 0, sizeof mblack);
   for (zero=m=0; m < 8; m++)
-    for (row=mask[m][0]; row < mask[m][2]; row++)
-      for (col=mask[m][1]; col < mask[m][3]; col++) {
+    for (row=MAX(mask[m][0],0); row < MIN(mask[m][2],raw_height); row++)
+      for (col=MAX(mask[m][1],0); col < MIN(mask[m][3],raw_width); col++) {
        c = FC(row-top_margin,col-left_margin);
        mblack[c] += val = RAW(row,col);
        mblack[4+c]++;
@@ -3435,8 +3850,10 @@ mask_set:
     black = (mblack[0]+mblack[1]+mblack[2]+mblack[3]) /
            (mblack[4]+mblack[5]+mblack[6]+mblack[7]) - 4;
     canon_600_correct();
-  } else if (zero < mblack[4] && mblack[5] && mblack[6] && mblack[7])
+  } else if (zero < mblack[4] && mblack[5] && mblack[6] && mblack[7]) {
     FORC4 cblack[c] = mblack[c] / mblack[4+c];
+    cblack[4] = cblack[5] = cblack[6] = 0;
+  }
 }
 
 void CLASS remove_zeroes()
@@ -3625,7 +4042,7 @@ void CLASS pseudoinverse (double (*in)[3], double (*out)[3], int size)
        out[i][j] += work[j][k+3] * in[i][k];
 }
 
-void CLASS cam_xyz_coeff (double cam_xyz[4][3])
+void CLASS cam_xyz_coeff (float rgb_cam[3][4], double cam_xyz[4][3])
 {
   double cam_rgb[4][3], inverse[4][3], num;
   int i, j, k;
@@ -3643,7 +4060,7 @@ void CLASS cam_xyz_coeff (double cam_xyz[4][3])
     pre_mul[i] = 1 / num;
   }
   pseudoinverse (cam_rgb, inverse, colors);
-  for (raw_color = i=0; i < 3; i++)
+  for (i=0; i < 3; i++)
     for (j=0; j < colors; j++)
       rgb_cam[i][j] = inverse[j][i];
 }
@@ -3682,8 +4099,8 @@ void CLASS colorcheck()
     { 0.310, 0.316, 9.0 },             // Neutral 3.5
     { 0.310, 0.316, 3.1 } };           // Black
   double gmb_cam[NSQ][4], gmb_xyz[NSQ][3];
-  double inverse[NSQ][3], cam_xyz[4][3], num;
-  int c, i, j, k, sq, row, col, count[4];
+  double inverse[NSQ][3], cam_xyz[4][3], balance[4], num;
+  int c, i, j, k, sq, row, col, pass, count[4];
 
   memset (gmb_cam, 0, sizeof gmb_cam);
   for (sq=0; sq < NSQ; sq++) {
@@ -3692,7 +4109,8 @@ void CLASS colorcheck()
       for (col=cut[sq][2]; col < cut[sq][2]+cut[sq][0]; col++) {
        c = FC(row,col);
        if (c >= colors) c -= 2;
-       gmb_cam[sq][c] += BAYER(row,col);
+       gmb_cam[sq][c] += BAYER2(row,col);
+       BAYER2(row,col) = black + (BAYER2(row,col)-black)/2;
        count[c]++;
       }
     FORCC gmb_cam[sq][c] = gmb_cam[sq][c]/count[c] - black;
@@ -3702,11 +4120,16 @@ void CLASS colorcheck()
                (1 - gmb_xyY[sq][0] - gmb_xyY[sq][1]) / gmb_xyY[sq][1];
   }
   pseudoinverse (gmb_xyz, inverse, NSQ);
-  for (i=0; i < colors; i++)
-    for (j=0; j < 3; j++)
-      for (cam_xyz[i][j] = k=0; k < NSQ; k++)
-       cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j];
-  cam_xyz_coeff (cam_xyz);
+  for (pass=0; pass < 2; pass++) {
+    for (raw_color = i=0; i < colors; i++)
+      for (j=0; j < 3; j++)
+       for (cam_xyz[i][j] = k=0; k < NSQ; k++)
+         cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j];
+    cam_xyz_coeff (rgb_cam, cam_xyz);
+    FORCC balance[c] = pre_mul[c] * gmb_cam[20][c];
+    for (sq=0; sq < NSQ; sq++)
+      FORCC gmb_cam[sq][c] *= balance[c];
+  }
   if (verbose) {
     printf ("    { \"%s %s\", %d,\n\t{", make, model, black);
     num = 10000 / (cam_xyz[1][0] + cam_xyz[1][1] + cam_xyz[1][2]);
@@ -3859,6 +4282,7 @@ skip_block: ;
     else
       fprintf (stderr,_("%s: Cannot use camera white balance.\n"), ifname);
   }
+  if (pre_mul[1] == 0) pre_mul[1] = 1;
   if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1;
   dark = black;
   sat = maximum;
@@ -3878,13 +4302,20 @@ skip_block: ;
     FORC4 fprintf (stderr, " %f", pre_mul[c]);
     fputc ('\n', stderr);
   }
+  if (filters > 1000 && (cblack[4]+1)/2 == 1 && (cblack[5]+1)/2 == 1) {
+    FORC4 cblack[FC(c/2,c%2)] +=
+       cblack[6 + c/2 % cblack[4] * cblack[5] + c%2 % cblack[5]];
+    cblack[4] = cblack[5] = 0;
+  }
   size = iheight*iwidth;
   for (i=0; i < size*4; i++) {
-    val = image[0][i];
-    if (!val) continue;
+    if (!(val = ((ushort *)image)[i])) continue;
+    if (cblack[4] && cblack[5])
+      val -= cblack[6 + i/4 / iwidth % cblack[4] * cblack[5] +
+                       i/4 % iwidth % cblack[5]];
     val -= cblack[i & 3];
     val *= scale_mul[i & 3];
-    image[0][i] = CLIP(val);
+    ((ushort *)image)[i] = CLIP(val);
   }
   if ((aber[0] != 1 || aber[2] != 1) && colors == 3) {
     if (verbose)
@@ -3923,8 +4354,20 @@ void CLASS pre_interpolate()
     if (half_size) {
       height = iheight;
       width  = iwidth;
+      if (filters == 9) {
+       for (row=0; row < 3; row++)
+         for (col=1; col < 4; col++)
+           if (!(image[row*width+col][0] | image[row*width+col][2]))
+             goto break2;  break2:
+       for ( ; row < height; row+=3)
+         for (col=(col-1)%3+1; col < width-1; col+=3) {
+           img = image + row*width+col;
+           for (c=0; c < 3; c+=2)
+             img[0][c] = (img[-1][c] + img[1][c]) >> 1;
+         }
+      }
     } else {
-      img = (ushort (*)[4]) calloc (height*width, sizeof *img);
+      img = (ushort (*)[4]) calloc (height, width*sizeof *img);
       merror (img, "pre_interpolate()");
       for (row=0; row < height; row++)
        for (col=0; col < width; col++) {
@@ -3937,8 +4380,8 @@ void CLASS pre_interpolate()
     }
   }
   if (filters > 1000 && colors == 3) {
-    if (four_color_rgb && colors++)
-      mix_green = !half_size;
+    mix_green = four_color_rgb ^ half_size;
+    if (four_color_rgb | half_size) colors++;
     else {
       for (row = FC(1,0) >> 1; row < height; row+=2)
        for (col = FC(row,1) & 1; col < width; col+=2)
@@ -3978,7 +4421,7 @@ void CLASS lin_interpolate()
   ushort *pix;
 
   if (verbose) fprintf (stderr,_("Bilinear interpolation...\n"));
-  if (filters == 2) size = 6;
+  if (filters == 9) size = 6;
   border_interpolate(1);
   for (row=0; row < size; row++)
     for (col=0; col < size; col++) {
@@ -4059,7 +4502,7 @@ void CLASS vng_interpolate()
   if (verbose) fprintf (stderr,_("VNG interpolation...\n"));
 
   if (filters == 1) prow = pcol = 16;
-  if (filters == 2) prow = pcol =  6;
+  if (filters == 9) prow = pcol =  6;
   ip = (int *) calloc (prow*pcol, 1280);
   merror (ip, "vng_interpolate()");
   for (row=0; row < prow; row++)               /* Precalculate for VNG */
@@ -4205,36 +4648,289 @@ void CLASS ppg_interpolate()
     }
 }
 
+void CLASS cielab (ushort rgb[3], short lab[3])
+{
+  int c, i, j, k;
+  float r, xyz[3];
+  static float cbrt[0x10000], xyz_cam[3][4];
+
+  if (!rgb) {
+    for (i=0; i < 0x10000; i++) {
+      r = i / 65535.0;
+      cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0;
+    }
+    for (i=0; i < 3; i++)
+      for (j=0; j < colors; j++)
+       for (xyz_cam[i][j] = k=0; k < 3; k++)
+         xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i];
+    return;
+  }
+  xyz[0] = xyz[1] = xyz[2] = 0.5;
+  FORCC {
+    xyz[0] += xyz_cam[0][c] * rgb[c];
+    xyz[1] += xyz_cam[1][c] * rgb[c];
+    xyz[2] += xyz_cam[2][c] * rgb[c];
+  }
+  xyz[0] = cbrt[CLIP((int) xyz[0])];
+  xyz[1] = cbrt[CLIP((int) xyz[1])];
+  xyz[2] = cbrt[CLIP((int) xyz[2])];
+  lab[0] = 64 * (116 * xyz[1] - 16);
+  lab[1] = 64 * 500 * (xyz[0] - xyz[1]);
+  lab[2] = 64 * 200 * (xyz[1] - xyz[2]);
+}
+
+#define TS 512         /* Tile Size */
+#define fcol(row,col) xtrans[(row+6) % 6][(col+6) % 6]
+
+/*
+   Frank Markesteijn's algorithm for Fuji X-Trans sensors
+ */
+void CLASS xtrans_interpolate (int passes)
+{
+  int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol;
+  int val, ndir, pass, hm[8], avg[4], color[3][8];
+  static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 },
+       patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 },
+                       { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } },
+       dir[4] = { 1,TS,TS+1,TS-1 };
+  short allhex[3][3][2][8], *hex;
+// CINELERRA
+  ushort min, max, sgrow=0, sgcol=0;
+  ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4];
+   short (*lab)    [TS][3], (*lix)[3];
+   float (*drv)[TS][TS], diff[6], tr;
+   char (*homo)[TS][TS], *buffer;
+
+  if (verbose)
+    fprintf (stderr,_("%d-pass X-Trans interpolation...\n"), passes);
+
+  cielab (0,0);
+  ndir = 4 << (passes > 1);
+  buffer = (char *) malloc (TS*TS*(ndir*11+6));
+  merror (buffer, "xtrans_interpolate()");
+  rgb  = (ushort(*)[TS][TS][3]) buffer;
+  lab  = (short (*)    [TS][3])(buffer + TS*TS*(ndir*6));
+  drv  = (float (*)[TS][TS])   (buffer + TS*TS*(ndir*6+6));
+  homo = (char  (*)[TS][TS])   (buffer + TS*TS*(ndir*10+6));
+
+/* Map a green hexagon around each non-green pixel and vice versa:     */
+  for (row=0; row < 3; row++)
+    for (col=0; col < 3; col++)
+      for (ng=d=0; d < 10; d+=2) {
+       g = fcol(row,col) == 1;
+       if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++;
+       if (ng == 4) { sgrow = row; sgcol = col; }
+       if (ng == g+1) FORC(8) {
+         v = orth[d  ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1];
+         h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1];
+         allhex[row][col][0][c^(g*2 & d)] = h + v*width;
+         allhex[row][col][1][c^(g*2 & d)] = h + v*TS;
+       }
+      }
+
+/* Set green1 and green3 to the minimum and maximum allowed values:    */
+  for (row=2; row < height-2; row++)
+    for (min=~(max=0), col=2; col < width-2; col++) {
+      if (fcol(row,col) == 1 && (min=~(max=0))) continue;
+      pix = image + row*width + col;
+      hex = allhex[row % 3][col % 3][0];
+      if (!max) FORC(6) {
+       val = pix[hex[c]][1];
+       if (min > val) min = val;
+       if (max < val) max = val;
+      }
+      pix[0][1] = min;
+      pix[0][3] = max;
+      switch ((row-sgrow) % 3) {
+       case 1: if (row < height-3) { row++; col--; } break;
+       case 2: if ((min=~(max=0)) && (col+=2) < width-3 && row > 2) row--;
+      }
+    }
+
+  for (top=3; top < height-19; top += TS-16)
+    for (left=3; left < width-19; left += TS-16) {
+      mrow = MIN (top+TS, height-3);
+      mcol = MIN (left+TS, width-3);
+      for (row=top; row < mrow; row++)
+       for (col=left; col < mcol; col++)
+         memcpy (rgb[0][row-top][col-left], image[row*width+col], 6);
+      FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb);
+
+/* Interpolate green horizontally, vertically, and along both diagonals: */
+      for (row=top; row < mrow; row++)
+       for (col=left; col < mcol; col++) {
+         if ((f = fcol(row,col)) == 1) continue;
+         pix = image + row*width + col;
+         hex = allhex[row % 3][col % 3][0];
+         color[1][0] = 174 * (pix[  hex[1]][1] + pix[  hex[0]][1]) -
+                        46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]);
+         color[1][1] = 223 *  pix[  hex[3]][1] + pix[  hex[2]][1] * 33 +
+                        92 * (pix[      0 ][f] - pix[ -hex[2]][f]);
+         FORC(2) color[1][2+c] =
+               164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 *
+               (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]);
+         FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] =
+               LIM(color[1][c] >> 8,pix[0][1],pix[0][3]);
+       }
+
+      for (pass=0; pass < passes; pass++) {
+       if (pass == 1)
+         memcpy (rgb+=4, buffer, 4*sizeof *rgb);
+
+/* Recalculate green from interpolated values of closer pixels:        */
+       if (pass) {
+         for (row=top+2; row < mrow-2; row++)
+           for (col=left+2; col < mcol-2; col++) {
+             if ((f = fcol(row,col)) == 1) continue;
+             pix = image + row*width + col;
+             hex = allhex[row % 3][col % 3][1];
+             for (d=3; d < 6; d++) {
+               rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left];
+               val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1]
+                   - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f];
+               rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]);
+             }
+           }
+       }
+
+/* Interpolate red and blue values for solitary green pixels:  */
+       for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3)
+         for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) {
+           rix = &rgb[0][row-top][col-left];
+           h = fcol(row,col+1);
+           memset (diff, 0, sizeof diff);
+           for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) {
+             for (c=0; c < 2; c++, h^=2) {
+               g = 2*rix[0][1] - rix[i<<c][1] - rix[-i<<c][1];
+               color[h][d] = g + rix[i<<c][h] + rix[-i<<c][h];
+               if (d > 1)
+                 diff[d] += SQR (rix[i<<c][1] - rix[-i<<c][1]
+                               - rix[i<<c][h] + rix[-i<<c][h]) + SQR(g);
+             }
+             if (d > 1 && (d & 1))
+               if (diff[d-1] < diff[d])
+                 FORC(2) color[c*2][d] = color[c*2][d-1];
+             if (d < 2 || (d & 1)) {
+               FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2);
+               rix += TS*TS;
+             }
+           }
+         }
+
+/* Interpolate red for blue pixels and vice versa:             */
+       for (row=top+3; row < mrow-3; row++)
+         for (col=left+3; col < mcol-3; col++) {
+           if ((f = 2-fcol(row,col)) == 1) continue;
+           rix = &rgb[0][row-top][col-left];
+           c = (row-sgrow) % 3 ? TS:1;
+           h = 3 * (c ^ TS ^ 1);
+           for (d=0; d < 4; d++, rix += TS*TS) {
+             i = d > 1 || ((d ^ c) & 1) ||
+                ((ABS(rix[0][1]-rix[c][1])+ABS(rix[0][1]-rix[-c][1])) <
+               2*(ABS(rix[0][1]-rix[h][1])+ABS(rix[0][1]-rix[-h][1]))) ? c:h;
+             rix[0][f] = CLIP((rix[i][f] + rix[-i][f] +
+                 2*rix[0][1] - rix[i][1] - rix[-i][1])/2);
+           }
+         }
+
+/* Fill in red and blue for 2x2 blocks of green:               */
+       for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3)
+         for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) {
+           rix = &rgb[0][row-top][col-left];
+           hex = allhex[row % 3][col % 3][1];
+           for (d=0; d < ndir; d+=2, rix += TS*TS)
+             if (hex[d] + hex[d+1]) {
+               g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1];
+               for (c=0; c < 4; c+=2) rix[0][c] =
+                       CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3);
+             } else {
+               g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1];
+               for (c=0; c < 4; c+=2) rix[0][c] =
+                       CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2);
+             }
+         }
+      }
+      rgb = (ushort(*)[TS][TS][3]) buffer;
+      mrow -= top;
+      mcol -= left;
+
+/* Convert to CIELab and differentiate in all directions:      */
+      for (d=0; d < ndir; d++) {
+       for (row=2; row < mrow-2; row++)
+         for (col=2; col < mcol-2; col++)
+           cielab (rgb[d][row][col], lab[row][col]);
+       for (f=dir[d & 3],row=3; row < mrow-3; row++)
+         for (col=3; col < mcol-3; col++) {
+           lix = &lab[row][col];
+           g = 2*lix[0][0] - lix[f][0] - lix[-f][0];
+           drv[d][row][col] = SQR(g)
+             + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232))
+             + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580));
+         }
+      }
+
+/* Build homogeneity maps from the derivatives:                        */
+      memset(homo, 0, ndir*TS*TS);
+      for (row=4; row < mrow-4; row++)
+       for (col=4; col < mcol-4; col++) {
+         for (tr=FLT_MAX, d=0; d < ndir; d++)
+           if (tr > drv[d][row][col])
+               tr = drv[d][row][col];
+         tr *= 8;
+         for (d=0; d < ndir; d++)
+           for (v=-1; v <= 1; v++)
+             for (h=-1; h <= 1; h++)
+               if (drv[d][row+v][col+h] <= tr)
+                 homo[d][row][col]++;
+       }
+
+/* Average the most homogenous pixels for the final result:    */
+      if (height-top < TS+4) mrow = height-top+2;
+      if (width-left < TS+4) mcol = width-left+2;
+      for (row = MIN(top,8); row < mrow-8; row++)
+       for (col = MIN(left,8); col < mcol-8; col++) {
+         for (d=0; d < ndir; d++)
+           for (hm[d]=0, v=-2; v <= 2; v++)
+             for (h=-2; h <= 2; h++)
+               hm[d] += homo[d][row+v][col+h];
+         for (d=0; d < ndir-4; d++)
+           if (hm[d] < hm[d+4]) hm[d  ] = 0; else
+           if (hm[d] > hm[d+4]) hm[d+4] = 0;
+         for (max=hm[0],d=1; d < ndir; d++)
+           if (max < hm[d]) max = hm[d];
+         max -= max >> 3;
+         memset (avg, 0, sizeof avg);
+         for (d=0; d < ndir; d++)
+           if (hm[d] >= max) {
+             FORC3 avg[c] += rgb[d][row][col][c];
+             avg[3]++;
+           }
+         FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3];
+       }
+    }
+  free(buffer);
+  border_interpolate(8);
+}
+#undef fcol
+
 /*
    Adaptive Homogeneity-Directed interpolation is based on
    the work of Keigo Hirakawa, Thomas Parks, and Paul Lee.
  */
-#define TS 256         /* Tile Size */
-
 void CLASS ahd_interpolate()
 {
-  int i, j, k, top, left, row, col, tr, tc, c, d, val, hm[2];
-  ushort (*pix)[4], (*rix)[3];
+  int i, j, top, left, row, col, tr, tc, c, d, val, hm[2];
   static const int dir[4] = { -1, 1, -TS, TS };
   unsigned ldiff[2][4], abdiff[2][4], leps, abeps;
-  float r, cbrt[0x10000], xyz[3], xyz_cam[3][4];
-  ushort (*rgb)[TS][TS][3];
+  ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4];
    short (*lab)[TS][TS][3], (*lix)[3];
    char (*homo)[TS][TS], *buffer;
 
   if (verbose) fprintf (stderr,_("AHD interpolation...\n"));
 
-  for (i=0; i < 0x10000; i++) {
-    r = i / 65535.0;
-    cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0;
-  }
-  for (i=0; i < 3; i++)
-    for (j=0; j < colors; j++)
-      for (xyz_cam[i][j] = k=0; k < 3; k++)
-       xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i];
-
+  cielab (0,0);
   border_interpolate(5);
-  buffer = (char *) malloc (26*TS*TS);         /* 1664 kB */
+  buffer = (char *) malloc (26*TS*TS);
   merror (buffer, "ahd_interpolate()");
   rgb  = (ushort(*)[TS][TS][3]) buffer;
   lab  = (short (*)[TS][TS][3])(buffer + 12*TS*TS);
@@ -4244,7 +4940,7 @@ void CLASS ahd_interpolate()
     for (left=2; left < width-5; left += TS-6) {
 
 /*  Interpolate green horizontally and vertically:             */
-      for (row = top; row < top+TS && row < height-2; row++) {
+      for (row=top; row < top+TS && row < height-2; row++) {
        col = left + (FC(row,left) & 1);
        for (c = FC(row,col); col < left+TS && col < width-2; col+=2) {
          pix = image + row*width+col;
@@ -4278,18 +4974,7 @@ void CLASS ahd_interpolate()
            rix[0][c] = CLIP(val);
            c = FC(row,col);
            rix[0][c] = pix[0][c];
-           xyz[0] = xyz[1] = xyz[2] = 0.5;
-           FORCC {
-             xyz[0] += xyz_cam[0][c] * rix[0][c];
-             xyz[1] += xyz_cam[1][c] * rix[0][c];
-             xyz[2] += xyz_cam[2][c] * rix[0][c];
-           }
-           xyz[0] = cbrt[CLIP((int) xyz[0])];
-           xyz[1] = cbrt[CLIP((int) xyz[1])];
-           xyz[2] = cbrt[CLIP((int) xyz[2])];
-           lix[0][0] = 64 * (116 * xyz[1] - 16);
-           lix[0][1] = 64 * 500 * (xyz[0] - xyz[1]);
-           lix[0][2] = 64 * 200 * (xyz[1] - xyz[2]);
+           cielab (rix[0],lix[0]);
          }
 /*  Build homogeneity maps from the CIELab images:             */
       memset (homo, 0, 2*TS*TS);
@@ -4419,7 +5104,7 @@ void CLASS recover_highlights()
     if (pre_mul[kc] < pre_mul[c]) kc = c;
   high = height / SCALE;
   wide =  width / SCALE;
-  map = (float *) calloc (high*wide, sizeof *map);
+  map = (float *) calloc (high, wide*sizeof *map);
   merror (map, "recover_highlights()");
   FORCC if (c != kc) {
     memset (map, 0, high*wide*sizeof *map);
@@ -4486,7 +5171,7 @@ void CLASS tiff_get (unsigned base,
   *type = get2();
   *len  = get4();
   *save = ftell(ifp) + 4;
-  if (*len * ("11124811248488"[*type < 14 ? *type:0]-'0') > 4)
+  if (*len * ("11124811248484"[*type < 14 ? *type:0]-'0') > 4)
     fseek (ifp, get4()+base, SEEK_SET);
 }
 
@@ -4573,10 +5258,12 @@ void CLASS parse_makernote (int base, int uptag)
     if (get2() != 42) goto quit;
     offset = get4();
     fseek (ifp, offset-8, SEEK_CUR);
-  } else if (!strcmp (buf,"OLYMPUS")) {
+  } else if (!strcmp (buf,"OLYMPUS") ||
+             !strcmp (buf,"PENTAX ")) {
     base = ftell(ifp)-10;
     fseek (ifp, -2, SEEK_CUR);
-    order = get2();  get2();
+    order = get2();
+    if (buf[0] == 'O') get2();
   } else if (!strncmp (buf,"SONY",4) ||
             !strcmp  (buf,"Panasonic")) {
     goto nf;
@@ -4630,10 +5317,8 @@ nf: order = 0x4949;
       shot_order = get4();
     if (tag == 9 && !strcmp(make,"Canon"))
       fread (artist, 64, 1, ifp);
-    if (tag == 0xc && len == 4) {
-      cam_mul[0] = getreal(type);
-      cam_mul[2] = getreal(type);
-    }
+    if (tag == 0xc && len == 4)
+      FORC3 cam_mul[(c << 1 | c >> 1) & 3] = getreal(type);
     if (tag == 0xd && type == 7 && get2() == 0xaaaa) {
       for (c=i=2; (ushort) c != 0xbbbb && i < len; i++)
        c = c << 8 | fgetc(ifp);
@@ -4669,6 +5354,13 @@ nf: order = 0x4949;
     if (tag == 0x1d)
       while ((c = fgetc(ifp)) && c != EOF)
        serial = serial*10 + (isdigit(c) ? c - '0' : c % 10);
+    if (tag == 0x29 && type == 1) {
+      c = wbi < 18 ? "012347800000005896"[wbi]-'0' : 0;
+      fseek (ifp, 8 + c*32, SEEK_CUR);
+      FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4();
+    }
+    if (tag == 0x3d && type == 3 && len == 4)
+      FORC4 cblack[c ^ c >> 1] = get2() >> (14-tiff_bps);
     if (tag == 0x81 && type == 4) {
       data_offset = get4();
       fseek (ifp, data_offset + 41, SEEK_SET);
@@ -4676,11 +5368,6 @@ nf: order = 0x4949;
       raw_width  = get2();
       filters = 0x61616161;
     }
-    if (tag == 0x29 && type == 1) {
-      c = wbi < 18 ? "012347800000005896"[wbi]-'0' : 0;
-      fseek (ifp, 8 + c*32, SEEK_CUR);
-      FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4();
-    }
     if ((tag == 0x81  && type == 7) ||
        (tag == 0x100 && type == 7) ||
        (tag == 0x280 && type == 1)) {
@@ -4703,7 +5390,8 @@ nf: order = 0x4949;
          break;
        case 102:
          fseek (ifp, 6, SEEK_CUR);
-         goto get2_rggb;
+         FORC4 cam_mul[c ^ (c >> 1)] = get2();
+         break;
        case 103:
          fseek (ifp, 16, SEEK_CUR);
          FORC4 cam_mul[c] = get2();
@@ -4737,7 +5425,7 @@ nf: order = 0x4949;
     if (tag == 0x200 && len == 4)
       FORC4 cblack[c ^ c >> 1] = get2();
     if (tag == 0x201 && len == 4)
-      goto get2_rggb;
+      FORC4 cam_mul[c ^ (c >> 1)] = get2();
     if (tag == 0x220 && type == 7)
       meta_offset = ftell(ifp);
     if (tag == 0x401 && type == 4 && len == 4)
@@ -4781,11 +5469,9 @@ get2_256:
       cam_mul[0] = get2() / 256.0;
       cam_mul[2] = get2() / 256.0;
     }
-    if ((tag | 0x70) == 0x2070 && type == 4)
+    if ((tag | 0x70) == 0x2070 && (type == 4 || type == 13))
       fseek (ifp, get4()+base, SEEK_SET);
-    if (tag == 0x2010 && type != 7)
-      load_raw = &CLASS olympus_load_raw;
-    if (tag == 0x2020)
+    if (tag == 0x2020 && !strncmp(buf,"OLYMP",5))
       parse_thumb_note (base, 257, 258);
     if (tag == 0x2040)
       parse_makernote (base, 0x2040);
@@ -4796,16 +5482,21 @@ get2_256:
     if (tag == 0x4001 && len > 500) {
       i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126;
       fseek (ifp, i, SEEK_CUR);
-get2_rggb:
       FORC4 cam_mul[c ^ (c >> 1)] = get2();
-      i = len >> 3 == 164 ? 112:22;
-      fseek (ifp, i, SEEK_CUR);
-      FORC4 sraw_mul[c ^ (c >> 1)] = get2();
+      for (i+=18; i <= len; i+=10) {
+       get2();
+       FORC4 sraw_mul[c ^ (c >> 1)] = get2();
+       if (sraw_mul[1] == 1170) break;
+      }
     }
+    if (tag == 0x4021 && get4() && get4())
+      FORC4 cam_mul[c] = 1024;
     if (tag == 0xa021)
       FORC4 cam_mul[c ^ (c >> 1)] = get4();
     if (tag == 0xa028)
       FORC4 cam_mul[c ^ (c >> 1)] -= get4();
+    if (tag == 0xb001)
+      unique_id = get2();
 next:
     fseek (ifp, save, SEEK_SET);
   }
@@ -4849,12 +5540,14 @@ void CLASS parse_exif (int base)
   while (entries--) {
     tiff_get (base, &tag, &type, &len, &save);
     switch (tag) {
-      case 33434:  shutter = getreal(type);            break;
+      case 33434:  tiff_ifd[tiff_nifds-1].shutter =
+                  shutter = getreal(type);             break;
       case 33437:  aperture = getreal(type);           break;
       case 34855:  iso_speed = get2();                 break;
       case 36867:
       case 36868:  get_timestamp(0);                   break;
       case 37377:  if ((expo = -getreal(type)) < 128)
+                    tiff_ifd[tiff_nifds-1].shutter =
                     shutter = pow (2, expo);           break;
       case 37378:  aperture = pow (2, getreal(type)/2);        break;
       case 37386:  focal_len = getreal(type);          break;
@@ -4913,7 +5606,8 @@ void CLASS parse_mos (int offset)
   { "","DCB2","Volare","Cantare","CMost","Valeo 6","Valeo 11","Valeo 22",
     "Valeo 11p","Valeo 17","","Aptus 17","Aptus 22","Aptus 75","Aptus 65",
     "Aptus 54S","Aptus 65S","Aptus 75S","AFi 5","AFi 6","AFi 7",
-    "","","","","","","","","","","","","","","","","","AFi-II 12" };
+    "AFi-II 7","Aptus-II 7","","Aptus-II 6","","","Aptus-II 10","Aptus-II 5",
+    "","","","","Aptus-II 10R","Aptus-II 8","","Aptus-II 12","","AFi-II 12" };
   float romm_cam[3][3];
 
   fseek (ifp, offset, SEEK_SET);
@@ -4938,12 +5632,12 @@ void CLASS parse_mos (int offset)
     }
     if (!strcmp(data,"icc_camera_to_tone_matrix")) {
       for (i=0; i < 9; i++)
-       romm_cam[0][i] = int_to_float(get4());
+       ((float *)romm_cam)[i] = int_to_float(get4());
       romm_coeff (romm_cam);
     }
     if (!strcmp(data,"CaptProf_color_matrix")) {
       for (i=0; i < 9; i++)
-       fscanf (ifp, "%f", &romm_cam[0][i]);
+       fscanf (ifp, "%f", (float *)romm_cam + i);
       romm_coeff (romm_cam);
     }
     if (!strcmp(data,"CaptProf_number_of_planes"))
@@ -5001,6 +5695,8 @@ void CLASS parse_kodak_ifd (int base)
       wbi = -2;
     }
     if (tag == 2118) wbtemp = getint(type);
+    if (tag == 2120 + wbi && wbi >= 0)
+      FORC3 cam_mul[c] = 2048.0 / getreal(type);
     if (tag == 2130 + wbi)
       FORC3 mul[c] = getreal(type);
     if (tag == 2140 + wbi && wbi >= 0)
@@ -5027,7 +5723,6 @@ int CLASS parse_tiff_ifd (int base)
 {
   unsigned entries, tag, type, len, plen=16, save;
   int ifd, use_cm=0, cfa, i, j, c, ima_len=0;
-  int blrr=1, blrc=1, dblack[] = { 0,0,0,0 };
   char software[64], *cbuf, *cp;
   uchar cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256];
   double cc[4][4], cm[4][3], cam_xyz[4][3], num;
@@ -5051,7 +5746,7 @@ int CLASS parse_tiff_ifd (int base)
       case 5:   width  = get2();  break;
       case 6:   height = get2();  break;
       case 7:   width += get2();  break;
-      case 9:  filters = get2();  break;
+      case 9:   if ((i = get2())) filters = i;  break;
       case 17: case 18:
        if (type == 3 && len == 1)
          cam_mul[(tag-17)*2] = get2() / 256.0;
@@ -5059,8 +5754,12 @@ int CLASS parse_tiff_ifd (int base)
       case 23:
        if (type == 3) iso_speed = get2();
        break;
+      case 28: case 29: case 30:
+       cblack[tag-28] = get2();
+       cblack[3] = cblack[1];
+       break;
       case 36: case 37: case 38:
-       cam_mul[tag-0x24] = get2();
+       cam_mul[tag-36] = get2();
        break;
       case 39:
        if (len < 50 || cam_mul[0]) break;
@@ -5073,6 +5772,7 @@ int CLASS parse_tiff_ifd (int base)
        thumb_length = len;
        break;
       case 61440:                      /* Fuji HS10 table */
+       fseek (ifp, get4()+base, SEEK_SET);
        parse_tiff_ifd (base);
        break;
       case 2: case 256: case 61441:    /* ImageWidth */
@@ -5085,11 +5785,14 @@ int CLASS parse_tiff_ifd (int base)
       case 61443:
        tiff_ifd[ifd].samples = len & 7;
        tiff_ifd[ifd].bps = getint(type);
+       if (tiff_bps < tiff_ifd[ifd].bps)
+           tiff_bps = tiff_ifd[ifd].bps;
        break;
       case 61446:
        raw_height = 0;
+       if (tiff_ifd[ifd].bps > 12) break;
        load_raw = &CLASS packed_load_raw;
-       load_flags = get4() && (filters=0x16161616) ? 24:80;
+       load_flags = get4() ? 24:80;
        break;
       case 259:                                /* Compression */
        tiff_ifd[ifd].comp = getint(type);
@@ -5124,6 +5827,10 @@ int CLASS parse_tiff_ifd (int base)
            tiff_ifd[ifd].samples = jh.clrs;
            if (!(jh.sraw || (jh.clrs & 1)))
              tiff_ifd[ifd].width *= jh.clrs;
+           if ((tiff_ifd[ifd].width > 4*tiff_ifd[ifd].height) & ~jh.clrs) {
+             tiff_ifd[ifd].width  /= 2;
+             tiff_ifd[ifd].height *= 2;
+           }
            i = order;
            parse_tiff (tiff_ifd[ifd].offset + 12);
            order = i;
@@ -5168,6 +5875,8 @@ int CLASS parse_tiff_ifd (int base)
        break;
       case 324:                                /* TileOffsets */
        tiff_ifd[ifd].offset = len > 1 ? ftell(ifp) : get4();
+       if (len == 1)
+         tiff_ifd[ifd].tile_width = tiff_ifd[ifd].tile_length = 0;
        if (len == 4) {
          load_raw = &CLASS sinar_4shot_load_raw;
          is_raw = 5;
@@ -5214,11 +5923,19 @@ int CLASS parse_tiff_ifd (int base)
       case 33405:                      /* Model2 */
        fgets (model2, 64, ifp);
        break;
+      case 33421:                      /* CFARepeatPatternDim */
+       if (get2() == 6 && get2() == 6)
+         filters = 9;
+       break;
       case 33422:                      /* CFAPattern */
+       if (filters == 9) {
+         FORC(36) ((char *)xtrans)[c] = fgetc(ifp) & 3;
+         break;
+       }
       case 64777:                      /* Kodak P-series */
        if ((plen=len) > 16) plen = 16;
        fread (cfa_pat, 1, plen, ifp);
-       for (colors=cfa=i=0; i < plen; i++) {
+       for (colors=cfa=i=0; i < plen && colors < 4; i++) {
          colors += !(cfa & (1 << cfa_pat[i]));
          cfa |= 1 << cfa_pat[i];
        }
@@ -5231,7 +5948,7 @@ int CLASS parse_tiff_ifd (int base)
        parse_kodak_ifd (base);
        break;
       case 33434:                      /* ExposureTime */
-       shutter = getreal(type);
+       tiff_ifd[ifd].shutter = shutter = getreal(type);
        break;
       case 33437:                      /* FNumber */
        aperture = getreal(type);
@@ -5284,6 +6001,14 @@ int CLASS parse_tiff_ifd (int base)
          FORC3 rgb_cam[i][c] = getreal(type);
        }
        break;
+      case 40976:
+       strip_offset = get4();
+       switch (tiff_ifd[ifd].comp) {
+         case 32770: load_raw = &CLASS samsung_load_raw;   break;
+         case 32772: load_raw = &CLASS samsung2_load_raw;  break;
+         case 32773: load_raw = &CLASS samsung3_load_raw;  break;
+       }
+       break;
       case 46275:                      /* Imacon tags */
        strcpy (make, "Imacon");
        data_offset = ftell(ifp);
@@ -5351,7 +6076,16 @@ int CLASS parse_tiff_ifd (int base)
        if (!make[0]) strcpy (make, "DNG");
        is_raw = 1;
        break;
+      case 50708:                      /* UniqueCameraModel */
+       if (model[0]) break;
+       fgets (make, 64, ifp);
+        if ((cp = strchr(make,' '))) {
+         strcpy(model,cp+1);
+         *cp = 0;
+       }
+       break;
       case 50710:                      /* CFAPlaneColor */
+       if (filters == 9) break;
        if (len > 4) len = 4;
        colors = len;
        fread (cfa_pc, 1, colors, ifp);
@@ -5360,39 +6094,33 @@ guess_cfa_pc:
        cdesc[c] = 0;
        for (i=16; i--; )
          filters = filters << 2 | tab[cfa_pat[i % plen]];
+       filters -= !filters;
        break;
       case 50711:                      /* CFALayout */
-       if (get2() == 2) {
-         fuji_width = 1;
-         filters = 0x49494949;
-       }
+       if (get2() == 2) fuji_width = 1;
        break;
       case 291:
       case 50712:                      /* LinearizationTable */
        linear_table (len);
        break;
       case 50713:                      /* BlackLevelRepeatDim */
-       blrr = get2();
-       blrc = get2();
+       cblack[4] = get2();
+       cblack[5] = get2();
+       if (cblack[4] * cblack[5] > sizeof cblack / sizeof *cblack - 6)
+           cblack[4] = cblack[5] = 1;
        break;
       case 61450:
-       blrr = blrc = 2;
+       cblack[4] = cblack[5] = MIN(sqrt(len),64);
       case 50714:                      /* BlackLevel */
-       black = getreal(type);
-       if (!filters || !~filters) break;
-       dblack[0] = black;
-       dblack[1] = (blrc == 2) ? getreal(type):dblack[0];
-       dblack[2] = (blrr == 2) ? getreal(type):dblack[0];
-       dblack[3] = (blrc == 2 && blrr == 2) ? getreal(type):dblack[1];
-       if (colors == 3)
-         filters |= ((filters >> 2 & 0x22222222) |
-                     (filters << 2 & 0x88888888)) & filters << 1;
-       FORC4 cblack[filters >> (c << 1) & 3] = dblack[c];
+       if (!(cblack[4] * cblack[5]))
+         cblack[4] = cblack[5] = 1;
+       FORC (cblack[4] * cblack[5])
+         cblack[6+c] = getreal(type);
        black = 0;
        break;
       case 50715:                      /* BlackLevelDeltaH */
       case 50716:                      /* BlackLevelDeltaV */
-       for (num=i=0; i < len; i++)
+       for (num=i=0; i < (len & 0xffff); i++)
          num += getreal(type);
        black += num/len + 0.5;
        break;
@@ -5443,7 +6171,7 @@ guess_cfa_pc:
        break;
       case 50830:                      /* MaskedAreas */
         for (i=0; i < len && i < 32; i++)
-         mask[0][i] = getint(type);
+         ((int *)mask)[i] = getint(type);
        black = 0;
        break;
       case 51009:                      /* OpcodeList2 */
@@ -5482,7 +6210,7 @@ guess_cfa_pc:
     FORCC for (i=0; i < 3; i++)
       for (cam_xyz[c][i]=j=0; j < colors; j++)
        cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i];
-    cam_xyz_coeff (cam_xyz);
+    cam_xyz_coeff (cmatrix, cam_xyz);
   }
   if (asn[0]) {
     cam_mul[3] = 0;
@@ -5510,7 +6238,7 @@ int CLASS parse_tiff (int base)
 
 void CLASS apply_tiff()
 {
-  int max_samp=0, raw=-1, thm=-1, i;
+  int max_samp=0, ties=0, os, ns, raw=-1, thm=-1, i;
   struct jhead jh;
 
   thumb_misc = 16;
@@ -5522,13 +6250,25 @@ void CLASS apply_tiff()
       thumb_height = jh.high;
     }
   }
+  for (i=tiff_nifds; i--; ) {
+    if (tiff_ifd[i].shutter)
+      shutter = tiff_ifd[i].shutter;
+    tiff_ifd[i].shutter = shutter;
+  }
   for (i=0; i < tiff_nifds; i++) {
     if (max_samp < tiff_ifd[i].samples)
        max_samp = tiff_ifd[i].samples;
     if (max_samp > 3) max_samp = 3;
+    os = raw_width*raw_height;
+    ns = tiff_ifd[i].width*tiff_ifd[i].height;
+    if (tiff_bps) {
+      os *= tiff_bps;
+      ns *= tiff_ifd[i].bps;
+    }
     if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) &&
        (tiff_ifd[i].width | tiff_ifd[i].height) < 0x10000 &&
-       tiff_ifd[i].width*tiff_ifd[i].height > raw_width*raw_height) {
+        ns && ((ns > os && (ties = 1)) ||
+               (ns == os && shot_select == ties++))) {
       raw_width     = tiff_ifd[i].width;
       raw_height    = tiff_ifd[i].height;
       tiff_bps      = tiff_ifd[i].bps;
@@ -5538,9 +6278,11 @@ void CLASS apply_tiff()
       tiff_samples  = tiff_ifd[i].samples;
       tile_width    = tiff_ifd[i].tile_width;
       tile_length   = tiff_ifd[i].tile_length;
+      shutter       = tiff_ifd[i].shutter;
       raw = i;
     }
   }
+  if (is_raw == 1 && ties) is_raw = ties;
   if (!tile_width ) tile_width  = INT_MAX;
   if (!tile_length) tile_length = INT_MAX;
   for (i=tiff_nifds; i--; )
@@ -5562,6 +6304,9 @@ void CLASS apply_tiff()
       case 32770:
       case 32773: goto slr;
       case 0:  case 1:
+       if (!strncmp(make,"OLYMPUS",7) &&
+               tiff_ifd[raw].bytes*2 == raw_width*raw_height*3)
+         load_flags = 24;
        if (tiff_ifd[raw].bytes*5 == raw_width*raw_height*8) {
          load_flags = 81;
          tiff_bps = 12;
@@ -5572,7 +6317,10 @@ void CLASS apply_tiff()
                     load_flags = 6;
                   load_raw = &CLASS packed_load_raw;           break;
          case 14: load_flags = 0;
-         case 16: load_raw = &CLASS unpacked_load_raw;         break;
+         case 16: load_raw = &CLASS unpacked_load_raw;
+                  if (!strncmp(make,"OLYMPUS",7) &&
+                       tiff_ifd[raw].bytes*7 > raw_width*raw_height)
+                    load_raw = &CLASS olympus_load_raw;
        }
        break;
       case 6:  case 7:  case 99:
@@ -5583,14 +6331,20 @@ void CLASS apply_tiff()
        if ((raw_width+9)/10*16*raw_height == tiff_ifd[raw].bytes) {
          load_raw = &CLASS packed_load_raw;
          load_flags = 1;
+       } else if (raw_width*raw_height*3 == tiff_ifd[raw].bytes*2) {
+         load_raw = &CLASS packed_load_raw;
+         if (model[0] == 'N') load_flags = 80;
+       } else if (raw_width*raw_height*3 == tiff_ifd[raw].bytes) {
+         load_raw = &CLASS nikon_yuv_load_raw;
+         gamma_curve (1/2.4, 12.92, 1, 4095);
+         memset (cblack, 0, sizeof cblack);
+         filters = 0;
        } else if (raw_width*raw_height*2 == tiff_ifd[raw].bytes) {
          load_raw = &CLASS unpacked_load_raw;
          load_flags = 4;
          order = 0x4d4d;
        } else
          load_raw = &CLASS nikon_load_raw;                     break;
-      case 34892:
-       load_raw = &CLASS lossy_dng_load_raw;                   break;
       case 65535:
        load_raw = &CLASS pentax_load_raw;                      break;
       case 65000:
@@ -5599,20 +6353,19 @@ void CLASS apply_tiff()
          case 6: load_raw = &CLASS kodak_ycbcr_load_raw; filters = 0;  break;
          case 32803: load_raw = &CLASS kodak_65000_load_raw;
        }
-      case 32867: break;
+      case 32867: case 34892: break;
       default: is_raw = 0;
     }
   if (!dng_version)
-    if ( (tiff_samples == 3 && tiff_ifd[raw].bytes &&
-         tiff_bps != 14 && tiff_bps != 2048 &&
-         tiff_compress != 32769 && tiff_compress != 32770)
-      || (tiff_bps == 8 && !strstr(make,"KODAK") && !strstr(make,"Kodak") &&
-         !strstr(model2,"DEBUG RAW")))
+    if ( (tiff_samples == 3 && tiff_ifd[raw].bytes && tiff_bps != 14 &&
+         (tiff_compress & -16) != 32768)
+      || (tiff_bps == 8 && strncmp(make,"Phase",5) &&
+         !strcasestr(make,"Kodak") && !strstr(model2,"DEBUG RAW")))
       is_raw = 0;
   for (i=0; i < tiff_nifds; i++)
     if (i != raw && tiff_ifd[i].samples == max_samp &&
-       tiff_ifd[i].width * tiff_ifd[i].height / SQR(tiff_ifd[i].bps+1) >
-             thumb_width *       thumb_height / SQR(thumb_misc+1)
+       tiff_ifd[i].width * tiff_ifd[i].height / (SQR(tiff_ifd[i].bps)+1) >
+             thumb_width *       thumb_height / (SQR(thumb_misc)+1)
        && tiff_ifd[i].comp != 34892) {
       thumb_width  = tiff_ifd[i].width;
       thumb_height = tiff_ifd[i].height;
@@ -5748,16 +6501,14 @@ void CLASS ciff_block_1030()
        bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]);
        vbits += 16;
       }
-      white[row][col] =
-       bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp);
-      vbits -= bpp;
+      white[row][col] = bitbuf >> (vbits -= bpp) & ~(-1 << bpp);
     }
 }
 
 /*
    Parse a CIFF file, better known as Canon CRW format.
  */
-void CLASS parse_ciff (int offset, int length)
+void CLASS parse_ciff (int offset, int length, int depth)
 {
   int tboff, nrecs, c, type, len, save, wbi=-1;
   ushort key[] = { 0x410, 0x45f3 };
@@ -5766,15 +6517,14 @@ void CLASS parse_ciff (int offset, int length)
   tboff = get4() + offset;
   fseek (ifp, tboff, SEEK_SET);
   nrecs = get2();
-  if (nrecs > 100) return;
+  if ((nrecs | depth) > 127) return;
   while (nrecs--) {
     type = get2();
     len  = get4();
     save = ftell(ifp) + 4;
     fseek (ifp, offset+get4(), SEEK_SET);
     if ((((type >> 8) + 8) | 8) == 0x38)
-      parse_ciff (ftell(ifp), len);    /* Parse a sub-table */
-
+      parse_ciff (ftell(ifp), len, depth+1); /* Parse a sub-table */
     if (type == 0x0810)
       fread (artist, 64, 1, ifp);
     if (type == 0x080a) {
@@ -5783,7 +6533,9 @@ void CLASS parse_ciff (int offset, int length)
       fread (model, 64, 1, ifp);
     }
     if (type == 0x1810) {
-      fseek (ifp, 12, SEEK_CUR);
+      width = get4();
+      height = get4();
+      pixel_aspect = int_to_float(get4());
       flip = get4();
     }
     if (type == 0x1835)                        /* Get the decoder table */
@@ -5933,8 +6685,9 @@ void CLASS parse_sinar_ia()
 
 void CLASS parse_phase_one (int base)
 {
+//CINELERRA
   unsigned entries, tag, /*type,*/ len, data, save, i, c;
-  float romm_cam[3][3], *fp;
+  float romm_cam[3][3];
   char *cp;
 
   memset (&ph1, 0, sizeof ph1);
@@ -5946,6 +6699,7 @@ void CLASS parse_phase_one (int base)
   get4();
   while (entries--) {
     tag  = get4();
+//CINELERRA
     /*type =*/ get4();
     len  = get4();
     data = get4();
@@ -5954,8 +6708,8 @@ void CLASS parse_phase_one (int base)
     switch (tag) {
       case 0x100:  flip = "0653"[data & 3]-'0';  break;
       case 0x106:
-       for( i=9,fp=&romm_cam[0][0]; --i>=0; ++fp )
-         *fp = getreal(11);
+       for (i=0; i < 9; i++)
+         ((float *)romm_cam)[i] = getreal(11);
        romm_coeff (romm_cam);
        break;
       case 0x107:
@@ -5977,7 +6731,9 @@ void CLASS parse_phase_one (int base)
       case 0x21c:  strip_offset  = data+base;          break;
       case 0x21d:  ph1.black     = data;               break;
       case 0x222:  ph1.split_col = data;               break;
-      case 0x223:  ph1.black_off = data+base;          break;
+      case 0x223:  ph1.black_col = data+base;          break;
+      case 0x224:  ph1.split_row = data;               break;
+      case 0x225:  ph1.black_row = data+base;          break;
       case 0x301:
        model[63] = 0;
        fread (model, 1, 63, ifp);
@@ -6018,12 +6774,16 @@ void CLASS parse_fuji (int offset)
     } else if (tag == 0x130) {
       fuji_layout = fgetc(ifp) >> 7;
       fuji_width = !(fgetc(ifp) & 8);
+    } else if (tag == 0x131) {
+      filters = 9;
+      FORC(36) xtrans_abs[0][35-c] = fgetc(ifp) & 3;
     } else if (tag == 0x2ff0) {
       FORC4 cam_mul[c ^ 1] = get2();
     } else if (tag == 0xc000) {
       c = order;
       order = 0x4949;
-      if ((width = get4()) > 10000) width = get4();
+      while ((tag = get4()) > raw_width);
+      width = tag;
       height = get4();
       order = c;
     }
@@ -6044,7 +6804,7 @@ int CLASS parse_jpeg (int offset)
     order = 0x4d4d;
     len   = get2() - 2;
     save  = ftell(ifp);
-    if (mark == 0xc0 || mark == 0xc3) {
+    if (mark == 0xc0 || mark == 0xc3 || mark == 0xc9) {
       fgetc(ifp);
       raw_height = get2();
       raw_width  = get2();
@@ -6052,7 +6812,7 @@ int CLASS parse_jpeg (int offset)
     order = get2();
     hlen  = get4();
     if (get4() == 0x48454150)          /* "HEAP" */
-      parse_ciff (save+hlen, len-hlen);
+      parse_ciff (save+hlen, len-hlen, 0);
     if (parse_tiff (save+6)) apply_tiff();
     fseek (ifp, save+len, SEEK_SET);
   }
@@ -6073,7 +6833,7 @@ void CLASS parse_riff()
   end = ftell(ifp) + size;
   if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) {
     get4();
-    while (ftell(ifp)+7 < end)
+    while (ftell(ifp)+7 < end && !feof(ifp))
       parse_riff();
   } else if (!memcmp(tag,"nctg",4)) {
     while (ftell(ifp)+7 < end) {
@@ -6099,6 +6859,26 @@ void CLASS parse_riff()
     fseek (ifp, size, SEEK_CUR);
 }
 
+void CLASS parse_qt (int end)
+{
+  unsigned save, size;
+  char tag[4];
+
+  order = 0x4d4d;
+  while (ftell(ifp)+7 < end) {
+    save = ftell(ifp);
+    if ((size = get4()) < 8) return;
+    fread (tag, 4, 1, ifp);
+    if (!memcmp(tag,"moov",4) ||
+       !memcmp(tag,"udta",4) ||
+       !memcmp(tag,"CNTH",4))
+      parse_qt (save+size);
+    if (!memcmp(tag,"CNDA",4))
+      parse_jpeg (ftell(ifp));
+    fseek (ifp, save+size, SEEK_SET);
+  }
+}
+
 void CLASS parse_smal (int offset, int fsize)
 {
   int ver;
@@ -6242,6 +7022,7 @@ void CLASS parse_foveon()
          raw_width  = wide;
          raw_height = high;
          data_offset = off+28;
+         is_foveon = 1;
        }
        fseek (ifp, off+28, SEEK_SET);
        if (fgetc(ifp) == 0xff && fgetc(ifp) == 0xd8
@@ -6267,7 +7048,7 @@ void CLASS parse_foveon()
        off += pent*8 + 24;
        if ((unsigned) pent > 256) pent=256;
        for (i=0; i < pent*2; i++)
-         poff[0][i] = off + get4()*2;
+         ((int *)poff)[i] = off + get4()*2;
        for (i=0; i < pent; i++) {
          foveon_gets (poff[i][0], name, 64);
          foveon_gets (poff[i][1], value, 64);
@@ -6294,7 +7075,6 @@ void CLASS parse_foveon()
     }
     fseek (ifp, save, SEEK_SET);
   }
-  is_foveon = 1;
 }
 
 /*
@@ -6306,7 +7086,7 @@ void CLASS adobe_coeff (const char *make, const char *model)
     const char *prefix;
     short black, maximum, trans[12];
   } table[] = {
-    { "AGFAPHOTO DC-833m", 0, 0,       /* DJC */
+    { "AgfaPhoto DC-833m", 0, 0,       /* DJC */
        { 11438,-3762,-1115,-2409,9914,2497,-1227,2295,5300 } },
     { "Apple QuickTake", 0, 0,         /* DJC */
        { 21392,-5653,-3353,2406,8010,-415,7166,1427,2078 } },
@@ -6318,6 +7098,8 @@ void CLASS adobe_coeff (const char *make, const char *model)
        { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } },
     { "Canon EOS D60", 0, 0xfa0,
        { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } },
+    { "Canon EOS 5DS", 0, 0x3c96,
+       { 6250,-711,-808,-5153,12794,2636,-1249,2198,5610 } },
     { "Canon EOS 5D Mark III", 0, 0x3c80,
        { 6722,-635,-963,-4287,12460,2028,-908,2162,5668 } },
     { "Canon EOS 5D Mark II", 0, 0x3cf0,
@@ -6326,6 +7108,8 @@ void CLASS adobe_coeff (const char *make, const char *model)
        { 6347,-479,-972,-8297,15954,2480,-1968,2131,7649 } },
     { "Canon EOS 6D", 0, 0x3c82,
        { 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 } },
+    { "Canon EOS 7D Mark II", 0, 0x3510,
+       { 7268,-1082,-969,-4186,11839,2663,-825,2029,5839 } },
     { "Canon EOS 7D", 0, 0x3510,
        { 6844,-996,-856,-3876,11761,2396,-593,1772,6198 } },
     { "Canon EOS 10D", 0, 0xfa0,
@@ -6342,6 +7126,12 @@ void CLASS adobe_coeff (const char *make, const char *model)
        { 4920,616,-593,-6493,13964,2784,-1774,3178,7005 } },
     { "Canon EOS 60D", 0, 0x2ff7,
        { 6719,-994,-925,-4408,12426,2211,-887,2129,6051 } },
+    { "Canon EOS 70D", 0, 0x3bc7,
+       { 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 } },
+    { "Canon EOS 80D", 0, 0,
+       { 7457,-671,-937,-4849,12495,2643,-1213,2354,5492 } },
+    { "Canon EOS 100D", 0, 0x350f,
+       { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } },
     { "Canon EOS 300D", 0, 0xfa0,
        { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
     { "Canon EOS 350D", 0, 0xfff,
@@ -6358,10 +7148,24 @@ void CLASS adobe_coeff (const char *make, const char *model)
        { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } },
     { "Canon EOS 650D", 0, 0x354d,
        { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } },
+    { "Canon EOS 700D", 0, 0x3c00,
+       { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } },
+    { "Canon EOS 750D", 0, 0x368e,
+       { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } },
+    { "Canon EOS 760D", 0, 0x350f,
+       { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } },
     { "Canon EOS 1000D", 0, 0xe43,
        { 6771,-1139,-977,-7818,15123,2928,-1244,1437,7533 } },
     { "Canon EOS 1100D", 0, 0x3510,
        { 6444,-904,-893,-4563,12308,2535,-903,2016,6728 } },
+    { "Canon EOS 1200D", 0, 0x37c2,
+       { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } },
+    { "Canon EOS 1300D", 0, 0x3510,
+       { 6939,-1016,-866,-4428,12473,2177,-1175,2178,6162 } },
+    { "Canon EOS M3", 0, 0,
+       { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } },
+    { "Canon EOS M10", 0, 0,
+       { 6400,-480,-888,-5294,13416,2047,-1296,2203,6137 } },
     { "Canon EOS M", 0, 0,
        { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } },
     { "Canon EOS-1Ds Mark III", 0, 0x3bb0,
@@ -6378,12 +7182,16 @@ void CLASS adobe_coeff (const char *make, const char *model)
        { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } },
     { "Canon EOS-1DS", 0, 0xe20,
        { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } },
+    { "Canon EOS-1D C", 0, 0x3c4e,
+       { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } },
+    { "Canon EOS-1D X Mark II", 0, 0,
+       { 7596,-978,-967,-4808,12571,2503,-1398,2567,5752 } },
     { "Canon EOS-1D X", 0, 0x3c4e,
        { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } },
     { "Canon EOS-1D", 0, 0xe20,
        { 6806,-179,-1020,-8097,16415,1687,-3267,4236,7690 } },
-    { "Canon EOS", 0, 0,
-       { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } },
+    { "Canon EOS C500", 853, 0,                /* DJC */
+       { 17851,-10604,922,-7425,16662,763,-3660,3636,22278 } },
     { "Canon PowerShot A530", 0, 0,
        { 0 } },        /* don't want the A5 matrix */
     { "Canon PowerShot A50", 0, 0,
@@ -6398,18 +7206,28 @@ void CLASS adobe_coeff (const char *make, const char *model)
        { 13244,-5501,-1248,-1508,9858,1935,-270,1083,4366 } },
     { "Canon PowerShot G15", 0, 0,
        { 7474,-2301,-567,-4056,11456,2975,-222,716,4181 } },
+    { "Canon PowerShot G16", 0, 0,
+       { 8020,-2687,-682,-3704,11879,2052,-965,1921,5556 } },
     { "Canon PowerShot G1 X", 0, 0,
        { 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 } },
     { "Canon PowerShot G1", 0, 0,
        { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } },
     { "Canon PowerShot G2", 0, 0,
        { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } },
+    { "Canon PowerShot G3 X", 0, 0,
+       { 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 } },
     { "Canon PowerShot G3", 0, 0,
        { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } },
+    { "Canon PowerShot G5 X", 0, 0,
+       { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } },
     { "Canon PowerShot G5", 0, 0,
        { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } },
     { "Canon PowerShot G6", 0, 0,
        { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } },
+    { "Canon PowerShot G7 X", 0, 0,
+       { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } },
+    { "Canon PowerShot G9 X", 0, 0,
+       { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } },
     { "Canon PowerShot G9", 0, 0,
        { 7368,-2141,-598,-5621,13254,2625,-1418,1696,5743 } },
     { "Canon PowerShot Pro1", 0, 0,
@@ -6438,10 +7256,16 @@ void CLASS adobe_coeff (const char *make, const char *model)
        { 7968,-2565,-636,-2873,10697,2513,180,667,4211 } },
     { "Canon PowerShot S110", 0, 0,
        { 8039,-2643,-654,-3783,11230,2930,-206,690,4194 } },
+    { "Canon PowerShot S120", 0, 0,
+       { 6961,-1685,-695,-4625,12945,1836,-1114,2152,5518 } },
     { "Canon PowerShot SX1 IS", 0, 0,
        { 6578,-259,-502,-5974,13030,3309,-308,1058,4970 } },
     { "Canon PowerShot SX50 HS", 0, 0,
        { 12432,-4753,-1247,-2110,10691,1629,-412,1623,4926 } },
+    { "Canon PowerShot SX60 HS", 0, 0,
+       { 13161,-5451,-1344,-1989,10654,1531,-47,1271,4955 } },
+    { "Canon PowerShot A3300", 0, 0,   /* DJC */
+       { 10826,-3654,-1023,-3215,11310,1906,0,999,4960 } },
     { "Canon PowerShot A470", 0, 0,    /* DJC */
        { 12513,-4407,-1242,-2680,10276,2405,-878,2215,4734 } },
     { "Canon PowerShot A610", 0, 0,    /* DJC */
@@ -6462,11 +7286,13 @@ void CLASS adobe_coeff (const char *make, const char *model)
        { 14134,-5576,-1527,-1991,10719,1273,-1158,1929,3581 } },
     { "Canon PowerShot SX220", 0, 0,   /* DJC */
        { 13898,-5076,-1447,-1405,10109,1297,-244,1860,3687 } },
-    { "CASIO EX-S20", 0, 0,            /* DJC */
+    { "Canon IXUS 160", 0, 0,          /* DJC */
+       { 11657,-3781,-1136,-3544,11262,2283,-160,1219,4700 } },
+    { "Casio EX-S20", 0, 0,            /* DJC */
        { 11634,-3924,-1128,-4968,12954,2015,-1588,2648,7206 } },
-    { "CASIO EX-Z750", 0, 0,           /* DJC */
+    { "Casio EX-Z750", 0, 0,           /* DJC */
        { 10819,-3873,-1099,-4903,13730,1175,-1755,3751,4632 } },
-    { "CASIO EX-Z10", 128, 0xfff,      /* DJC */
+    { "Casio EX-Z10", 128, 0xfff,      /* DJC */
        { 9790,-3338,-603,-2321,10222,2099,-344,1273,4799 } },
     { "CINE 650", 0, 0,
        { 3390,480,-500,-800,3610,340,-550,2336,1192 } },
@@ -6476,93 +7302,129 @@ void CLASS adobe_coeff (const char *make, const char *model)
        { 20183,-4295,-423,-3940,15330,3985,-280,4870,9800 } },
     { "Contax N Digital", 0, 0xf1e,
        { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } },
-    { "EPSON R-D1", 0, 0,
+    { "DXO ONE", 0, 0,
+       { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } },
+    { "Epson R-D1", 0, 0,
        { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } },
-    { "FUJIFILM E550", 0, 0,
+    { "Fujifilm E550", 0, 0,
        { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } },
-    { "FUJIFILM E900", 0, 0,
+    { "Fujifilm E900", 0, 0,
        { 9183,-2526,-1078,-7461,15071,2574,-2022,2440,8639 } },
-    { "FUJIFILM F5", 0, 0,
+    { "Fujifilm F5", 0, 0,
        { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } },
-    { "FUJIFILM F6", 0, 0,
+    { "Fujifilm F6", 0, 0,
        { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } },
-    { "FUJIFILM F77", 0, 0xfe9,
+    { "Fujifilm F77", 0, 0xfe9,
        { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } },
-    { "FUJIFILM F7", 0, 0,
+    { "Fujifilm F7", 0, 0,
        { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
-    { "FUJIFILM F8", 0, 0,
+    { "Fujifilm F8", 0, 0,
        { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } },
-    { "FUJIFILM S100FS", 514, 0,
+    { "Fujifilm S100FS", 514, 0,
        { 11521,-4355,-1065,-6524,13767,3058,-1466,1984,6045 } },
-    { "FUJIFILM S200EXR", 512, 0x3fff,
-       { 11401,-4498,-1312,-5088,12751,2613,-838,1568,5941 } },
-    { "FUJIFILM S20Pro", 0, 0,
+    { "Fujifilm S1", 0, 0,
+       { 12297,-4882,-1202,-2106,10691,1623,-88,1312,4790 } },
+    { "Fujifilm S20Pro", 0, 0,
        { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } },
-    { "FUJIFILM S2Pro", 128, 0,
+    { "Fujifilm S20", 512, 0x3fff,
+       { 11401,-4498,-1312,-5088,12751,2613,-838,1568,5941 } },
+    { "Fujifilm S2Pro", 128, 0,
        { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } },
-    { "FUJIFILM S3Pro", 0, 0,
+    { "Fujifilm S3Pro", 0, 0,
        { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } },
-    { "FUJIFILM S5Pro", 0, 0,
+    { "Fujifilm S5Pro", 0, 0,
        { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } },
-    { "FUJIFILM S5000", 0, 0,
+    { "Fujifilm S5000", 0, 0,
        { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } },
-    { "FUJIFILM S5100", 0, 0,
+    { "Fujifilm S5100", 0, 0,
        { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } },
-    { "FUJIFILM S5500", 0, 0,
+    { "Fujifilm S5500", 0, 0,
        { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } },
-    { "FUJIFILM S5200", 0, 0,
+    { "Fujifilm S5200", 0, 0,
        { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } },
-    { "FUJIFILM S5600", 0, 0,
+    { "Fujifilm S5600", 0, 0,
        { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } },
-    { "FUJIFILM S6", 0, 0,
+    { "Fujifilm S6", 0, 0,
        { 12628,-4887,-1401,-6861,14996,1962,-2198,2782,7091 } },
-    { "FUJIFILM S7000", 0, 0,
+    { "Fujifilm S7000", 0, 0,
        { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } },
-    { "FUJIFILM S9000", 0, 0,
+    { "Fujifilm S9000", 0, 0,
        { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } },
-    { "FUJIFILM S9500", 0, 0,
+    { "Fujifilm S9500", 0, 0,
        { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } },
-    { "FUJIFILM S9100", 0, 0,
+    { "Fujifilm S9100", 0, 0,
        { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } },
-    { "FUJIFILM S9600", 0, 0,
+    { "Fujifilm S9600", 0, 0,
        { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } },
-    { "FUJIFILM IS-1", 0, 0,
+    { "Fujifilm SL1000", 0, 0,
+       { 11705,-4262,-1107,-2282,10791,1709,-555,1713,4945 } },
+    { "Fujifilm IS-1", 0, 0,
        { 21461,-10807,-1441,-2332,10599,1999,289,875,7703 } },
-    { "FUJIFILM IS Pro", 0, 0,
+    { "Fujifilm IS Pro", 0, 0,
        { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } },
-    { "FUJIFILM HS10 HS11", 0, 0xf68,
+    { "Fujifilm HS10 HS11", 0, 0xf68,
        { 12440,-3954,-1183,-1123,9674,1708,-83,1614,4086 } },
-    { "FUJIFILM HS20EXR", 0, 0,
+    { "Fujifilm HS2", 0, 0,
        { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } },
-    { "FUJIFILM HS3", 0, 0,
+    { "Fujifilm HS3", 0, 0,
        { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } },
-    { "FUJIFILM X100", 0, 0,
+    { "Fujifilm HS50EXR", 0, 0,
+       { 12085,-4727,-953,-3257,11489,2002,-511,2046,4592 } },
+    { "Fujifilm F900EXR", 0, 0,
+       { 12085,-4727,-953,-3257,11489,2002,-511,2046,4592 } },
+    { "Fujifilm X100S", 0, 0,
+       { 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 } },
+    { "Fujifilm X100T", 0, 0,
+       { 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 } },
+    { "Fujifilm X100", 0, 0,
        { 12161,-4457,-1069,-5034,12874,2400,-795,1724,6904 } },
-    { "FUJIFILM X10", 0, 0,
+    { "Fujifilm X10", 0, 0,
        { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } },
-    { "FUJIFILM X-Pro1", 0, 0,
+    { "Fujifilm X20", 0, 0,
+       { 11768,-4971,-1133,-4904,12927,2183,-480,1723,4605 } },
+    { "Fujifilm X30", 0, 0,
+       { 12328,-5256,-1144,-4469,12927,1675,-87,1291,4351 } },
+    { "Fujifilm X70", 0, 0,
+       { 10450,-4329,-878,-3217,11105,2421,-752,1758,6519 } },
+    { "Fujifilm X-Pro1", 0, 0,
+       { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } },
+    { "Fujifilm X-Pro2", 0, 0,
+       { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } },
+    { "Fujifilm X-A1", 0, 0,
+       { 11086,-4555,-839,-3512,11310,2517,-815,1341,5940 } },
+    { "Fujifilm X-A2", 0, 0,
+       { 10763,-4560,-917,-3346,11311,2322,-475,1135,5843 } },
+    { "Fujifilm X-E1", 0, 0,
        { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } },
-    { "FUJIFILM X-E1", 0, 0,
+    { "Fujifilm X-E2S", 0, 0,
+       { 11562,-5118,-961,-3022,11007,2311,-525,1569,6097 } },
+    { "Fujifilm X-E2", 0, 0,
+       { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } },
+    { "Fujifilm X-M1", 0, 0,
        { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } },
-    { "FUJIFILM XF1", 0, 0,
+    { "Fujifilm X-S1", 0, 0,
        { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } },
-    { "FUJIFILM X-S1", 0, 0,
+    { "Fujifilm X-T1", 0, 0,   /* also X-T10 */
+       { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } },
+    { "Fujifilm XF1", 0, 0,
        { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } },
+    { "Fujifilm XQ", 0, 0,     /* XQ1 and XQ2 */
+       { 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 } },
     { "Imacon Ixpress", 0, 0,          /* DJC */
        { 7025,-1415,-704,-5188,13765,1424,-1248,2742,6038 } },
-    { "KODAK NC2000", 0, 0,
+    { "Kodak NC2000", 0, 0,
        { 13891,-6055,-803,-465,9919,642,2121,82,1291 } },
     { "Kodak DCS315C", 8, 0,
        { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } },
     { "Kodak DCS330C", 8, 0,
        { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } },
-    { "KODAK DCS420", 0, 0,
+    { "Kodak DCS420", 0, 0,
        { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } },
-    { "KODAK DCS460", 0, 0,
+    { "Kodak DCS460", 0, 0,
        { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
-    { "KODAK EOSDCS1", 0, 0,
+    { "Kodak EOSDCS1", 0, 0,
        { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } },
-    { "KODAK EOSDCS3B", 0, 0,
+    { "Kodak EOSDCS3B", 0, 0,
        { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } },
     { "Kodak DCS520C", 178, 0,
        { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } },
@@ -6588,19 +7450,19 @@ void CLASS adobe_coeff (const char *make, const char *model)
        { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } },
     { "Kodak ProBack", 0, 0,
        { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } },
-    { "KODAK P712", 0, 0,
+    { "Kodak P712", 0, 0,
        { 9658,-3314,-823,-5163,12695,2768,-1342,1843,6044 } },
-    { "KODAK P850", 0, 0xf7c,
+    { "Kodak P850", 0, 0xf7c,
        { 10511,-3836,-1102,-6946,14587,2558,-1481,1792,6246 } },
-    { "KODAK P880", 0, 0xfff,
+    { "Kodak P880", 0, 0xfff,
        { 12805,-4662,-1376,-7480,15267,2360,-1626,2194,7904 } },
-    { "KODAK EasyShare Z980", 0, 0,
+    { "Kodak EasyShare Z980", 0, 0,
        { 11313,-3559,-1101,-3893,11891,2257,-1214,2398,4908 } },
-    { "KODAK EasyShare Z981", 0, 0,
+    { "Kodak EasyShare Z981", 0, 0,
        { 12729,-4717,-1188,-1367,9187,2582,274,860,4411 } },
-    { "KODAK EasyShare Z990", 0, 0xfed,
+    { "Kodak EasyShare Z990", 0, 0xfed,
        { 11749,-4048,-1309,-1867,10572,1489,-138,1449,4522 } },
-    { "KODAK EASYSHARE Z1015", 0, 0xef1,
+    { "Kodak EASYSHARE Z1015", 0, 0xef1,
        { 11265,-4286,-992,-4694,12343,2647,-1090,1523,5447 } },
     { "Leaf CMost", 0, 0,
        { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } },
@@ -6626,287 +7488,397 @@ void CLASS adobe_coeff (const char *make, const char *model)
        { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } },
     { "Minolta DiMAGE A1", 0, 0xf8b,
        { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } },
-    { "MINOLTA DiMAGE A200", 0, 0,
+    { "Minolta DiMAGE A200", 0, 0,
        { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } },
     { "Minolta DiMAGE A2", 0, 0xf8f,
        { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } },
     { "Minolta DiMAGE Z2", 0, 0,       /* DJC */
        { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } },
-    { "MINOLTA DYNAX 5", 0, 0xffb,
+    { "Minolta DYNAX 5", 0, 0xffb,
        { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } },
-    { "MINOLTA DYNAX 7", 0, 0xffb,
+    { "Minolta DYNAX 7", 0, 0xffb,
        { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } },
-    { "MOTOROLA PIXL", 0, 0,           /* DJC */
+    { "Motorola PIXL", 0, 0,           /* DJC */
        { 8898,-989,-1033,-3292,11619,1674,-661,3178,5216 } },
-    { "NIKON D100", 0, 0,
+    { "Nikon D100", 0, 0,
        { 5902,-933,-782,-8983,16719,2354,-1402,1455,6464 } },
-    { "NIKON D1H", 0, 0,
+    { "Nikon D1H", 0, 0,
        { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } },
-    { "NIKON D1X", 0, 0,
+    { "Nikon D1X", 0, 0,
        { 7702,-2245,-975,-9114,17242,1875,-2679,3055,8521 } },
-    { "NIKON D1", 0, 0, /* multiplied by 2.218750, 1.0, 1.148438 */
+    { "Nikon D1", 0, 0, /* multiplied by 2.218750, 1.0, 1.148438 */
        { 16772,-4726,-2141,-7611,15713,1972,-2846,3494,9521 } },
-    { "NIKON D200", 0, 0xfbc,
+    { "Nikon D200", 0, 0xfbc,
        { 8367,-2248,-763,-8758,16447,2422,-1527,1550,8053 } },
-    { "NIKON D2H", 0, 0,
+    { "Nikon D2H", 0, 0,
        { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } },
-    { "NIKON D2X", 0, 0,
+    { "Nikon D2X", 0, 0,
        { 10231,-2769,-1255,-8301,15900,2552,-797,680,7148 } },
-    { "NIKON D3000", 0, 0,
+    { "Nikon D3000", 0, 0,
        { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } },
-    { "NIKON D3100", 0, 0,
+    { "Nikon D3100", 0, 0,
        { 7911,-2167,-813,-5327,13150,2408,-1288,2483,7968 } },
-    { "NIKON D3200", 0, 0xfb9,
+    { "Nikon D3200", 0, 0xfb9,
        { 7013,-1408,-635,-5268,12902,2640,-1470,2801,7379 } },
-    { "NIKON D300", 0, 0,
+    { "Nikon D3300", 0, 0,
+       { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } },
+    { "Nikon D300", 0, 0,
        { 9030,-1992,-715,-8465,16302,2255,-2689,3217,8069 } },
-    { "NIKON D3X", 0, 0,
+    { "Nikon D3X", 0, 0,
        { 7171,-1986,-648,-8085,15555,2718,-2170,2512,7457 } },
-    { "NIKON D3S", 0, 0,
+    { "Nikon D3S", 0, 0,
        { 8828,-2406,-694,-4874,12603,2541,-660,1509,7587 } },
-    { "NIKON D3", 0, 0,
+    { "Nikon D3", 0, 0,
        { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } },
-    { "NIKON D40X", 0, 0,
+    { "Nikon D40X", 0, 0,
        { 8819,-2543,-911,-9025,16928,2151,-1329,1213,8449 } },
-    { "NIKON D40", 0, 0,
+    { "Nikon D40", 0, 0,
        { 6992,-1668,-806,-8138,15748,2543,-874,850,7897 } },
-    { "NIKON D4", 0, 0,
+    { "Nikon D4S", 0, 0,
+       { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } },
+    { "Nikon D4", 0, 0,
        { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } },
-    { "NIKON D5000", 0, 0xf00,
+    { "Nikon Df", 0, 0,
+       { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } },
+    { "Nikon D5000", 0, 0xf00,
        { 7309,-1403,-519,-8474,16008,2622,-2433,2826,8064 } },
-    { "NIKON D5100", 0, 0x3de6,
+    { "Nikon D5100", 0, 0x3de6,
        { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } },
-    { "NIKON D50", 0, 0,
+    { "Nikon D5200", 0, 0,
+       { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } },
+    { "Nikon D5300", 0, 0,
+       { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } },
+    { "Nikon D5500", 0, 0,
+       { 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 } },
+    { "Nikon D500", 0, 0,
+       { 8813,-3210,-1036,-4703,12868,2021,-1054,1940,6129 } },
+    { "Nikon D50", 0, 0,
        { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } },
-    { "NIKON D600", 0, 0x3e07,
+    { "Nikon D5", 0, 0,
+       { 9200,-3522,-992,-5755,13803,2117,-753,1486,6338 } },
+    { "Nikon D600", 0, 0x3e07,
+       { 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 } },
+    { "Nikon D610", 0, 0,
        { 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 } },
-    { "NIKON D60", 0, 0,
+    { "Nikon D60", 0, 0,
        { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } },
-    { "NIKON D7000", 0, 0,
+    { "Nikon D7000", 0, 0,
        { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } },
-    { "NIKON D700", 0, 0,
+    { "Nikon D7100", 0, 0,
+       { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } },
+    { "Nikon D7200", 0, 0,
+       { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } },
+    { "Nikon D750", 0, 0,
+       { 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 } },
+    { "Nikon D700", 0, 0,
        { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } },
-    { "NIKON D70", 0, 0,
+    { "Nikon D70", 0, 0,
        { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } },
-    { "NIKON D800", 0, 0,
+    { "Nikon D810", 0, 0,
+       { 9369,-3195,-791,-4488,12430,2301,-893,1796,6872 } },
+    { "Nikon D800", 0, 0,
        { 7866,-2108,-555,-4869,12483,2681,-1176,2069,7501 } },
-    { "NIKON D80", 0, 0,
+    { "Nikon D80", 0, 0,
        { 8629,-2410,-883,-9055,16940,2171,-1490,1363,8520 } },
-    { "NIKON D90", 0, 0xf00,
+    { "Nikon D90", 0, 0xf00,
        { 7309,-1403,-519,-8474,16008,2622,-2434,2826,8064 } },
-    { "NIKON E950", 0, 0x3dd,          /* DJC */
+    { "Nikon E700", 0, 0x3dd,          /* DJC */
+       { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } },
+    { "Nikon E800", 0, 0x3dd,          /* DJC */
        { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } },
-    { "NIKON E995", 0, 0,      /* copied from E5000 */
+    { "Nikon E950", 0, 0x3dd,          /* DJC */
+       { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } },
+    { "Nikon E995", 0, 0,      /* copied from E5000 */
        { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
-    { "NIKON E2100", 0, 0,     /* copied from Z2, new white balance */
+    { "Nikon E2100", 0, 0,     /* copied from Z2, new white balance */
        { 13142,-4152,-1596,-4655,12374,2282,-1769,2696,6711} },
-    { "NIKON E2500", 0, 0,
+    { "Nikon E2500", 0, 0,
        { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
-    { "NIKON E3200", 0, 0,             /* DJC */
+    { "Nikon E3200", 0, 0,             /* DJC */
        { 9846,-2085,-1019,-3278,11109,2170,-774,2134,5745 } },
-    { "NIKON E4300", 0, 0,     /* copied from Minolta DiMAGE Z2 */
+    { "Nikon E4300", 0, 0,     /* copied from Minolta DiMAGE Z2 */
        { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } },
-    { "NIKON E4500", 0, 0,
+    { "Nikon E4500", 0, 0,
        { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
-    { "NIKON E5000", 0, 0,
+    { "Nikon E5000", 0, 0,
        { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } },
-    { "NIKON E5400", 0, 0,
+    { "Nikon E5400", 0, 0,
        { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } },
-    { "NIKON E5700", 0, 0,
+    { "Nikon E5700", 0, 0,
        { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } },
-    { "NIKON E8400", 0, 0,
+    { "Nikon E8400", 0, 0,
        { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } },
-    { "NIKON E8700", 0, 0,
+    { "Nikon E8700", 0, 0,
        { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } },
-    { "NIKON E8800", 0, 0,
+    { "Nikon E8800", 0, 0,
        { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } },
-    { "NIKON COOLPIX P6000", 0, 0,
+    { "Nikon COOLPIX A", 0, 0,
+       { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } },
+    { "Nikon COOLPIX P330", 200, 0,
+       { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } },
+    { "Nikon COOLPIX P340", 200, 0,
+       { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } },
+    { "Nikon COOLPIX P6000", 0, 0,
        { 9698,-3367,-914,-4706,12584,2368,-837,968,5801 } },
-    { "NIKON COOLPIX P7000", 0, 0,
+    { "Nikon COOLPIX P7000", 0, 0,
        { 11432,-3679,-1111,-3169,11239,2202,-791,1380,4455 } },
-    { "NIKON COOLPIX P7100", 0, 0,
+    { "Nikon COOLPIX P7100", 0, 0,
        { 11053,-4269,-1024,-1976,10182,2088,-526,1263,4469 } },
-    { "NIKON COOLPIX P7700", 200, 0,
+    { "Nikon COOLPIX P7700", 200, 0,
+       { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } },
+    { "Nikon COOLPIX P7800", 200, 0,
        { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } },
-    { "NIKON 1 V2", 0, 0,
+    { "Nikon 1 V3", 0, 0,
+       { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } },
+    { "Nikon 1 J4", 0, 0,
+       { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } },
+    { "Nikon 1 J5", 0, 0,
+       { 7520,-2518,-645,-3844,12102,1945,-913,2249,6835 } },
+    { "Nikon 1 S2", 200, 0,
+       { 6612,-1342,-618,-3338,11055,2623,-174,1792,5075 } },
+    { "Nikon 1 V2", 0, 0,
+       { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } },
+    { "Nikon 1 J3", 0, 0,
        { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } },
-    { "NIKON 1 ", 0, 0,
+    { "Nikon 1 AW1", 0, 0,
+       { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } },
+    { "Nikon 1 ", 0, 0,                /* J1, J2, S1, V1 */
        { 8994,-2667,-865,-4594,12324,2552,-699,1786,6260 } },
-    { "OLYMPUS C5050", 0, 0,
+    { "Olympus AIR A01", 0, 0,
+       { 8992,-3093,-639,-2563,10721,2122,-437,1270,5473 } },
+    { "Olympus C5050", 0, 0,
        { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } },
-    { "OLYMPUS C5060", 0, 0,
+    { "Olympus C5060", 0, 0,
        { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } },
-    { "OLYMPUS C7070", 0, 0,
+    { "Olympus C7070", 0, 0,
        { 10252,-3531,-1095,-7114,14850,2436,-1451,1723,6365 } },
-    { "OLYMPUS C70", 0, 0,
+    { "Olympus C70", 0, 0,
        { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } },
-    { "OLYMPUS C80", 0, 0,
+    { "Olympus C80", 0, 0,
        { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } },
-    { "OLYMPUS E-10", 0, 0xffc,
+    { "Olympus E-10", 0, 0xffc,
        { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } },
-    { "OLYMPUS E-1", 0, 0,
+    { "Olympus E-1", 0, 0,
        { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } },
-    { "OLYMPUS E-20", 0, 0xffc,
+    { "Olympus E-20", 0, 0xffc,
        { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } },
-    { "OLYMPUS E-300", 0, 0,
+    { "Olympus E-300", 0, 0,
        { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } },
-    { "OLYMPUS E-330", 0, 0,
+    { "Olympus E-330", 0, 0,
        { 8961,-2473,-1084,-7979,15990,2067,-2319,3035,8249 } },
-    { "OLYMPUS E-30", 0, 0xfbc,
+    { "Olympus E-30", 0, 0xfbc,
        { 8144,-1861,-1111,-7763,15894,1929,-1865,2542,7607 } },
-    { "OLYMPUS E-3", 0, 0xf99,
+    { "Olympus E-3", 0, 0xf99,
        { 9487,-2875,-1115,-7533,15606,2010,-1618,2100,7389 } },
-    { "OLYMPUS E-400", 0, 0,
+    { "Olympus E-400", 0, 0,
        { 6169,-1483,-21,-7107,14761,2536,-2904,3580,8568 } },
-    { "OLYMPUS E-410", 0, 0xf6a,
+    { "Olympus E-410", 0, 0xf6a,
        { 8856,-2582,-1026,-7761,15766,2082,-2009,2575,7469 } },
-    { "OLYMPUS E-420", 0, 0xfd7,
+    { "Olympus E-420", 0, 0xfd7,
        { 8746,-2425,-1095,-7594,15612,2073,-1780,2309,7416 } },
-    { "OLYMPUS E-450", 0, 0xfd2,
+    { "Olympus E-450", 0, 0xfd2,
        { 8745,-2425,-1095,-7594,15613,2073,-1780,2309,7416 } },
-    { "OLYMPUS E-500", 0, 0,
+    { "Olympus E-500", 0, 0,
        { 8136,-1968,-299,-5481,13742,1871,-2556,4205,6630 } },
-    { "OLYMPUS E-510", 0, 0xf6a,
+    { "Olympus E-510", 0, 0xf6a,
        { 8785,-2529,-1033,-7639,15624,2112,-1783,2300,7817 } },
-    { "OLYMPUS E-520", 0, 0xfd2,
+    { "Olympus E-520", 0, 0xfd2,
        { 8344,-2322,-1020,-7596,15635,2048,-1748,2269,7287 } },
-    { "OLYMPUS E-5", 0, 0xeec,
+    { "Olympus E-5", 0, 0xeec,
        { 11200,-3783,-1325,-4576,12593,2206,-695,1742,7504 } },
-    { "OLYMPUS E-600", 0, 0xfaf,
+    { "Olympus E-600", 0, 0xfaf,
        { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } },
-    { "OLYMPUS E-620", 0, 0xfaf,
+    { "Olympus E-620", 0, 0xfaf,
        { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } },
-    { "OLYMPUS E-P1", 0, 0xffd,
+    { "Olympus E-P1", 0, 0xffd,
        { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } },
-    { "OLYMPUS E-P2", 0, 0xffd,
+    { "Olympus E-P2", 0, 0xffd,
        { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } },
-    { "OLYMPUS E-P3", 0, 0,
+    { "Olympus E-P3", 0, 0,
        { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } },
-    { "OLYMPUS E-PL1s", 0, 0,
+    { "Olympus E-P5", 0, 0,
+       { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } },
+    { "Olympus E-PL1s", 0, 0,
        { 11409,-3872,-1393,-4572,12757,2003,-709,1810,7415 } },
-    { "OLYMPUS E-PL1", 0, 0,
+    { "Olympus E-PL1", 0, 0,
        { 11408,-4289,-1215,-4286,12385,2118,-387,1467,7787 } },
-    { "OLYMPUS E-PL2", 0, 0,
+    { "Olympus E-PL2", 0, 0xcf3,
        { 15030,-5552,-1806,-3987,12387,1767,-592,1670,7023 } },
-    { "OLYMPUS E-PL3", 0, 0,
+    { "Olympus E-PL3", 0, 0,
        { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } },
-    { "OLYMPUS E-PL5", 0, 0xfcb,
+    { "Olympus E-PL5", 0, 0xfcb,
+       { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } },
+    { "Olympus E-PL6", 0, 0,
        { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } },
-    { "OLYMPUS E-PM1", 0, 0,
+    { "Olympus E-PL7", 0, 0,
+       { 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 } },
+    { "Olympus E-PM1", 0, 0,
        { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } },
-    { "OLYMPUS E-PM2", 0, 0,
+    { "Olympus E-PM2", 0, 0,
        { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } },
-    { "OLYMPUS E-M5", 0, 0xfe1,
+    { "Olympus E-M10", 0, 0,   /* also E-M10 Mark II */
        { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } },
-    { "OLYMPUS SP350", 0, 0,
+    { "Olympus E-M1", 0, 0,
+       { 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 } },
+    { "Olympus E-M5MarkII", 0, 0,
+       { 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 } },
+    { "Olympus E-M5", 0, 0xfe1,
+       { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } },
+    { "Olympus PEN-F", 0, 0,
+       { 9476,-3182,-765,-2613,10958,1893,-449,1315,5268 } },
+    { "Olympus SH-2", 0, 0,
+       { 10156,-3425,-1077,-2611,11177,1624,-385,1592,5080 } },
+    { "Olympus SP350", 0, 0,
        { 12078,-4836,-1069,-6671,14306,2578,-786,939,7418 } },
-    { "OLYMPUS SP3", 0, 0,
+    { "Olympus SP3", 0, 0,
        { 11766,-4445,-1067,-6901,14421,2707,-1029,1217,7572 } },
-    { "OLYMPUS SP500UZ", 0, 0xfff,
+    { "Olympus SP500UZ", 0, 0xfff,
        { 9493,-3415,-666,-5211,12334,3260,-1548,2262,6482 } },
-    { "OLYMPUS SP510UZ", 0, 0xffe,
+    { "Olympus SP510UZ", 0, 0xffe,
        { 10593,-3607,-1010,-5881,13127,3084,-1200,1805,6721 } },
-    { "OLYMPUS SP550UZ", 0, 0xffe,
+    { "Olympus SP550UZ", 0, 0xffe,
        { 11597,-4006,-1049,-5432,12799,2957,-1029,1750,6516 } },
-    { "OLYMPUS SP560UZ", 0, 0xff9,
+    { "Olympus SP560UZ", 0, 0xff9,
        { 10915,-3677,-982,-5587,12986,2911,-1168,1968,6223 } },
-    { "OLYMPUS SP570UZ", 0, 0,
+    { "Olympus SP570UZ", 0, 0,
        { 11522,-4044,-1146,-4736,12172,2904,-988,1829,6039 } },
-    { "OLYMPUS XZ-1", 0, 0,
+    { "Olympus STYLUS1", 0, 0,
+       { 8360,-2420,-880,-3928,12353,1739,-1381,2416,5173 } },
+    { "Olympus TG-4", 0, 0,
+       { 11426,-4159,-1126,-2066,10678,1593,-120,1327,4998 } },
+    { "Olympus XZ-10", 0, 0,
+       { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } },
+    { "Olympus XZ-1", 0, 0,
        { 10901,-4095,-1074,-1141,9208,2293,-62,1417,5158 } },
-    { "OLYMPUS XZ-2", 0, 0,
+    { "Olympus XZ-2", 0, 0,
        { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } },
-    { "PENTAX *ist DL2", 0, 0,
+    { "OmniVision", 0, 0,              /* DJC */
+       { 12782,-4059,-379,-478,9066,1413,1340,1513,5176 } },
+    { "Pentax *ist DL2", 0, 0,
        { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } },
-    { "PENTAX *ist DL", 0, 0,
+    { "Pentax *ist DL", 0, 0,
        { 10829,-2838,-1115,-8339,15817,2696,-837,680,11939 } },
-    { "PENTAX *ist DS2", 0, 0,
+    { "Pentax *ist DS2", 0, 0,
        { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } },
-    { "PENTAX *ist DS", 0, 0,
+    { "Pentax *ist DS", 0, 0,
        { 10371,-2333,-1206,-8688,16231,2602,-1230,1116,11282 } },
-    { "PENTAX *ist D", 0, 0,
+    { "Pentax *ist D", 0, 0,
        { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } },
-    { "PENTAX K10D", 0, 0,
+    { "Pentax K10D", 0, 0,
        { 9566,-2863,-803,-7170,15172,2112,-818,803,9705 } },
-    { "PENTAX K1", 0, 0,
+    { "Pentax K1", 0, 0,
        { 11095,-3157,-1324,-8377,15834,2720,-1108,947,11688 } },
-    { "PENTAX K20D", 0, 0,
+    { "Pentax K20D", 0, 0,
        { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } },
-    { "PENTAX K200D", 0, 0,
+    { "Pentax K200D", 0, 0,
        { 9186,-2678,-907,-8693,16517,2260,-1129,1094,8524 } },
-    { "PENTAX K2000", 0, 0,
+    { "Pentax K2000", 0, 0,
        { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } },
-    { "PENTAX K-m", 0, 0,
+    { "Pentax K-m", 0, 0,
        { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } },
-    { "PENTAX K-x", 0, 0,
+    { "Pentax K-x", 0, 0,
        { 8843,-2837,-625,-5025,12644,2668,-411,1234,7410 } },
-    { "PENTAX K-r", 0, 0,
+    { "Pentax K-r", 0, 0,
        { 9895,-3077,-850,-5304,13035,2521,-883,1768,6936 } },
-    { "PENTAX K-5 II", 0, 0,
+    { "Pentax K-1", 0, 0,
+       { 8566,-2746,-1201,-3612,12204,1550,-893,1680,6264 } },
+    { "Pentax K-30", 0, 0,
+       { 8710,-2632,-1167,-3995,12301,1881,-981,1719,6535 } },
+    { "Pentax K-3 II", 0, 0,
+       { 8626,-2607,-1155,-3995,12301,1881,-1039,1822,6925 } },
+    { "Pentax K-3", 0, 0,
+       { 7415,-2052,-721,-5186,12788,2682,-1446,2157,6773 } },
+    { "Pentax K-5 II", 0, 0,
        { 8170,-2725,-639,-4440,12017,2744,-771,1465,6599 } },
-    { "PENTAX K-5", 0, 0,
+    { "Pentax K-5", 0, 0,
        { 8713,-2833,-743,-4342,11900,2772,-722,1543,6247 } },
-    { "PENTAX K-7", 0, 0,
+    { "Pentax K-7", 0, 0,
        { 9142,-2947,-678,-8648,16967,1663,-2224,2898,8615 } },
-    { "PENTAX 645D", 0, 0x3e00,
+    { "Pentax K-S1", 0, 0,
+       { 8512,-3211,-787,-4167,11966,2487,-638,1288,6054 } },
+    { "Pentax K-S2", 0, 0,
+       { 8662,-3280,-798,-3928,11771,2444,-586,1232,6054 } },
+    { "Pentax Q-S1", 0, 0,
+       { 12995,-5593,-1107,-1879,10139,2027,-64,1233,4919 } },
+    { "Pentax 645D", 0, 0x3e00,
        { 10646,-3593,-1158,-3329,11699,1831,-667,2874,6287 } },
+    { "Panasonic DMC-CM1", 15, 0,
+       { 8770,-3194,-820,-2871,11281,1803,-513,1552,4434 } },
     { "Panasonic DMC-FZ8", 0, 0xf7f,
        { 8986,-2755,-802,-6341,13575,3077,-1476,2144,6379 } },
     { "Panasonic DMC-FZ18", 0, 0,
        { 9932,-3060,-935,-5809,13331,2753,-1267,2155,5575 } },
     { "Panasonic DMC-FZ28", 15, 0xf96,
        { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } },
+    { "Panasonic DMC-FZ330", 15, 0,
+       { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } },
+    { "Panasonic DMC-FZ300", 15, 0,
+       { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } },
     { "Panasonic DMC-FZ30", 0, 0xf94,
        { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } },
-    { "Panasonic DMC-FZ3", 143, 0,
+    { "Panasonic DMC-FZ3", 15, 0,
        { 9938,-2780,-890,-4604,12393,2480,-1117,2304,4620 } },
-    { "Panasonic DMC-FZ4", 143, 0,
+    { "Panasonic DMC-FZ4", 15, 0,
        { 13639,-5535,-1371,-1698,9633,2430,316,1152,4108 } },
     { "Panasonic DMC-FZ50", 0, 0,
        { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } },
-    { "LEICA V-LUX1", 0, 0,
+    { "Panasonic DMC-FZ7", 15, 0,
+       { 11532,-4324,-1066,-2375,10847,1749,-564,1699,4351 } },
+    { "Leica V-LUX1", 0, 0,
        { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } },
     { "Panasonic DMC-L10", 15, 0xf96,
        { 8025,-1942,-1050,-7920,15904,2100,-2456,3005,7039 } },
     { "Panasonic DMC-L1", 0, 0xf7f,
        { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } },
-    { "LEICA DIGILUX 3", 0, 0xf7f,
+    { "Leica DIGILUX 3", 0, 0xf7f,
        { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } },
     { "Panasonic DMC-LC1", 0, 0,
        { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } },
-    { "LEICA DIGILUX 2", 0, 0,
+    { "Leica DIGILUX 2", 0, 0,
        { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } },
+    { "Panasonic DMC-LX100", 15, 0,
+       { 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 } },
+    { "Leica D-LUX (Typ 109)", 15, 0,
+       { 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 } },
+    { "Panasonic DMC-LF1", 15, 0,
+       { 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 } },
+    { "Leica C (Typ 112)", 15, 0,
+       { 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 } },
     { "Panasonic DMC-LX1", 0, 0xf7f,
        { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } },
-    { "LEICA D-LUX2", 0, 0xf7f,
+    { "Leica D-LUX2", 0, 0xf7f,
        { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } },
     { "Panasonic DMC-LX2", 0, 0,
        { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } },
-    { "LEICA D-LUX3", 0, 0,
+    { "Leica D-LUX3", 0, 0,
        { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } },
     { "Panasonic DMC-LX3", 15, 0,
        { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } },
-    { "LEICA D-LUX 4", 15, 0,
+    { "Leica D-LUX 4", 15, 0,
        { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } },
-    { "Panasonic DMC-LX5", 143, 0,
+    { "Panasonic DMC-LX5", 15, 0,
        { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } },
-    { "LEICA D-LUX 5", 143, 0,
+    { "Leica D-LUX 5", 15, 0,
        { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } },
-    { "Panasonic DMC-LX7", 143, 0,
+    { "Panasonic DMC-LX7", 15, 0,
        { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } },
-    { "LEICA D-LUX 6", 143, 0,
+    { "Leica D-LUX 6", 15, 0,
        { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } },
-    { "Panasonic DMC-FZ100", 143, 0xfff,
+    { "Panasonic DMC-FZ1000", 15, 0,
+       { 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 } },
+    { "Leica V-LUX (Typ 114)", 15, 0,
+       { 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 } },
+    { "Panasonic DMC-FZ100", 15, 0xfff,
        { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } },
-    { "LEICA V-LUX 2", 143, 0xfff,
+    { "Leica V-LUX 2", 15, 0xfff,
        { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } },
-    { "Panasonic DMC-FZ150", 143, 0xfff,
+    { "Panasonic DMC-FZ150", 15, 0xfff,
        { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } },
-    { "LEICA V-LUX 3", 143, 0xfff,
+    { "Leica V-LUX 3", 15, 0xfff,
        { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } },
-    { "Panasonic DMC-FZ200", 143, 0xfff,
+    { "Panasonic DMC-FZ200", 15, 0xfff,
        { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } },
-    { "LEICA V-LUX 4", 143, 0xfff,
+    { "Leica V-LUX 4", 15, 0xfff,
        { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } },
     { "Panasonic DMC-FX150", 15, 0xfff,
        { 9082,-2907,-925,-6119,13377,3058,-1797,2641,5609 } },
@@ -6916,26 +7888,72 @@ void CLASS adobe_coeff (const char *make, const char *model)
        { 8199,-2065,-1056,-8124,16156,2033,-2458,3022,7220 } },
     { "Panasonic DMC-G2", 15, 0xf3c,
        { 10113,-3400,-1114,-4765,12683,2317,-377,1437,6710 } },
-    { "Panasonic DMC-G3", 143, 0xfff,
+    { "Panasonic DMC-G3", 15, 0xfff,
        { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } },
-    { "Panasonic DMC-G5", 143, 0xfff,
+    { "Panasonic DMC-G5", 15, 0xfff,
        { 7798,-2562,-740,-3879,11584,2613,-1055,2248,5434 } },
+    { "Panasonic DMC-G6", 15, 0xfff,
+       { 8294,-2891,-651,-3869,11590,2595,-1183,2267,5352 } },
+    { "Panasonic DMC-G7", 15, 0xfff,
+       { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } },
     { "Panasonic DMC-GF1", 15, 0xf92,
        { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } },
-    { "Panasonic DMC-GF2", 143, 0xfff,
+    { "Panasonic DMC-GF2", 15, 0xfff,
        { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } },
-    { "Panasonic DMC-GF3", 143, 0xfff,
+    { "Panasonic DMC-GF3", 15, 0xfff,
        { 9051,-2468,-1204,-5212,13276,2121,-1197,2510,6890 } },
-    { "Panasonic DMC-GF5", 143, 0xfff,
+    { "Panasonic DMC-GF5", 15, 0xfff,
        { 8228,-2945,-660,-3938,11792,2430,-1094,2278,5793 } },
+    { "Panasonic DMC-GF6", 15, 0,
+       { 8130,-2801,-946,-3520,11289,2552,-1314,2511,5791 } },
+    { "Panasonic DMC-GF7", 15, 0,
+       { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } },
+    { "Panasonic DMC-GF8", 15, 0,
+       { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } },
     { "Panasonic DMC-GH1", 15, 0xf92,
        { 6299,-1466,-532,-6535,13852,2969,-2331,3112,5984 } },
     { "Panasonic DMC-GH2", 15, 0xf95,
        { 7780,-2410,-806,-3913,11724,2484,-1018,2390,5298 } },
-    { "Panasonic DMC-GH3", 144, 0,
+    { "Panasonic DMC-GH3", 15, 0,
        { 6559,-1752,-491,-3672,11407,2586,-962,1875,5130 } },
-    { "Panasonic DMC-GX1", 143, 0,
+    { "Panasonic DMC-GH4", 15, 0,
+       { 7122,-2108,-512,-3155,11201,2231,-541,1423,5045 } },
+    { "Panasonic DMC-GM1", 15, 0,
+       { 6770,-1895,-744,-5232,13145,2303,-1664,2691,5703 } },
+    { "Panasonic DMC-GM5", 15, 0,
+       { 8238,-3244,-679,-3921,11814,2384,-836,2022,5852 } },
+    { "Panasonic DMC-GX1", 15, 0,
        { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } },
+    { "Panasonic DMC-GX7", 15, 0,
+       { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } },
+    { "Panasonic DMC-GX8", 15, 0,
+       { 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 } },
+    { "Panasonic DMC-TZ1", 15, 0,
+       { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } },
+    { "Panasonic DMC-ZS1", 15, 0,
+       { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } },
+    { "Panasonic DMC-TZ6", 15, 0,
+       { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } },
+    { "Panasonic DMC-ZS4", 15, 0,
+       { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } },
+    { "Panasonic DMC-TZ7", 15, 0,
+       { 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 } },
+    { "Panasonic DMC-ZS5", 15, 0,
+       { 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 } },
+    { "Panasonic DMC-TZ8", 15, 0,
+       { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } },
+    { "Panasonic DMC-ZS6", 15, 0,
+       { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } },
+    { "Leica S (Typ 007)", 0, 0,
+       { 6063,-2234,-231,-5210,13787,1500,-1043,2866,6997 } },
+    { "Leica X", 0, 0,         /* X and X-U, both (Typ 113) */
+       { 7712,-2059,-653,-3882,11494,2726,-710,1332,5958 } },
+    { "Leica Q (Typ 116)", 0, 0,
+       { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830 } },
+    { "Leica M (Typ 262)", 0, 0,
+       { 6653,-1486,-611,-4221,13303,929,-881,2416,7226 } },
+    { "Leica SL (Typ 601)", 0, 0,
+       { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830} },
     { "Phase One H 20", 0, 0,          /* DJC */
        { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } },
     { "Phase One H 25", 0, 0,
@@ -6950,97 +7968,159 @@ void CLASS adobe_coeff (const char *make, const char *model)
        { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } },
     { "Phase One P65", 0, 0,
        { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } },
-    { "RED ONE", 704, 0xffff,          /* DJC */
+    { "Photron BC2-HD", 0, 0,          /* DJC */
+       { 14603,-4122,-528,-1810,9794,2017,-297,2763,5936 } },
+    { "Red One", 704, 0xffff,          /* DJC */
        { 21014,-7891,-2613,-3056,12201,856,-2203,5125,8042 } },
-    { "SAMSUNG EX1", 0, 0x3e00,
+    { "Ricoh GR II", 0, 0,
+       { 4630,-834,-423,-4977,12805,2417,-638,1467,6115 } },
+    { "Ricoh GR", 0, 0,
+       { 3708,-543,-160,-5381,12254,3556,-1471,1929,8234 } },
+    { "Samsung EX1", 0, 0x3e00,
        { 8898,-2498,-994,-3144,11328,2066,-760,1381,4576 } },
-    { "SAMSUNG EX2F", 0, 0x7ff,
+    { "Samsung EX2F", 0, 0x7ff,
        { 10648,-3897,-1055,-2022,10573,1668,-492,1611,4742 } },
-    { "SAMSUNG NX2", 0, 0xfff, /* NX20, NX200, NX210 */
+    { "Samsung EK-GN120", 0, 0,
+       { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } },
+    { "Samsung NX mini", 0, 0,
+       { 5222,-1196,-550,-6540,14649,2009,-1666,2819,5657 } },
+    { "Samsung NX3300", 0, 0,
+       { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } },
+    { "Samsung NX3000", 0, 0,
+       { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } },
+    { "Samsung NX30", 0, 0,    /* NX30, NX300, NX300M */
+       { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } },
+    { "Samsung NX2000", 0, 0,
+       { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } },
+    { "Samsung NX2", 0, 0xfff, /* NX20, NX200, NX210 */
        { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } },
-    { "SAMSUNG NX1000", 0, 0,
+    { "Samsung NX1000", 0, 0,
        { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } },
-    { "SAMSUNG NX", 0, 0,      /* NX5, NX10, NX11, NX100 */
+    { "Samsung NX1100", 0, 0,
+       { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } },
+    { "Samsung NX11", 0, 0,
+       { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } },
+    { "Samsung NX10", 0, 0,    /* also NX100 */
+       { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } },
+    { "Samsung NX500", 0, 0,
+       { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } },
+    { "Samsung NX5", 0, 0,
        { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } },
-    { "SAMSUNG WB2000", 0, 0xfff,
+    { "Samsung NX1", 0, 0,
+       { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } },
+    { "Samsung WB2000", 0, 0xfff,
        { 12093,-3557,-1155,-1000,9534,1733,-22,1787,4576 } },
-    { "SAMSUNG GX-1", 0, 0,
+    { "Samsung GX-1", 0, 0,
        { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } },
-    { "SAMSUNG S85", 0, 0xffff,                /* DJC */
+    { "Samsung GX20", 0, 0,    /* copied from Pentax K20D */
+       { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } },
+    { "Samsung S85", 0, 0,             /* DJC */
        { 11885,-3968,-1473,-4214,12299,1916,-835,1655,5549 } },
     { "Sinar", 0, 0,                   /* DJC */
        { 16442,-2956,-2422,-2877,12128,750,-1136,6066,4559 } },
-    { "SONY DSC-F828", 0, 0,
+    { "Sony DSC-F828", 0, 0,
        { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } },
-    { "SONY DSC-R1", 512, 0,
+    { "Sony DSC-R1", 0, 0,
        { 8512,-2641,-694,-8042,15670,2526,-1821,2117,7414 } },
-    { "SONY DSC-V3", 0, 0,
+    { "Sony DSC-V3", 0, 0,
        { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } },
-    { "SONY DSC-RX100", 200, 0,
+    { "Sony DSC-RX100M", 0, 0,         /* M2, M3, and M4 */
+       { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } },
+    { "Sony DSC-RX100", 0, 0,
        { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } },
-    { "SONY DSC-RX1", 128, 0,
+    { "Sony DSC-RX10", 0, 0,           /* also RX10M2 */
+       { 6679,-1825,-745,-5047,13256,1953,-1580,2422,5183 } },
+    { "Sony DSC-RX1RM2", 0, 0,
+       { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } },
+    { "Sony DSC-RX1", 0, 0,
        { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } },
-    { "SONY DSLR-A100", 0, 0xfeb,
+    { "Sony DSLR-A100", 0, 0xfeb,
        { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } },
-    { "SONY DSLR-A290", 0, 0,
+    { "Sony DSLR-A290", 0, 0,
        { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } },
-    { "SONY DSLR-A2", 0, 0,
+    { "Sony DSLR-A2", 0, 0,
        { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } },
-    { "SONY DSLR-A300", 0, 0,
+    { "Sony DSLR-A300", 0, 0,
        { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } },
-    { "SONY DSLR-A330", 0, 0,
+    { "Sony DSLR-A330", 0, 0,
        { 9847,-3091,-929,-8485,16346,2225,-714,595,7103 } },
-    { "SONY DSLR-A350", 0, 0xffc,
+    { "Sony DSLR-A350", 0, 0xffc,
        { 6038,-1484,-578,-9146,16746,2513,-875,746,7217 } },
-    { "SONY DSLR-A380", 0, 0,
+    { "Sony DSLR-A380", 0, 0,
        { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } },
-    { "SONY DSLR-A390", 0, 0,
+    { "Sony DSLR-A390", 0, 0,
        { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } },
-    { "SONY DSLR-A450", 128, 0xfeb,
+    { "Sony DSLR-A450", 0, 0xfeb,
        { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } },
-    { "SONY DSLR-A580", 128, 0xfeb,
+    { "Sony DSLR-A580", 0, 0xfeb,
        { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } },
-    { "SONY DSLR-A5", 128, 0xfeb,
+    { "Sony DSLR-A500", 0, 0xfeb,
+       { 6046,-1127,-278,-5574,13076,2786,-691,1419,7625 } },
+    { "Sony DSLR-A5", 0, 0xfeb,
        { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } },
-    { "SONY DSLR-A700", 126, 0,
+    { "Sony DSLR-A700", 0, 0,
        { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } },
-    { "SONY DSLR-A850", 128, 0,
+    { "Sony DSLR-A850", 0, 0,
        { 5413,-1162,-365,-5665,13098,2866,-608,1179,8440 } },
-    { "SONY DSLR-A900", 128, 0,
+    { "Sony DSLR-A900", 0, 0,
        { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } },
-    { "SONY NEX-5N", 128, 0,
+    { "Sony ILCA-68", 0, 0,
+       { 6435,-1903,-536,-4722,12449,2550,-663,1363,6517 } },
+    { "Sony ILCA-77M2", 0, 0,
+       { 5991,-1732,-443,-4100,11989,2381,-704,1467,5992 } },
+    { "Sony ILCE-6300", 0, 0,
+       { 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 } },
+    { "Sony ILCE-7M2", 0, 0,
+       { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } },
+    { "Sony ILCE-7S", 0, 0,    /* also ILCE-7SM2 */
+       { 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 } },
+    { "Sony ILCE-7RM2", 0, 0,
+       { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } },
+    { "Sony ILCE-7R", 0, 0,
+       { 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 } },
+    { "Sony ILCE-7", 0, 0,
+       { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } },
+    { "Sony ILCE", 0, 0,       /* 3000, 5000, 5100, 6000, and QX1 */
+       { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } },
+    { "Sony NEX-5N", 0, 0,
        { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } },
-    { "SONY NEX-5R", 128, 0,
+    { "Sony NEX-5R", 0, 0,
+       { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } },
+    { "Sony NEX-5T", 0, 0,
        { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } },
-    { "SONY NEX-3", 138, 0,            /* DJC */
+    { "Sony NEX-3N", 0, 0,
+       { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } },
+    { "Sony NEX-3", 138, 0,            /* DJC */
        { 6907,-1256,-645,-4940,12621,2320,-1710,2581,6230 } },
-    { "SONY NEX-5", 116, 0,            /* DJC */
+    { "Sony NEX-5", 116, 0,            /* DJC */
        { 6807,-1350,-342,-4216,11649,2567,-1089,2001,6420 } },
-    { "SONY NEX-3", 128, 0,            /* Adobe */
+    { "Sony NEX-3", 0, 0,              /* Adobe */
        { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } },
-    { "SONY NEX-5", 128, 0,            /* Adobe */
+    { "Sony NEX-5", 0, 0,              /* Adobe */
        { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } },
-    { "SONY NEX-6", 128, 0,
+    { "Sony NEX-6", 0, 0,
        { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } },
-    { "SONY NEX-7", 128, 0,
+    { "Sony NEX-7", 0, 0,
        { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } },
-    { "SONY NEX", 128, 0,      /* NEX-C3, NEX-F3 */
+    { "Sony NEX", 0, 0,        /* NEX-C3, NEX-F3 */
        { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } },
-    { "SONY SLT-A33", 128, 0,
+    { "Sony SLT-A33", 0, 0,
        { 6069,-1221,-366,-5221,12779,2734,-1024,2066,6834 } },
-    { "SONY SLT-A35", 128, 0,
+    { "Sony SLT-A35", 0, 0,
        { 5986,-1618,-415,-4557,11820,3120,-681,1404,6971 } },
-    { "SONY SLT-A37", 128, 0,
+    { "Sony SLT-A37", 0, 0,
        { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } },
-    { "SONY SLT-A55", 128, 0,
+    { "Sony SLT-A55", 0, 0,
        { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } },
-    { "SONY SLT-A57", 128, 0,
+    { "Sony SLT-A57", 0, 0,
+       { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } },
+    { "Sony SLT-A58", 0, 0,
        { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } },
-    { "SONY SLT-A65", 128, 0,
+    { "Sony SLT-A65", 0, 0,
        { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } },
-    { "SONY SLT-A77", 128, 0,
+    { "Sony SLT-A77", 0, 0,
        { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } },
-    { "SONY SLT-A99", 128, 0,
+    { "Sony SLT-A99", 0, 0,
        { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } },
   };
   double cam_xyz[4][3];
@@ -7053,10 +8133,9 @@ void CLASS adobe_coeff (const char *make, const char *model)
       if (table[i].black)   black   = (ushort) table[i].black;
       if (table[i].maximum) maximum = (ushort) table[i].maximum;
       if (table[i].trans[0]) {
-        double *dp = &cam_xyz[0][0];
-       const short *sp = &table[i].trans[0];
-       for( j=12; --j>=0; ++dp,++sp ) *dp = *sp / 10000.0;
-       cam_xyz_coeff (cam_xyz);
+       for (raw_color = j=0; j < 12; j++)
+         ((double *)cam_xyz)[j] = table[i].trans[j] / 10000.0;
+       cam_xyz_coeff (rgb_cam, cam_xyz);
       }
       break;
     }
@@ -7132,10 +8211,7 @@ float CLASS find_green (int bps, int bite, int off0, int off1)
  */
 void CLASS identify()
 {
-  char head[32], *cp;
-  int hlen, flen, fsize, zero_fsize=1, i, c, is_canon;
-  struct jhead jh;
-  short pana[][6] = {
+  static const short pana[][6] = {
     { 3130, 1743,  4,  0, -6,  0 },
     { 3130, 2055,  4,  0, -6,  0 },
     { 3130, 2319,  4,  0, -6,  0 },
@@ -7158,105 +8234,231 @@ void CLASS identify()
     { 4290, 2391,  3,  0, -8, -1 },
     { 4330, 2439, 17, 15,-44,-19 },
     { 4508, 2962,  0,  0, -3, -4 },
-    { 4508, 3330,  0,  0, -3, -6 } };
+    { 4508, 3330,  0,  0, -3, -6 },
+  };
+  static const ushort canon[][11] = {
+    { 1944, 1416,   0,  0, 48,  0 },
+    { 2144, 1560,   4,  8, 52,  2, 0, 0, 0, 25 },
+    { 2224, 1456,  48,  6,  0,  2 },
+    { 2376, 1728,  12,  6, 52,  2 },
+    { 2672, 1968,  12,  6, 44,  2 },
+    { 3152, 2068,  64, 12,  0,  0, 16 },
+    { 3160, 2344,  44, 12,  4,  4 },
+    { 3344, 2484,   4,  6, 52,  6 },
+    { 3516, 2328,  42, 14,  0,  0 },
+    { 3596, 2360,  74, 12,  0,  0 },
+    { 3744, 2784,  52, 12,  8, 12 },
+    { 3944, 2622,  30, 18,  6,  2 },
+    { 3948, 2622,  42, 18,  0,  2 },
+    { 3984, 2622,  76, 20,  0,  2, 14 },
+    { 4104, 3048,  48, 12, 24, 12 },
+    { 4116, 2178,   4,  2,  0,  0 },
+    { 4152, 2772, 192, 12,  0,  0 },
+    { 4160, 3124, 104, 11,  8, 65 },
+    { 4176, 3062,  96, 17,  8,  0, 0, 16, 0, 7, 0x49 },
+    { 4192, 3062,  96, 17, 24,  0, 0, 16, 0, 0, 0x49 },
+    { 4312, 2876,  22, 18,  0,  2 },
+    { 4352, 2874,  62, 18,  0,  0 },
+    { 4476, 2954,  90, 34,  0,  0 },
+    { 4480, 3348,  12, 10, 36, 12, 0, 0, 0, 18, 0x49 },
+    { 4480, 3366,  80, 50,  0,  0 },
+    { 4496, 3366,  80, 50, 12,  0 },
+    { 4768, 3516,  96, 16,  0,  0, 0, 16 },
+    { 4832, 3204,  62, 26,  0,  0 },
+    { 4832, 3228,  62, 51,  0,  0 },
+    { 5108, 3349,  98, 13,  0,  0 },
+    { 5120, 3318, 142, 45, 62,  0 },
+    { 5280, 3528,  72, 52,  0,  0 },
+    { 5344, 3516, 142, 51,  0,  0 },
+    { 5344, 3584, 126,100,  0,  2 },
+    { 5360, 3516, 158, 51,  0,  0 },
+    { 5568, 3708,  72, 38,  0,  0 },
+    { 5632, 3710,  96, 17,  0,  0, 0, 16, 0, 0, 0x49 },
+    { 5712, 3774,  62, 20, 10,  2 },
+    { 5792, 3804, 158, 51,  0,  0 },
+    { 5920, 3950, 122, 80,  2,  0 },
+    { 6096, 4056,  72, 34,  0,  0 },
+    { 6288, 4056, 264, 34,  0,  0 },
+    { 8896, 5920, 160, 64,  0,  0 },
+  };
+  static const struct {
+    ushort id;
+    char model[20];
+  } unique[] = {
+    { 0x168, "EOS 10D" },    { 0x001, "EOS-1D" },
+    { 0x175, "EOS 20D" },    { 0x174, "EOS-1D Mark II" },
+    { 0x234, "EOS 30D" },    { 0x232, "EOS-1D Mark II N" },
+    { 0x190, "EOS 40D" },    { 0x169, "EOS-1D Mark III" },
+    { 0x261, "EOS 50D" },    { 0x281, "EOS-1D Mark IV" },
+    { 0x287, "EOS 60D" },    { 0x167, "EOS-1DS" },
+    { 0x325, "EOS 70D" },
+    { 0x350, "EOS 80D" },    { 0x328, "EOS-1D X Mark II" },
+    { 0x170, "EOS 300D" },   { 0x188, "EOS-1Ds Mark II" },
+    { 0x176, "EOS 450D" },   { 0x215, "EOS-1Ds Mark III" },
+    { 0x189, "EOS 350D" },   { 0x324, "EOS-1D C" },
+    { 0x236, "EOS 400D" },   { 0x269, "EOS-1D X" },
+    { 0x252, "EOS 500D" },   { 0x213, "EOS 5D" },
+    { 0x270, "EOS 550D" },   { 0x218, "EOS 5D Mark II" },
+    { 0x286, "EOS 600D" },   { 0x285, "EOS 5D Mark III" },
+    { 0x301, "EOS 650D" },   { 0x302, "EOS 6D" },
+    { 0x326, "EOS 700D" },   { 0x250, "EOS 7D" },
+    { 0x393, "EOS 750D" },   { 0x289, "EOS 7D Mark II" },
+    { 0x347, "EOS 760D" },
+    { 0x254, "EOS 1000D" },
+    { 0x288, "EOS 1100D" },
+    { 0x327, "EOS 1200D" },  { 0x382, "Canon EOS 5DS" },
+    { 0x404, "EOS 1300D" },  { 0x401, "Canon EOS 5DS R" },
+    { 0x346, "EOS 100D" },
+  }, sonique[] = {
+    { 0x002, "DSC-R1" },     { 0x100, "DSLR-A100" },
+    { 0x101, "DSLR-A900" },  { 0x102, "DSLR-A700" },
+    { 0x103, "DSLR-A200" },  { 0x104, "DSLR-A350" },
+    { 0x105, "DSLR-A300" },  { 0x108, "DSLR-A330" },
+    { 0x109, "DSLR-A230" },  { 0x10a, "DSLR-A290" },
+    { 0x10d, "DSLR-A850" },  { 0x111, "DSLR-A550" },
+    { 0x112, "DSLR-A500" },  { 0x113, "DSLR-A450" },
+    { 0x116, "NEX-5" },      { 0x117, "NEX-3" },
+    { 0x118, "SLT-A33" },    { 0x119, "SLT-A55V" },
+    { 0x11a, "DSLR-A560" },  { 0x11b, "DSLR-A580" },
+    { 0x11c, "NEX-C3" },     { 0x11d, "SLT-A35" },
+    { 0x11e, "SLT-A65V" },   { 0x11f, "SLT-A77V" },
+    { 0x120, "NEX-5N" },     { 0x121, "NEX-7" },
+    { 0x123, "SLT-A37" },    { 0x124, "SLT-A57" },
+    { 0x125, "NEX-F3" },     { 0x126, "SLT-A99V" },
+    { 0x127, "NEX-6" },      { 0x128, "NEX-5R" },
+    { 0x129, "DSC-RX100" },  { 0x12a, "DSC-RX1" },
+    { 0x12e, "ILCE-3000" },  { 0x12f, "SLT-A58" },
+    { 0x131, "NEX-3N" },     { 0x132, "ILCE-7" },
+    { 0x133, "NEX-5T" },     { 0x134, "DSC-RX100M2" },
+    { 0x135, "DSC-RX10" },   { 0x136, "DSC-RX1R" },
+    { 0x137, "ILCE-7R" },    { 0x138, "ILCE-6000" },
+    { 0x139, "ILCE-5000" },  { 0x13d, "DSC-RX100M3" },
+    { 0x13e, "ILCE-7S" },    { 0x13f, "ILCA-77M2" },
+    { 0x153, "ILCE-5100" },  { 0x154, "ILCE-7M2" },
+    { 0x155, "DSC-RX100M4" },{ 0x156, "DSC-RX10M2" },
+    { 0x158, "DSC-RX1RM2" }, { 0x15a, "ILCE-QX1" },
+    { 0x15b, "ILCE-7RM2" },  { 0x15e, "ILCE-7SM2" },
+    { 0x161, "ILCA-68" },    { 0x165, "ILCE-6300" },
+  };
   static const struct {
-    int fsize;
-    char make[12], model[19], withjpeg;
+    unsigned fsize;
+    ushort rw, rh;
+    uchar lm, tm, rm, bm, lf, cf, max, flags;
+    char make[10], model[20];
+    ushort offset;
   } table[] = {
-    {    62464, "Kodak",    "DC20"            ,0 },
-    {   124928, "Kodak",    "DC20"            ,0 },
-    {  1652736, "Kodak",    "DCS200"          ,0 },
-    {  4159302, "Kodak",    "C330"            ,0 },
-    {  4162462, "Kodak",    "C330"            ,0 },
-    {   460800, "Kodak",    "C603v"           ,0 },
-    {   614400, "Kodak",    "C603v"           ,0 },
-    {  6163328, "Kodak",    "C603"            ,0 },
-    {  6166488, "Kodak",    "C603"            ,0 },
-    {  9116448, "Kodak",    "C603y"           ,0 },
-    {   311696, "ST Micro", "STV680 VGA"      ,0 },  /* SPYz */
-    {   787456, "Creative", "PC-CAM 600"      ,0 },
-    {  1138688, "Minolta",  "RD175"           ,0 },
-    {  3840000, "Foculus",  "531C"            ,0 },
-    {   307200, "Generic",  "640x480"         ,0 },
-    {   786432, "AVT",      "F-080C"          ,0 },
-    {  1447680, "AVT",      "F-145C"          ,0 },
-    {  1920000, "AVT",      "F-201C"          ,0 },
-    {  5067304, "AVT",      "F-510C"          ,0 },
-    {  5067316, "AVT",      "F-510C"          ,0 },
-    { 10134608, "AVT",      "F-510C"          ,0 },
-    { 10134620, "AVT",      "F-510C"          ,0 },
-    { 16157136, "AVT",      "F-810C"          ,0 },
-    {  1409024, "Sony",     "XCD-SX910CR"     ,0 },
-    {  2818048, "Sony",     "XCD-SX910CR"     ,0 },
-    {  3884928, "Micron",   "2010"            ,0 },
-    {  6624000, "Pixelink", "A782"            ,0 },
-    { 13248000, "Pixelink", "A782"            ,0 },
-    {  6291456, "RoverShot","3320AF"          ,0 },
-    {  6553440, "Canon",    "PowerShot A460"  ,0 },
-    {  6653280, "Canon",    "PowerShot A530"  ,0 },
-    {  6573120, "Canon",    "PowerShot A610"  ,0 },
-    {  9219600, "Canon",    "PowerShot A620"  ,0 },
-    {  9243240, "Canon",    "PowerShot A470"  ,0 },
-    { 10341600, "Canon",    "PowerShot A720 IS",0 },
-    { 10383120, "Canon",    "PowerShot A630"  ,0 },
-    { 12945240, "Canon",    "PowerShot A640"  ,0 },
-    { 15636240, "Canon",    "PowerShot A650"  ,0 },
-    {  5298000, "Canon",    "PowerShot SD300" ,0 },
-    {  7710960, "Canon",    "PowerShot S3 IS" ,0 },
-    { 15467760, "Canon",    "PowerShot SX110 IS",0 },
-    { 15534576, "Canon",    "PowerShot SX120 IS",0 },
-    { 18653760, "Canon",    "PowerShot SX20 IS",0 },
-    { 19131120, "Canon",    "PowerShot SX220 HS",0 },
-    { 21936096, "Canon",    "PowerShot SX30 IS",0 },
-    {  5939200, "OLYMPUS",  "C770UZ"          ,0 },
-    {  1581060, "NIKON",    "E900"            ,1 },  /* or E900s,E910 */
-    {  2465792, "NIKON",    "E950"            ,1 },  /* or E800,E700 */
-    {  2940928, "NIKON",    "E2100"           ,1 },  /* or E2500 */
-    {  4771840, "NIKON",    "E990"            ,1 },  /* or E995, Oly C3030Z */
-    {  4775936, "NIKON",    "E3700"           ,1 },  /* or Optio 33WR */
-    {  5869568, "NIKON",    "E4300"           ,1 },  /* or DiMAGE Z2 */
-    {  5865472, "NIKON",    "E4500"           ,1 },
-    {  7438336, "NIKON",    "E5000"           ,1 },  /* or E5700 */
-    {  8998912, "NIKON",    "COOLPIX S6"      ,1 },
-    {  1976352, "CASIO",    "QV-2000UX"       ,1 },
-    {  3217760, "CASIO",    "QV-3*00EX"       ,1 },
-    {  6218368, "CASIO",    "QV-5700"         ,1 },
-    {  6054400, "CASIO",    "QV-R41"          ,1 },
-    {  7530816, "CASIO",    "QV-R51"          ,1 },
-    {  7684000, "CASIO",    "QV-4000"         ,1 },
-    {  2937856, "CASIO",    "EX-S20"          ,1 },
-    {  4948608, "CASIO",    "EX-S100"         ,1 },
-    {  7542528, "CASIO",    "EX-Z50"          ,1 },
-    {  7562048, "CASIO",    "EX-Z500"         ,1 },
-    {  7753344, "CASIO",    "EX-Z55"          ,1 },
-    {  7816704, "CASIO",    "EX-Z60"          ,1 },
-    { 10843712, "CASIO",    "EX-Z75"          ,1 },
-    { 10834368, "CASIO",    "EX-Z750"         ,1 },
-    { 12310144, "CASIO",    "EX-Z850"         ,1 },
-    { 12489984, "CASIO",    "EX-Z8"           ,1 },
-    { 15499264, "CASIO",    "EX-Z1050"        ,1 },
-    { 18702336, "CASIO",    "EX-ZR100"        ,1 },
-    {  7426656, "CASIO",    "EX-P505"         ,1 },
-    {  9313536, "CASIO",    "EX-P600"         ,1 },
-    { 10979200, "CASIO",    "EX-P700"         ,1 },
-    {  3178560, "PENTAX",   "Optio S"         ,1 },
-    {  4841984, "PENTAX",   "Optio S"         ,1 },
-    {  6114240, "PENTAX",   "Optio S4"        ,1 },  /* or S4i, CASIO EX-Z4 */
-    { 10702848, "PENTAX",   "Optio 750Z"      ,1 },
-    { 15980544, "AGFAPHOTO","DC-833m"         ,1 },
-    { 16098048, "SAMSUNG",  "S85"             ,1 },
-    { 16215552, "SAMSUNG",  "S85"             ,1 },
-    { 20487168, "SAMSUNG",  "WB550"           ,1 },
-    { 24000000, "SAMSUNG",  "WB550"           ,1 },
-    { 12582980, "Sinar",    ""                ,0 },
-    { 33292868, "Sinar",    ""                ,0 },
-    { 44390468, "Sinar",    ""                ,0 } };
+    {   786432,1024, 768, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-080C" },
+    {  1447680,1392,1040, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-145C" },
+    {  1920000,1600,1200, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-201C" },
+    {  5067304,2588,1958, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-510C" },
+    {  5067316,2588,1958, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-510C",12 },
+    { 10134608,2588,1958, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-510C" },
+    { 10134620,2588,1958, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-510C",12 },
+    { 16157136,3272,2469, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-810C" },
+    { 15980544,3264,2448, 0, 0, 0, 0, 8,0x61,0,1,"AgfaPhoto","DC-833m" },
+    {  9631728,2532,1902, 0, 0, 0, 0,96,0x61,0,0,"Alcatel","5035D" },
+    {  2868726,1384,1036, 0, 0, 0, 0,64,0x49,0,8,"Baumer","TXG14",1078 },
+    {  5298000,2400,1766,12,12,44, 2,40,0x94,0,2,"Canon","PowerShot SD300" },
+    {  6553440,2664,1968, 4, 4,44, 4,40,0x94,0,2,"Canon","PowerShot A460" },
+    {  6573120,2672,1968,12, 8,44, 0,40,0x94,0,2,"Canon","PowerShot A610" },
+    {  6653280,2672,1992,10, 6,42, 2,40,0x94,0,2,"Canon","PowerShot A530" },
+    {  7710960,2888,2136,44, 8, 4, 0,40,0x94,0,2,"Canon","PowerShot S3 IS" },
+    {  9219600,3152,2340,36,12, 4, 0,40,0x94,0,2,"Canon","PowerShot A620" },
+    {  9243240,3152,2346,12, 7,44,13,40,0x49,0,2,"Canon","PowerShot A470" },
+    { 10341600,3336,2480, 6, 5,32, 3,40,0x94,0,2,"Canon","PowerShot A720 IS" },
+    { 10383120,3344,2484,12, 6,44, 6,40,0x94,0,2,"Canon","PowerShot A630" },
+    { 12945240,3736,2772,12, 6,52, 6,40,0x94,0,2,"Canon","PowerShot A640" },
+    { 15636240,4104,3048,48,12,24,12,40,0x94,0,2,"Canon","PowerShot A650" },
+    { 15467760,3720,2772, 6,12,30, 0,40,0x94,0,2,"Canon","PowerShot SX110 IS" },
+    { 15534576,3728,2778,12, 9,44, 9,40,0x94,0,2,"Canon","PowerShot SX120 IS" },
+    { 18653760,4080,3048,24,12,24,12,40,0x94,0,2,"Canon","PowerShot SX20 IS" },
+    { 19131120,4168,3060,92,16, 4, 1,40,0x94,0,2,"Canon","PowerShot SX220 HS" },
+    { 21936096,4464,3276,25,10,73,12,40,0x16,0,2,"Canon","PowerShot SX30 IS" },
+    { 24724224,4704,3504, 8,16,56, 8,40,0x94,0,2,"Canon","PowerShot A3300 IS" },
+    { 30858240,5248,3920, 8,16,56,16,40,0x94,0,2,"Canon","IXUS 160" },
+    {  1976352,1632,1211, 0, 2, 0, 1, 0,0x94,0,1,"Casio","QV-2000UX" },
+    {  3217760,2080,1547, 0, 0,10, 1, 0,0x94,0,1,"Casio","QV-3*00EX" },
+    {  6218368,2585,1924, 0, 0, 9, 0, 0,0x94,0,1,"Casio","QV-5700" },
+    {  7816704,2867,2181, 0, 0,34,36, 0,0x16,0,1,"Casio","EX-Z60" },
+    {  2937856,1621,1208, 0, 0, 1, 0, 0,0x94,7,13,"Casio","EX-S20" },
+    {  4948608,2090,1578, 0, 0,32,34, 0,0x94,7,1,"Casio","EX-S100" },
+    {  6054400,2346,1720, 2, 0,32, 0, 0,0x94,7,1,"Casio","QV-R41" },
+    {  7426656,2568,1928, 0, 0, 0, 0, 0,0x94,0,1,"Casio","EX-P505" },
+    {  7530816,2602,1929, 0, 0,22, 0, 0,0x94,7,1,"Casio","QV-R51" },
+    {  7542528,2602,1932, 0, 0,32, 0, 0,0x94,7,1,"Casio","EX-Z50" },
+    {  7562048,2602,1937, 0, 0,25, 0, 0,0x16,7,1,"Casio","EX-Z500" },
+    {  7753344,2602,1986, 0, 0,32,26, 0,0x94,7,1,"Casio","EX-Z55" },
+    {  9313536,2858,2172, 0, 0,14,30, 0,0x94,7,1,"Casio","EX-P600" },
+    { 10834368,3114,2319, 0, 0,27, 0, 0,0x94,0,1,"Casio","EX-Z750" },
+    { 10843712,3114,2321, 0, 0,25, 0, 0,0x94,0,1,"Casio","EX-Z75" },
+    { 10979200,3114,2350, 0, 0,32,32, 0,0x94,7,1,"Casio","EX-P700" },
+    { 12310144,3285,2498, 0, 0, 6,30, 0,0x94,0,1,"Casio","EX-Z850" },
+    { 12489984,3328,2502, 0, 0,47,35, 0,0x94,0,1,"Casio","EX-Z8" },
+    { 15499264,3754,2752, 0, 0,82, 0, 0,0x94,0,1,"Casio","EX-Z1050" },
+    { 18702336,4096,3044, 0, 0,24, 0,80,0x94,7,1,"Casio","EX-ZR100" },
+    {  7684000,2260,1700, 0, 0, 0, 0,13,0x94,0,1,"Casio","QV-4000" },
+    {   787456,1024, 769, 0, 1, 0, 0, 0,0x49,0,0,"Creative","PC-CAM 600" },
+    { 28829184,4384,3288, 0, 0, 0, 0,36,0x61,0,0,"DJI" },
+    { 15151104,4608,3288, 0, 0, 0, 0, 0,0x94,0,0,"Matrix" },
+    {  3840000,1600,1200, 0, 0, 0, 0,65,0x49,0,0,"Foculus","531C" },
+    {   307200, 640, 480, 0, 0, 0, 0, 0,0x94,0,0,"Generic" },
+    {    62464, 256, 244, 1, 1, 6, 1, 0,0x8d,0,0,"Kodak","DC20" },
+    {   124928, 512, 244, 1, 1,10, 1, 0,0x8d,0,0,"Kodak","DC20" },
+    {  1652736,1536,1076, 0,52, 0, 0, 0,0x61,0,0,"Kodak","DCS200" },
+    {  4159302,2338,1779, 1,33, 1, 2, 0,0x94,0,0,"Kodak","C330" },
+    {  4162462,2338,1779, 1,33, 1, 2, 0,0x94,0,0,"Kodak","C330",3160 },
+    {  2247168,1232, 912, 0, 0,16, 0, 0,0x00,0,0,"Kodak","C330" },
+    {  3370752,1232, 912, 0, 0,16, 0, 0,0x00,0,0,"Kodak","C330" },
+    {  6163328,2864,2152, 0, 0, 0, 0, 0,0x94,0,0,"Kodak","C603" },
+    {  6166488,2864,2152, 0, 0, 0, 0, 0,0x94,0,0,"Kodak","C603",3160 },
+    {   460800, 640, 480, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","C603" },
+    {  9116448,2848,2134, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","C603" },
+    { 12241200,4040,3030, 2, 0, 0,13, 0,0x49,0,0,"Kodak","12MP" },
+    { 12272756,4040,3030, 2, 0, 0,13, 0,0x49,0,0,"Kodak","12MP",31556 },
+    { 18000000,4000,3000, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","12MP" },
+    {   614400, 640, 480, 0, 3, 0, 0,64,0x94,0,0,"Kodak","KAI-0340" },
+    { 15360000,3200,2400, 0, 0, 0, 0,96,0x16,0,0,"Lenovo","A820" },
+    {  3884928,1608,1207, 0, 0, 0, 0,96,0x16,0,0,"Micron","2010",3212 },
+    {  1138688,1534, 986, 0, 0, 0, 0, 0,0x61,0,0,"Minolta","RD175",513 },
+    {  1581060,1305, 969, 0, 0,18, 6, 6,0x1e,4,1,"Nikon","E900" },
+    {  2465792,1638,1204, 0, 0,22, 1, 6,0x4b,5,1,"Nikon","E950" },
+    {  2940928,1616,1213, 0, 0, 0, 7,30,0x94,0,1,"Nikon","E2100" },
+    {  4771840,2064,1541, 0, 0, 0, 1, 6,0xe1,0,1,"Nikon","E990" },
+    {  4775936,2064,1542, 0, 0, 0, 0,30,0x94,0,1,"Nikon","E3700" },
+    {  5865472,2288,1709, 0, 0, 0, 1, 6,0xb4,0,1,"Nikon","E4500" },
+    {  5869568,2288,1710, 0, 0, 0, 0, 6,0x16,0,1,"Nikon","E4300" },
+    {  7438336,2576,1925, 0, 0, 0, 1, 6,0xb4,0,1,"Nikon","E5000" },
+    {  8998912,2832,2118, 0, 0, 0, 0,30,0x94,7,1,"Nikon","COOLPIX S6" },
+    {  5939200,2304,1718, 0, 0, 0, 0,30,0x16,0,0,"Olympus","C770UZ" },
+    {  3178560,2064,1540, 0, 0, 0, 0, 0,0x94,0,1,"Pentax","Optio S" },
+    {  4841984,2090,1544, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S" },
+    {  6114240,2346,1737, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S4" },
+    { 10702848,3072,2322, 0, 0, 0,21,30,0x94,0,1,"Pentax","Optio 750Z" },
+    {  4147200,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD" },
+    {  4151666,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD",8 },
+    { 13248000,2208,3000, 0, 0, 0, 0,13,0x61,0,0,"Pixelink","A782" },
+    {  6291456,2048,1536, 0, 0, 0, 0,96,0x61,0,0,"RoverShot","3320AF" },
+    {   311696, 644, 484, 0, 0, 0, 0, 0,0x16,0,8,"ST Micro","STV680 VGA" },
+    { 16098048,3288,2448, 0, 0,24, 0, 9,0x94,0,1,"Samsung","S85" },
+    { 16215552,3312,2448, 0, 0,48, 0, 9,0x94,0,1,"Samsung","S85" },
+    { 20487168,3648,2808, 0, 0, 0, 0,13,0x94,5,1,"Samsung","WB550" },
+    { 24000000,4000,3000, 0, 0, 0, 0,13,0x94,5,1,"Samsung","WB550" },
+    { 12582980,3072,2048, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 },
+    { 33292868,4080,4080, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 },
+    { 44390468,4080,5440, 0, 0, 0, 0,33,0x61,0,0,"Sinar","",68 },
+    {  1409024,1376,1024, 0, 0, 1, 0, 0,0x49,0,0,"Sony","XCD-SX910CR" },
+    {  2818048,1376,1024, 0, 0, 1, 0,97,0x49,0,0,"Sony","XCD-SX910CR" },
+  };
   static const char *corp[] =
-    { "Canon", "NIKON", "EPSON", "KODAK", "Kodak", "OLYMPUS", "PENTAX",
-      "MINOLTA", "Minolta", "Konica", "CASIO", "Sinar", "Phase One",
-      "SAMSUNG", "Mamiya", "MOTOROLA", "LEICA" };
+    { "AgfaPhoto", "Canon", "Casio", "Epson", "Fujifilm",
+      "Mamiya", "Minolta", "Motorola", "Kodak", "Konica", "Leica",
+      "Nikon", "Nokia", "Olympus", "Ricoh", "Pentax", "Phase One",
+      "Samsung", "Sigma", "Sinar", "Sony" };
+  char head[32], *cp;
+  int hlen, flen, fsize, zero_fsize=1, i, c;
+  struct jhead jh;
 
-  tiff_flip = flip = filters = -1;     /* 0 is valid, so -1 is unknown */
+  tiff_flip = flip = filters = UINT_MAX;       /* unknown */
   raw_height = raw_width = fuji_width = fuji_layout = cr2_slice[0] = 0;
   maximum = height = width = top_margin = left_margin = 0;
   cdesc[0] = desc[0] = artist[0] = make[0] = model[0] = model2[0] = 0;
@@ -7270,7 +8472,7 @@ void CLASS identify()
   thumb_offset = thumb_length = thumb_width = thumb_height = 0;
   load_raw = thumb_load_raw = 0;
   write_thumb = &CLASS jpeg_thumb;
-  data_offset = meta_length = tiff_bps = tiff_compress = 0;
+  data_offset = meta_offset = meta_length = tiff_bps = tiff_compress = 0;
   kodak_cbpp = zero_after_ff = dng_version = load_flags = 0;
   timestamp = shot_order = tiff_samples = black = is_foveon = 0;
   mix_green = profile_length = data_error = zero_is_bad = 0;
@@ -7298,7 +8500,8 @@ void CLASS identify()
   } else if (order == 0x4949 || order == 0x4d4d) {
     if (!memcmp (head+6,"HEAPCCDR",8)) {
       data_offset = hlen;
-      parse_ciff (hlen, flen - hlen);
+      parse_ciff (hlen, flen-hlen, 0);
+      load_raw = &CLASS canon_load_raw;
     } else if (parse_tiff(0)) apply_tiff();
   } else if (!memcmp (head,"\xff\xd8\xff\xe1",4) &&
             !memcmp (head+6,"Exif",4)) {
@@ -7346,6 +8549,10 @@ void CLASS identify()
   } else if (!memcmp (head,"RIFF",4)) {
     fseek (ifp, 0, SEEK_SET);
     parse_riff();
+  } else if (!memcmp (head+4,"ftypqt   ",9)) {
+    fseek (ifp, 0, SEEK_SET);
+    parse_qt (fsize);
+    is_raw = 0;
   } else if (!memcmp (head,"\0\001\0\001\0@",6)) {
     fseek (ifp, 6, SEEK_SET);
     fread (make, 1, 8, ifp);
@@ -7359,15 +8566,18 @@ void CLASS identify()
     filters = 0x61616161;
   } else if (!memcmp (head,"NOKIARAW",8)) {
     strcpy (make, "NOKIA");
-    strcpy (model, "X2");
     order = 0x4949;
     fseek (ifp, 300, SEEK_SET);
     data_offset = get4();
     i = get4();
     width = get2();
     height = get2();
-    data_offset += i - width * 5 / 4 * height;
-    load_raw = &CLASS nokia_load_raw;
+    switch (tiff_bps = i*8 / (width * height)) {
+      case  8: load_raw = &CLASS eight_bit_load_raw;  break;
+      case 10: load_raw = &CLASS nokia_load_raw;
+    }
+    raw_height = height + (top_margin = i / (width * tiff_bps/8) - height);
+    mask[0][3] = 1;
     filters = 0x61616161;
   } else if (!memcmp (head,"ARRI",4)) {
     order = 0x4949;
@@ -7381,9 +8591,20 @@ void CLASS identify()
     load_raw = &CLASS packed_load_raw;
     load_flags = 88;
     filters = 0x61616161;
+  } else if (!memcmp (head,"XPDS",4)) {
+    order = 0x4949;
+    fseek (ifp, 0x800, SEEK_SET);
+    fread (make, 1, 41, ifp);
+    raw_height = get2();
+    raw_width  = get2();
+    fseek (ifp, 56, SEEK_CUR);
+    fread (model, 1, 30, ifp);
+    data_offset = 0x10000;
+    load_raw = &CLASS canon_rmf_load_raw;
+    gamma_curve (0, 12.25, 1, 1023);
   } else if (!memcmp (head+4,"RED1",4)) {
-    strcpy (make, "RED");
-    strcpy (model,"ONE");
+    strcpy (make, "Red");
+    strcpy (model,"One");
     parse_redcine();
     load_raw = &CLASS redcine_load_raw;
     gamma_curve (1/2.4, 12.92, 1, 4095);
@@ -7398,26 +8619,66 @@ void CLASS identify()
     parse_foveon();
   else if (!memcmp (head,"CI",2))
     parse_cine();
-  else
+  if (make[0] == 0)
     for (zero_fsize=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)
+       flip = table[i].flags >> 2;
+       zero_is_bad = table[i].flags & 2;
+       if (table[i].flags & 1)
          parse_external_jpeg();
+       data_offset = table[i].offset;
+       raw_width   = table[i].rw;
+       raw_height  = table[i].rh;
+       left_margin = table[i].lm;
+        top_margin = table[i].tm;
+       width  = raw_width - left_margin - table[i].rm;
+       height = raw_height - top_margin - table[i].bm;
+       filters = 0x1010101 * table[i].cf;
+       colors = 4 - !((filters & filters >> 1) & 0x5555);
+       load_flags = table[i].lf;
+       switch (tiff_bps = (fsize-data_offset)*8 / (raw_width*raw_height)) {
+         case 6:
+           load_raw = &CLASS minolta_rd175_load_raw;  break;
+         case 8:
+           load_raw = &CLASS eight_bit_load_raw;  break;
+         case 10: case 12:
+           load_flags |= 128;
+           load_raw = &CLASS packed_load_raw;     break;
+         case 16:
+           order = 0x4949 | 0x404 * (load_flags & 1);
+           tiff_bps -= load_flags >> 4;
+           tiff_bps -= load_flags = load_flags >> 1 & 7;
+           load_raw = &CLASS unpacked_load_raw;
+       }
+       maximum = (1 << tiff_bps) - (1 << table[i].max);
       }
   if (zero_fsize) fsize = 0;
   if (make[0] == 0) parse_smal (0, flen);
-  if (make[0] == 0) parse_jpeg (is_raw = 0);
+  if (make[0] == 0) {
+    parse_jpeg(0);
+    if (!(strncmp(model,"ov",2) && strncmp(model,"RP_OV",5)) &&
+       !fseek (ifp, -6404096, SEEK_END) &&
+       fread (head, 1, 32, ifp) && !strcmp(head,"BRCMn")) {
+      strcpy (make, "OmniVision");
+      data_offset = ftell(ifp) + 0x8000-32;
+      width = raw_width;
+      raw_width = 2611;
+      load_raw = &CLASS nokia_load_raw;
+      filters = 0x16161616;
+    } else is_raw = 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) &&
-       ((cp = strstr(model," DIGITAL CAMERA")) ||
-        (cp = strstr(model," Digital Camera")) ||
+    if (strcasestr (make, corp[i]))    /* Simplify company names */
+           strcpy (make, corp[i]);
+  if ((!strcmp(make,"Kodak") || !strcmp(make,"Leica")) &&
+       ((cp = strcasestr(model," DIGITAL CAMERA")) ||
         (cp = strstr(model,"FILE VERSION"))))
      *cp = 0;
+  if (!strncasecmp(model,"PENTAX",6))
+    strcpy (make, "Pentax");
   cp = make + strlen(make);            /* Remove trailing spaces */
   while (*--cp == ' ') *cp = 0;
   cp = model + strlen(model);
@@ -7444,6 +8705,8 @@ void CLASS identify()
     { left_margin = 10; width  = 4950; filters = 0x16161616; }
   if (width == 4736 && !strcmp(model,"K-7"))
     { height  = 3122;   width  = 4684; filters = 0x16161616; top_margin = 2; }
+  if (width == 6080 && !strcmp(model,"K-3"))
+    { left_margin = 4;  width  = 6040; }
   if (width == 7424 && !strcmp(model,"645D"))
     { height  = 5502;   width  = 7328; filters = 0x61616161; top_margin = 29;
       left_margin = 48; }
@@ -7451,48 +8714,88 @@ void CLASS identify()
                        width  = 4014;
   if (dng_version) {
     if (filters == UINT_MAX) filters = 0;
-    if (filters) is_raw = tiff_samples;
-    else        colors = tiff_samples;
-    if (tiff_compress == 1)
-      load_raw = &CLASS packed_dng_load_raw;
-    if (tiff_compress == 7)
-      load_raw = &CLASS lossless_dng_load_raw;
+    if (filters) is_raw *= tiff_samples;
+    else        colors  = tiff_samples;
+    switch (tiff_compress) {
+      case 0:
+      case 1:     load_raw = &CLASS   packed_dng_load_raw;  break;
+      case 7:     load_raw = &CLASS lossless_dng_load_raw;  break;
+      case 34892: load_raw = &CLASS    lossy_dng_load_raw;  break;
+      default:    load_raw = 0;
+    }
     goto dng_skip;
   }
-  if ((is_canon = !strcmp(make,"Canon")))
-    load_raw = memcmp (head+6,"HEAPCCDR",8) ?
-       &CLASS lossless_jpeg_load_raw : &CLASS canon_load_raw;
-  if (!strcmp(make,"NIKON")) {
+  if (!strcmp(make,"Canon") && !fsize && tiff_bps != 15) {
+    if (!load_raw)
+      load_raw = &CLASS lossless_jpeg_load_raw;
+    for (i=0; i < sizeof canon / sizeof *canon; i++)
+      if (raw_width == canon[i][0] && raw_height == canon[i][1]) {
+       width  = raw_width - (left_margin = canon[i][2]);
+       height = raw_height - (top_margin = canon[i][3]);
+       width  -= canon[i][4];
+       height -= canon[i][5];
+       mask[0][1] =  canon[i][6];
+       mask[0][3] = -canon[i][7];
+       mask[1][1] =  canon[i][8];
+       mask[1][3] = -canon[i][9];
+       if (canon[i][10]) filters = canon[i][10] * 0x01010101;
+      }
+    if ((unique_id | 0x20000) == 0x2720000) {
+      left_margin = 8;
+      top_margin = 16;
+    }
+  }
+  for (i=0; i < sizeof unique / sizeof *unique; i++)
+    if (unique_id == 0x80000000 + unique[i].id) {
+      adobe_coeff ("Canon", unique[i].model);
+      if (model[4] == 'K' && strlen(model) == 8)
+       strcpy (model, unique[i].model);
+    }
+  for (i=0; i < sizeof sonique / sizeof *sonique; i++)
+    if (unique_id == sonique[i].id)
+      strcpy (model, sonique[i].model);
+  if (!strcmp(make,"Nikon")) {
     if (!load_raw)
       load_raw = &CLASS packed_load_raw;
     if (model[0] == 'E')
       load_flags |= !data_offset << 2 | 2;
   }
-  if (!strcmp(make,"CASIO")) {
-    load_raw = &CLASS packed_load_raw;
-    maximum = 0xf7f;
-  }
 
 /* Set parameters based on camera name (for non-DNG files). */
 
+  if (!strcmp(model,"KAI-0340")
+       && find_green (16, 16, 3840, 5120) < 25) {
+    height = 480;
+    top_margin = filters = 0;
+    strcpy (model,"C603");
+  }
+  if (!strcmp(make,"Sony") && raw_width > 3888)
+    black = 128 << (tiff_bps - 12);
   if (is_foveon) {
     if (height*2 < width) pixel_aspect = 0.5;
     if (height   > width) pixel_aspect = 2;
     filters = 0;
     simple_coeff(0);
-  } else if (is_canon && tiff_bps == 15) {
+  } else if (!strcmp(make,"Canon") && tiff_bps == 15) {
     switch (width) {
       case 3344: width -= 66;
       case 3872: width -= 6;
     }
-    if (height > width) SWAP(height,width);
+    if (height > width) {
+      SWAP(height,width);
+      SWAP(raw_height,raw_width);
+    }
+    if (width == 7200 && height == 3888) {
+      raw_width  = width  = 6480;
+      raw_height = height = 4320;
+    }
     filters = 0;
+    tiff_samples = colors = 3;
     load_raw = &CLASS canon_sraw_load_raw;
   } else if (!strcmp(model,"PowerShot 600")) {
     height = 613;
     width  = 854;
     raw_width = 896;
-    pixel_aspect = 607/628.0;
     colors = 4;
     filters = 0xe1e4e1e4;
     load_raw = &CLASS canon_600_load_raw;
@@ -7502,362 +8805,34 @@ void CLASS identify()
     width  = 960;
     raw_width = 992;
     pixel_aspect = 256/235.0;
-    colors = 4;
     filters = 0x1e4e1e4e;
     goto canon_a5;
   } else if (!strcmp(model,"PowerShot A50")) {
     height =  968;
     width  = 1290;
     raw_width = 1320;
-    colors = 4;
     filters = 0x1b4e4b1e;
     goto canon_a5;
   } else if (!strcmp(model,"PowerShot Pro70")) {
     height = 1024;
     width  = 1552;
-    colors = 4;
     filters = 0x1e4b4e1b;
-    goto canon_a5;
-  } else if (!strcmp(model,"PowerShot SD300")) {
-    height = 1752;
-    width  = 2344;
-    raw_height = 1766;
-    raw_width  = 2400;
-    top_margin  = 12;
-    left_margin = 12;
-    goto canon_a5;
-  } else if (!strcmp(model,"PowerShot A460")) {
-    height = 1960;
-    width  = 2616;
-    raw_height = 1968;
-    raw_width  = 2664;
-    top_margin  = 4;
-    left_margin = 4;
-    goto canon_a5;
-  } else if (!strcmp(model,"PowerShot A530")) {
-    height = 1984;
-    width  = 2620;
-    raw_height = 1992;
-    raw_width  = 2672;
-    top_margin  = 6;
-    left_margin = 10;
-    goto canon_a5;
-  } else if (!strcmp(model,"PowerShot A610")) {
-    if (canon_s2is()) strcpy (model+10, "S2 IS");
-    height = 1960;
-    width  = 2616;
-    raw_height = 1968;
-    raw_width  = 2672;
-    top_margin  = 8;
-    left_margin = 12;
-    goto canon_a5;
-  } else if (!strcmp(model,"PowerShot A620")) {
-    height = 2328;
-    width  = 3112;
-    raw_height = 2340;
-    raw_width  = 3152;
-    top_margin  = 12;
-    left_margin = 36;
-    goto canon_a5;
-  } else if (!strcmp(model,"PowerShot A470")) {
-    height = 2328;
-    width  = 3096;
-    raw_height = 2346;
-    raw_width  = 3152;
-    top_margin  = 6;
-    left_margin = 12;
-    goto canon_a5;
-  } else if (!strcmp(model,"PowerShot A720 IS")) {
-    height = 2472;
-    width  = 3298;
-    raw_height = 2480;
-    raw_width  = 3336;
-    top_margin  = 5;
-    left_margin = 6;
-    goto canon_a5;
-  } else if (!strcmp(model,"PowerShot A630")) {
-    height = 2472;
-    width  = 3288;
-    raw_height = 2484;
-    raw_width  = 3344;
-    top_margin  = 6;
-    left_margin = 12;
-    goto canon_a5;
-  } else if (!strcmp(model,"PowerShot A640")) {
-    height = 2760;
-    width  = 3672;
-    raw_height = 2772;
-    raw_width  = 3736;
-    top_margin  = 6;
-    left_margin = 12;
-    goto canon_a5;
-  } else if (!strcmp(model,"PowerShot A650")) {
-    height = 3024;
-    width  = 4032;
-    raw_height = 3048;
-    raw_width  = 4104;
-    top_margin  = 12;
-    left_margin = 48;
-    goto canon_a5;
-  } else if (!strcmp(model,"PowerShot S3 IS")) {
-    height = 2128;
-    width  = 2840;
-    raw_height = 2136;
-    raw_width  = 2888;
-    top_margin  = 8;
-    left_margin = 44;
 canon_a5:
+    colors = 4;
     tiff_bps = 10;
     load_raw = &CLASS packed_load_raw;
     load_flags = 40;
-    if (raw_width > 1600) zero_is_bad = 1;
-  } else if (!strcmp(model,"PowerShot SX110 IS")) {
-    height = 2760;
-    width  = 3684;
-    raw_height = 2772;
-    raw_width  = 3720;
-    top_margin  = 12;
-    left_margin = 6;
-    load_raw = &CLASS packed_load_raw;
-    load_flags = 40;
-    zero_is_bad = 1;
-  } else if (!strcmp(model,"PowerShot SX120 IS")) {
-    height = 2742;
-    width  = 3664;
-    raw_height = 2778;
-    raw_width  = 3728;
-    top_margin  = 18;
-    left_margin = 16;
-    filters = 0x49494949;
-    load_raw = &CLASS packed_load_raw;
-    load_flags = 40;
-    zero_is_bad = 1;
-  } else if (!strcmp(model,"PowerShot SX20 IS")) {
-    height = 3024;
-    width  = 4032;
-    raw_height = 3048;
-    raw_width  = 4080;
-    top_margin  = 12;
-    left_margin = 24;
-    load_raw = &CLASS packed_load_raw;
-    load_flags = 40;
-    zero_is_bad = 1;
-  } else if (!strcmp(model,"PowerShot SX220 HS")) {
-    height = 3043;
-    width  = 4072;
-    raw_height = 3060;
-    raw_width  = 4168;
-    mask[0][0] = top_margin = 16;
-    mask[0][2] = top_margin + height;
-    mask[0][3] = left_margin = 92;
-    load_raw = &CLASS packed_load_raw;
-    load_flags = 8;
-    zero_is_bad = 1;
-  } else if (!strcmp(model,"PowerShot SX30 IS")) {
-    height = 3254;
-    width  = 4366;
-    raw_height = 3276;
-    raw_width  = 4464;
-    top_margin  = 10;
-    left_margin = 25;
-    filters = 0x16161616;
-    load_raw = &CLASS packed_load_raw;
-    load_flags = 40;
-    zero_is_bad = 1;
-  } else if (!strcmp(model,"PowerShot Pro90 IS")) {
-    width  = 1896;
+  } else if (!strcmp(model,"PowerShot Pro90 IS") ||
+            !strcmp(model,"PowerShot G1")) {
     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;
-    if (unique_id == 0x80000170)
-      adobe_coeff ("Canon","EOS 300D");
-  } 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,"PowerShot A610")) {
+    if (canon_s2is()) strcpy (model+10, "S2 IS");
+  } else if (!strcmp(model,"PowerShot SX220 HS")) {
+    mask[1][3] = -4;
   } else if (!strcmp(model,"EOS D2000C")) {
     filters = 0x61616161;
     black = curve[200];
-  } else if (is_canon && raw_width == 3516) {
-    top_margin  = 14;
-    left_margin = 42;
-    if (unique_id == 0x80000189)
-      adobe_coeff ("Canon","EOS 350D");
-    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 == 3744) {
-    height = 2760;
-    width  = 3684;
-    top_margin  = 16;
-    left_margin = 8;
-    if (unique_id > 0x2720000) {
-      top_margin  = 12;
-      left_margin = 52;
-    }
-  } else if (is_canon && raw_width == 3944) {
-    height = 2602;
-    width  = 3908;
-    top_margin  = 18;
-    left_margin = 30;
-  } else if (is_canon && raw_width == 3948) {
-    top_margin  = 18;
-    left_margin = 42;
-    height -= 2;
-    if (unique_id == 0x80000236)
-      adobe_coeff ("Canon","EOS 400D");
-    if (unique_id == 0x80000254)
-      adobe_coeff ("Canon","EOS 1000D");
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 3984) {
-    top_margin  = 20;
-    left_margin = 76;
-    height -= 2;
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 4104) {
-    height = 3024;
-    width  = 4032;
-    top_margin  = 12;
-    left_margin = 48;
-  } else if (is_canon && raw_width == 4152) {
-    top_margin  = 12;
-    left_margin = 192;
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 4160) {
-    height = 3048;
-    width  = 4048;
-    top_margin  = 11;
-    left_margin = 104;
-  } else if (is_canon && raw_width == 4176) {
-    height = 3045;
-    width  = 4072;
-    left_margin = 96;
-    mask[0][0] = top_margin = 17;
-    mask[0][2] = raw_height;
-    mask[0][3] = 80;
-    filters = 0x49494949;
-  } else if (is_canon && raw_width == 4312) {
-    top_margin  = 18;
-    left_margin = 22;
-    height -= 2;
-    if (unique_id == 0x80000176)
-      adobe_coeff ("Canon","EOS 450D");
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 4352) {
-    top_margin  = 18;
-    left_margin = 62;
-    if (unique_id == 0x80000288)
-      adobe_coeff ("Canon","EOS 1100D");
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 4476) {
-    top_margin  = 34;
-    left_margin = 90;
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 4480) {
-    height = 3326;
-    width  = 4432;
-    top_margin  = 10;
-    left_margin = 12;
-    filters = 0x49494949;
-  } else if (is_canon && raw_width == 4496) {
-    height = 3316;
-    width  = 4404;
-    top_margin  = 50;
-    left_margin = 80;
-  } else if (is_canon && raw_width == 4832) {
-    top_margin = unique_id == 0x80000261 ? 51:26;
-    left_margin = 62;
-    if (unique_id == 0x80000252)
-      adobe_coeff ("Canon","EOS 500D");
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 5108) {
-    top_margin  = 13;
-    left_margin = 98;
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 5120) {
-    height -= top_margin = 45;
-    left_margin = 142;
-    width = 4916;
-  } else if (is_canon && raw_width == 5280) {
-    top_margin  = 52;
-    left_margin = 72;
-    if (unique_id == 0x80000301)
-      adobe_coeff ("Canon","EOS 650D");
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 5344) {
-    top_margin = 51;
-    left_margin = 142;
-    if (unique_id == 0x80000269) {
-      top_margin = 100;
-      left_margin = 126;
-      height -= 2;
-      adobe_coeff ("Canon","EOS-1D X");
-    }
-    if (unique_id == 0x80000270)
-      adobe_coeff ("Canon","EOS 550D");
-    if (unique_id == 0x80000286)
-      adobe_coeff ("Canon","EOS 600D");
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 5360) {
-    top_margin = 51;
-    left_margin = 158;
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 5568) {
-    top_margin = 38;
-    left_margin = 72;
-    goto canon_cr2;
-  } else if (is_canon && raw_width == 5712) {
-    height = 3752;
-    width  = 5640;
-    top_margin  = 20;
-    left_margin = 62;
-  } else if (is_canon && raw_width == 5792) {
-    top_margin  = 51;
-    left_margin = 158;
-canon_cr2:
-    height -= top_margin;
-    width  -= left_margin;
-  } else if (is_canon && raw_width == 5920) {
-    height = 3870;
-    width  = 5796;
-    top_margin  = 80;
-    left_margin = 122;
   } else if (!strcmp(model,"D1")) {
     cam_mul[0] *= 256/527.0;
     cam_mul[2] *= 256/317.0;
@@ -7882,13 +8857,15 @@ canon_cr2:
             !strcmp(model,"D90")) {
     width -= 42;
   } else if (!strcmp(model,"D5100") ||
-            !strcmp(model,"D7000")) {
+            !strcmp(model,"D7000") ||
+            !strcmp(model,"COOLPIX A")) {
     width -= 44;
   } else if (!strcmp(model,"D3200") ||
-            !strcmp(model,"D600")  ||
-            !strcmp(model,"D800")) {
+           !strncmp(model,"D6",2)  ||
+           !strncmp(model,"D800",4)) {
     width -= 46;
-  } else if (!strcmp(model,"D4")) {
+  } else if (!strcmp(model,"D4") ||
+            !strcmp(model,"Df")) {
     width -= 52;
     left_margin = 2;
   } else if (!strncmp(model,"D40",3) ||
@@ -7910,9 +8887,7 @@ canon_cr2:
     else width -= 8;
   } else if (!strncmp(model,"D300",4)) {
     width -= 32;
-  } else if (!strcmp(make,"NIKON") && raw_width == 4032) {
-    adobe_coeff ("NIKON","COOLPIX P7700");
-  } else if (!strncmp(model,"COOLPIX P",9)) {
+  } else if (!strncmp(model,"COOLPIX P",9) && raw_width != 4032) {
     load_flags = 24;
     filters = 0x94949494;
     if (model[9] == '7' && iso_speed >= 400)
@@ -7920,35 +8895,14 @@ canon_cr2:
   } else if (!strncmp(model,"1 ",2)) {
     height -= 2;
   } else if (fsize == 1581060) {
-    height = 963;
-    width = 1287;
-    raw_width = 1632;
-    maximum = 0x3f4;
-    colors = 4;
-    filters = 0x1e1e1e1e;
     simple_coeff(3);
     pre_mul[0] = 1.2085;
     pre_mul[1] = 1.0943;
     pre_mul[3] = 1.1103;
-    goto e900;
-  } else if (fsize == 2465792) {
-    height = 1203;
-    width  = 1616;
-    raw_width = 2048;
-    colors = 4;
-    filters = 0x4b4b4b4b;
-    adobe_coeff ("NIKON","E950");
-e900:
-    tiff_bps = 10;
-    load_raw = &CLASS packed_load_raw;
-    load_flags = 6;
+  } else if (fsize == 3178560) {
+    cam_mul[0] *= 4;
+    cam_mul[2] *= 4;
   } else if (fsize == 4771840) {
-    height = 1540;
-    width  = 2064;
-    colors = 4;
-    filters = 0xe1e1e1e1;
-    load_raw = &CLASS packed_load_raw;
-    load_flags = 6;
     if (!timestamp && nikon_e995())
       strcpy (model, "E995");
     if (strcmp(model,"E995")) {
@@ -7958,23 +8912,16 @@ e900:
       pre_mul[1] = 1.246;
       pre_mul[2] = 1.018;
     }
-  } else if (!strcmp(model,"E2100")) {
-    if (!timestamp && !nikon_e2100()) goto cp_e2500;
-    height = 1206;
-    width  = 1616;
-    load_flags = 30;
-  } else if (!strcmp(model,"E2500")) {
-cp_e2500:
-    strcpy (model, "E2500");
-    height = 1204;
-    width  = 1616;
-    colors = 4;
-    filters = 0x4b4b4b4b;
+  } else if (fsize == 2940928) {
+    if (!timestamp && !nikon_e2100())
+      strcpy (model,"E2500");
+    if (!strcmp(model,"E2500")) {
+      height -= 2;
+      load_flags = 6;
+      colors = 4;
+      filters = 0x4b4b4b4b;
+    }
   } else if (fsize == 4775936) {
-    height = 1542;
-    width  = 2064;
-    load_raw = &CLASS packed_load_raw;
-    load_flags = 30;
     if (!timestamp) nikon_3700();
     if (model[0] == 'E' && atoi(model+1) < 3700)
       filters = 0x49494949;
@@ -7992,32 +8939,21 @@ cp_e2500:
       if (i < 0) filters = 0x61616161;
     }
   } else if (fsize == 5869568) {
-    height = 1710;
-    width  = 2288;
-    filters = 0x16161616;
     if (!timestamp && minolta_z2()) {
       strcpy (make, "Minolta");
       strcpy (model,"DiMAGE Z2");
     }
-    load_raw = &CLASS packed_load_raw;
     load_flags = 6 + 24*(make[0] == 'M');
-  } else if (!strcmp(model,"E4500")) {
-    height = 1708;
-    width  = 2288;
-    colors = 4;
-    filters = 0xb4b4b4b4;
-  } else if (fsize == 7438336) {
-    height = 1924;
-    width  = 2576;
-    colors = 4;
-    filters = 0xb4b4b4b4;
-  } else if (fsize == 8998912) {
-    height = 2118;
-    width  = 2832;
-    maximum = 0xf83;
-    load_raw = &CLASS packed_load_raw;
-    load_flags = 30;
-  } else if (!strcmp(make,"FUJIFILM")) {
+  } else if (fsize == 6291456) {
+    fseek (ifp, 0x300000, SEEK_SET);
+    if ((order = guess_byte_order(0x10000)) == 0x4d4d) {
+      height -= (top_margin = 16);
+      width -= (left_margin = 28);
+      maximum = 0xf5c0;
+      strcpy (make, "ISG");
+      model[0] = 0;
+    }
+  } else if (!strcmp(make,"Fujifilm")) {
     if (!strcmp(model+7,"S2Pro")) {
       strcpy (model,"S2Pro");
       height = 2144;
@@ -8027,22 +8963,20 @@ cp_e2500:
       maximum = (is_raw == 2 && shot_select) ? 0x2f00 : 0x3e00;
     top_margin = (raw_height - height) >> 2 << 1;
     left_margin = (raw_width - width ) >> 2 << 1;
-    if (width == 2848) filters = 0x16161616;
-    if (width == 3328) {
-      width = 3262;
-      left_margin = 34;
-    }
-    if (width == 4952) {
+    if (width == 2848 || width == 3664) filters = 0x16161616;
+    if (width == 4032 || width == 4952 || width == 6032) left_margin = 0;
+    if (width == 3328 && (width -= 66)) left_margin = 34;
+    if (width == 4936) left_margin = 4;
+    if (!strcmp(model,"HS50EXR") ||
+       !strcmp(model,"F900EXR")) {
+      width += 2;
       left_margin = 0;
-      filters = 2;
+      filters = 0x16161616;
     }
     if (fuji_layout) raw_width *= is_raw;
-  } else if (!strcmp(model,"RD175")) {
-    height = 986;
-    width = 1534;
-    data_offset = 513;
-    filters = 0x61616161;
-    load_raw = &CLASS minolta_rd175_load_raw;
+    if (filters == 9)
+      FORC(36) ((char *)xtrans)[c] =
+       xtrans_abs[(c/6+top_margin) % 6][(c+left_margin) % 6];
   } else if (!strcmp(model,"KD-400Z")) {
     height = 1712;
     width  = 2312;
@@ -8050,9 +8984,9 @@ cp_e2500:
     goto konica_400z;
   } else if (!strcmp(model,"KD-510Z")) {
     goto konica_510z;
-  } else if (!strcasecmp(make,"MINOLTA")) {
-    load_raw = &CLASS unpacked_load_raw;
-    maximum = 0xfff;
+  } else if (!strcasecmp(make,"Minolta")) {
+    if (!load_raw && (maximum = 0xfff))
+      load_raw = &CLASS unpacked_load_raw;
     if (!strncmp(model,"DiMAGE A",8)) {
       if (!strcmp(model,"DiMAGE A200"))
        filters = 0x49494949;
@@ -8089,54 +9023,31 @@ konica_400z:
     data_error = -1;
   } else if (!strcmp(model,"*ist DS")) {
     height -= 2;
-  } else if (!strcmp(model,"Optio S")) {
-    if (fsize == 3178560) {
-      height = 1540;
-      width  = 2064;
-      load_raw = &CLASS eight_bit_load_raw;
-      cam_mul[0] *= 4;
-      cam_mul[2] *= 4;
-    } else {
-      height = 1544;
-      width  = 2068;
-      raw_width = 3136;
-      load_raw = &CLASS packed_load_raw;
-      maximum = 0xf7c;
-    }
-  } else if (fsize == 6114240) {
-    height = 1737;
-    width  = 2324;
-    raw_width = 3520;
-    load_raw = &CLASS packed_load_raw;
-    maximum = 0xf7a;
-  } else if (!strcmp(model,"Optio 750Z")) {
-    height = 2302;
-    width  = 3072;
-    load_raw = &CLASS packed_load_raw;
-    load_flags = 30;
-  } else if (!strcmp(model,"DC-833m")) {
-    height = 2448;
-    width  = 3264;
-    order = 0x4949;
-    filters = 0x61616161;
-    load_raw = &CLASS unpacked_load_raw;
-    maximum = 0xfc00;
-  } else if (!strncmp(model,"S85",3)) {
-    height = 2448;
-    width  = 3264;
-    raw_width = fsize/height/2;
-    order = 0x4d4d;
-    load_raw = &CLASS unpacked_load_raw;
-  } else if (!strcmp(make,"SAMSUNG") && raw_width == 4704) {
+  } else if (!strcmp(make,"Samsung") && raw_width == 4704) {
     height -= top_margin = 8;
     width -= 2 * (left_margin = 8);
     load_flags = 32;
-  } else if (!strcmp(make,"SAMSUNG") && raw_width == 5632) {
+  } else if (!strcmp(make,"Samsung") && raw_height == 3714) {
+    height -= top_margin = 18;
+    left_margin = raw_width - (width = 5536);
+    if (raw_width != 5600)
+      left_margin = top_margin = 0;
+    filters = 0x61616161;
+    colors = 3;
+  } else if (!strcmp(make,"Samsung") && raw_width == 5632) {
     order = 0x4949;
     height = 3694;
     top_margin = 2;
     width  = 5574 - (left_margin = 32 + tiff_bps);
     if (tiff_bps == 12) load_flags = 80;
+  } else if (!strcmp(make,"Samsung") && raw_width == 5664) {
+    height -= top_margin = 17;
+    left_margin = 96;
+    width = 5544;
+    filters = 0x49494949;
+  } else if (!strcmp(make,"Samsung") && raw_width == 6496) {
+    filters = 0x61616161;
+    black = 1 << (tiff_bps - 7);
   } else if (!strcmp(model,"EX1")) {
     order = 0x4949;
     height -= 20;
@@ -8155,19 +9066,8 @@ konica_400z:
       width  -= 56;
       top_margin = 8;
     }
-  } else if (fsize == 20487168) {
-    height = 2808;
-    width  = 3648;
-    goto wb550;
-  } else if (fsize == 24000000) {
-    height = 3000;
-    width  = 4000;
-wb550:
+  } else if (strstr(model,"WB550")) {
     strcpy (model, "WB550");
-    order = 0x4d4d;
-    load_raw = &CLASS unpacked_load_raw;
-    load_flags = 6;
-    maximum = 0x3df;
   } else if (!strcmp(model,"EX2F")) {
     height = 3045;
     width  = 4070;
@@ -8176,85 +9076,11 @@ wb550:
     filters = 0x49494949;
     load_raw = &CLASS unpacked_load_raw;
   } else if (!strcmp(model,"STV680 VGA")) {
-    height = 484;
-    width  = 644;
-    load_raw = &CLASS eight_bit_load_raw;
-    flip = 2;
-    filters = 0x16161616;
     black = 16;
   } else if (!strcmp(model,"N95")) {
     height = raw_height - (top_margin = 2);
-  } else if (!strcmp(model,"531C")) {
-    height = 1200;
-    width  = 1600;
-    load_raw = &CLASS unpacked_load_raw;
-    filters = 0x49494949;
   } else if (!strcmp(model,"640x480")) {
-    height = 480;
-    width  = 640;
-    load_raw = &CLASS eight_bit_load_raw;
     gamma_curve (0.45, 4.5, 1, 255);
-  } else if (!strcmp(model,"F-080C")) {
-    height = 768;
-    width  = 1024;
-    load_raw = &CLASS eight_bit_load_raw;
-  } else if (!strcmp(model,"F-145C")) {
-    height = 1040;
-    width  = 1392;
-    load_raw = &CLASS eight_bit_load_raw;
-  } else if (!strcmp(model,"F-201C")) {
-    height = 1200;
-    width  = 1600;
-    load_raw = &CLASS eight_bit_load_raw;
-  } else if (!strcmp(model,"F-510C")) {
-    height = 1958;
-    width  = 2588;
-    load_raw = fsize < 7500000 ?
-       &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw;
-    data_offset = fsize - width*height*(fsize >> 22);
-    maximum = 0xfff0;
-  } else if (!strcmp(model,"F-810C")) {
-    height = 2469;
-    width  = 3272;
-    load_raw = &CLASS unpacked_load_raw;
-    maximum = 0xfff0;
-  } else if (!strcmp(model,"XCD-SX910CR")) {
-    height = 1024;
-    width  = 1375;
-    raw_width = 1376;
-    filters = 0x49494949;
-    maximum = 0x3ff;
-    load_raw = fsize < 2000000 ?
-       &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw;
-  } else if (!strcmp(model,"2010")) {
-    height = 1207;
-    width  = 1608;
-    order = 0x4949;
-    filters = 0x16161616;
-    data_offset = 3212;
-    maximum = 0x3ff;
-    load_raw = &CLASS unpacked_load_raw;
-  } else if (!strcmp(model,"A782")) {
-    height = 3000;
-    width  = 2208;
-    filters = 0x61616161;
-    load_raw = fsize < 10000000 ?
-       &CLASS eight_bit_load_raw : &CLASS unpacked_load_raw;
-    maximum = 0xffc0;
-  } else if (!strcmp(model,"3320AF")) {
-    height = 1536;
-    raw_width = width = 2048;
-    filters = 0x61616161;
-    load_raw = &CLASS unpacked_load_raw;
-    maximum = 0x3ff;
-    fseek (ifp, 0x300000, SEEK_SET);
-    if ((order = guess_byte_order(0x10000)) == 0x4d4d) {
-      height -= (top_margin = 16);
-      width -= (left_margin = 28);
-      maximum = 0xf5c0;
-      strcpy (make, "ISG");
-      model[0] = 0;
-    }
   } else if (!strcmp(make,"Hasselblad")) {
     if (load_raw == &CLASS lossless_jpeg_load_raw)
       load_raw = &CLASS hasselblad_load_raw;
@@ -8264,9 +9090,9 @@ wb550:
       top_margin  = 4;
       left_margin = 7;
       filters = 0x61616161;
-    } else if (raw_width == 7410) {
-      height = 5502;
-      width  = 7328;
+    } else if (raw_width == 7410 || raw_width == 8282) {
+      height -= 84;
+      width  -= 82;
       top_margin  = 4;
       left_margin = 41;
       filters = 0x61616161;
@@ -8283,15 +9109,13 @@ wb550:
       width -= (left_margin = 3) + 7;
       filters = 0x61616161;
     }
-  } else if (!strcmp(make,"Sinar")) {
-    if (!memcmp(head,"8BPS",4)) {
-      fseek (ifp, 14, SEEK_SET);
-      height = get4();
-      width  = get4();
-      filters = 0x61616161;
-      data_offset = 68;
+    if (tiff_samples > 1) {
+      is_raw = tiff_samples+1;
+      if (!shot_select && !half_size) filters = 0;
     }
+  } else if (!strcmp(make,"Sinar")) {
     if (!load_raw) load_raw = &CLASS unpacked_load_raw;
+    if (is_raw > 1 && !shot_select && !half_size) filters = 0;
     maximum = 0x3fff;
   } else if (!strcmp(make,"Leaf")) {
     maximum = 0x3fff;
@@ -8335,7 +9159,7 @@ wb550:
       width -= 2 * (left_margin = 24);
       filters = 0x16161616;
     }
-  } else if (!strcmp(make,"LEICA") || !strcmp(make,"Panasonic")) {
+  } else if (!strcmp(make,"Leica") || !strcmp(make,"Panasonic")) {
     if ((flen - data_offset) / (raw_width*8/7) == raw_height)
       load_raw = &CLASS panasonic_load_raw;
     if (!load_raw) {
@@ -8359,11 +9183,12 @@ wb550:
     filters = 0x16161616;
     load_raw = &CLASS packed_load_raw;
     load_flags = 30;
-  } else if (!strcmp(make,"OLYMPUS")) {
+  } else if (!strcmp(make,"Olympus")) {
     height += height & 1;
-    filters = exif_cfa;
+    if (exif_cfa) filters = exif_cfa;
     if (width == 4100) width -= 4;
     if (width == 4080) width -= 24;
+    if (width == 9280) { width -= 6; height -= 6; }
     if (load_raw == &CLASS unpacked_load_raw)
       load_flags = 4;
     tiff_bps = 12;
@@ -8382,9 +9207,8 @@ wb550:
       thumb_length = flen - (thumb_offset = 0xa39800);
       thumb_height = 480;
       thumb_width  = 640;
-    } else if (!strcmp(model,"XZ-2")) {
-      load_raw = &CLASS packed_load_raw;
-      load_flags = 24;
+    } else if (!strcmp(model,"TG-4")) {
+      width -= 16;
     }
   } else if (!strcmp(model,"N Digital")) {
     height = 2047;
@@ -8407,95 +9231,78 @@ wb550:
     mask[0][1] = 9;
     data_offset = 787392;
     load_raw = &CLASS sony_load_raw;
-  } else if (!strcmp(make,"SONY") && raw_width == 3984) {
-    adobe_coeff ("SONY","DSC-R1");
+  } else if (!strcmp(make,"Sony") && raw_width == 3984) {
     width = 3925;
     order = 0x4d4d;
-  } else if (!strcmp(make,"SONY") && raw_width == 5504) {
-    width -= 8;
-  } else if (!strcmp(make,"SONY") && raw_width == 6048) {
+  } else if (!strcmp(make,"Sony") && raw_width == 4288) {
+    width -= 32;
+  } else if (!strcmp(make,"Sony") && raw_width == 4600) {
+    if (!strcmp(model,"DSLR-A350"))
+      height -= 4;
+    black = 0;
+  } else if (!strcmp(make,"Sony") && raw_width == 4928) {
+    if (height < 3280) width -= 8;
+  } else if (!strcmp(make,"Sony") && raw_width == 5504) {
+    width -= height > 3664 ? 8 : 32;
+    if (!strncmp(model,"DSC",3))
+      black = 200 << (tiff_bps - 12);
+  } else if (!strcmp(make,"Sony") && raw_width == 6048) {
     width -= 24;
+    if (strstr(model,"RX1") || strstr(model,"A99"))
+      width -= 6;
+  } else if (!strcmp(make,"Sony") && raw_width == 7392) {
+    width -= 30;
+  } else if (!strcmp(make,"Sony") && raw_width == 8000) {
+    width -= 32;
+    if (!strncmp(model,"DSC",3)) {
+      tiff_bps = 14;
+      load_raw = &CLASS unpacked_load_raw;
+      black = 512;
+    }
   } else if (!strcmp(model,"DSLR-A100")) {
     if (width == 3880) {
       height--;
       width = ++raw_width;
     } else {
+      height -= 4;
+      width  -= 4;
       order = 0x4d4d;
       load_flags = 2;
     }
     filters = 0x61616161;
-  } else if (!strcmp(model,"DSLR-A350")) {
-    height -= 4;
   } else if (!strcmp(model,"PIXL")) {
     height -= top_margin = 4;
     width -= left_margin = 32;
     gamma_curve (0, 7, 1, 255);
-  } else if (!strcmp(model,"C603v")) {
-    height = 480;
-    width  = 640;
-    if (fsize < 614400 || find_green (16, 16, 3840, 5120) < 25) goto c603v;
-    strcpy (model,"KAI-0340");
-    height -= 3;
-    data_offset = 3840;
+  } else if (!strcmp(model,"C603") || !strcmp(model,"C330")
+       || !strcmp(model,"12MP")) {
     order = 0x4949;
-    load_raw = &CLASS unpacked_load_raw;
-  } else if (!strcmp(model,"C603y")) {
-    height = 2134;
-    width  = 2848;
-c603v:
-    filters = 0;
-    load_raw = &CLASS kodak_yrgb_load_raw;
-    gamma_curve (0, 3.875, 1, 255);
-  } else if (!strcmp(model,"C603")) {
-    raw_height = height = 2152;
-    raw_width  = width  = 2864;
-    goto c603;
-  } else if (!strcmp(model,"C330")) {
-    height = 1744;
-    width  = 2336;
-    raw_height = 1779;
-    raw_width  = 2338;
-    top_margin = 33;
-    left_margin = 1;
-c603:
-    order = 0x4949;
-    if ((data_offset = fsize - raw_height*raw_width)) {
-      fseek (ifp, 168, SEEK_SET);
+    if (filters && data_offset) {
+      fseek (ifp, data_offset < 4096 ? 168 : 5252, SEEK_SET);
       read_shorts (curve, 256);
     } else gamma_curve (0, 3.875, 1, 255);
-    load_raw = &CLASS eight_bit_load_raw;
+    load_raw  =  filters   ? &CLASS eight_bit_load_raw :
+      strcmp(model,"C330") ? &CLASS kodak_c603_load_raw :
+                            &CLASS kodak_c330_load_raw;
+    load_flags = tiff_bps > 16;
+    tiff_bps = 8;
   } else if (!strncasecmp(model,"EasyShare",9)) {
     data_offset = data_offset < 0x15000 ? 0x15000 : 0x17000;
     load_raw = &CLASS packed_load_raw;
-  } else if (!strcasecmp(make,"KODAK")) {
+  } else if (!strcasecmp(make,"Kodak")) {
     if (filters == UINT_MAX) filters = 0x61616161;
-    if (!strncmp(model,"NC2000",6)) {
-      width -= 4;
-      left_margin = 2;
-    } else if (!strcmp(model,"EOSDCS3B")) {
-      width -= 4;
-      left_margin = 2;
-    } else if (!strcmp(model,"EOSDCS1")) {
-      width -= 4;
-      left_margin = 2;
-    } else if (!strcmp(model,"DCS420")) {
-      width -= 4;
-      left_margin = 2;
-    } else if (!strncmp(model,"DCS460 ",7)) {
-      model[6] = 0;
-      width -= 4;
-      left_margin = 2;
-    } else if (!strcmp(model,"DCS460A")) {
+    if (!strncmp(model,"NC2000",6) ||
+       !strncmp(model,"EOSDCS",6) ||
+       !strncmp(model,"DCS4",4)) {
       width -= 4;
       left_margin = 2;
-      colors = 1;
-      filters = 0;
+      if (model[6] == ' ') model[6] = 0;
+      if (!strcmp(model,"DCS460A")) goto bw;
     } else if (!strcmp(model,"DCS660M")) {
       black = 214;
-      colors = 1;
-      filters = 0;
+      goto bw;
     } else if (!strcmp(model,"DCS760M")) {
-      colors = 1;
+bw:   colors = 1;
       filters = 0;
     }
     if (!strcmp(model+4,"20X"))
@@ -8505,7 +9312,7 @@ c603:
       data_offset = 15424;
     }
     if (!strncmp(model,"DC2",3)) {
-      raw_height = height = 242;
+      raw_height = 2 + (height = 242);
       if (flen < 100000) {
        raw_width = 256; width = 249;
        pixel_aspect = (4.0*height) / (3.0*width);
@@ -8513,7 +9320,7 @@ c603:
        raw_width = 512; width = 501;
        pixel_aspect = (493.0*height) / (373.0*width);
       }
-      data_offset += raw_width + 1;
+      top_margin = left_margin = 1;
       colors = 4;
       filters = 0x8d8d8d8d;
       simple_coeff(1);
@@ -8527,6 +9334,7 @@ c603:
       width  = 768;
       data_offset = 1152;
       load_raw = &CLASS kodak_radc_load_raw;
+      tiff_bps = 12;
     } else if (strstr(model,"DC50")) {
       strcpy (model, "DC50");
       height = 512;
@@ -8546,10 +9354,6 @@ c603:
       thumb_offset = 6144;
       thumb_misc   = 360;
       write_thumb = &CLASS layer_thumb;
-      height = 1024;
-      width  = 1536;
-      data_offset = 79872;
-      load_raw = &CLASS eight_bit_load_raw;
       black = 17;
     }
   } else if (!strcmp(model,"Fotoman Pixtura")) {
@@ -8587,118 +9391,10 @@ c603:
     }
     filters = 0x16161616;
     load_raw = &CLASS rollei_load_raw;
-  } else if (!strcmp(model,"PC-CAM 600")) {
-    height = 768;
-    data_offset = width = 1024;
-    filters = 0x49494949;
-    load_raw = &CLASS eight_bit_load_raw;
-  } else if (!strcmp(model,"QV-2000UX")) {
-    height = 1208;
-    width  = 1632;
-    data_offset = width * 2;
-    load_raw = &CLASS eight_bit_load_raw;
-  } else if (fsize == 3217760) {
-    height = 1546;
-    width  = 2070;
-    raw_width = 2080;
-    load_raw = &CLASS eight_bit_load_raw;
-  } else if (!strcmp(model,"QV-4000")) {
-    height = 1700;
-    width  = 2260;
-    load_raw = &CLASS unpacked_load_raw;
-    maximum = 0xffff;
-  } else if (!strcmp(model,"QV-5700")) {
-    height = 1924;
-    width  = 2576;
-    raw_width = 3232;
-    tiff_bps = 10;
-  } else if (!strcmp(model,"QV-R41")) {
-    height = 1720;
-    width  = 2312;
-    raw_width = 3520;
-    left_margin = 2;
-  } else if (!strcmp(model,"QV-R51")) {
-    height = 1926;
-    width  = 2580;
-    raw_width = 3904;
-  } else if (!strcmp(model,"EX-S20")) {
-    height = 1208;
-    width  = 1620;
-    raw_width = 2432;
-    flip = 3;
-  } else if (!strcmp(model,"EX-S100")) {
-    height = 1544;
-    width  = 2058;
-    raw_width = 3136;
-  } else if (!strcmp(model,"EX-Z50")) {
-    height = 1931;
-    width  = 2570;
-    raw_width = 3904;
-  } else if (!strcmp(model,"EX-Z500")) {
-    height = 1937;
-    width  = 2577;
-    raw_width = 3904;
-    filters = 0x16161616;
-  } else if (!strcmp(model,"EX-Z55")) {
-    height = 1960;
-    width  = 2570;
-    raw_width = 3904;
-  } else if (!strcmp(model,"EX-Z60")) {
-    height = 2145;
-    width  = 2833;
-    raw_width = 3584;
-    filters = 0x16161616;
-    tiff_bps = 10;
-  } else if (!strcmp(model,"EX-Z75")) {
-    height = 2321;
-    width  = 3089;
-    raw_width = 4672;
-    maximum = 0xfff;
-  } else if (!strcmp(model,"EX-Z750")) {
-    height = 2319;
-    width  = 3087;
-    raw_width = 4672;
-    maximum = 0xfff;
-  } else if (!strcmp(model,"EX-Z850")) {
-    height = 2468;
-    width  = 3279;
-    raw_width = 4928;
-    maximum = 0xfff;
-  } else if (!strcmp(model,"EX-Z8")) {
-    height = 2467;
-    width  = 3281;
-    raw_height = 2502;
-    raw_width  = 4992;
-    maximum = 0xfff;
-  } else if (fsize == 15499264) {      /* EX-Z1050 or EX-Z1080 */
-    height = 2752;
-    width  = 3672;
-    raw_width = 5632;
-  } else if (!strcmp(model,"EX-ZR100")) {
-    height = 3044;
-    width  = 4072;
-    raw_width = 4096;
-    load_flags = 80;
-  } else if (!strcmp(model,"EX-P505")) {
-    height = 1928;
-    width  = 2568;
-    raw_width = 3852;
-    maximum = 0xfff;
-  } else if (fsize == 9313536) {       /* EX-P600 or QV-R61 */
-    height = 2142;
-    width  = 2844;
-    raw_width = 4288;
-  } else if (!strcmp(model,"EX-P700")) {
-    height = 2318;
-    width  = 3082;
-    raw_width = 4672;
   }
   if (!model[0])
     sprintf (model, "%dx%d", width, height);
   if (filters == UINT_MAX) filters = 0x94949494;
-  if (raw_color) adobe_coeff (make, model);
-  if (load_raw == &CLASS kodak_radc_load_raw)
-    if (raw_color) adobe_coeff ("Apple","Quicktake");
   if (thumb_offset && !thumb_height) {
     fseek (ifp, thumb_offset, SEEK_SET);
     if (ljpeg_start (&jh, 1)) {
@@ -8707,9 +9403,17 @@ c603:
     }
   }
 dng_skip:
+  if ((use_camera_matrix & (use_camera_wb || dng_version))
+       && cmatrix[0][0] > 0.125) {
+    memcpy (rgb_cam, cmatrix, sizeof cmatrix);
+    raw_color = 0;
+  }
+  if (raw_color) adobe_coeff (make, model);
+  if (load_raw == &CLASS kodak_radc_load_raw)
+    if (raw_color) adobe_coeff ("Apple","Quicktake");
   if (fuji_width) {
     fuji_width = width >> !fuji_layout;
-    if (~fuji_width & 1) filters = 0x49494949;
+    filters = fuji_width & 1 ? 0x94949494 : 0x49494949;
     width = (height >> fuji_layout) + fuji_width;
     height = width - 1;
     pixel_aspect = 1;
@@ -8719,7 +9423,9 @@ dng_skip:
   }
   if (!tiff_bps) tiff_bps = 12;
   if (!maximum) maximum = (1 << tiff_bps) - 1;
-  if (!load_raw || height < 22) is_raw = 0;
+  if (!load_raw || height < 22 || width < 22 ||
+       tiff_bps > 16 || tiff_samples > 6 || colors > 4)
+    is_raw = 0;
 #ifdef NO_JASPER
   if (load_raw == &CLASS redcine_load_raw) {
     fprintf (stderr,_("%s: You must link dcraw with %s!!\n"),
@@ -8739,21 +9445,18 @@ dng_skip:
     strcpy (cdesc, colors == 3 ? "RGBG":"GMCY");
   if (!raw_height) raw_height = height;
   if (!raw_width ) raw_width  = width;
-  if (filters && colors == 3)
+  if (filters > 999 && colors == 3)
     filters |= ((filters >> 2 & 0x22222222) |
                (filters << 2 & 0x88888888)) & filters << 1;
 notraw:
-  if (flip == -1) flip = tiff_flip;
-  if (flip == -1) flip = 0;
-
-
-
+  if (flip == UINT_MAX) flip = tiff_flip;
+  if (flip == UINT_MAX) flip = 0;
 
 // CINELERRA
   if (flip & 4)
-       sprintf(dcraw_info, "%d %d", height, width);
+        sprintf(dcraw_info, "%d %d", height, width);
   else
-       sprintf(dcraw_info, "%d %d", width, height);
+        sprintf(dcraw_info, "%d %d", width, height);
 }
 
 #ifndef NO_LCMS
@@ -8765,7 +9468,6 @@ void CLASS apply_profile (const char *input, const char *output)
   FILE *fp;
   unsigned size;
 
-  cmsErrorAction (LCMS_ERROR_SHOW);
   if (strcmp (input, "embed"))
     hInProfile = cmsOpenProfileFromFile (input, "r");
   else if (profile_length) {
@@ -8831,10 +9533,14 @@ void CLASS convert_to_rgb()
   { { 0.529317, 0.330092, 0.140588 },
     { 0.098368, 0.873465, 0.028169 },
     { 0.016879, 0.117663, 0.865457 } };
+  static const double aces_rgb[3][3] =
+  { { 0.432996, 0.375380, 0.189317 },
+    { 0.089427, 0.816523, 0.102989 },
+    { 0.019165, 0.118150, 0.941914 } };
   static const double (*out_rgb[])[3] =
-  { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb };
+  { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb, aces_rgb };
   static const char *name[] =
-  { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ" };
+  { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ", "ACES" };
   static const unsigned phead[] =
   { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0,
     0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d };
@@ -8855,7 +9561,7 @@ void CLASS convert_to_rgb()
   gamma_curve (gamm[0], gamm[1], 0, 0);
   memcpy (out_cam, rgb_cam, sizeof out_cam);
   raw_color |= colors == 1 || document_mode ||
-               output_color < 1 || output_color > 5;
+               output_color < 1 || output_color > 6;
   if (!raw_color) {
     oprof = (unsigned *) calloc (phead[0], 1);
     merror (oprof, "convert_to_rgb()");
@@ -8912,18 +9618,15 @@ void CLASS convert_to_rgb()
   if (colors == 4 && output_color) colors = 3;
   if (document_mode && filters) colors = 1;
 
-
-
-
 // CINELERRA
 // Export color matrix to Cinelerra.
 // It can't be applied before interpolation.
-k = 0;
-for(i = 0; i < 3; i++)
-{
-       for(j = 0; j < 3; j++)
-               dcraw_matrix[k++] = rgb_cam[i][j];
-}
+  k = 0;
+  for(i = 0; i < 3; i++) {
+    for(j = 0; j < 3; j++)
+       dcraw_matrix[k++] = rgb_cam[i][j];
+  }
+
 }
 
 void CLASS fuji_rotate()
@@ -8941,7 +9644,7 @@ void CLASS fuji_rotate()
   step = sqrt(0.5);
   wide = fuji_width / step;
   high = (height - fuji_width) / step;
-  img = (ushort (*)[4]) calloc (wide*high, sizeof *img);
+  img = (ushort (*)[4]) calloc (high, wide*sizeof *img);
   merror (img, "fuji_rotate()");
 
   for (row=0; row < high; row++)
@@ -8974,7 +9677,7 @@ void CLASS stretch()
   if (verbose) fprintf (stderr,_("Stretching the image...\n"));
   if (pixel_aspect < 1) {
     newdim = height / pixel_aspect + 0.5;
-    img = (ushort (*)[4]) calloc (width*newdim, sizeof *img);
+    img = (ushort (*)[4]) calloc (width, newdim*sizeof *img);
     merror (img, "stretch()");
     for (rc=row=0; row < newdim; row++, rc+=pixel_aspect) {
       frac = rc - (c = rc);
@@ -8986,7 +9689,7 @@ void CLASS stretch()
     height = newdim;
   } else {
     newdim = width * pixel_aspect + 0.5;
-    img = (ushort (*)[4]) calloc (height*newdim, sizeof *img);
+    img = (ushort (*)[4]) calloc (height, newdim*sizeof *img);
     merror (img, "stretch()");
     for (rc=col=0; col < newdim; col++, rc+=1/pixel_aspect) {
       frac = rc - (c = rc);
@@ -9031,21 +9734,25 @@ struct tiff_hdr {
   char desc[512], make[64], model[64], soft[32], date[20], artist[64];
 };
 
-void CLASS tiff_set (ushort *ntag,
+void CLASS tiff_set (struct tiff_hdr *th, ushort *ntag,
        ushort tag, ushort type, int count, int val)
 {
   struct tiff_tag *tt;
   int c;
 
   tt = (struct tiff_tag *)(ntag+1) + (*ntag)++;
-  tt->tag = tag;
-  tt->type = type;
-  tt->count = count;
-  if (type < 3 && count <= 4)
+  tt->val.i = val;
+  if (type == 1 && count <= 4)
     FORC(4) tt->val.c[c] = val >> (c << 3);
-  else if (type == 3 && count <= 2)
+  else if (type == 2) {
+    count = strnlen((char *)th + val, count-1) + 1;
+    if (count <= 4)
+      FORC(4) tt->val.c[c] = ((char *)th)[val+c];
+  } else if (type == 3 && count <= 2)
     FORC(2) tt->val.s[c] = val >> (c << 4);
-  else tt->val.i = val;
+  tt->count = count;
+  tt->type = type;
+  tt->tag = tag;
 }
 
 #define TOFF(ptr) ((char *)(&(ptr)) - (char *)th)
@@ -9059,55 +9766,6 @@ void CLASS tiff_head (struct tiff_hdr *th, int full)
   th->order = htonl(0x4d4d4949) >> 16;
   th->magic = 42;
   th->ifd = 10;
-  if (full) {
-    tiff_set (&th->ntag, 254, 4, 1, 0);
-    tiff_set (&th->ntag, 256, 4, 1, width);
-    tiff_set (&th->ntag, 257, 4, 1, height);
-    tiff_set (&th->ntag, 258, 3, colors, output_bps);
-    if (colors > 2)
-      th->tag[th->ntag-1].val.i = TOFF(th->bps);
-    FORC4 th->bps[c] = output_bps;
-    tiff_set (&th->ntag, 259, 3, 1, 1);
-    tiff_set (&th->ntag, 262, 3, 1, 1 + (colors > 1));
-  }
-  tiff_set (&th->ntag, 270, 2, 512, TOFF(th->desc));
-  tiff_set (&th->ntag, 271, 2, 64, TOFF(th->make));
-  tiff_set (&th->ntag, 272, 2, 64, TOFF(th->model));
-  if (full) {
-    if (oprof) psize = ntohl(oprof[0]);
-    tiff_set (&th->ntag, 273, 4, 1, sizeof *th + psize);
-    tiff_set (&th->ntag, 277, 3, 1, colors);
-    tiff_set (&th->ntag, 278, 4, 1, height);
-    tiff_set (&th->ntag, 279, 4, 1, height*width*colors*output_bps/8);
-  } else
-    tiff_set (&th->ntag, 274, 3, 1, "12435867"[flip]-'0');
-  tiff_set (&th->ntag, 282, 5, 1, TOFF(th->rat[0]));
-  tiff_set (&th->ntag, 283, 5, 1, TOFF(th->rat[2]));
-  tiff_set (&th->ntag, 284, 3, 1, 1);
-  tiff_set (&th->ntag, 296, 3, 1, 2);
-  tiff_set (&th->ntag, 305, 2, 32, TOFF(th->soft));
-  tiff_set (&th->ntag, 306, 2, 20, TOFF(th->date));
-  tiff_set (&th->ntag, 315, 2, 64, TOFF(th->artist));
-  tiff_set (&th->ntag, 34665, 4, 1, TOFF(th->nexif));
-  if (psize) tiff_set (&th->ntag, 34675, 7, psize, sizeof *th);
-  tiff_set (&th->nexif, 33434, 5, 1, TOFF(th->rat[4]));
-  tiff_set (&th->nexif, 33437, 5, 1, TOFF(th->rat[6]));
-  tiff_set (&th->nexif, 34855, 3, 1, iso_speed);
-  tiff_set (&th->nexif, 37386, 5, 1, TOFF(th->rat[8]));
-  if (gpsdata[1]) {
-    tiff_set (&th->ntag, 34853, 4, 1, TOFF(th->ngps));
-    tiff_set (&th->ngps,  0, 1,  4, 0x202);
-    tiff_set (&th->ngps,  1, 2,  2, gpsdata[29]);
-    tiff_set (&th->ngps,  2, 5,  3, TOFF(th->gps[0]));
-    tiff_set (&th->ngps,  3, 2,  2, gpsdata[30]);
-    tiff_set (&th->ngps,  4, 5,  3, TOFF(th->gps[6]));
-    tiff_set (&th->ngps,  5, 1,  1, gpsdata[31]);
-    tiff_set (&th->ngps,  6, 5,  1, TOFF(th->gps[18]));
-    tiff_set (&th->ngps,  7, 5,  3, TOFF(th->gps[12]));
-    tiff_set (&th->ngps, 18, 2, 12, TOFF(th->gps[20]));
-    tiff_set (&th->ngps, 29, 2, 12, TOFF(th->gps[23]));
-    memcpy (th->gps, gpsdata, sizeof th->gps);
-  }
   th->rat[0] = th->rat[2] = 300;
   th->rat[1] = th->rat[3] = 1;
   FORC(6) th->rat[4+c] = 1000000;
@@ -9122,6 +9780,55 @@ void CLASS tiff_head (struct tiff_hdr *th, int full)
   sprintf (th->date, "%04d:%02d:%02d %02d:%02d:%02d",
       t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
   strncpy (th->artist, artist, 64);
+  if (full) {
+    tiff_set (th, &th->ntag, 254, 4, 1, 0);
+    tiff_set (th, &th->ntag, 256, 4, 1, width);
+    tiff_set (th, &th->ntag, 257, 4, 1, height);
+    tiff_set (th, &th->ntag, 258, 3, colors, output_bps);
+    if (colors > 2)
+      th->tag[th->ntag-1].val.i = TOFF(th->bps);
+    FORC4 th->bps[c] = output_bps;
+    tiff_set (th, &th->ntag, 259, 3, 1, 1);
+    tiff_set (th, &th->ntag, 262, 3, 1, 1 + (colors > 1));
+  }
+  tiff_set (th, &th->ntag, 270, 2, 512, TOFF(th->desc));
+  tiff_set (th, &th->ntag, 271, 2, 64, TOFF(th->make));
+  tiff_set (th, &th->ntag, 272, 2, 64, TOFF(th->model));
+  if (full) {
+    if (oprof) psize = ntohl(oprof[0]);
+    tiff_set (th, &th->ntag, 273, 4, 1, sizeof *th + psize);
+    tiff_set (th, &th->ntag, 277, 3, 1, colors);
+    tiff_set (th, &th->ntag, 278, 4, 1, height);
+    tiff_set (th, &th->ntag, 279, 4, 1, height*width*colors*output_bps/8);
+  } else
+    tiff_set (th, &th->ntag, 274, 3, 1, "12435867"[flip]-'0');
+  tiff_set (th, &th->ntag, 282, 5, 1, TOFF(th->rat[0]));
+  tiff_set (th, &th->ntag, 283, 5, 1, TOFF(th->rat[2]));
+  tiff_set (th, &th->ntag, 284, 3, 1, 1);
+  tiff_set (th, &th->ntag, 296, 3, 1, 2);
+  tiff_set (th, &th->ntag, 305, 2, 32, TOFF(th->soft));
+  tiff_set (th, &th->ntag, 306, 2, 20, TOFF(th->date));
+  tiff_set (th, &th->ntag, 315, 2, 64, TOFF(th->artist));
+  tiff_set (th, &th->ntag, 34665, 4, 1, TOFF(th->nexif));
+  if (psize) tiff_set (th, &th->ntag, 34675, 7, psize, sizeof *th);
+  tiff_set (th, &th->nexif, 33434, 5, 1, TOFF(th->rat[4]));
+  tiff_set (th, &th->nexif, 33437, 5, 1, TOFF(th->rat[6]));
+  tiff_set (th, &th->nexif, 34855, 3, 1, iso_speed);
+  tiff_set (th, &th->nexif, 37386, 5, 1, TOFF(th->rat[8]));
+  if (gpsdata[1]) {
+    tiff_set (th, &th->ntag, 34853, 4, 1, TOFF(th->ngps));
+    tiff_set (th, &th->ngps,  0, 1,  4, 0x202);
+    tiff_set (th, &th->ngps,  1, 2,  2, gpsdata[29]);
+    tiff_set (th, &th->ngps,  2, 5,  3, TOFF(th->gps[0]));
+    tiff_set (th, &th->ngps,  3, 2,  2, gpsdata[30]);
+    tiff_set (th, &th->ngps,  4, 5,  3, TOFF(th->gps[6]));
+    tiff_set (th, &th->ngps,  5, 1,  1, gpsdata[31]);
+    tiff_set (th, &th->ngps,  6, 5,  1, TOFF(th->gps[18]));
+    tiff_set (th, &th->ngps,  7, 5,  3, TOFF(th->gps[12]));
+    tiff_set (th, &th->ngps, 18, 2, 12, TOFF(th->gps[20]));
+    tiff_set (th, &th->ngps, 29, 2, 12, TOFF(th->gps[23]));
+    memcpy (th->gps, gpsdata, sizeof th->gps);
+  }
 }
 
 void CLASS jpeg_thumb()
@@ -9196,11 +9903,6 @@ void CLASS write_ppm_tiff()
   free (ppm);
 }
 
-
-
-
-
-
 // CINELERRA
 void CLASS write_cinelerra (FILE *ofp)
 {
@@ -9240,29 +9942,9 @@ void CLASS write_cinelerra (FILE *ofp)
    }
 }
 
-
-
-
-
-
-
-
-
-
-
-
-
 // CINELERRA
 int CLASS dcraw_main (int argc, const char **argv)
-//int CLASS main (int argc, const char **argv)
 {
-// CINELERRA
-// Globals must be reset
-       document_mode = 0;
-       use_camera_wb = 0;
-
-
-
   int arg, status=0, quality, i, c;
   int timestamp_only=0, thumbnail_only=0, identify_only=0;
   int user_qual=-1, user_black=-1, user_sat=-1, user_flip=-1;
@@ -9274,6 +9956,9 @@ int CLASS dcraw_main (int argc, const char **argv)
   const char *cam_profile=0, *out_profile=0;
 #endif
 
+// CINELERRA
+  reset(); // Globals must be reset
+
 #ifndef LOCALTIME
   putenv ((char *) "TZ=UTC");
 #endif
@@ -9307,7 +9992,7 @@ int CLASS dcraw_main (int argc, const char **argv)
     puts(_("-n <num>  Set threshold for wavelet denoising"));
     puts(_("-H [0-9]  Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)"));
     puts(_("-t [0-7]  Flip image (0=none, 3=180, 5=90CCW, 6=90CW)"));
-    puts(_("-o [0-5]  Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ)"));
+    puts(_("-o [0-6]  Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ,ACES)"));
 #ifndef NO_LCMS
     puts(_("-o <file> Apply output ICC profile from file"));
     puts(_("-p <file> Apply camera ICC profile from file or \"embed\""));
@@ -9374,12 +10059,12 @@ int CLASS dcraw_main (int argc, const char **argv)
       case 'i':  identify_only     = 1;  break;
       case 'c':  write_to_stdout   = 1;  break;
       case 'v':  verbose           = 1;  break;
-      case 'h':  half_size         = 1;                /* "-h" implies "-f" */
+      case 'h':  half_size         = 1;  break;
       case 'f':  four_color_rgb    = 1;  break;
       case 'A':  FORC4 greybox[c]  = atoi(argv[arg++]);
       case 'a':  use_auto_wb       = 1;  break;
       case 'w':  use_camera_wb     = 1;  break;
-      case 'M':  use_camera_matrix = (opm == '+');  break;
+      case 'M':  use_camera_matrix = 3 * (opm == '+');  break;
       case 'I':  read_from_stdin   = 1;  break;
       case 'E':  document_mode++;
       case 'D':  document_mode++;
@@ -9395,16 +10080,13 @@ int CLASS dcraw_main (int argc, const char **argv)
        return 1;
     }
   }
-  if (use_camera_matrix < 0)
-      use_camera_matrix = use_camera_wb;
   if (arg == argc) {
     fprintf (stderr,_("No files to process.\n"));
     return 1;
   }
   if (write_to_stdout) {
 // CINELERRA
-    if (0) {
-//    if (isatty(1)) {
+    if (0 && isatty(1)) {
       fprintf (stderr,_("Will not write an image to the terminal!\n"));
       return 1;
     }
@@ -9454,15 +10136,9 @@ int CLASS dcraw_main (int argc, const char **argv)
       }
       goto next;
     }
-    write_fun = &CLASS write_ppm_tiff;
-
-
-
 // CINELERRA
-       write_fun = write_cinelerra;
-
-
-
+//    write_fun = &CLASS write_ppm_tiff;
+    write_fun = write_cinelerra;
 
     if (thumbnail_only) {
       if ((status = !thumb_offset)) {
@@ -9474,6 +10150,7 @@ int CLASS dcraw_main (int argc, const char **argv)
        height = thumb_height;
        width  = thumb_width;
        filters = 0;
+       colors = 3;
       } else {
        fseek (ifp, thumb_offset, SEEK_SET);
        write_fun = write_thumb;
@@ -9510,18 +10187,9 @@ int CLASS dcraw_main (int argc, const char **argv)
        printf (_("Thumb size:  %4d x %d\n"), thumb_width, thumb_height);
       printf (_("Full size:   %4d x %d\n"), raw_width, raw_height);
     }
-
-
-
 // CINELERRA
-//      else if (!is_raw)
-//      fprintf (stderr,_("Cannot decode file %s\n"), ifname);
-
-
-
-
-
-
+//  else if (!is_raw)
+//    fprintf (stderr,_("Cannot decode file %s\n"), ifname);
     if (!is_raw) goto next;
     shrink = filters && (half_size || (!identify_only &&
        (threshold || aber[0] != 1 || aber[2] != 1)));
@@ -9532,9 +10200,7 @@ int CLASS dcraw_main (int argc, const char **argv)
        if (document_mode == 3) {
          top_margin = left_margin = fuji_width = 0;
          height = raw_height;
-         if  (width <= raw_width * 8 / tiff_bps)
-              width  = raw_width * 8 / tiff_bps;
-         else width  = raw_width;
+         width  = raw_width;
        }
        iheight = (height + shrink) >> shrink;
        iwidth  = (width  + shrink) >> shrink;
@@ -9554,9 +10220,15 @@ int CLASS dcraw_main (int argc, const char **argv)
        printf (_("Output size: %4d x %d\n"), iwidth, iheight);
        printf (_("Raw colors: %d"), colors);
        if (filters) {
+         int fhigh = 2, fwide = 2;
+         if ((filters ^ (filters >>  8)) & 0xff)   fhigh = 4;
+         if ((filters ^ (filters >> 16)) & 0xffff) fhigh = 8;
+         if (filters == 1) fhigh = fwide = 16;
+         if (filters == 9) fhigh = fwide = 6;
          printf (_("\nFilter pattern: "));
-         for (i=0; i < 16; i++)
-           putchar (cdesc[fcol(i >> 1,i & 1)]);
+         for (i=0; i < fhigh; i++)
+           for (c = i && putchar('/') && 0; c < fwide; c++)
+             putchar (cdesc[fcol(i,c)]);
        }
        printf (_("\nDaylight multipliers:"));
        FORCC printf (" %f", pre_mul[c]);
@@ -9565,26 +10237,23 @@ int CLASS dcraw_main (int argc, const char **argv)
          FORC4 printf (" %f", cam_mul[c]);
        }
        putchar ('\n');
-      } else
+      }
 // CINELERRA
+//    else
 //     printf (_("%s is a %s %s image.\n"), ifname, make, model);
 next:
       fclose(ifp);
       continue;
     }
-    if (use_camera_matrix && cmatrix[0][0] > 0.25) {
-      memcpy (rgb_cam, cmatrix, sizeof cmatrix);
-      raw_color = 0;
-    }
     if (meta_length) {
       meta_data = (char *) malloc (meta_length);
       merror (meta_data, "main()");
     }
     if (filters || colors == 1) {
-      raw_image = (ushort *) calloc ((raw_height+7)*raw_width, 2);
+      raw_image = (ushort *) calloc ((raw_height+7), raw_width*2);
       merror (raw_image, "main()");
     } else {
-      image = (ushort (*)[4]) calloc (iheight*iwidth, sizeof *image);
+      image = (ushort (*)[4]) calloc (iheight, iwidth*sizeof *image);
       merror (image, "main()");
     }
     if (verbose)
@@ -9600,14 +10269,12 @@ next:
     if (document_mode == 3) {
       top_margin = left_margin = fuji_width = 0;
       height = raw_height;
-      if  (width <= raw_width * 8 / tiff_bps)
-           width  = raw_width * 8 / tiff_bps;
-      else width  = raw_width;
+      width  = raw_width;
     }
     iheight = (height + shrink) >> shrink;
     iwidth  = (width  + shrink) >> shrink;
     if (raw_image) {
-      image = (ushort (*)[4]) calloc (iheight*iwidth, sizeof *image);
+      image = (ushort (*)[4]) calloc (iheight, iwidth*sizeof *image);
       merror (image, "main()");
       crop_masked_pixels();
       free (raw_image);
@@ -9621,6 +10288,12 @@ next:
     FORC3 if (i > cblack[c]) i = cblack[c];
     FORC4 cblack[c] -= i;
     black += i;
+    i = cblack[6];
+    FORC (cblack[4] * cblack[5])
+      if (i > cblack[6+c]) i = cblack[6+c];
+    FORC (cblack[4] * cblack[5])
+      cblack[6+c] -= i;
+    black += i;
     if (user_black >= 0) black = user_black;
     FORC4 cblack[c] += black;
     if (user_sat > 0) maximum = user_sat;
@@ -9638,11 +10311,14 @@ next:
     if (filters && !document_mode) {
       if (quality == 0)
        lin_interpolate();
-      else if (quality == 1 || colors > 3 || filters < 1000)
+      else if (quality == 1 || colors > 3)
        vng_interpolate();
-      else if (quality == 2)
+      else if (quality == 2 && filters > 1000)
        ppg_interpolate();
-      else ahd_interpolate();
+      else if (filters == 9)
+       xtrans_interpolate (quality*2-3);
+      else
+       ahd_interpolate();
     }
     if (mix_green)
       for (colors=3, i=0; i < height*width; i++)
diff --git a/cinelerra-5.1/cinelerra/dcraw.h b/cinelerra-5.1/cinelerra/dcraw.h
new file mode 100644 (file)
index 0000000..d739dfc
--- /dev/null
@@ -0,0 +1,188 @@
+
+/* CINELERRA dcraw.c */
+static int CLASS fcol(int row,int col);
+#if 0
+static char *my_memmem(char *haystack,size_t haystacklen,char *needle,size_t needlelen);
+static char *my_strcasestr(char *haystack,const char *needle);
+#endif
+static void CLASS merror(void *ptr,const char *where);
+static void CLASS derror(void);
+static ushort CLASS sget2(uchar *s);
+static ushort CLASS get2(void);
+static unsigned CLASS sget4(uchar *s);
+static unsigned CLASS get4(void);
+static unsigned CLASS getint(int type);
+static float CLASS int_to_float(int i);
+static double CLASS getreal(int type);
+static void CLASS read_shorts(ushort *pixel,int count);
+static void CLASS cubic_spline(const int *x_,const int *y_,const int len);
+static void CLASS canon_600_fixed_wb(int temp);
+static int CLASS canon_600_color(int ratio[2],int mar);
+static void CLASS canon_600_auto_wb(void);
+static void CLASS canon_600_coeff(void);
+static void CLASS canon_600_load_raw(void);
+static void CLASS canon_600_correct(void);
+static int CLASS canon_s2is(void);
+static unsigned CLASS getbithuff(int nbits,ushort *huff);
+static ushort *CLASS make_decoder_ref(const uchar **source);
+static ushort *CLASS make_decoder(const uchar *source);
+static void CLASS crw_init_tables(unsigned table,ushort *huff[2]);
+static int CLASS canon_has_lowbits(void);
+static void CLASS canon_load_raw(void);
+static int CLASS ljpeg_start(struct jhead *jh,int info_only);
+static void CLASS ljpeg_end(struct jhead *jh);
+static int CLASS ljpeg_diff(ushort *huff);
+static ushort *CLASS ljpeg_row(int jrow,struct jhead *jh);
+static void CLASS lossless_jpeg_load_raw(void);
+static void CLASS canon_sraw_load_raw(void);
+static void CLASS adobe_copy_pixel(unsigned row,unsigned col,ushort **rp);
+static void CLASS ljpeg_idct(struct jhead *jh);
+static void CLASS lossless_dng_load_raw(void);
+static void CLASS packed_dng_load_raw(void);
+static void CLASS pentax_load_raw(void);
+static void CLASS nikon_load_raw(void);
+static void CLASS nikon_yuv_load_raw(void);
+static int CLASS nikon_e995(void);
+static int CLASS nikon_e2100(void);
+static void CLASS nikon_3700(void);
+static int CLASS minolta_z2(void);
+static void CLASS ppm_thumb(void);
+static void CLASS ppm16_thumb(void);
+static void CLASS layer_thumb(void);
+static void CLASS rollei_thumb(void);
+static void CLASS rollei_load_raw(void);
+static int CLASS raw(unsigned row,unsigned col);
+static void CLASS phase_one_flat_field(int is_float,int nc);
+static void CLASS phase_one_correct(void);
+static void CLASS phase_one_load_raw(void);
+static unsigned CLASS ph1_bithuff(int nbits,ushort *huff);
+static void CLASS phase_one_load_raw_c(void);
+static void CLASS hasselblad_load_raw(void);
+static void CLASS leaf_hdr_load_raw(void);
+static void CLASS unpacked_load_raw(void);
+static void CLASS sinar_4shot_load_raw(void);
+static void CLASS imacon_full_load_raw(void);
+static void CLASS packed_load_raw(void);
+static void CLASS nokia_load_raw(void);
+static void CLASS canon_rmf_load_raw(void);
+static unsigned CLASS pana_bits(int nbits);
+static void CLASS panasonic_load_raw(void);
+static void CLASS olympus_load_raw(void);
+static void CLASS minolta_rd175_load_raw(void);
+static void CLASS quicktake_100_load_raw(void);
+static void CLASS kodak_radc_load_raw(void);
+static void CLASS kodak_jpeg_load_raw(void);
+static void CLASS lossy_dng_load_raw(void);
+#ifndef NO_JPEG
+static int boolean fill_input_buffer(j_decompress_ptr cinfo);
+#endif
+static void CLASS kodak_jpeg_load_raw(void);
+static void CLASS lossy_dng_load_raw(void);
+static void CLASS kodak_dc120_load_raw(void);
+static void CLASS eight_bit_load_raw(void);
+static void CLASS kodak_c330_load_raw(void);
+static void CLASS kodak_c603_load_raw(void);
+static void CLASS kodak_262_load_raw(void);
+static int CLASS kodak_65000_decode(short *out,int bsize);
+static void CLASS kodak_65000_load_raw(void);
+static void CLASS kodak_ycbcr_load_raw(void);
+static void CLASS kodak_rgb_load_raw(void);
+static void CLASS kodak_thumb_load_raw(void);
+static void CLASS sony_decrypt(unsigned *data,int len,int start,int key);
+static void CLASS sony_load_raw(void);
+static void CLASS sony_arw_load_raw(void);
+static void CLASS sony_arw2_load_raw(void);
+static void CLASS samsung_load_raw(void);
+static void CLASS samsung2_load_raw(void);
+static void CLASS samsung3_load_raw(void);
+static void CLASS smal_decode_segment(unsigned seg[2][2],int holes);
+static void CLASS smal_v6_load_raw(void);
+static int CLASS median4(int *p);
+static void CLASS fill_holes(int holes);
+static void CLASS smal_v9_load_raw(void);
+static void CLASS redcine_load_raw(void);
+static void CLASS foveon_decoder(unsigned size,unsigned code);
+static void CLASS foveon_thumb(void);
+static void CLASS foveon_sd_load_raw(void);
+static void CLASS foveon_huff(ushort *huff);
+static void CLASS foveon_dp_load_raw(void);
+static void CLASS foveon_load_camf(void);
+static const char *CLASS foveon_camf_param(const char *block,const char *param);
+static void *CLASS foveon_camf_matrix(unsigned dim[3],const char *name);
+static int CLASS foveon_fixed(void *ptr,int size,const char *name);
+static float CLASS foveon_avg(short *pix,int range[2],float cfilt);
+static short *CLASS foveon_make_curve(double max,double mul,double filt);
+static void CLASS foveon_make_curves(short **curvep,float dq[3],float div[3],float filt);
+static int CLASS foveon_apply_curve(short *curve,int i);
+static void CLASS foveon_interpolate(void);
+static void CLASS crop_masked_pixels(void);
+static void CLASS remove_zeroes(void);
+static void CLASS bad_pixels(const char *cfname);
+static void CLASS subtract(const char *fname);
+static void CLASS gamma_curve(double pwr,double ts,int mode,int imax);
+static void CLASS pseudoinverse (double (*in)[3],double (*out)[3],int size);
+static void CLASS cam_xyz_coeff(float rgb_cam[3][4],double cam_xyz[4][3]);
+#ifdef COLORCHECK
+static void CLASS colorcheck(void);
+#endif
+static void CLASS hat_transform(float *temp,float *base,int st,int size,int sc);
+static void CLASS wavelet_denoise(void);
+static void CLASS scale_colors(void);
+static void CLASS pre_interpolate(void);
+static void CLASS border_interpolate(int border);
+static void CLASS lin_interpolate(void);
+static void CLASS vng_interpolate(void);
+static void CLASS ppg_interpolate(void);
+static void CLASS cielab(ushort rgb[3],short lab[3]);
+static void CLASS xtrans_interpolate(int passes);
+static void CLASS ahd_interpolate(void);
+static void CLASS median_filter(void);
+static void CLASS blend_highlights(void);
+static void CLASS recover_highlights(void);
+static void CLASS tiff_get(unsigned base,unsigned *tag,unsigned *type,unsigned *len,unsigned *save);
+static void CLASS parse_thumb_note(int base,unsigned toff,unsigned tlen);
+static void CLASS parse_makernote(int base,int uptag);
+static void CLASS get_timestamp(int reversed);
+static void CLASS parse_exif(int base);
+static void CLASS parse_gps(int base);
+static void CLASS romm_coeff(float romm_cam[3][3]);
+static void CLASS parse_mos(int offset);
+static void CLASS linear_table(unsigned len);
+static void CLASS parse_kodak_ifd(int base);
+static int CLASS parse_tiff_ifd(int base);
+static int CLASS parse_tiff(int base);
+static void CLASS apply_tiff(void);
+static void CLASS parse_minolta(int base);
+static void CLASS parse_external_jpeg(void);
+static void CLASS ciff_block_1030(void);
+static void CLASS parse_ciff(int offset,int length,int depth);
+static void CLASS parse_rollei(void);
+static void CLASS parse_sinar_ia(void);
+static void CLASS parse_phase_one(int base);
+static void CLASS parse_fuji(int offset);
+static int CLASS parse_jpeg(int offset);
+static void CLASS parse_riff(void);
+static void CLASS parse_qt(int end);
+static void CLASS parse_smal(int offset,int fsize);
+static void CLASS parse_cine(void);
+static void CLASS parse_redcine(void);
+static char *CLASS foveon_gets(int offset,char *str,int len);
+static void CLASS parse_foveon(void);
+static void CLASS adobe_coeff(const char *make,const char *model);
+static void CLASS simple_coeff(int index);
+static short CLASS guess_byte_order(int words);
+static float CLASS find_green(int bps,int bite,int off0,int off1);
+static void CLASS identify(void);
+#ifndef NO_LCMS
+static void CLASS apply_profile(const char *input,const char *output);
+#endif
+static void CLASS convert_to_rgb(void);
+static void CLASS fuji_rotate(void);
+static void CLASS stretch(void);
+static int CLASS flip_index(int row, int col);
+static void CLASS tiff_set(struct tiff_hdr *th,ushort *ntag,ushort tag,ushort type,int count,int val);
+static void CLASS tiff_head(struct tiff_hdr *th,int full);
+static void CLASS jpeg_thumb(void);
+static void CLASS write_ppm_tiff(void);
+static void CLASS write_cinelerra(FILE *ofp);
+
index 10ad05036ee64b71a5cb8d7e2336434fe2e52108..f2b02c24449952f529b229101966da1a7702469f 100644 (file)
@@ -320,11 +320,15 @@ int FFStream::decode_activate()
                                ret = AVERROR(ENOMEM);
                        }
                        if( ret >= 0 ) {
+                               av_codec_set_pkt_timebase(avctx, st->time_base);
+                               if( decoder->capabilities & AV_CODEC_CAP_DR1 )
+                                       avctx->flags |= CODEC_FLAG_EMU_EDGE;
                                avcodec_parameters_to_context(avctx, st->codecpar);
                                ret = avcodec_open2(avctx, decoder, &copts);
                        }
-                       if( ret >= 0 )
+                       if( ret >= 0 ) {
                                reading = 1;
+                       }
                        else
                                eprintf(_("open decoder failed\n"));
                }
@@ -2079,7 +2083,7 @@ int FFMPEG::decode_activate()
                        }
                }
                int64_t nudge = vstart_time > min_nudge ? vstart_time :
-                       astart_time > min_nudge ? astart_time : AV_NOPTS_VALUE;
+                       astart_time > min_nudge ? astart_time : 0;
                for( int vidx=0; vidx<ffvideo.size(); ++vidx ) {
                        if( ffvideo[vidx]->nudge == AV_NOPTS_VALUE )
                                ffvideo[vidx]->nudge = nudge;
index 8179d0d3977f68a9c4c20921bb5ed377ff1055ce..5301f7d1ff4d555491a8f11d06a7f40e9cc9361a 100644 (file)
@@ -71,6 +71,7 @@
 #include "packagingengine.h"
 #include "pluginserver.h"
 #include "preferences.h"
+#include "probeprefs.h"
 #include "samples.h"
 #include "vframe.h"
 
@@ -359,15 +360,139 @@ int File::delete_oldest()
        return frame_cache->delete_oldest();
 }
 
-
-
-
-
-
-
-
-
-
+// file driver in order of probe precidence
+//  can be reordered in preferences->interface
+const char *File::default_probes[] = { 
+       "FFMPEG_Early",
+       "Scene", 
+       "DB",
+#ifdef HAVE_DV 
+       "DV",   
+#endif 
+       "SndFile",
+       "PNG",
+       "JPEG",
+       "GIF",
+       "EXR",
+       "FLAC",
+       "CR2",
+       "TGA",
+       "TIFF",
+       "OGG",
+       "Vorbis",
+       "MPEG",
+       "EDL",
+               "FFMPEG_Late", 
+}; 
+const int File::nb_probes =
+       sizeof(File::default_probes)/sizeof(File::default_probes[0]); 
+
+
+int File::probe()
+{
+       FILE *fp = fopen(this->asset->path, "rb");
+       if( !fp ) return FILE_NOT_FOUND;
+       char data[16];
+       memset(data,0,sizeof(data));
+       int ret = fread(data, 1, 16, fp);
+       fclose(fp);
+       if( !ret ) return FILE_NOT_FOUND;
+
+       for( int i=0; i<preferences->file_probes.size(); ++i ) {
+               ProbePref *pref = preferences->file_probes[i];
+               if( !pref->armed ) continue;
+               if( !strncmp(pref->name,"FFMPEG",6) ) { // FFMPEG Early/Late
+                       if( !FileFFMPEG::check_sig(this->asset) ) continue;
+                       file = new FileFFMPEG(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"DB") ) { // MediaDB
+                       if( !FileDB::check_sig(this->asset) ) continue;
+                       file = new FileDB(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"Scene") ) { // scene file
+                       if( !FileScene::check_sig(this->asset, data)) continue;
+                       file = new FileScene(this->asset, this);
+                       return FILE_OK;
+               }
+#ifdef HAVE_DV
+               if( !strcmp(pref->name,"DV") ) { // libdv
+                       if( !FileDV::check_sig(this->asset) ) continue;
+                       file = new FileDV(this->asset, this);
+                       return FILE_OK;
+               }
+#endif
+               if( !strcmp(pref->name,"SndFile") ) { // libsndfile
+                       if( !FileSndFile::check_sig(this->asset) ) continue;
+                       file = new FileSndFile(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"PNG") ) { // PNG file
+                       if( !FilePNG::check_sig(this->asset) ) continue;
+                       file = new FilePNG(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"JPEG") ) { // JPEG file
+                       if( !FileJPEG::check_sig(this->asset) ) continue;
+                       file = new FileJPEG(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"GIF") ) { // GIF file
+                       if( !FileGIF::check_sig(this->asset)) continue;
+                       file = new FileGIF(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"EXR") ) { // EXR file
+                       if( !FileEXR::check_sig(this->asset, data)) continue;
+                       file = new FileEXR(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"FLAC") ) { // FLAC file
+                       if( !FileFLAC::check_sig(this->asset, data)) continue;
+                       file = new FileFLAC(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"CR2") ) { // CR2 file
+                       if( !FileCR2::check_sig(this->asset)) continue;
+                       file = new FileCR2(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"TGA") ) { // TGA file
+                       if( !FileTGA::check_sig(this->asset) ) continue;
+                       file = new FileTGA(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"TIFF") ) { // TIFF file
+                       if( !FileTIFF::check_sig(this->asset) ) continue;
+                       file = new FileTIFF(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"OGG") ) { // OGG file
+                       if( !FileOGG::check_sig(this->asset) ) continue;
+                       file = new FileOGG(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"Vorbis") ) { // VorbisFile file
+                       if( !FileVorbis::check_sig(this->asset) ) continue;
+                       file = new FileVorbis(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"MPEG") ) { // MPEG file
+                       if( !FileMPEG::check_sig(this->asset) ) continue;
+                       file = new FileMPEG(this->asset, this);
+                       return FILE_OK;
+               }
+               if( !strcmp(pref->name,"EDL") ) { // XML file
+                       if( data[0] != '<' ) continue;
+                       if( !strncmp(&data[1],"EDL>",4) ||
+                           !strncmp(&data[1],"HTAL>",5) ||
+                           !strncmp(&data[1],"?xml",4) )
+                               return FILE_IS_XML;
+               }
+       }
+       return FILE_UNRECOGNIZED_CODEC; // maybe PCM file ?
+}
 
 int File::open_file(Preferences *preferences,
        Asset *asset,
@@ -386,138 +511,14 @@ int File::open_file(Preferences *preferences,
 
        if(debug) printf("File::open_file %p %d\n", this, __LINE__);
 
-       switch(this->asset->format)
-       {
+       switch(this->asset->format) {
 // get the format now
 // If you add another format to case 0, you also need to add another case for the
 // file format #define.
-               case FILE_UNKNOWN:
-                       if(FileDB::check_sig(this->asset)) {
-// MediaDb file
-                               file = new FileDB(this->asset, this);
-                               break;
-                       }
-// if early probe enabled
-                       if( preferences->ffmpeg_early_probe &&
-                           FileFFMPEG::check_sig(this->asset)) {
-                               file = new FileFFMPEG(this->asset, this);
-                               break;
-                       }
-
-                       FILE *stream;
-                       if(!(stream = fopen(this->asset->path, "rb"))) {
-// file not found
-                               return 1;
-                       }
-
-                       char test[16];  memset(test,0,sizeof(test)); // int result =
-                       fread(test, 16, 1, stream);
-
-                       if(FileScene::check_sig(this->asset, test)) {
-// scene file
-                               fclose(stream);
-                               file = new FileScene(this->asset, this);
-                               break;
-                       }
-#ifdef HAVE_DV
-                       if(FileDV::check_sig(this->asset)) {
-// libdv
-                               fclose(stream);
-                               file = new FileDV(this->asset, this);
-                               break;
-                       }
-#endif
-                       if(FileSndFile::check_sig(this->asset)) {
-// libsndfile
-                               fclose(stream);
-                               file = new FileSndFile(this->asset, this);
-                               break;
-                       }
-                       if(FilePNG::check_sig(this->asset)) {
-// PNG file
-                               fclose(stream);
-                               file = new FilePNG(this->asset, this);
-                               break;
-                       }
-                       if(FileJPEG::check_sig(this->asset)) {
-// JPEG file
-                               fclose(stream);
-                               file = new FileJPEG(this->asset, this);
-                               break;
-                       }
-                       if(FileGIF::check_sig(this->asset)) {
-// GIF file
-                               fclose(stream);
-                               file = new FileGIF(this->asset, this);
-                               break;
-                       }
-                       if(FileEXR::check_sig(this->asset, test)) {
-// EXR file
-                               fclose(stream);
-                               file = new FileEXR(this->asset, this);
-                               break;
-                       }
-                       if(FileFLAC::check_sig(this->asset, test)) {
-// FLAC file
-                               fclose(stream);
-                               file = new FileFLAC(this->asset, this);
-                               break;
-                       }
-                       if(FileCR2::check_sig(this->asset)) {
-// CR2 file
-                               fclose(stream);
-                               file = new FileCR2(this->asset, this);
-                               break;
-                       }
-                       if(FileTGA::check_sig(this->asset)) {
-// TGA file
-                               fclose(stream);
-                               file = new FileTGA(this->asset, this);
-                               break;
-                       }
-                       if(FileTIFF::check_sig(this->asset)) {
-// TIFF file
-                               fclose(stream);
-                               file = new FileTIFF(this->asset, this);
-                               break;
-                       }
-                       if(FileOGG::check_sig(this->asset)) {
-// OGG file
-                               fclose(stream);
-                               file = new FileOGG(this->asset, this);
-                               break;
-                       }
-                       if(FileVorbis::check_sig(this->asset)) {
-// VorbisFile file
-                               fclose(stream);
-                               file = new FileVorbis(this->asset, this);
-                               break;
-                       }
-                       if(FileMPEG::check_sig(this->asset)) {
-// MPEG file
-                               fclose(stream);
-                               file = new FileMPEG(this->asset, this);
-                               break;
-                       }
-                       if( test[0] == '<' && (
-                               !strncmp(&test[1],"EDL>",4) ||
-                               !strncmp(&test[1],"HTAL>",5) ||
-                               !strncmp(&test[1],"?xml",4) ) ) {
-// XML file
-                               fclose(stream);
-                               return FILE_IS_XML;
-                       }    // can't load project file
-                       if( !preferences->ffmpeg_early_probe &&
-                           FileFFMPEG::check_sig(this->asset) ) {
-                               fclose(stream);
-                               file = new FileFFMPEG(this->asset, this);
-                               break;
-                       }
-// PCM file
-                       fclose(stream);
-                       return FILE_UNRECOGNIZED_CODEC;
-                       break;
-
+               case FILE_UNKNOWN: {
+                       int ret = probe();
+                       if( ret != FILE_OK ) return ret;
+                       break; }
 // format already determined
                case FILE_AC3:
                        file = new FileAC3(this->asset, this);
index 442bdc58cbc512d11367de1cad7a475b82df2b49..a2ed78d55cec022902bc17d168ec2f3e911d1558 100644 (file)
@@ -58,6 +58,7 @@ public:
        File();
        ~File();
 
+       int probe();
 // Get attributes for various file formats.
 // The dither parameter is carried over from recording, where dither is done at the device.
        int get_options(FormatTools *format,
@@ -329,6 +330,9 @@ public:
        static const char *get_ladspa_path() { return getenv("CIN_LADSPA"); }
        static const char *get_locale_path() { return getenv("CIN_LOCALE"); }
 
+       static const char *default_probes[];
+       static const int nb_probes;
+
 private:
        void reset_parameters();
 
index b7dcff6c43c906d5a5290b2cbcd9434c992b60b0..0d36b26f26564c2abc038d12e29d77f40a827e36 100644 (file)
@@ -39,6 +39,14 @@ extern float dcraw_matrix[9];
 int dcraw_main (int argc, const char **argv);
 }
 
+static int dcraw_run(int argc, const char **argv)
+{
+       static Mutex dcraw_lock;
+       dcraw_lock.lock("dcraw_run");
+       int result = dcraw_main(argc, argv);
+       dcraw_lock.unlock();
+       return result;
+}
 
 FileCR2::FileCR2(Asset *asset, File *file)
  : FileList(asset, file, "CR2LIST", ".cr2", FILE_CR2, FILE_CR2_LIST)
@@ -96,7 +104,7 @@ int FileCR2::check_sig(Asset *asset)
                0
        };
 
-       int result = dcraw_main(argc, argv);
+       int result = dcraw_run(argc, argv);
 
 //printf("FileCR2::check_sig %d %d\n", __LINE__, result);
 
@@ -115,7 +123,7 @@ int FileCR2::check_sig(Asset *asset)
 //             0
 //     };
 //
-//     int result = dcraw_main(argc, argv);
+//     int result = dcraw_run(argc, argv);
 //     if(!result) format_to_asset();
 //
 //     return result;
@@ -133,7 +141,7 @@ printf("FileCR2::read_frame_header %d\n", __LINE__);
                0
        };
 
-       int result = dcraw_main(argc, argv);
+       int result = dcraw_run(argc, argv);
        if(!result) format_to_asset();
 
 printf("FileCR2::read_frame_header %d %d\n", __LINE__, result);
@@ -214,7 +222,7 @@ printf("FileCR2::read_frame %d %s\n", __LINE__, path);
        dcraw_data = (float**)frame->get_rows();
 
 //Timer timer;
-       int result = dcraw_main(argc, (const char**) argv);
+       int result = dcraw_run(argc, (const char**) argv);
 
 // This was only used by the bayer interpolate plugin, which itself created
 // too much complexity to use effectively.
index 5542c97587ab7f976e2c57fc38db699917811969..33f3fa478d4a13d0f2449601a90aa9c950ad0e4b 100644 (file)
@@ -210,7 +210,6 @@ int FileFFMPEG::select_video_stream(Asset *asset, int vstream)
        if( !ff || !asset->video_data ) return 1;
        asset->width = ff->ff_video_width(vstream);
        asset->height = ff->ff_video_height(vstream);
-       asset->video_length = ff->ff_video_frames(vstream);
        if( (asset->video_length = ff->ff_video_frames(vstream)) < 2 )
                asset->video_length = asset->video_length < 0 ? 0 : -1;
        asset->frame_rate = ff->ff_frame_rate(vstream);
index 8cf8306ee3b54b79140815703dbe55adf41f9436..7f44a58554c3ae3e94ed41a6324218eb3049fcef 100644 (file)
@@ -49,6 +49,8 @@
 
 class Garbage
 {
+       Garbage(Garbage &v) {} //disallow copy constructor
+       Garbage &operator=(Garbage &v) { return *this=v; } //disallow = operator
 public:
        Garbage(const char *title);
        virtual ~Garbage();
index fb58b22eea391a89394bb338bf8850096a4c029b..1a3f1be553c983b84575215abed6d205d00857c8 100644 (file)
@@ -160,16 +160,17 @@ void InterfacePrefs::create_objects()
        y += 5;
 
        add_subwindow(new BC_Title(x, y, _("Index files"), LARGEFONT, resources->text_default));
+       add_subwindow(ffmpeg_marker_files = new IndexFFMPEGMarkerFiles(this, x1, y));
 
 
-       y += 25;
+       y += 30;
        add_subwindow(new BC_Title(x, y + 5,
                _("Index files go here:"), MEDIUMFONT, resources->text_default));
        add_subwindow(ipathtext = new IndexPathText(x + 230, y,
                pwindow,
                pwindow->thread->preferences->index_directory));
        add_subwindow(ipath = new BrowseButton(mwindow->theme, this, ipathtext,
-               x + 230 + ipathtext->get_w(), y,
+               x1 = x + 230 + ipathtext->get_w(), y,
                pwindow->thread->preferences->index_directory,
                _("Index Path"),
                _("Select the directory for index files"),
@@ -190,9 +191,6 @@ void InterfacePrefs::create_objects()
        add_subwindow(deleteall = new DeleteAllIndexes(mwindow, pwindow, 350, y));
 
 
-
-
-
        y += 35;
        add_subwindow(new BC_Bar(5, y,  get_w() - 10));
        y += 5;
@@ -292,23 +290,12 @@ void InterfacePrefs::create_objects()
 
 const char* InterfacePrefs::behavior_to_text(int mode)
 {
-       switch(mode)
-       {
-               case MOVE_ALL_EDITS:
-                       return _(MOVE_ALL_EDITS_TITLE);
-                       break;
-               case MOVE_ONE_EDIT:
-                       return _(MOVE_ONE_EDIT_TITLE);
-                       break;
-               case MOVE_NO_EDITS:
-                       return _(MOVE_NO_EDITS_TITLE);
-                       break;
-               case MOVE_EDITS_DISABLED:
-                       return _(MOVE_EDITS_DISABLED_TITLE);
-                       break;
-               default:
-                       return "";
-                       break;
+       switch(mode) {
+               case MOVE_ALL_EDITS: return _(MOVE_ALL_EDITS_TITLE);
+               case MOVE_ONE_EDIT:  return _(MOVE_ONE_EDIT_TITLE);
+               case MOVE_NO_EDITS:  return _(MOVE_NO_EDITS_TITLE);
+               case MOVE_EDITS_DISABLED: return _(MOVE_EDITS_DISABLED_TITLE);
+               default: return "";
        }
 }
 
@@ -329,17 +316,6 @@ int InterfacePrefs::update(int new_value)
 
 
 
-
-
-
-
-
-
-
-
-
-
-
 IndexPathText::IndexPathText(int x,
        int y,
        PreferencesWindow *pwindow,
@@ -403,15 +379,22 @@ int IndexCount::handle_event()
 
 
 
+IndexFFMPEGMarkerFiles::IndexFFMPEGMarkerFiles(InterfacePrefs *iface_prefs, int x, int y)
+ : BC_CheckBox(x, y,
+       iface_prefs->pwindow->thread->preferences->ffmpeg_marker_indexes,
+       _("build ffmpeg marker indexes"))
+{
+       this->iface_prefs = iface_prefs;
+}
+IndexFFMPEGMarkerFiles::~IndexFFMPEGMarkerFiles()
+{
+}
 
-
-
-
-
-
-
-
-
+int IndexFFMPEGMarkerFiles::handle_event()
+{
+       iface_prefs->pwindow->thread->preferences->ffmpeg_marker_indexes = get_value();
+       return 1;
+}
 
 
 
index a16cb750720b3f9872309d3fb91273fe5ac18adc..d4f2b97b9e1d0f610f1cfb61b5734a35900ec816 100644 (file)
 #ifndef INTERFACEPREFS_H
 #define INTERFACEPREFS_H
 
+class InterfacePrefs;
+class IndexPathText;
 class IndexSize;
 class IndexCount;
-class IndexPathText;
 class TimeFormatHMS;
 class TimeFormatHMSF;
 class TimeFormatSamples;
@@ -32,19 +33,33 @@ class TimeFormatFrames;
 class TimeFormatHex;
 class TimeFormatFeet;
 class TimeFormatSeconds;
+class TimeFormatFeetSetting;
 class MeterMinDB;
 class MeterMaxDB;
 class MeterVUDB;
 class MeterVUInt;
 class ViewBehaviourText;
+class ViewBehaviourItem;
 class ViewTheme;
 class ViewThumbnails;
 class ViewThemeItem;
 class UseTipWindow;
+class UseWarnIndecies;
+class UseWarnVersion;
+class BD_WarnRoot;
+class ScanCommercials;
+class AndroidRemote;
+class PopupMenuBtnup;
+class ActivateFocusPolicy;
+class DeactivateFocusPolicy;
+class AndroidPIN;
+class AndroidPort;
+class ShBtnPrefs;
 class StillImageUseDuration;
 class StillImageDuration;
 class KeyframeReticle;
-class PopupMenuBtnup;
+class HairlineItem;
+class IndexFFMPEGMarkerFiles;
 
 #include "browsebutton.h"
 #include "deleteallindexes.inc"
@@ -70,6 +85,7 @@ public:
        IndexCount *icount;
        IndexPathText *ipathtext;
        DeleteAllIndexes *deleteall;
+       IndexFFMPEGMarkerFiles *ffmpeg_marker_files;
 
        TimeFormatHMS *hms;
        TimeFormatHMSF *hmsf;
@@ -414,4 +430,16 @@ public:
        int hairline;
 };
 
+class IndexFFMPEGMarkerFiles : public BC_CheckBox
+{
+public:
+       IndexFFMPEGMarkerFiles(InterfacePrefs *iface_prefs, int x, int y);
+       ~IndexFFMPEGMarkerFiles();
+
+       int handle_event();
+
+       InterfacePrefs *iface_prefs;
+};
+
+
 #endif
index 1b75ddfcd4078dd0f9fa00f6f6a8e6cdb255f9e8..a3fb40385fab857918ea6a0f5c68a81f9b670a5e 100644 (file)
@@ -616,7 +616,8 @@ Undo::Undo(MWindow *mwindow) : BC_MenuItem(_("Undo"), "z", 'z')
 }
 int Undo::handle_event()
 {
-       mwindow->undo_entry(mwindow->gui);
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->undo_entry(mwindow->gui);
        return 1;
 }
 int Undo::update_caption(const char *new_caption)
@@ -636,8 +637,8 @@ Redo::Redo(MWindow *mwindow) : BC_MenuItem(_("Redo"), _("Shift-Z"), 'Z')
 
 int Redo::handle_event()
 {
-       mwindow->redo_entry(mwindow->gui);
-
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->redo_entry(mwindow->gui);
        return 1;
 }
 int Redo::update_caption(const char *new_caption)
@@ -657,7 +658,8 @@ CutKeyframes::CutKeyframes(MWindow *mwindow)
 
 int CutKeyframes::handle_event()
 {
-       mwindow->cut_automation();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->cut_automation();
        return 1;
 }
 
@@ -670,7 +672,8 @@ CopyKeyframes::CopyKeyframes(MWindow *mwindow)
 
 int CopyKeyframes::handle_event()
 {
-       mwindow->copy_automation();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->copy_automation();
        return 1;
 }
 
@@ -683,7 +686,8 @@ PasteKeyframes::PasteKeyframes(MWindow *mwindow)
 
 int PasteKeyframes::handle_event()
 {
-       mwindow->paste_automation();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->paste_automation();
        return 1;
 }
 
@@ -696,7 +700,8 @@ ClearKeyframes::ClearKeyframes(MWindow *mwindow)
 
 int ClearKeyframes::handle_event()
 {
-       mwindow->clear_automation();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->clear_automation();
        return 1;
 }
 
@@ -799,7 +804,8 @@ CutDefaultKeyframe::CutDefaultKeyframe(MWindow *mwindow)
 
 int CutDefaultKeyframe::handle_event()
 {
-       mwindow->cut_default_keyframe();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->cut_default_keyframe();
        return 1;
 }
 
@@ -812,7 +818,8 @@ CopyDefaultKeyframe::CopyDefaultKeyframe(MWindow *mwindow)
 
 int CopyDefaultKeyframe::handle_event()
 {
-       mwindow->copy_default_keyframe();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->copy_default_keyframe();
        return 1;
 }
 
@@ -825,7 +832,8 @@ PasteDefaultKeyframe::PasteDefaultKeyframe(MWindow *mwindow)
 
 int PasteDefaultKeyframe::handle_event()
 {
-       mwindow->paste_default_keyframe();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->paste_default_keyframe();
        return 1;
 }
 
@@ -838,7 +846,8 @@ ClearDefaultKeyframe::ClearDefaultKeyframe(MWindow *mwindow)
 
 int ClearDefaultKeyframe::handle_event()
 {
-       mwindow->clear_default_keyframe();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->clear_default_keyframe();
        return 1;
 }
 
@@ -850,7 +859,8 @@ Cut::Cut(MWindow *mwindow)
 
 int Cut::handle_event()
 {
-       mwindow->cut();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->cut();
        return 1;
 }
 
@@ -862,7 +872,8 @@ Copy::Copy(MWindow *mwindow)
 
 int Copy::handle_event()
 {
-       mwindow->copy();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->copy();
        return 1;
 }
 
@@ -874,7 +885,8 @@ Paste::Paste(MWindow *mwindow)
 
 int Paste::handle_event()
 {
-       mwindow->paste();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->paste();
        return 1;
 }
 
@@ -886,9 +898,11 @@ Clear::Clear(MWindow *mwindow)
 
 int Clear::handle_event()
 {
-       mwindow->cwindow->gui->lock_window("Clear::handle_event");
-       mwindow->clear_entry();
-       mwindow->cwindow->gui->unlock_window();
+       if( mwindow->session->current_operation == NO_OPERATION ) {
+               mwindow->cwindow->gui->lock_window("Clear::handle_event");
+               mwindow->clear_entry();
+               mwindow->cwindow->gui->unlock_window();
+       }
        return 1;
 }
 
@@ -901,7 +915,8 @@ PasteSilence::PasteSilence(MWindow *mwindow)
 
 int PasteSilence::handle_event()
 {
-       mwindow->paste_silence();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->paste_silence();
        return 1;
 }
 
@@ -913,7 +928,8 @@ SelectAll::SelectAll(MWindow *mwindow)
 
 int SelectAll::handle_event()
 {
-       mwindow->select_all();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->select_all();
        return 1;
 }
 
@@ -959,7 +975,8 @@ MuteSelection::MuteSelection(MWindow *mwindow)
 
 int MuteSelection::handle_event()
 {
-       mwindow->mute_selection();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->mute_selection();
        return 1;
 }
 
@@ -997,7 +1014,8 @@ AddAudioTrack::AddAudioTrack(MWindow *mwindow)
 
 int AddAudioTrack::handle_event()
 {
-       mwindow->add_audio_track_entry(0, 0);
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->add_audio_track_entry(0, 0);
        return 1;
 }
 
@@ -1020,7 +1038,8 @@ DefaultATransition::DefaultATransition(MWindow *mwindow)
 
 int DefaultATransition::handle_event()
 {
-       mwindow->paste_audio_transition();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->paste_audio_transition();
        return 1;
 }
 
@@ -1064,7 +1083,8 @@ AddVideoTrack::AddVideoTrack(MWindow *mwindow)
 
 int AddVideoTrack::handle_event()
 {
-       mwindow->add_video_track_entry();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->add_video_track_entry();
        return 1;
 }
 
@@ -1104,7 +1124,8 @@ DefaultVTransition::DefaultVTransition(MWindow *mwindow)
 
 int DefaultVTransition::handle_event()
 {
-       mwindow->paste_video_transition();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->paste_video_transition();
        return 1;
 }
 
@@ -1143,7 +1164,8 @@ DeleteTrack::DeleteTrack(MWindow *mwindow)
 
 int DeleteTrack::handle_event()
 {
-       mwindow->delete_track();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->delete_track();
        return 1;
 }
 
@@ -1155,7 +1177,8 @@ MoveTracksUp::MoveTracksUp(MWindow *mwindow)
 
 int MoveTracksUp::handle_event()
 {
-       mwindow->move_tracks_up();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->move_tracks_up();
        return 1;
 }
 
@@ -1167,7 +1190,8 @@ MoveTracksDown::MoveTracksDown(MWindow *mwindow)
 
 int MoveTracksDown::handle_event()
 {
-       mwindow->move_tracks_down();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->move_tracks_down();
        return 1;
 }
 
@@ -1201,8 +1225,10 @@ LoopPlayback::LoopPlayback(MWindow *mwindow)
 
 int LoopPlayback::handle_event()
 {
-       mwindow->toggle_loop_playback();
-       set_checked(mwindow->edl->local_session->loop_playback);
+       if( mwindow->session->current_operation == NO_OPERATION ) {
+               mwindow->toggle_loop_playback();
+               set_checked(mwindow->edl->local_session->loop_playback);
+       }
        return 1;
 }
 
@@ -1220,7 +1246,8 @@ AddSubttlTrack::AddSubttlTrack(MWindow *mwindow)
 
 int AddSubttlTrack::handle_event()
 {
-       mwindow->add_subttl_track_entry();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->add_subttl_track_entry();
        return 1;
 }
 
@@ -1232,7 +1259,8 @@ PasteSubttl::PasteSubttl(MWindow *mwindow)
 
 int PasteSubttl::handle_event()
 {
-       mwindow->gui->swindow->paste_subttl();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->gui->swindow->paste_subttl();
        return 1;
 }
 
@@ -1246,9 +1274,11 @@ SetBRenderActive::SetBRenderActive(MWindow *mwindow)
 
 int SetBRenderActive::handle_event()
 {
-       int v = mwindow->brender_active ? 0 : 1;
-       set_checked(v);
-       mwindow->set_brender_active(v);
+       if( mwindow->session->current_operation == NO_OPERATION ) {
+               int v = mwindow->brender_active ? 0 : 1;
+               set_checked(v);
+               mwindow->set_brender_active(v);
+       }
        return 1;
 }
 
@@ -1419,11 +1449,13 @@ ShowGWindow::ShowGWindow(MWindow *mwindow)
 }
 int ShowGWindow::handle_event()
 {
-       if( !mwindow->session->show_gwindow )
-               mwindow->show_gwindow();
-       else
-               mwindow->hide_gwindow();
-       set_checked(mwindow->session->show_gwindow);
+       if( mwindow->session->current_operation == NO_OPERATION ) {
+               if( !mwindow->session->show_gwindow )
+                       mwindow->show_gwindow();
+               else
+                       mwindow->hide_gwindow();
+               set_checked(mwindow->session->show_gwindow);
+       }
        return 1;
 }
 
@@ -1450,11 +1482,13 @@ TileWindows::TileWindows(MWindow *mwindow, const char *item_title, int config,
 }
 int TileWindows::handle_event()
 {
-       int window_config = config >= 0 ? config :
-               mwindow->session->window_config;
-       if( mwindow->tile_windows(window_config) ) {
-               mwindow->restart_status = 1;
-               mwindow->gui->set_done(0);
+       if( mwindow->session->current_operation == NO_OPERATION ) {
+               int window_config = config >= 0 ? config :
+                       mwindow->session->window_config;
+               if( mwindow->tile_windows(window_config) ) {
+                       mwindow->restart_status = 1;
+                       mwindow->gui->set_done(0);
+               }
        }
        return 1;
 }
@@ -1468,7 +1502,8 @@ SplitX::SplitX(MWindow *mwindow)
 }
 int SplitX::handle_event()
 {
-       mwindow->split_x();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->split_x();
        return 1;
 }
 
@@ -1481,7 +1516,8 @@ SplitY::SplitY(MWindow *mwindow)
 }
 int SplitY::handle_event()
 {
-       mwindow->split_y();
+       if( mwindow->session->current_operation == NO_OPERATION )
+               mwindow->split_y();
        return 1;
 }
 
index 478c845c2279d08ea4ec29ce9d345297e68113ce..ec1376878f4a2ee62926ebfcb417df4c33dc2fa9 100644 (file)
@@ -1461,11 +1461,9 @@ SET_TRACE
                        case FILE_UNRECOGNIZED_CODEC:
                        {
 // Test index file
-                               IndexFile indexfile(this, new_asset);
-                               result = indexfile.open_index();
-                               if(!result)
-                               {
-                                       indexfile.close_index();
+                               {       IndexFile indexfile(this, new_asset);
+                                       if( !(result = indexfile.open_index()) )
+                                               indexfile.close_index();
                                }
 
 // Test existing EDLs
@@ -1474,7 +1472,7 @@ SET_TRACE
                                                new_edls[j]->assets->get_asset(new_asset->path) :
                                                edl->assets->get_asset(new_asset->path);
                                        if( old_asset ) {
-                                               *new_asset = *old_asset;
+                                               new_asset->copy_from(old_asset,1);
                                                result = 0;
                                        }
                                }
index 9724470dc31d927b695eaa452aa0b1531979858b..ed12ca654267b0dbce7b66ec9464669c1324a8f7 100644 (file)
@@ -2272,12 +2272,12 @@ int PaneButton::button_release_event()
 
 
 FFMpegToggle::FFMpegToggle(MWindow *mwindow, MButtons *mbuttons, int x, int y)
- : BC_Toggle(x, y, mwindow->theme->ffmpeg_toggle, mwindow->preferences->ffmpeg_early_probe)
+ : BC_Toggle(x, y, mwindow->theme->ffmpeg_toggle,
+        mwindow->preferences->get_file_probe_armed("FFMPEG_Early") > 0 ? 1 : 0)
 {
        this->mwindow = mwindow;
        this->mbuttons = mbuttons;
-       set_tooltip( mwindow->preferences->ffmpeg_early_probe ?
-               _("Try FFMpeg first") : _("Try FFMpeg last"));
+       set_tooltip( !get_value() ? _("Try FFMpeg first") : _("Try FFMpeg last") );
 }
 
 FFMpegToggle::~FFMpegToggle()
@@ -2286,9 +2286,11 @@ FFMpegToggle::~FFMpegToggle()
 
 int FFMpegToggle::handle_event()
 {
-       mwindow->preferences->ffmpeg_early_probe = get_value();
-       set_tooltip( mwindow->preferences->ffmpeg_early_probe ?
-               _("Try FFMpeg first") : _("Try FFMpeg last"));
+       int ffmpeg_early_probe = get_value();
+       set_tooltip( !ffmpeg_early_probe ?  _("Try FFMpeg first") : _("Try FFMpeg last"));
+       mwindow->preferences->set_file_probe_armed("FFMPEG_Early", ffmpeg_early_probe);
+       mwindow->preferences->set_file_probe_armed("FFMPEG_Late", !ffmpeg_early_probe);
+       
        mwindow->show_warning(&mwindow->preferences->warn_indexes,
                _("Changing the base codecs may require rebuilding indexes."));
        return 1;
index f6b2ab0344eae3b7e676ea016ef6be19fe358563..8edc41d51bc264b1e31f2e23d6582cecef64511e 100644 (file)
@@ -28,6 +28,7 @@
 #include "mwindow.h"
 #include "performanceprefs.h"
 #include "preferences.h"
+#include "probeprefs.h"
 #include <string.h>
 #include "theme.h"
 
@@ -40,11 +41,13 @@ PerformancePrefs::PerformancePrefs(MWindow *mwindow, PreferencesWindow *pwindow)
  : PreferencesDialog(mwindow, pwindow)
 {
        hot_node = -1;
+       file_probe_dialog = 0;
 }
 
 PerformancePrefs::~PerformancePrefs()
 {
        delete brender_tools;
+       delete file_probe_dialog;
        nodes[0].remove_all_objects();
        nodes[1].remove_all_objects();
        nodes[2].remove_all_objects();
@@ -61,7 +64,7 @@ void PerformancePrefs::create_objects()
        char string[BCTEXTLEN];
        BC_Resources *resources = BC_WindowBase::get_resources();
        BC_WindowBase *win;
-       int maxw, curw, y1;
+       int maxw, curw;
 
        node_list = 0;
        generate_node_list();
@@ -77,30 +80,25 @@ void PerformancePrefs::create_objects()
 //
 //     y += get_text_height(LARGEFONT) + 5;
 
-       int ybx[2];
-       ybx[0] = y;
+       int y0 = y;
 
        win = add_subwindow(new BC_Title(x, y + 5, _("Cache size (MB):"), MEDIUMFONT, resources->text_default));
        maxw = win->get_w();
 
-       ybx[1] = y += 30;
+       int y1 = y += 30;
        win = add_subwindow(new BC_Title(x, y + 5, _("Seconds to preroll renders:")));
        if((curw = win->get_w()) > maxw)
                maxw = curw;
        maxw += x + 5;
 
-       cache_size = new CICacheSize(maxw,
-               ybx[0],
-               pwindow,
-               this);
+       cache_size = new CICacheSize(maxw, y0, pwindow, this);
        cache_size->create_objects();
+       int x1 = cache_size->get_x() + cache_size->get_w() + 30;
+       add_subwindow(file_probes = new PrefsFileProbes(pwindow, this, x1, y0));
+
        add_subwindow(new BC_Title(x, y + 5, _("Seconds to preroll renders:")));
-       PrefsRenderPreroll *preroll = new PrefsRenderPreroll(pwindow,
-               this,
-               maxw,
-               ybx[1]);
+       PrefsRenderPreroll *preroll = new PrefsRenderPreroll(pwindow, this, maxw, y1);
        preroll->create_objects();
-       int x1 = preroll->get_x() + preroll->get_w() + 20;
        BC_Title *smp_title = new BC_Title(x1, y + 5, _("Project SMP cpus:"));
        add_subwindow(smp_title);
        int x2 = x1 + smp_title->get_w() + 5;
@@ -122,13 +120,8 @@ void PerformancePrefs::create_objects()
        PrefsTrapSigINTR *trap_intr = new PrefsTrapSigINTR(this, x1, y);
        add_subwindow(trap_intr);
        add_subwindow(new BC_Title(x2, y, _("(must be root)"), MEDIUMFONT, RED));
-       ffmpeg_marker_indexes = new PrefsFFMPEGMarkerIndecies(this, x, y);
-       add_subwindow(ffmpeg_marker_indexes);
        y += 30;
 
-       ffmpeg_early_probe = new PrefsFFMPEGEarlyProbe(this, x, y);
-       add_subwindow(ffmpeg_early_probe);
-
        yuv420p_dvdlace = new PrefsYUV420P_DVDlace(pwindow, this, x1, y);
        add_subwindow(yuv420p_dvdlace);
        y += 30;
@@ -353,6 +346,29 @@ void PerformancePrefs::update_rates()
        update_node_list();
 }
 
+void PerformancePrefs::start_probe_dialog()
+{
+       if( !file_probe_dialog )
+               file_probe_dialog = new FileProbeDialog(pwindow);
+       file_probe_dialog->start();
+}
+
+PrefsFileProbes::PrefsFileProbes(PreferencesWindow *pwindow,
+               PerformancePrefs *perf_prefs, int x, int y)
+ : BC_GenericButton(x, y, _("Probe Order"))
+{
+       this->pwindow = pwindow;
+       this->perf_prefs = perf_prefs;
+       set_tooltip(_("File Open Probe Ordering"));
+}
+
+int PrefsFileProbes::handle_event()
+{
+       perf_prefs->start_probe_dialog();
+       return 1;
+}
+
+
 
 PrefsUseBRender::PrefsUseBRender(PreferencesWindow *pwindow,
        int x,
@@ -559,44 +575,6 @@ int PrefsTrapSigINTR::handle_event()
 }
 
 
-PrefsFFMPEGEarlyProbe::PrefsFFMPEGEarlyProbe(PerformancePrefs *perf_prefs, int x, int y)
- : BC_CheckBox(x, y,
-       perf_prefs->pwindow->thread->preferences->ffmpeg_early_probe,
-       _("On file open, ffmpeg probes early"))
-{
-       this->perf_prefs = perf_prefs;
-}
-PrefsFFMPEGEarlyProbe::~PrefsFFMPEGEarlyProbe()
-{
-}
-
-int PrefsFFMPEGEarlyProbe::handle_event()
-{
-       perf_prefs->pwindow->thread->preferences->ffmpeg_early_probe = get_value();
-       return 1;
-}
-
-
-PrefsFFMPEGMarkerIndecies::PrefsFFMPEGMarkerIndecies(PerformancePrefs *perf_prefs, int x, int y)
- : BC_CheckBox(x, y,
-       perf_prefs->pwindow->thread->preferences->ffmpeg_marker_indexes,
-       _("build ffmpeg marker indexes"))
-{
-       this->perf_prefs = perf_prefs;
-}
-PrefsFFMPEGMarkerIndecies::~PrefsFFMPEGMarkerIndecies()
-{
-}
-
-int PrefsFFMPEGMarkerIndecies::handle_event()
-{
-       perf_prefs->pwindow->thread->preferences->ffmpeg_marker_indexes = get_value();
-       return 1;
-}
-
-
-
-
 
 
 PrefsRenderFarmConsolidate::PrefsRenderFarmConsolidate(PreferencesWindow *pwindow, int x, int y)
@@ -617,9 +595,6 @@ int PrefsRenderFarmConsolidate::handle_event()
 }
 
 
-
-
-
 PrefsRenderFarmPort::PrefsRenderFarmPort(PreferencesWindow *pwindow,
        PerformancePrefs *subwindow,
        int x,
index a792300261cd2b3e8c6cfeae880c214f7aceb59b..22ba6c439a90c3a2ee79ab344181b8e454741a63 100644 (file)
@@ -27,6 +27,7 @@
 #include "mwindow.inc"
 #include "performanceprefs.inc"
 #include "preferencesthread.h"
+#include "probeprefs.inc"
 
 
 class PerformancePrefs : public PreferencesDialog
@@ -40,10 +41,12 @@ public:
        void generate_node_list();
        void update_node_list();
        void update_rates();
+       void start_probe_dialog();
 
        int hot_node;
 
        CICacheSize *cache_size;
+       PrefsFileProbes *file_probes;
 
        enum
        {
@@ -60,9 +63,8 @@ public:
        PrefsRenderFarmNodes *node_list;
        FormatTools *brender_tools;
        BC_Title *master_rate;
-       PrefsFFMPEGEarlyProbe *ffmpeg_early_probe;
        PrefsYUV420P_DVDlace *yuv420p_dvdlace;
-       PrefsFFMPEGMarkerIndecies *ffmpeg_marker_indexes;
+       FileProbeDialog *file_probe_dialog;
 };
 
 
@@ -145,17 +147,6 @@ public:
        PerformancePrefs *perf_prefs;
 };
 
-class PrefsFFMPEGEarlyProbe : public BC_CheckBox
-{
-public:
-       PrefsFFMPEGEarlyProbe(PerformancePrefs *perf_prefs, int x, int y);
-       ~PrefsFFMPEGEarlyProbe();
-
-       int handle_event();
-
-       PerformancePrefs *perf_prefs;
-};
-
 class PrefsFFMPEGMarkerIndecies : public BC_CheckBox
 {
 public:
@@ -382,4 +373,16 @@ public:
        PreferencesWindow *pwindow;
 };
 
+
+class PrefsFileProbes : public BC_GenericButton
+{
+public:
+       PreferencesWindow *pwindow;
+       PerformancePrefs *perf_prefs;
+
+       int handle_event();
+       PrefsFileProbes(PreferencesWindow *pwindow, PerformancePrefs *perf_prefs, int x, int y);
+};
+
+
 #endif
index 59e3d8dfc7d0a5f28051bac76849fbcac3fee46c..af2297162cfe23a869e80e84e1af6443d0aa9f9b 100644 (file)
@@ -47,5 +47,7 @@ class PrefsRenderFarmSortNodes;
 class PrefsRenderFarmReset;
 class PrefsYUV420P_DVDlace;
 class CICacheSize;
+class PrefsFileProbes;
+
 
 #endif
index f69ab3e847898b9e5520b194df0174b0fb0b529c..5bc21f62d77829c2b0bbef4f5ec63abb32fbe981 100644 (file)
@@ -33,6 +33,7 @@
 #include "indexfile.h"
 #include "mutex.h"
 #include "preferences.h"
+#include "probeprefs.h"
 #include "shbtnprefs.h"
 #include "theme.h"
 #include "videoconfig.h"
@@ -77,7 +78,6 @@ Preferences::Preferences()
        renderfarm_job_count = 20;
        project_smp = processors = calculate_processors(0);
        real_processors = calculate_processors(1);
-       ffmpeg_early_probe = 1;
        ffmpeg_marker_indexes = 1;
        warn_indexes = 1;
        warn_version = 1;
@@ -120,6 +120,7 @@ Preferences::~Preferences()
 {
        brender_asset->Garbage::remove_user();
        shbtn_prefs.remove_all_objects();
+       file_probes.remove_all_objects();
        renderfarm_nodes.remove_all_objects();
        delete preferences_lock;
 }
@@ -180,6 +181,9 @@ void Preferences::copy_from(Preferences *that)
        this->shbtn_prefs.remove_all_objects();
        for( int i=0; i<that->shbtn_prefs.size(); ++i )
                this->shbtn_prefs.append(new ShBtnPref(*that->shbtn_prefs[i]));
+       this->file_probes.remove_all_objects();
+       for( int i=0; i<that->file_probes.size(); ++i )
+               this->file_probes.append(new ProbePref(*that->file_probes[i]));
        cache_size = that->cache_size;
        project_smp = that->project_smp;
        force_uniprocessor = that->force_uniprocessor;
@@ -187,7 +191,6 @@ void Preferences::copy_from(Preferences *that)
        trap_sigintr = that->trap_sigintr;
        processors = that->processors;
        real_processors = that->real_processors;
-       ffmpeg_early_probe = that->ffmpeg_early_probe;
        ffmpeg_marker_indexes = that->ffmpeg_marker_indexes;
        warn_indexes = that->warn_indexes;
        warn_version = that->warn_version;
@@ -339,7 +342,6 @@ int Preferences::load_defaults(BC_Hash *defaults)
 
        project_smp = defaults->get("PROJECT_SMP", project_smp);
        force_uniprocessor = defaults->get("FORCE_UNIPROCESSOR", force_uniprocessor);
-       ffmpeg_early_probe = defaults->get("FFMPEG_EARLY_PROBE", ffmpeg_early_probe);
        ffmpeg_marker_indexes = defaults->get("FFMPEG_MARKER_INDEXES", ffmpeg_marker_indexes);
        warn_indexes = defaults->get("WARN_INDEXES", warn_indexes);
        warn_version = defaults->get("WARN_VERSION", warn_version);
@@ -406,6 +408,28 @@ int Preferences::load_defaults(BC_Hash *defaults)
                shbtn_prefs.append(new ShBtnPref(name, commands, warn));
        }
 
+       file_probes.remove_all_objects();
+       int file_probe_total = defaults->get("FILE_PROBE_TOTAL", 0);
+       for( int i=0; i<file_probe_total; ++i ) {
+               char name[BCTEXTLEN];
+               sprintf(string, "FILE_PROBE%d_NAME", i);
+               defaults->get(string, name);
+               sprintf(string, "FILE_PROBE%d_ARMED", i);
+               int armed = defaults->get(string, 1);
+               file_probes.append(new ProbePref(name, armed));
+       }
+       // append any missing probes
+       for( int i=0; i<File::nb_probes; ++i ) {
+               const char *nm = File::default_probes[i];
+               int k = file_probes.size();
+               while( --k>=0 && strcmp(nm, file_probes[k]->name) );
+               if( k >= 0 ) continue;
+               int armed = 1;
+               if( !strcmp(nm, "FFMPEG_Late") ||
+                   !strcmp(nm, "CR2") ) armed = 0;
+               file_probes.append(new ProbePref(nm, armed));
+       }
+
 // Redo with the proper value of force_uniprocessor
        processors = calculate_processors(0);
        boundaries();
@@ -445,7 +469,6 @@ int Preferences::save_defaults(BC_Hash *defaults)
 
        defaults->update("PROJECT_SMP", project_smp);
        defaults->update("FORCE_UNIPROCESSOR", force_uniprocessor);
-       defaults->update("FFMPEG_EARLY_PROBE", ffmpeg_early_probe);
        defaults->update("FFMPEG_MARKER_INDEXES", ffmpeg_marker_indexes);
        defaults->update("WARN_INDEXES", warn_indexes);
        defaults->update("WARN_VERSION", warn_version);
@@ -487,6 +510,14 @@ int Preferences::save_defaults(BC_Hash *defaults)
                sprintf(string, "SHBTN%d_WARN", i);
                defaults->update(string, pref->warn);
        }
+       defaults->update("FILE_PROBE_TOTAL", file_probes.size());
+       for( int i=0; i<file_probes.size(); ++i ) {
+               ProbePref *pref = file_probes[i];
+               sprintf(string, "FILE_PROBE%d_NAME", i);
+               defaults->update(string, pref->name);
+               sprintf(string, "FILE_PROBE%d_ARMED", i);
+               defaults->update(string, pref->armed);
+       }
        return 0;
 }
 
@@ -739,3 +770,19 @@ int Preferences::calculate_processors(int interactive)
        return BC_WindowBase::get_resources()->machine_cpus;
 }
 
+int Preferences::get_file_probe_armed(const char *nm)
+{
+       int k = file_probes.size();
+       while( --k>=0 && strcmp(nm, file_probes[k]->name) );
+       if( k < 0 ) return -1;
+       return file_probes[k]->armed;
+}
+
+void Preferences::set_file_probe_armed(const char *nm, int v)
+{
+       int k = file_probes.size();
+       while( --k>=0 && strcmp(nm, file_probes[k]->name) );
+       if( k < 0 ) return;
+       file_probes[k]->armed = v;
+}
+
index a54aa4662fb666dc3ec66712ce49973594c02973..af401ac08932a3dfa0968b06a71ec714cbdaf038 100644 (file)
@@ -29,6 +29,7 @@
 #include "maxchannels.h"
 #include "mutex.inc"
 #include "preferences.inc"
+#include "probeprefs.inc"
 #include "shbtnprefs.inc"
 #include "videoconfig.inc"
 
@@ -76,7 +77,9 @@ public:
 // Determined by /proc/cpuinfo and force_uniprocessor.
 // interactive forces it to ignore force_uniprocessor
        int calculate_processors(int interactive = 0);
-
+// file probe armed
+       int get_file_probe_armed(const char *nm);
+       void set_file_probe_armed(const char *nm, int v);
 // ================================= Performance ================================
 // directory to look in for indexes
        char index_directory[BCTEXTLEN];
@@ -99,8 +102,6 @@ public:
        int processors;
 // Number of processors for interactive operations.
        int real_processors;
-// ffmpeg probes early/late during File::open_file read
-       int ffmpeg_early_probe;
 // ffmpeg builds marker indexes as it builds idx files
        int ffmpeg_marker_indexes;
 // warning
@@ -153,6 +154,8 @@ public:
        char android_pin[BCSTRLEN];
 // shell cmd line menu ops
        ArrayList<ShBtnPref *> shbtn_prefs;
+// file open probe order
+       ArrayList<ProbePref *> file_probes;
 
 // ====================================== Plugin Set ==============================
        char plugin_dir[BCTEXTLEN];
index dd8e9c5182ee8dfdf3f004cf3102c1921f3e065d..4d1a41561c4e2896d5ad1bade1f68160a10187b0 100644 (file)
@@ -229,8 +229,9 @@ int PreferencesThread::apply_settings()
        }
 
        mwindow->reset_android_remote();
-       mwindow->gui->ffmpeg_toggle->update(mwindow->preferences->ffmpeg_early_probe);
-       mwindow->gui->ffmpeg_toggle->set_tooltip( mwindow->preferences->ffmpeg_early_probe ?
+       int ffmpeg_early_probe = mwindow->preferences->get_file_probe_armed("FFPMEG_Early");
+       mwindow->gui->ffmpeg_toggle->update(ffmpeg_early_probe);
+       mwindow->gui->ffmpeg_toggle->set_tooltip(ffmpeg_early_probe ?
                _("Try FFMpeg first") : _("Try FFMpeg last") );
        mwindow->gui->mainshbtns->load(mwindow->preferences);
        double tc_position =
diff --git a/cinelerra-5.1/cinelerra/probeprefs.C b/cinelerra-5.1/cinelerra/probeprefs.C
new file mode 100644 (file)
index 0000000..dcce262
--- /dev/null
@@ -0,0 +1,270 @@
+#include "bcwindowbase.h"
+#include "bcdisplayinfo.h"
+#include "bcdialog.h"
+#include "language.h"
+#include "mainerror.h"
+#include "mwindow.h"
+#include "probeprefs.h"
+#include "preferences.h"
+#include "preferencesthread.h"
+#include "theme.h"
+
+#include <sys/wait.h>
+
+ProbePref::ProbePref(const char *nm, int armed)
+{
+       strncpy(name, nm, sizeof(name));
+       this->armed = armed;
+}
+
+ProbePref::~ProbePref()
+{
+}
+
+FileProbeDialog::FileProbeDialog(PreferencesWindow *pwindow)
+ : BC_DialogThread()
+{
+       this->pwindow = pwindow;
+}
+
+FileProbeDialog::~FileProbeDialog()
+{
+       close_window();
+}
+
+BC_Window* FileProbeDialog::new_gui()
+{
+       BC_DisplayInfo display_info;
+       int x = display_info.get_abs_cursor_x();
+       int y = display_info.get_abs_cursor_y();
+
+       pb_window = new ProbeEditWindow(this, x, y);
+       pb_window->create_objects();
+       return pb_window;
+}
+
+void FileProbeDialog::handle_close_event(int result)
+{
+       pb_window = 0;
+}
+
+
+ProbeEditWindow::ProbeEditWindow(FileProbeDialog *pb_dialog, int x, int y)
+ : BC_Window(_(PROGRAM_NAME ": Probes"), x, y, 300, 200, 300, 200, 0, 0, 1)
+{
+       this->pb_dialog = pb_dialog;
+       probe_list = 0;
+       probe_up_button = 0;
+       probe_down_button = 0;
+       probe_enabled = 0;
+       pb_enabled = 0;
+       pb_disabled = 0;
+}
+
+ProbeEditWindow::~ProbeEditWindow()
+{
+       delete pb_enabled;
+       delete pb_disabled;
+}
+
+void ProbeEditWindow::create_objects()
+{
+       pb_enabled = new BC_Pixmap(this,
+                BC_WindowBase::get_resources()->listbox_up,
+                PIXMAP_ALPHA);
+       pb_disabled = new BC_Pixmap(this,
+                BC_WindowBase::get_resources()->listbox_dn,
+                PIXMAP_ALPHA);
+       Preferences *preferences = pb_dialog->pwindow->thread->preferences;
+       for( int i=0; i<preferences->file_probes.size(); ++i ) {
+               probe_items.append(new ProbePrefItem(this, preferences->file_probes[i]));
+       }
+       int x = 10, y = 10;
+       add_subwindow(probe_list = new ProbePrefList(this, x, y));
+       y += probe_list->get_h();
+       int x1 = x, y1 = y;
+       add_subwindow(probe_up_button = new ProbeUpButton(this, x1, y1));
+       x1 += probe_up_button->get_w() + 10;
+       add_subwindow(probe_down_button = new ProbeDownButton(this, x1, y1));
+       x1 += probe_down_button->get_w() + 10;
+       add_subwindow(probe_enabled = new ProbeEnabled(this, x1, y1));
+       probe_enabled->disable();
+
+       add_subwindow(new ProbeEditOK(this));
+       add_subwindow(new BC_CancelButton(this));
+
+       list_update();
+       show_window();
+}
+
+ProbeEditOK::ProbeEditOK(ProbeEditWindow *pb_window)
+ : BC_OKButton(pb_window)
+{
+        this->pb_window = pb_window;
+}
+
+ProbeEditOK::~ProbeEditOK()
+{
+}
+
+int ProbeEditOK::handle_event()
+{
+        Preferences *preferences = pb_window->pb_dialog->pwindow->thread->preferences;
+       ArrayList<ProbePref *> &file_probes = preferences->file_probes;
+       file_probes.remove_all_objects();
+       ArrayList<ProbePrefItem *> &probe_items = pb_window->probe_items;
+        for( int i=0; i<probe_items.size(); ++i ) {
+                ProbePrefItem *item = probe_items[i];
+                file_probes.append(new ProbePref(item->get_text(), item->armed));
+        }
+        return BC_OKButton::handle_event();
+}
+
+int ProbeEditWindow::list_update()
+{
+//for( int i=0; i<probe_items.size(); ++i ) printf("%s, ",probe_items[i]->get_text()); printf("\n");
+       probe_list->update((ArrayList<BC_ListBoxItem*> *)&probe_items, 0, 0, 1,
+               probe_list->get_xposition(), probe_list->get_yposition(),
+               probe_list->get_highlighted_item(), 1, 0);
+       probe_list->center_selection();
+       return 1;
+}
+
+ProbeUpButton::ProbeUpButton(ProbeEditWindow *pb_window, int x, int y)
+ : BC_GenericButton(x, y, _("Up"))
+{
+       this->pb_window = pb_window;
+}
+
+ProbeUpButton::~ProbeUpButton()
+{
+}
+
+int ProbeUpButton::handle_event()
+{
+       ArrayList<ProbePrefItem *> &probe_items = pb_window->probe_items;
+       int n = probe_items.size();
+       if( n > 1 ) {
+               ProbePrefItem **pitem = &probe_items[0], *item0 = *pitem;
+               for( int i=1; i<n; ++i ) {
+                       ProbePrefItem *&item = probe_items[i];
+                       if( item->get_selected() ) {
+                               ProbePrefItem *t = item;  item = *pitem; *pitem = t;
+                       }
+                       pitem = &item;
+               }
+               if( item0->get_selected() ) {
+                       ProbePrefItem *t = *pitem;  *pitem = item0;  probe_items[0] = t;
+               }
+       }
+       pb_window->list_update();
+       return 1;
+}
+
+ProbeDownButton::ProbeDownButton(ProbeEditWindow *pb_window, int x, int y)
+ : BC_GenericButton(x, y, _("Down"))
+{
+       this->pb_window = pb_window;
+}
+
+ProbeDownButton::~ProbeDownButton()
+{
+}
+
+ProbeEnabled::ProbeEnabled(ProbeEditWindow *pb_window, int x, int y)
+ : BC_CheckBox(x, y, 0, _("Enabled"))
+{
+       this->pb_window = pb_window;
+}
+ProbeEnabled::~ProbeEnabled()
+{
+}
+
+int ProbeEnabled::handle_event()
+{
+       ProbePrefItem *item = (ProbePrefItem *)pb_window->probe_list->get_selection(0,0);
+       if( item ) {
+               item->set_armed(get_value());
+               pb_window->list_update();
+       }
+       return 1;
+}
+
+int ProbeDownButton::handle_event()
+{
+       ArrayList<ProbePrefItem *> &probe_items = pb_window->probe_items;
+       int n = probe_items.size();
+       if( n > 1 ) {
+               ProbePrefItem **pitem = &probe_items[n-1], *item1 = *pitem;
+               for( int i=n-1; --i>=0; ) {
+                       ProbePrefItem *&item = probe_items[i];
+                       if( item->get_selected() ) {
+                               ProbePrefItem *t = item;  item = *pitem; *pitem = t;
+                       }
+                       pitem = &item;
+               }
+               if( item1->get_selected() ) {
+                       ProbePrefItem *t = *pitem;  *pitem = item1;  probe_items[n-1] = t;
+               }
+       }
+       pb_window->list_update();
+       return 1;
+}
+
+ProbePrefItem::ProbePrefItem(ProbeEditWindow *pb_window, ProbePref *pref)
+ : BC_ListBoxItem(pref->name, pref->armed ?
+               pb_window->pb_enabled : pb_window->pb_disabled)
+{
+       this->pb_window = pb_window;
+       this->armed = pref->armed;
+}
+
+ProbePrefItem::~ProbePrefItem()
+{
+}
+
+void ProbePrefItem::set_armed(int armed)
+{
+       this->armed = armed;
+       set_icon(armed ? pb_window->pb_enabled : pb_window->pb_disabled);
+}
+
+ProbePrefList::ProbePrefList(ProbeEditWindow *pb_window, int x, int y)
+ : BC_ListBox(x, y, pb_window->get_w()-x-10, pb_window->get_h()-y-80, LISTBOX_ICON_LIST,
+       (ArrayList<BC_ListBoxItem *>*) &pb_window->probe_items, 0, 0)
+{
+       this->pb_window = pb_window;
+}
+
+ProbePrefList::~ProbePrefList()
+{
+}
+
+int ProbePrefList::selection_changed()
+{
+       ProbePrefItem *item = (ProbePrefItem *)pb_window->probe_list->get_selection(0,0);
+       if( item ) {
+               pb_window->probe_enabled->set_value(item->armed);
+               pb_window->probe_enabled->enable();
+       }
+       else {
+               pb_window->probe_enabled->set_value(0);
+               pb_window->probe_enabled->disable();
+       }
+       pb_window->list_update();
+       return 1;
+}
+
+int ProbePrefList::handle_event()
+{
+       if( get_double_click() && get_buttonpress() == 1 ) {
+               ProbePrefItem *item = (ProbePrefItem *)get_selection(0,0);
+               int armed = item->armed ? 0 : 1;
+               pb_window->probe_enabled->enable();
+               pb_window->probe_enabled->set_value(armed);
+               item->set_armed(armed);
+               pb_window->list_update();
+       }
+       return 1;
+}
+
diff --git a/cinelerra-5.1/cinelerra/probeprefs.h b/cinelerra-5.1/cinelerra/probeprefs.h
new file mode 100644 (file)
index 0000000..e7fb5bf
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef __PROBEPREFS_H__
+#define __PROBEPREFS_H__
+
+#include "bcwindowbase.h"
+#include "bcbutton.h"
+#include "bcdialog.h"
+#include "bclistbox.h"
+#include "bclistboxitem.h"
+#include "bctoggle.h"
+#include "preferences.inc"
+#include "preferencesthread.inc"
+#include "thread.h"
+#include "probeprefs.inc"
+
+
+class FileProbeDialog : public BC_DialogThread
+{
+public:
+       PreferencesWindow *pwindow;
+
+        ProbeEditWindow *pb_window;
+       BC_Window* new_gui();
+       void handle_close_event(int result);
+
+       FileProbeDialog(PreferencesWindow *pwindow);
+       ~FileProbeDialog();
+};
+
+class ProbePref
+{
+public:
+       char name[BCSTRLEN];
+       int armed;
+
+       ProbePref(const char *nm, int armed);
+       ~ProbePref();
+};
+
+class ProbeUpButton : public BC_GenericButton {
+public:
+       ProbeEditWindow *pb_window;
+       int handle_event();
+
+       ProbeUpButton(ProbeEditWindow *pb_window, int x, int y);
+       ~ProbeUpButton();
+};
+
+class ProbeDownButton : public BC_GenericButton {
+public:
+       ProbeEditWindow *pb_window;
+       int handle_event();
+
+       ProbeDownButton(ProbeEditWindow *pb_window, int x, int y);
+       ~ProbeDownButton();
+};
+
+class ProbeEnabled : public BC_CheckBox
+{
+public:
+       ProbeEditWindow *pb_window;
+       int handle_event();
+
+       ProbeEnabled(ProbeEditWindow *pb_window, int x, int y);
+       ~ProbeEnabled();
+};
+
+class ProbePrefItem : public BC_ListBoxItem {
+public:
+       ProbeEditWindow *pb_window;
+       int armed;
+       void set_armed(int armed);
+
+       ProbePrefItem(ProbeEditWindow *pb_window, ProbePref *pref);
+       ~ProbePrefItem();
+};
+
+class ProbePrefList : public BC_ListBox
+{
+public:
+       ProbeEditWindow *pb_window;
+       int handle_event();
+       int selection_changed();
+
+       ProbePrefList(ProbeEditWindow *pb_window, int x, int y);
+       ~ProbePrefList();
+};
+
+class ProbeEditOK : public BC_OKButton
+{
+public:
+       ProbeEditWindow *pb_window;
+       int handle_event();
+
+       ProbeEditOK(ProbeEditWindow *pb_window);
+       ~ProbeEditOK();
+};
+
+class ProbeEditWindow : public BC_Window
+{
+public:
+       ProbeUpButton *probe_up_button;
+       ProbeDownButton *probe_down_button;
+       ProbeEnabled *probe_enabled;
+       ArrayList<ProbePrefItem *> probe_items;
+       ProbePrefList *probe_list;
+       BC_Pixmap *pb_enabled, *pb_disabled;
+
+       void create_objects();
+       int list_update();
+
+       ProbeEditWindow(FileProbeDialog *pb_dialog, int x, int y);
+       ~ProbeEditWindow();
+
+       FileProbeDialog *pb_dialog;
+};
+
+#endif
diff --git a/cinelerra-5.1/cinelerra/probeprefs.inc b/cinelerra-5.1/cinelerra/probeprefs.inc
new file mode 100644 (file)
index 0000000..e20e0b4
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef __PROBEPREFS_INC__
+#define __PROBEPREFS_INC__
+
+class FileProbeDialog;
+class ProbePref;
+class ProbeUpButton;
+class ProbeDownButton;
+class ProbePrefItem;
+class ProbePrefList;
+class ProbeEditOK;
+class ProbeEditWindow;
+
+#endif
index 30e167713695b8570a3bc464d4f329ff0eed0397..9e8735cab911e2065f18f13c32ea5e028541c724 100644 (file)
@@ -1,3 +1,4 @@
+https://www.cybercom.net/~dcoffin/dcraw/dcraw.c
 http://download-mirror.savannah.gnu.org/releases//openexr/ilmbase-2.2.0.tar.gz
 http://gnu.mirrors.pair.com/savannah/savannah//openexr/openexr-2.2.0.tar.gz
 https://sourceforge.net/projects/opencvlibrary/files/latest/download?source=directory = 3.2.0