Changes to black compression and saturation controls. Black compression from 0-50 acts the same as 0-100 on the previous version, compressing dark tones without crushing blacks. 50-100 then starts crushing blacks until by 100 on the slider, all tones up to the set black point are sent to zero. In the new saturation control, negative values of the slider set a linear curve rather than an inverted S curve, and smoothly decrease saturation to zero across the board.

This commit is contained in:
Emil Martinec
2010-10-26 22:59:18 -05:00
commit 926056c2c2
620 changed files with 130476 additions and 0 deletions

727
rtengine/dcraw.patch Normal file
View File

@@ -0,0 +1,727 @@
--- 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;
+ 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);
+
+dcrMutex->unlock ();
+
+ return tpp;
+}
+
+
+}
+