--- dcraw.c	2010-11-11 20:35:59.000000000 -0500
+++ dcraw.cc	2010-11-15 21:14:19.000000000 -0500
@@ -1,3 +1,15 @@
+/*RT*/#include <glib.h>
+/*RT*/#include <glib/gstdio.h>
+/*RT*/#undef MAX
+/*RT*/#undef MIN
+/*RT*/#define NO_LCMS
+/*RT*/#define NO_JPEG
+/*RT*/#define LOCALTIME
+/*RT*/#define DJGPP
+/*RT*/#include <rtthumbnail.h>
+
+#include "myfile.h"
+
 /*
    dcraw.c -- Dave Coffin's raw photo decoder
    Copyright 1997-2010 by Dave Coffin, dcoffin a cybercom o net
@@ -46,7 +58,9 @@
    NO_LCMS disables the "-p" option.
  */
 #ifndef NO_JPEG
-#include <jpeglib.h>
+/*RT*/extern "C" {
+/*RT*/#include <jpeglib.h>
+/*RT*/}
 #endif
 #ifndef NO_LCMS
 #include <lcms.h>
@@ -96,59 +110,84 @@
 typedef unsigned char uchar;
 typedef unsigned short ushort;
 
+// RT specify thread local storage
+#ifdef __GNUC__
+#define THREAD_LOCAL static __thread
+#define THREAD_LOCK  
+#else
+#define THREAD_LOCAL static
+#define THREAD_LOCK  Glib::Mutex::Lock locker(*dcrMutex);
+#endif
+
+// patch for gcc<=4.2 on OSX
+#ifdef __APPLE__
+#define GCC_VERSION (__GNUC__ * 10000 \
+                               + __GNUC_MINOR__ * 100 \
+                               + __GNUC_PATCHLEVEL__)
+#if GCC_VERSION < 40300
+#undef THREAD_LOCAL
+#undef THREAD_LOCK
+#define THREAD_LOCAL static 
+#define THREAD_LOCK  Glib::Mutex::Lock locker(*dcrMutex);
+#endif
+#endif
+
+
 /*
    All global variables are defined here, and all functions that
    access them are prefixed with "CLASS".  Note that a thread-safe
    C++ class cannot have non-const static local variables.
  */
-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[8], 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;
-int flip, tiff_flip, colors;
-double pixel_aspect, aber[4]={1,1,1,1}, gamm[6]={ 0.45,4.5,0,0,0,0 };
-ushort (*image)[4], white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4];
-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 */
+/*RT*/THREAD_LOCAL int ciff_base, ciff_len, exif_base, pre_filters;
+/*RT*/THREAD_LOCAL IMFILE *ifp;
+THREAD_LOCAL FILE * ofp;
+THREAD_LOCAL short order;
+THREAD_LOCAL const char *ifname;
+THREAD_LOCAL char *meta_data;
+THREAD_LOCAL char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64];
+THREAD_LOCAL float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len;
+THREAD_LOCAL time_t timestamp;
+THREAD_LOCAL unsigned shot_order, kodak_cbpp, filters, exif_cfa, unique_id;
+THREAD_LOCAL off_t    strip_offset, data_offset;
+THREAD_LOCAL off_t    thumb_offset, meta_offset, profile_offset;
+THREAD_LOCAL unsigned thumb_length, meta_length, profile_length;
+THREAD_LOCAL unsigned thumb_misc, *oprof, fuji_layout, shot_select=0, multi_out=0;
+THREAD_LOCAL unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress;
+THREAD_LOCAL unsigned black, cblack[8], maximum, mix_green, raw_color, zero_is_bad;
+THREAD_LOCAL unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error;
+THREAD_LOCAL unsigned tile_width, tile_length, gpsdata[32], load_flags;
+THREAD_LOCAL ushort raw_height, raw_width, height, width, top_margin, left_margin;
+THREAD_LOCAL ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height;
+THREAD_LOCAL int flip, tiff_flip, colors;
+THREAD_LOCAL double pixel_aspect, aber[4]={1,1,1,1}, gamm[6]={ 0.45,4.5,0,0,0,0 };
+THREAD_LOCAL ushort (*image)[4], white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4];
+THREAD_LOCAL float bright=1, user_mul[4]={0,0,0,0}, threshold=0;
+THREAD_LOCAL int half_size=0, four_color_rgb=0, document_mode=0, highlight=0;
+THREAD_LOCAL int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=-1;
+THREAD_LOCAL int output_color=1, output_bps=8, output_tiff=0, med_passes=0;
+THREAD_LOCAL int no_auto_bright=0;
+THREAD_LOCAL unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX };
+THREAD_LOCAL 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 };
+THREAD_LOCAL int histogram[4][0x2000];
+THREAD_LOCAL void (*write_thumb)(), (*write_fun)();
+THREAD_LOCAL void (*load_raw)(), (*thumb_load_raw)();
+THREAD_LOCAL jmp_buf failure;
 
-struct decode {
+THREAD_LOCAL struct decode {
   struct decode *branch[2];
   int leaf;
 } first_decode[2048], *second_decode, *free_decode;
 
-struct tiff_ifd {
+THREAD_LOCAL struct tiff_ifd {
   int width, height, bps, comp, phint, offset, flip, samples, bytes;
 } tiff_ifd[10];
 
-struct ph1 {
+THREAD_LOCAL struct ph1 {
   int format, key_off, black, black_off, split_col, tag_21a;
   float tag_210;
 } ph1;
@@ -271,6 +310,7 @@
       fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp));
   }
   data_error++;
+  /*RT*/  longjmp (failure, 1);
 }
 
 ushort CLASS sget2 (uchar *s)
@@ -344,7 +384,7 @@
 {
   if (fread (pixel, 2, count, ifp) < count) derror();
   if ((order == 0x4949) == (ntohs(0x1234) == 0x1234))
-    swab (pixel, pixel, count*2);
+    swab ((char*)pixel, (char*)pixel, count*2);
 }
 
 void CLASS canon_600_fixed_wb (int temp)
@@ -538,8 +578,8 @@
  */
 unsigned CLASS getbithuff (int nbits, ushort *huff)
 {
-  static unsigned bitbuf=0;
-  static int vbits=0, reset=0;
+  THREAD_LOCAL unsigned bitbuf=0;
+  THREAD_LOCAL int vbits=0, reset=0;
   unsigned c;
 
   if (nbits == -1)
@@ -1563,8 +1603,8 @@
 
 unsigned CLASS ph1_bithuff (int nbits, ushort *huff)
 {
-  static UINT64 bitbuf=0;
-  static int vbits=0;
+  THREAD_LOCAL UINT64 bitbuf=0;
+  THREAD_LOCAL int vbits=0;
   unsigned c;
 
   if (nbits == -1)
@@ -1828,8 +1868,8 @@
 
 unsigned CLASS pana_bits (int nbits)
 {
-  static uchar buf[0x4000];
-  static int vbits;
+  THREAD_LOCAL uchar buf[0x4000];
+  THREAD_LOCAL int vbits;
   int byte;
 
   if (!nbits) return vbits=0;
@@ -2118,11 +2158,11 @@
 METHODDEF(boolean)
 fill_input_buffer (j_decompress_ptr cinfo)
 {
-  static uchar jpeg_buffer[4096];
+  THREAD_LOCAL uchar jpeg_buffer[4096];
   size_t nbytes;
 
   nbytes = fread (jpeg_buffer, 1, 4096, ifp);
-  swab (jpeg_buffer, jpeg_buffer, nbytes);
+  swab ((char*)jpeg_buffer, (char*)jpeg_buffer, nbytes);
   cinfo->src->next_input_byte = jpeg_buffer;
   cinfo->src->bytes_in_buffer = nbytes;
   return TRUE;
@@ -2396,7 +2436,7 @@
 
 void CLASS sony_decrypt (unsigned *data, int len, int start, int key)
 {
-  static unsigned pad[128], p;
+  THREAD_LOCAL unsigned pad[128], p;
 
   if (start) {
     for (p=0; p < 4; p++)
@@ -2643,7 +2683,7 @@
 
 void CLASS foveon_decoder (unsigned size, unsigned code)
 {
-  static unsigned huff[1024];
+  THREAD_LOCAL unsigned huff[1024];
   struct decode *cur;
   int i, len;
 
@@ -3765,15 +3805,18 @@
     }
   }
   if (filters && colors == 3) {
-    if ((mix_green = four_color_rgb)) colors++;
-    else {
-      for (row = FC(1,0) >> 1; row < height; row+=2)
-	for (col = FC(row,1) & 1; col < width; col+=2)
-	  image[row*width+col][1] = image[row*width+col][3];
-      filters &= ~((filters & 0x55555555) << 1);
-    }
-  }
-  if (half_size) filters = 0;
+		if ((mix_green = four_color_rgb))
+			colors++;
+		else {
+			for (row = FC(1,0) >> 1; row < height; row += 2)
+				for (col = FC(row,1) & 1; col < width; col += 2)
+					image[row * width + col][1] = image[row * width + col][3];
+			/*RT*/	pre_filters = filters;
+			filters &= ~((filters & 0x55555555) << 1);
+		}
+	}
+	if (half_size)
+		filters = 0;
 }
 
 void CLASS border_interpolate (int border)
@@ -4452,7 +4495,7 @@
     }
     if (tag == 0xd && type == 7 && get2() == 0xaaaa) {
       fread (buf97, 1, sizeof buf97, ifp);
-      i = (uchar *) memmem (buf97, sizeof buf97,"\xbb\xbb",2) - buf97 + 10;
+      i = (uchar *) memmem ((char*) buf97, sizeof buf97,"\xbb\xbb",2) - buf97 + 10;
       if (i < 70 && buf97[i] < 3)
 	flip = "065"[buf97[i]]-'0';
     }
@@ -4836,7 +4879,7 @@
   unsigned sony_curve[] = { 0,0,0,0,0,4095 };
   unsigned *buf, sony_offset=0, sony_length=0, sony_key=0;
   struct jhead jh;
-  FILE *sfp;
+/*RT*/  IMFILE *sfp;
 
   if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0])
     return 1;
@@ -5254,12 +5297,13 @@
     fread (buf, sony_length, 1, ifp);
     sony_decrypt (buf, sony_length/4, 1, sony_key);
     sfp = ifp;
-    if ((ifp = tmpfile())) {
-      fwrite (buf, sony_length, 1, ifp);
-      fseek (ifp, 0, SEEK_SET);
+/*RT*/    ifp = fopen (buf, sony_length);
+//    if ((ifp = tmpfile())) {
+//      fwrite (buf, sony_length, 1, ifp);
+//      fseek (ifp, 0, SEEK_SET);
       parse_tiff_ifd (-sony_offset);
-      fclose (ifp);
-    }
+//      fclose (ifp);
+//    }
     ifp = sfp;
     free (buf);
   }
@@ -5284,6 +5328,8 @@
 {
   int doff;
 
+  /*RT*/  if (exif_base == -1) exif_base = base;
+
   fseek (ifp, base, SEEK_SET);
   order = get2();
   if (order != 0x4949 && order != 0x4d4d) return 0;
@@ -5458,7 +5504,7 @@
 {
   const char *file, *ext;
   char *jname, *jfile, *jext;
-  FILE *save=ifp;
+/*RT*/  IMFILE *save=ifp;
 
   ext  = strrchr (ifname, '.');
   file = strrchr (ifname, '/');
@@ -5486,7 +5532,8 @@
       *jext = '0';
     }
   if (strcmp (jname, ifname)) {
-    if ((ifp = fopen (jname, "rb"))) {
+/*RT*/    if ((ifp = fopen (jname))) {
+//    if ((ifp = fopen (jname, "rb"))) {
       if (verbose)
 	fprintf (stderr,_("Reading metadata from %s ...\n"), jname);
       parse_tiff (12);
@@ -5824,7 +5871,11 @@
     order = get2();
     hlen  = get4();
     if (get4() == 0x48454150)		/* "HEAP" */
-      parse_ciff (save+hlen, len-hlen);
+/*RT*/    {
+/*RT*/      ciff_base = save+hlen;
+/*RT*/      ciff_len = len-hlen;
+        parse_ciff (save+hlen, len-hlen);
+/*RT*/    }
     if (parse_tiff (save+6)) apply_tiff();
     fseek (ifp, save+len, SEEK_SET);
   }
@@ -6845,6 +6896,12 @@
   fread (head, 1, 32, ifp);
   fseek (ifp, 0, SEEK_END);
   flen = fsize = ftell(ifp);
+
+  /*RT*/ if (fsize<100000) {
+        is_raw = 0;
+        return;
+    }
+
   if ((cp = (char *) memmem (head, 32, "MMMM", 4)) ||
       (cp = (char *) memmem (head, 32, "IIII", 4))) {
     parse_phase_one (cp-head);
@@ -6852,6 +6909,8 @@
   } else if (order == 0x4949 || order == 0x4d4d) {
     if (!memcmp (head+6,"HEAPCCDR",8)) {
       data_offset = hlen;
+/*RT*/      ciff_base = hlen;
+/*RT*/      ciff_len = fsize - hlen;
       parse_ciff (hlen, flen - hlen);
     } else if (parse_tiff(0)) apply_tiff();
   } else if (!memcmp (head,"\xff\xd8\xff\xe1",4) &&
@@ -7331,6 +7390,11 @@
   } else if (!strcmp(model,"D1X")) {
     width -= 4;
     pixel_aspect = 0.5;
+  } else if (!strcmp(model,"D7000")) {
+    width -= 40;
+  } else if (!strcmp(model,"D3100")) {
+    width -= 24;
+    left_margin = 4;
   } else if (!strcmp(model,"D40X") ||
 	     !strcmp(model,"D60")  ||
 	     !strcmp(model,"D80")  ||
@@ -7548,7 +7612,7 @@
   } else if (!strcmp(model,"*ist DS")) {
     height -= 2;
   } else if (!strcmp(model,"K-x")) {
-    width = 4309;
+    width = 4308;
     filters = 0x16161616;
   } else if (!strcmp(model,"Optio S")) {
     if (fsize == 3178560) {
@@ -8560,13 +8624,13 @@
 	   FORCC ppm [col*colors+c] = curve[image[soff][c]] >> 8;
       else FORCC ppm2[col*colors+c] = curve[image[soff][c]];
     if (output_bps == 16 && !output_tiff && htons(0x55aa) != 0x55aa)
-      swab (ppm2, ppm2, width*colors*2);
+      swab ((char*)ppm2, (char*)ppm2, width*colors*2);
     fwrite (ppm, colors*output_bps/8, width, ofp);
   }
   free (ppm);
 }
 
-int CLASS main (int argc, const char **argv)
+/*int CLASS main (int argc, const char **argv)
 {
   int arg, status=0;
   int timestamp_only=0, thumbnail_only=0, identify_only=0;
@@ -8679,7 +8743,7 @@
       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;		/* "-h" implies "-f" *//*
       case 'f':  four_color_rgb    = 1;  break;
       case 'A':  FORC4 greybox[c]  = atoi(argv[arg++]);
       case 'a':  use_auto_wb       = 1;  break;
@@ -8943,3 +9007,594 @@
   }
   return status;
 }
+*/
+
+#include <common.h>
+#include <rawmetadatalocation.h>
+#include <utils.h>
+#include <colortemp.h>
+#include <settings.h>
+
+namespace rtengine {
+
+extern Settings* settings;
+
+Glib::Mutex* dcrMutex=NULL;
+
+int RawImage::loadRaw (bool loadData) {
+
+  THREAD_LOCK
+
+  ifname = fname.c_str();
+  image = NULL;
+  exif_base = -1;
+  ciff_base = -1;
+  ciff_len = -1;
+  verbose = settings->verbose;
+  oprof = NULL;
+
+  ifp = gfopen (fname.c_str());
+  if (!ifp)
+    return 3;
+
+  thumb_length = 0;
+  thumb_offset = 0;
+  thumb_load_raw = 0;
+  use_camera_wb = 0;
+  highlight = 1;
+  half_size = 0;
+
+  //***************** Read ALL raw file info
+  identify ();
+  if (!is_raw) {
+    fclose(ifp);
+    return 2;
+  }
+  this->filters = ::filters;
+  this->height = ::height;
+  this->width = ::width;
+  this->colors = ::colors;
+  this->profile_len = ::profile_length;
+
+  this->maximum = ::maximum;
+  this->fuji_width = ::fuji_width;
+
+  for(int i=0; i<8;i++)
+	  for(int j=0;j<8;j++)
+		  this->white[i][j] = ::white[i][j];
+
+  if (flip==5)
+     this->rotate_deg = 270;
+  else if (flip==3)
+     this->rotate_deg = 180;
+  else if (flip==6)
+     this->rotate_deg = 90;
+  else
+     this->rotate_deg = 0;
+
+  this->make = strdup (::make);
+  this->model = strdup (::model);
+  this->iso_speed = ::iso_speed;
+  this->shutter = ::shutter;
+  this->aperture = ::aperture;
+  this->focal_len = ::focal_len;
+  this->timestamp = ::timestamp;
+  this->exifbase = ::exif_base;
+  this->ciff_base = ::ciff_base;
+  this->ciff_len = ::ciff_len;
+  this->thumbOffset = ::thumb_offset;
+  this->thumbLength = ::thumb_length;
+  this->thumbHeight = ::thumb_height;
+  this->thumbWidth = ::thumb_width;
+  if (!thumb_load_raw && thumb_offset && write_thumb == jpeg_thumb)
+     this->thumbType = 1;
+  else if (!thumb_load_raw && thumb_offset && write_thumb == ppm_thumb)
+     this->thumbType = 2;
+  else {
+	 this->thumbType = 0;
+	 this->thumbWidth = ::width;
+	 this->thumbHeight = ::height;
+  }
+
+  if( loadData ){
+	  allocData();
+	  use_camera_wb = 1;
+	  shrink = 0;
+	  if (settings->verbose) printf ("Loading %s %s image from %s...\n", make, model, fname.c_str());
+	  iheight = height;
+	  iwidth  = width;
+
+	  // dcraw needs this global variable to hold pixel data
+	  image = (UshORt (*)[4])calloc (height*width*sizeof *image + meta_length, 1);
+	  meta_data = (char *) (image + height*width);
+	  if(!image)
+		  return 200;
+
+	  if (setjmp (failure)) {
+		  if (image)
+			free (image);
+		  fclose (ifp);
+		  return 100;
+	  }
+
+	  // Load raw pixels data
+	  fseek (ifp, data_offset, SEEK_SET);
+	  (*load_raw)();
+
+	  // Load embedded profile
+	  if (profile_length) {
+		fseek (ifp, profile_offset, SEEK_SET);
+		fread ( this->profile_data, 1, this->profile_len, ifp);
+	  }
+	  fclose(ifp);
+
+	  // Setting the black_point and cblack
+	  int i = ::cblack[3];
+	  for (int c=0; c <3; c++)
+		  if (i > ::cblack[c])
+			  i = ::cblack[c];
+	  for (int c=0; c < 4; c++)
+		  ::cblack[c] -= i;
+	  ::black += i;
+	  for (int c=0; c < 4; c++) this->cblack[c] = ::cblack[c];
+	  for (int c=0; c < 4; c++) this->cam_mul[c] = ::cam_mul[c];
+	  for (int c=0; c < 4; c++) this->pre_mul[c] = ::pre_mul[c];
+	  for (int a = 0; a < 3; a++)
+			for (int b = 0; b < 3; b++)
+				this->coeff[a][b] = ::rgb_cam[a][b];
+
+	  this->black_point = ::black;
+
+	  // copy pixel raw data: the compressed format earns space
+	  if (this->filters) {
+			for (int row = 0; row < height; row++)
+				for (int col = 0; col < width; col++)
+					this->data[row][col] = image[row * width + col][FC(row,col)];
+	  } else {
+			for (int row = 0; row < height; row++)
+				for (int col = 0; col < width; col++) {
+					this->data[row][3 * col + 0] = image[row * width + col][0];
+					this->data[row][3 * col + 1] = image[row * width + col][1];
+					this->data[row][3 * col + 2] = image[row * width + col][2];
+				}
+	  }
+	  free(image); // we don't need this anymore
+  }
+  else
+  {
+	  fclose(ifp);
+  }
+  return 0;
+}
+
+
+
+int getRawFileBasicInfo (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int& rotation, int& thumbWidth, int& thumbHeight, int& thumbOffset, int& thumbType) {
+
+  THREAD_LOCK
+
+  int status=0;
+
+  exif_base = -1;
+  ciff_base = -1;
+  ciff_len = -1;
+  
+  half_size = 1;
+  bright = 1.0;
+  verbose = settings->verbose;
+  use_camera_wb = 1;
+
+  thumb_length = 0;
+  thumb_offset = 0;
+  thumb_load_raw = 0;
+  status = 1;
+
+  ifname = fname.c_str();
+  if (!(ifp = gfopen (ifname))) {
+    status = 2;
+    return status;
+  }
+  identify ();
+  if (!is_raw || colors>3) {
+    status = 3;
+    fclose (ifp);
+    return status;
+  }
+
+  thumbOffset = thumb_offset;
+
+  if (flip==5)
+    rotation = 270;
+  else if (flip==3)
+    rotation = 180;
+  else if (flip==6)
+    rotation = 90;
+  else
+    rotation = 0;
+
+  thumbWidth = thumb_width;
+  thumbHeight = thumb_height;
+  if (!thumb_load_raw && thumb_offset && write_thumb == jpeg_thumb)
+    thumbType = 1;
+  else if (!thumb_load_raw && thumb_offset && write_thumb == ppm_thumb)
+    thumbType = 2;
+  else {
+    thumbType = 0;
+    thumbWidth = width;
+    thumbHeight = height;
+  }
+
+  rml.exifBase = exif_base;
+  rml.ciffBase = ciff_base;
+  rml.ciffLength = ciff_len;
+
+  fclose (ifp);
+  return !is_raw;
+}
+
+#include <mytime.h>
+
+rtengine::Thumbnail* rtengine::Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh) {
+
+    THREAD_LOCK
+
+	image = NULL;
+	ifname = fname.c_str();
+	exif_base = -1;
+	ciff_base = -1;
+	ciff_len = -1;
+	verbose = settings->verbose;
+	oprof = NULL;
+	ifp = gfopen (fname.c_str());
+	if (!ifp) {
+		printf("DCRAW: failed0\n");
+		return NULL;
+	}
+
+	if (setjmp (failure)) {
+		printf("DCRAW: failed1\n");
+		fclose (ifp);
+		return NULL;
+	}   
+
+	identify ();
+	if (!is_raw || colors>3) {
+		printf("DCRAW: failed2\n");
+		fclose(ifp);
+		return NULL;
+	}
+
+    rml.exifBase = exif_base;
+    rml.ciffBase = ciff_base;
+    rml.ciffLength = ciff_len;
+
+	rtengine::Thumbnail* tpp = rtengine::Thumbnail::loadFromMemory(fdata(thumb_offset,ifp),thumb_length,w,h,fixwh);
+
+	fclose(ifp);
+
+	if ( tpp == 0 )
+	{
+		printf("DCRAW: failed4\n");
+		return NULL;
+	}
+
+	int deg = 0;
+	if (flip==5)
+		deg = 270;
+	else if (flip==3)
+		deg = 180;
+	else if (flip==6)
+		deg = 90;
+
+	if (deg>0) {
+		Image16* rot = tpp->thumbImg->rotate (deg);
+		delete tpp->thumbImg;
+		tpp->thumbImg = rot;
+	}
+
+	return tpp;
+}
+
+rtengine::Thumbnail* rtengine::Thumbnail::loadFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh) {
+
+	THREAD_LOCK
+
+MyTime t0, t1, t2, t3, t4, t5, t6;
+t0.set ();
+
+    image = NULL;
+    ifname = fname.c_str();
+    exif_base = -1;
+    ciff_base = -1;
+    ciff_len = -1;
+    verbose = settings->verbose;
+    oprof = NULL;
+    ifp = gfopen (fname.c_str());
+    if (!ifp) {
+        return NULL;
+    }
+
+t1.set ();
+
+    if (setjmp (failure)) {
+	if (image)
+        free (image);
+      fclose (ifp);
+      return NULL;
+    }   
+    
+    use_camera_wb = 0;
+    highlight = 1;
+    half_size = 0;
+    shrink = 0;
+    identify ();
+    use_camera_wb = 1;
+    if (!is_raw || colors>3) {
+        fclose(ifp);
+        return NULL;
+    }
+
+t2.set();
+  
+    iheight = ::height;
+    iwidth  = ::width;
+
+    image = (UshORt (*)[4])calloc (::height*::width*sizeof *image + meta_length, 1);
+    meta_data = (char *) (image + ::height*::width);
+
+    if (settings->verbose) printf ("Loading %s %s image from %s...\n", make, model, fname.c_str());
+    fseek (ifp, data_offset, SEEK_SET);
+    (*load_raw)();
+    if (zero_is_bad) remove_zeroes();
+
+  rtengine::Thumbnail* tpp = new rtengine::Thumbnail;
+  
+    tpp->isRaw = true;
+    tpp->embProfileLength = 0;
+    if (profile_length) {
+        tpp->embProfileLength = profile_length;
+        tpp->embProfileData = new unsigned char[profile_length];
+        fseek (ifp, profile_offset, SEEK_SET);
+        fread (tpp->embProfileData, 1, profile_length, ifp);
+        tpp->embProfile = cmsOpenProfileFromMem (tpp->embProfileData, tpp->embProfileLength);
+    }
+    else {
+        tpp->embProfile = NULL;
+        tpp->embProfileData = NULL;
+    }
+        
+    fclose(ifp);
+    tpp->redMultiplier = pre_mul[0];
+    tpp->greenMultiplier = pre_mul[1];
+    tpp->blueMultiplier = pre_mul[2];
+  
+t3.set ();
+
+    scale_colors();
+    pre_interpolate ();
+
+    unsigned filter = filters;
+    int firstgreen = 1;
+    // locate first green location in the first row
+    while (!FISGREEN(filter,1,firstgreen)) 
+        firstgreen++;
+
+    int skip = 1;
+    if (fixwh==1) // fix height, scale width
+        skip = (::height-firstgreen-1) / h;
+    else 
+        skip = (::width-firstgreen-1) / w;
+    if (skip%2)
+        skip--;
+    if (skip<1)
+        skip = 1;
+
+    int hskip = skip, vskip = skip;
+    if (!strcmp (model, "D1X"))
+        hskip *=2;
+        
+    rml.exifBase = exif_base;
+    rml.ciffBase = ciff_base;
+    rml.ciffLength = ciff_len;
+    tpp->camwbRed = tpp->redMultiplier / pre_mul[0];
+    tpp->camwbGreen = tpp->greenMultiplier / pre_mul[1];
+    tpp->camwbBlue = tpp->blueMultiplier / pre_mul[2];
+
+    tpp->defGain = 1.0 / MIN(MIN(pre_mul[0],pre_mul[1]),pre_mul[2]);  
+    tpp->gammaCorrected = true;
+
+    int ix = 0;
+    int rofs = 0;
+    int tmpw = (::width-2)/hskip;
+    int tmph = (::height-2)/vskip;
+    Image16* tmpImg = new Image16 (tmpw, tmph);
+    if (filter) {
+        for (int row=1, y=0; row< ::height-1 && y<tmph; row+=vskip, y++) {
+            rofs = row*::width;
+            for (int col=firstgreen,x=0; col< ::width-1 && x<tmpw; col+=hskip, x++) {
+                int ofs = rofs+col;
+                int g = image[ofs][1];
+                int r, b;
+                if (FISRED(filter,row,col+1)) {
+                    r = (image[ofs+1][0] + image[ofs-1][0]) >> 1;
+                    b = (image[ofs+::width][2] + image[ofs-::width][2]) >> 1;
+                }
+                else {
+                    b = (image[ofs+1][2] + image[ofs-1][2]) >> 1;
+                    r = (image[ofs+::width][0] + image[ofs-::width][0]) >> 1;
+                }
+                tmpImg->r[y][x] = r;
+                tmpImg->g[y][x] = g;
+                tmpImg->b[y][x] = b;
+            }
+        }       
+    }
+    else {
+        for (int row=1, y=0; row< ::height-1 && y<tmph; row+=vskip, y++) {
+            rofs = row*::width;
+            for (int col=firstgreen,x=0; col< ::width-1 && x<tmpw; col+=hskip, x++) {
+                int ofs = rofs+col;
+                tmpImg->r[y][x] = image[ofs][0];
+                tmpImg->g[y][x] = image[ofs][1];
+                tmpImg->b[y][x] = image[ofs][2];
+            }
+        }       
+    }
+        
+    if (fuji_width) {
+        int fw = fuji_width / hskip;
+        double step = sqrt(0.5);
+        int wide = fw / step;
+        int high = (tmph - fw) / step;
+        Image16* fImg = new Image16 (wide, high);
+        float r, c;
+
+        for (int row=0; row < high; row++)
+            for (int col=0; col < wide; col++) {
+                unsigned ur = r = fw + (row-col)*step;
+                unsigned uc = c = (row+col)*step;
+                if (ur > tmph-2 || uc > tmpw-2) 
+                    continue;
+                double fr = r - ur;
+                double fc = c - uc;
+                int oofs = (ur*tmpw + uc)*3;
+                int fofs = (row*wide+col)*3;
+                fImg->r[row][col] = (tmpImg->r[ur][uc] * (1-fc) + tmpImg->r[ur][uc+1] * fc) * (1-fr) + (tmpImg->r[ur+1][uc] * (1-fc) + tmpImg->r[ur+1][uc+1] * fc) * fr;
+                fImg->g[row][col] = (tmpImg->g[ur][uc] * (1-fc) + tmpImg->g[ur][uc+1] * fc) * (1-fr) + (tmpImg->g[ur+1][uc] * (1-fc) + tmpImg->g[ur+1][uc+1] * fc) * fr;
+                fImg->b[row][col] = (tmpImg->b[ur][uc] * (1-fc) + tmpImg->b[ur][uc+1] * fc) * (1-fr) + (tmpImg->b[ur+1][uc] * (1-fc) + tmpImg->b[ur+1][uc+1] * fc) * fr;
+            }
+        delete tmpImg;
+        tmpImg = fImg;
+    }
+    
+    
+    if (fixwh==1) // fix height, scale width
+        w = tmpw * h / tmph;
+    else
+        h = tmph * w / tmpw;
+        
+    tpp->thumbImg = tmpImg->resize (w, h, TI_Bilinear);
+    delete tmpImg;
+
+    if (fuji_width)
+        tpp->scale = (double)(::height - fuji_width) / sqrt(0.5) / h;
+    else
+        tpp->scale = (double)::height / h;      
+    
+t4.set ();  
+
+    // generate histogram for auto exposure
+    tpp->aeHistCompression = 3;
+    tpp->aeHistogram = new unsigned int[65536>>tpp->aeHistCompression];
+    memset (tpp->aeHistogram, 0, (65536>>tpp->aeHistCompression)*sizeof(int));
+    int radd = 4;
+    int gadd = 2;
+    int badd = 4;
+    if (!filter)
+        radd = gadd = badd = 1;
+    for (int i=8; i< ::height-8; i++) {
+        int start, end;
+        if (fuji_width) {
+            int fw = fuji_width;
+            start = ABS(fw-i) + 8;
+            end = MIN( ::height+ ::width-fw-i, fw+i) - 8;
+        }
+        else {
+            start = 8;
+            end = ::width-8;
+        }
+        for (int j=start; j<end; j++) 
+            if (FISGREEN(filter,i,j))
+                tpp->aeHistogram[image[i* ::width+j][1]>>tpp->aeHistCompression]+=gadd;
+            else if (FISRED(filter,i,j))
+                tpp->aeHistogram[image[i* ::width+j][0]>>tpp->aeHistCompression]+=radd;
+            else if (FISBLUE(filter,i,j))
+                tpp->aeHistogram[image[i* ::width+j][2]>>tpp->aeHistCompression]+=badd;
+    }
+                
+t5.set ();
+
+    // generate autoWB
+    double avg_r = 0;
+    double avg_g = 0;
+    double avg_b = 0;
+    int rn = 0, gn = 0, bn = 0;
+
+    for (int i=32; i< ::height-32; i++) {
+        int start, end;
+        if (fuji_width) {
+            int fw = fuji_width;
+            start = ABS(fw-i) + 32;
+            end = MIN( ::height+ ::width-fw-i, fw+i) - 32;
+        }
+        else {
+            start = 32;
+            end = ::width-32;
+        }
+        for (int j=start; j<end; j++) {            
+            if (FISGREEN(filter,i,j)) {
+                double d = tpp->defGain * image[i* ::width+j][1];
+                if (d>64000)
+                    continue;
+                avg_g += d;
+                gn++;
+            }
+            if (FISRED(filter,i,j)) {
+                double d = tpp->defGain * image[i* ::width+j][0];
+                if (d>64000)
+                    continue;
+                avg_r += d;
+                rn++;
+            }
+            if (FISBLUE(filter,i,j)) {
+                double d = tpp->defGain * image[i* ::width+j][2];
+                if (d>64000)
+                    continue;
+                avg_b += d;
+                bn++;
+            }
+        }
+    }
+
+    double reds   = avg_r/rn * tpp->camwbRed;
+    double greens = avg_g/gn * tpp->camwbGreen;
+    double blues  = avg_b/bn * tpp->camwbBlue;
+    
+    double rm = rgb_cam[0][0]*reds + rgb_cam[0][1]*greens + rgb_cam[0][2]*blues;
+    double gm = rgb_cam[1][0]*reds + rgb_cam[1][1]*greens + rgb_cam[1][2]*blues;
+    double bm = rgb_cam[2][0]*reds + rgb_cam[2][1]*greens + rgb_cam[2][2]*blues;
+
+    ColorTemp::mul2temp (rm, gm, bm, tpp->autowbTemp, tpp->autowbGreen);
+
+t6.set ();
+
+if (settings->verbose) printf ("0: %d, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d All: %d\n", t1.etime(t0), t2.etime(t1), t3.etime(t2), t4.etime(t3), t5.etime(t4), t6.etime(t5), t6.etime(t0));    
+
+    int deg = 0;
+    if (flip==5)
+        deg = 270;
+    else if (flip==3)
+        deg = 180;
+    else if (flip==6)
+        deg = 90;
+
+    if (deg>0) {
+        Image16* rot = tpp->thumbImg->rotate (deg);
+        delete tpp->thumbImg;
+        tpp->thumbImg = rot;
+    }
+
+    for (int a=0; a < 3; a++)
+      for (int b=0; b < 3; b++)
+        tpp->colorMatrix[a][b] = rgb_cam[a][b];
+
+    tpp->init ();
+    
+  free (image);
+  
+  return tpp;
+}
+
+
+}
+
