Files
rawTherapee/rtengine/dcraw.patch
ffsup2 eef14f76dd Added dark frame subtraction
Moved debayer and preprocessing parameters to class ProcParams for every single image.
Added tab RAW for changing those parameters.
Progress bar shows only load step (work to do)
2010-08-19 00:37:53 +02:00

728 lines
20 KiB
Diff

--- dcraw.c 2010-06-30 10:40:16.000000000 -0600
+++ dcraw.cc 2010-06-30 10:36:00.000000000 -0600
@@ -1,3 +1,16 @@
+/*RT*/#include <glib.h>
+/*RT*/#include <glib/gstdio.h>
+/*RT*/int ciff_base, ciff_len, exif_base, pre_filters;
+/*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 +59,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>
@@ -101,7 +116,8 @@
access them are prefixed with "CLASS". Note that a thread-safe
C++ class cannot have non-const static local variables.
*/
-FILE *ifp, *ofp;
+/*RT*/IMFILE *ifp;
+FILE * ofp;
short order;
const char *ifname;
char *meta_data;
@@ -271,6 +287,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 +361,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)
@@ -2117,7 +2134,7 @@
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;
@@ -3765,6 +3782,7 @@
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);
}
}
@@ -4817,7 +4835,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;
@@ -5225,12 +5243,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);
}
@@ -5256,6 +5275,8 @@
int doff, max_samp=0, raw=-1, thm=-1, i;
struct jhead jh;
+ /*RT*/ exif_base = base;
+
fseek (ifp, base, SEEK_SET);
order = get2();
if (order != 0x4949 && order != 0x4d4d) return;
@@ -5424,7 +5445,7 @@
{
const char *file, *ext;
char *jname, *jfile, *jext;
- FILE *save=ifp;
+/*RT*/ IMFILE *save=ifp;
ext = strrchr (ifname, '.');
file = strrchr (ifname, '/');
@@ -5452,7 +5473,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);
@@ -5790,7 +5812,11 @@
order = get2();
hlen = get4();
if (get4() == 0x48454150) /* "HEAP" */
+/*RT*/ {
+/*RT*/ ciff_base = save+hlen;
+/*RT*/ ciff_len = len-hlen;
parse_ciff (save+hlen, len-hlen);
+/*RT*/ }
parse_tiff (save+6);
fseek (ifp, save+len, SEEK_SET);
}
@@ -6738,6 +6764,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);
@@ -6745,6 +6777,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 {
parse_tiff(0);
@@ -8494,13 +8528,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;
@@ -8613,7 +8647,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;
@@ -8877,3 +8911,537 @@
}
return status;
}
+*/
+
+#include <common.h>
+#include <rawmetadatalocation.h>
+#include <glibmm.h>
+#include <utils.h>
+#include <colortemp.h>
+#include <settings.h>
+
+namespace rtengine {
+
+extern Settings* settings;
+
+Glib::Mutex* dcrMutex=NULL;
+
+int loadRaw (const char* fname, struct RawImage *ri) {
+
+ static const double xyzd50_srgb[3][3] =
+ { { 0.436083, 0.385083, 0.143055 },
+ { 0.222507, 0.716888, 0.060608 },
+ { 0.013930, 0.097097, 0.714022 } };
+
+dcrMutex->lock ();
+
+ ifname = fname;//strdup (fname);
+ image = NULL;
+
+ exif_base = -1;
+ ciff_base = -1;
+ ciff_len = -1;
+ verbose = settings->verbose;
+ oprof = NULL;
+ ri->data = NULL;
+ ri->allocation = NULL;
+ ri->profile_data = NULL;
+ ifp = gfopen (fname);
+ if (!ifp) {
+ dcrMutex->unlock ();
+ return 3;
+ }
+
+ use_camera_wb = 0;
+ highlight = 1;
+ half_size = 0;
+
+ identify ();
+ use_camera_wb = 1;
+ if (!is_raw) {
+ fclose(ifp);
+ dcrMutex->unlock ();
+ return 2;
+ }
+
+ shrink = 0;
+
+ if (settings->verbose) printf ("Loading %s %s image from %s...\n", make, model, fname);
+ iheight = height;
+ iwidth = width;
+
+ image = (UshORt (*)[4])calloc (height*width*sizeof *image + meta_length, 1);
+ meta_data = (char *) (image + height*width);
+
+ if (setjmp (failure)) {
+ if (image)
+ free (image);
+ if (ri->data)
+ free(ri->data);
+ fclose (ifp);
+ dcrMutex->unlock ();
+ return 100;
+ }
+
+ fseek (ifp, data_offset, SEEK_SET);
+ (*load_raw)();
+
+ ri->profile_len = 0;
+ ri->profile_data = NULL;
+ if (profile_length) {
+ ri->profile_len = profile_length;
+ ri->profile_data = (char *) malloc (profile_length);
+ fseek (ifp, profile_offset, SEEK_SET);
+ fread (ri->profile_data, 1, profile_length, ifp);
+ }
+
+ fclose(ifp);
+ if (zero_is_bad) remove_zeroes();
+
+ ri->red_multiplier = pre_mul[0];
+ ri->green_multiplier = pre_mul[1];
+ ri->blue_multiplier = pre_mul[2];
+
+ scale_colors();
+ pre_interpolate ();
+
+ ri->width = width;
+ ri->height = height;
+ ri->filters = filters;
+
+ if (filters) {
+ ri->allocation = (short unsigned int*)calloc(height*width, sizeof(unsigned short));
+ ri->data = (unsigned short**)calloc(height, sizeof(unsigned short*));
+ for (int i=0; i<height; i++)
+ ri->data[i] = ri->allocation + i*width;
+ for (int row = 0; row < height; row++)
+ for (int col = 0; col < width; col++)
+ if (ISGREEN(ri,row,col))
+ ri->data[row][col] = image[row*width+col][1];
+ else if (ISRED(ri,row,col))
+ ri->data[row][col] = image[row*width+col][0];
+ else
+ ri->data[row][col] = image[row*width+col][2];
+ }
+ else {
+ ri->allocation = (short unsigned int*)calloc(3*height*width, sizeof(unsigned short));
+ ri->data = (unsigned short**)calloc(height, sizeof(unsigned short*));
+ for (int i=0; i<height; i++)
+ ri->data[i] = ri->allocation + 3*i*width;
+ for (int row = 0; row < height; row++)
+ for (int col = 0; col < width; col++) {
+ ri->data[row][3*col+0] = image[row*width+col][0];
+ ri->data[row][3*col+1] = image[row*width+col][1];
+ ri->data[row][3*col+2] = image[row*width+col][2];
+ }
+ }
+
+ if (flip==5)
+ ri->rotate_deg = 270;
+ else if (flip==3)
+ ri->rotate_deg = 180;
+ else if (flip==6)
+ ri->rotate_deg = 90;
+ else
+ ri->rotate_deg = 0;
+
+ ri->make = strdup (make);
+ ri->model = strdup (model);
+
+ ri->exifbase = exif_base;
+ ri->prefilters = pre_filters;
+ ri->ciff_base = ciff_base;
+ ri->ciff_len = ciff_len;
+
+ ri->camwb_red = ri->red_multiplier / pre_mul[0];
+ ri->camwb_green = ri->green_multiplier / pre_mul[1];
+ ri->camwb_blue = ri->blue_multiplier / pre_mul[2];
+
+ ri->defgain = 1.0 / MIN(MIN(pre_mul[0],pre_mul[1]),pre_mul[2]);
+
+ ri->fuji_width = fuji_width;
+
+ for (int a=0; a < 3; a++)
+ for (int b=0; b < 3; b++)
+ ri->coeff[a][b] = rgb_cam[a][b];
+
+ free (image);
+dcrMutex->unlock ();
+ return 0;
+}
+
+int getRawFileBasicInfo (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int& rotation, int& thumbWidth, int& thumbHeight, int& thumbOffset, int& thumbType) {
+
+ int status=0;
+
+dcrMutex->lock ();
+
+ 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;
+ dcrMutex->unlock ();
+ return status;
+ }
+ identify ();
+ if (!is_raw || colors>3) {
+ status = 3;
+ fclose (ifp);
+ dcrMutex->unlock ();
+ 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);
+dcrMutex->unlock ();
+ return !is_raw;
+}
+
+#include <mytime.h>
+
+rtengine::Thumbnail* rtengine::Thumbnail::loadFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh) {
+
+dcrMutex->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) {
+ dcrMutex->unlock ();
+ return NULL;
+ }
+
+t1.set ();
+
+ if (setjmp (failure)) {
+ if (image)
+ free (image);
+ fclose (ifp);
+ dcrMutex->unlock ();
+ 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);
+ dcrMutex->unlock ();
+ 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 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*d*d*d*d*d;
+ gn++;
+ }
+ if (FISRED(filter,i,j)) {
+ double d = tpp->defGain * image[i* ::width+j][0];
+ if (d>64000)
+ continue;
+ avg_r += d*d*d*d*d*d;
+ rn++;
+ }
+ if (FISBLUE(filter,i,j)) {
+ double d = tpp->defGain * image[i* ::width+j][2];
+ if (d>64000)
+ continue;
+ avg_b += d*d*d*d*d*d;
+ bn++;
+ }
+ }
+ }
+
+ double reds = pow (avg_r/rn, 1.0/6.0) * tpp->camwbRed;
+ double greens = pow (avg_g/gn, 1.0/6.0) * tpp->camwbGreen;
+ double blues = pow (avg_b/bn, 1.0/6.0) * 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);
+
+dcrMutex->unlock ();
+
+ return tpp;
+}
+
+
+}
+