From 4674c42490c600e95fe3f46cd190aec723abdfa7 Mon Sep 17 00:00:00 2001 From: ffsup2 Date: Thu, 25 Nov 2010 23:25:21 +0100 Subject: [PATCH] dcraw C++ --- rtengine/cfa_linedn_RT.cc | 2 +- rtengine/dcraw.cc | 789 ++++-------------------------- rtengine/dcraw.h | 374 ++++++++++++++ rtengine/dfmanager.cc | 7 +- rtengine/dfmanager.h | 2 +- rtengine/imagedata.h | 2 +- rtengine/init.cc | 2 - rtengine/rawimage.cc | 245 ++++++++++ rtengine/{common.h => rawimage.h} | 68 +-- rtengine/rawimagesource.cc | 19 +- rtengine/rawimagesource.h | 2 +- rtengine/rtengine.h | 11 - rtengine/rtthumbnail.cc | 283 +++++++++++ 13 files changed, 1037 insertions(+), 769 deletions(-) create mode 100644 rtengine/dcraw.h create mode 100644 rtengine/rawimage.cc rename rtengine/{common.h => rawimage.h} (68%) diff --git a/rtengine/cfa_linedn_RT.cc b/rtengine/cfa_linedn_RT.cc index 623373876..59cba81b8 100644 --- a/rtengine/cfa_linedn_RT.cc +++ b/rtengine/cfa_linedn_RT.cc @@ -64,7 +64,7 @@ void RawImageSource::CLASS cfa_linedn(float noise) int ex, ey; int verbose=1; - const float clip_pt = 0.8*initialGain; + const float clip_pt = 0.8*initialGain* 65535.0; float eps=1e-5; //tolerance to avoid dividing by zero diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index b9df5a542..84fc6595a 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -6,9 +6,6 @@ /*RT*/#define NO_JPEG /*RT*/#define LOCALTIME /*RT*/#define DJGPP -/*RT*/#include - -#include "myfile.h" /* dcraw.c -- Dave Coffin's raw photo decoder @@ -58,9 +55,7 @@ NO_LCMS disables the "-p" option. */ #ifndef NO_JPEG -/*RT*/extern "C" { -/*RT*/#include -/*RT*/} +#include #endif #ifndef NO_LCMS #include @@ -110,89 +105,65 @@ typedef unsigned long long UINT64; typedef unsigned char uchar; typedef unsigned short ushort; -// RT specify thread local storage -#ifdef __XXXGNUC__ -#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 - - +#include "dcraw.h" /* 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. - */ -/*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 */ + +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 { 0.412453, 0.357580, 0.180423 }, { 0.212671, 0.715160, 0.072169 }, { 0.019334, 0.119193, 0.950227 } }; -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; +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; -THREAD_LOCAL struct decode { +struct decode { struct decode *branch[2]; int leaf; } first_decode[2048], *second_decode, *free_decode; -THREAD_LOCAL struct tiff_ifd { +struct tiff_ifd { int width, height, bps, comp, phint, offset, flip, samples, bytes; } tiff_ifd[10]; -THREAD_LOCAL struct ph1 { +struct ph1 { int format, key_off, black, black_off, split_col, tag_21a; float tag_210; } ph1; - -#define CLASS +*/ +#define CLASS DCraw:: #define FORC(cnt) for (c=0; c < cnt; c++) #define FORC3 FORC(3) @@ -576,10 +547,10 @@ int CLASS canon_s2is() getbits(-1) initializes the buffer getbits(n) where 0 <= n <= 25 returns an n-bit integer */ -unsigned CLASS getbithuff (int nbits, ushort *huff) +unsigned CLASS getbithuff_t::operator() (int nbits, ushort *huff) { - THREAD_LOCAL unsigned bitbuf=0; - THREAD_LOCAL int vbits=0, reset=0; +// static unsigned bitbuf=0; +// static int vbits=0, reset=0; unsigned c; if (nbits == -1) @@ -1326,7 +1297,7 @@ void CLASS fuji_load_raw() free (pixel); } -void CLASS jpeg_thumb(); +//void CLASS jpeg_thumb(); void CLASS ppm_thumb() { @@ -1601,10 +1572,10 @@ void CLASS phase_one_load_raw() phase_one_correct(); } -unsigned CLASS ph1_bithuff (int nbits, ushort *huff) +unsigned CLASS ph1_bithuff_t::operator() (int nbits, ushort *huff) { - THREAD_LOCAL UINT64 bitbuf=0; - THREAD_LOCAL int vbits=0; +// static UINT64 bitbuf=0; +// static int vbits=0; unsigned c; if (nbits == -1) @@ -1730,7 +1701,7 @@ void CLASS leaf_hdr_load_raw() } } -void CLASS unpacked_load_raw(); +//void CLASS unpacked_load_raw(); void CLASS sinar_4shot_load_raw() { @@ -1866,10 +1837,10 @@ void CLASS nokia_load_raw() maximum = 0x3ff; } -unsigned CLASS pana_bits (int nbits) +unsigned CLASS pana_bits_t::operator() (int nbits) { - THREAD_LOCAL uchar buf[0x4000]; - THREAD_LOCAL int vbits; +// static uchar buf[0x4000]; +// static int vbits; int byte; if (!nbits) return vbits=0; @@ -2158,11 +2129,11 @@ void CLASS kodak_jpeg_load_raw() {} METHODDEF(boolean) fill_input_buffer (j_decompress_ptr cinfo) { - THREAD_LOCAL uchar jpeg_buffer[4096]; + static uchar jpeg_buffer[4096]; size_t nbytes; nbytes = fread (jpeg_buffer, 1, 4096, ifp); - swab ((char*)jpeg_buffer, (char*)jpeg_buffer, nbytes); + swab (jpeg_buffer, jpeg_buffer, nbytes); cinfo->src->next_input_byte = jpeg_buffer; cinfo->src->bytes_in_buffer = nbytes; return TRUE; @@ -2434,9 +2405,9 @@ void CLASS kodak_thumb_load_raw() maximum = (1 << (thumb_misc & 31)) - 1; } -void CLASS sony_decrypt (unsigned *data, int len, int start, int key) +void CLASS sony_decrypt_t::operator()(unsigned *data, int len, int start, int key) { - THREAD_LOCAL unsigned pad[128], p; +// static unsigned pad[128], p; if (start) { for (p=0; p < 4; p++) @@ -2683,7 +2654,7 @@ void CLASS smal_v9_load_raw() void CLASS foveon_decoder (unsigned size, unsigned code) { - THREAD_LOCAL unsigned huff[1024]; + //static unsigned huff[1024]; struct decode *cur; int i, len; @@ -3805,18 +3776,15 @@ void CLASS pre_interpolate() } } 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]; - /*RT*/ pre_filters = filters; - 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]; + filters &= ~((filters & 0x55555555) << 1); + } + } + if (half_size) filters = 0; } void CLASS border_interpolate (int border) @@ -4370,7 +4338,7 @@ void CLASS parse_thumb_note (int base, unsigned toff, unsigned tlen) } } -int CLASS parse_tiff_ifd (int base); +//int CLASS parse_tiff_ifd (int base); void CLASS parse_makernote (int base, int uptag) { @@ -4495,7 +4463,7 @@ void CLASS parse_makernote (int base, int uptag) } if (tag == 0xd && type == 7 && get2() == 0xaaaa) { fread (buf97, 1, sizeof buf97, ifp); - i = (uchar *) memmem ((char*) 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'; } @@ -4864,8 +4832,8 @@ void CLASS parse_kodak_ifd (int base) } } -void CLASS parse_minolta (int base); -int CLASS parse_tiff (int base); +//void CLASS parse_minolta (int base); +//int CLASS parse_tiff (int base); int CLASS parse_tiff_ifd (int base) { @@ -5328,7 +5296,7 @@ int CLASS parse_tiff (int base) { int doff; - /*RT*/ if (exif_base == -1) exif_base = base; + /*RT*/ if( exif_base ==-1 ) exif_base = base; fseek (ifp, base, SEEK_SET); order = get2(); @@ -5871,11 +5839,11 @@ int CLASS parse_jpeg (int offset) 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*/ } + /*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); } @@ -6909,8 +6877,8 @@ void CLASS identify() } else if (order == 0x4949 || order == 0x4d4d) { if (!memcmp (head+6,"HEAPCCDR",8)) { data_offset = hlen; -/*RT*/ ciff_base = hlen; -/*RT*/ ciff_len = fsize - 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) && @@ -8630,7 +8598,7 @@ void CLASS write_ppm_tiff() 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; @@ -8743,7 +8711,7 @@ void CLASS write_ppm_tiff() 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; @@ -8787,13 +8755,13 @@ void CLASS write_ppm_tiff() meta_data = ofname = 0; ofp = stdout; if (setjmp (failure)) { - if (fileno(ifp) > 2) fclose(ifp); - if (fileno(ofp) > 2) fclose(ofp); + //if (fileno(ifp) > 2) fclose(ifp); + //if (fileno(ofp) > 2) fclose(ofp); status = 1; goto cleanup; } ifname = argv[arg]; - if (!(ifp = fopen (ifname, "rb"))) { + if (!(ifp = fopen (ifname))) { perror (ifname); continue; } @@ -8924,7 +8892,7 @@ next: fprintf (stderr,_("%s: \"-s %d\" requests a nonexistent image!\n"), ifname, shot_select); fseeko (ifp, data_offset, SEEK_SET); - (*load_raw)(); + ( this->*load_raw)(); if (zero_is_bad) remove_zeroes(); bad_pixels (bpfile); if (dark_frame) subtract (dark_frame); @@ -8992,7 +8960,7 @@ thumbnail: } if (verbose) fprintf (stderr,_("Writing data to %s ...\n"), ofname); - (*write_fun)(); + (this->*write_fun)(); fclose(ifp); if (ofp != stdout) fclose(ofp); cleanup: @@ -9007,588 +8975,3 @@ cleanup: } return status; } -*/ - -#include -#include -#include -#include -#include - -namespace rtengine { - -extern Settings* settings; - -Glib::Mutex* dcrMutex=NULL; - -int RawImage::loadRaw (bool loadData) { - - THREAD_LOCK - - ifname = get_filename().c_str(); - image = NULL; - exif_base = -1; - ciff_base = -1; - ciff_len = -1; - verbose = settings->verbose; - oprof = NULL; - - ifp = gfopen (filename.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->timestamp = ::timestamp; - this->exifbase = ::exif_base; - this->ciff_base = ::ciff_base; - this->ciff_len = ::ciff_len; - - if( loadData ){ - allocData(); - use_camera_wb = 1; - shrink = 0; - if (settings->verbose) printf ("Loading %s %s image from %s...\n", make, model, filename.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 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 = ::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 - -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; -} - -#define FISRED(filter,row,col) \ - ((filter >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==0 || !filter) -#define FISGREEN(filter,row,col) \ - ((filter >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==1 || !filter) -#define FISBLUE(filter,row,col) \ - ((filter >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==2 || !filter) - -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> 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 && yr[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; jaeHistogram[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; jdefGain * 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; -} -#undef FISRED -#undef FISGREEN -#undef FISBLUE - -} - diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h new file mode 100644 index 000000000..c54ebeb1e --- /dev/null +++ b/rtengine/dcraw.h @@ -0,0 +1,374 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2010 Fabio Suprani + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#ifndef DCRAW_H +#define DCRAW_H + +#include +#include + + +class DCraw +{ +public: + typedef unsigned short ushort; + typedef unsigned char uchar; + typedef unsigned short (*dcrawImage_t)[4]; +#ifdef WIN32 + typedef __int64 INT64; + typedef unsigned __int64 UINT64; +#else + typedef long long INT64; + typedef unsigned long long UINT64; +#endif + + + DCraw() + :ifp(NULL),ofp(NULL) + ,order(0x4949) + ,ifname(NULL) + ,meta_data(NULL) + ,shot_select(0),multi_out(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) + ,bright(1.),threshold(0.) + ,getbithuff(this,ifp,zero_after_ff) + ,pana_bits(ifp,load_flags) + ,ph1_bithuff(this,ifp,order) + ,image(NULL) + ,exif_base(-1), ciff_base(-1), ciff_len(0) + { + aber[0]=aber[1]=aber[2]=aber[3]=1; + gamm[0]=0.45;gamm[1]=4.5;gamm[2]=gamm[3]=gamm[4]=gamm[5]=0; + user_mul[0]=user_mul[1]=user_mul[2]=user_mul[3]=0; + greybox[0]=greybox[1]=0; greybox[2]=greybox[3]= UINT_MAX; + } + + int main (int argc, const char **argv); +protected: + int exif_base, ciff_base, ciff_len; + IMFILE *ifp; + FILE *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, multi_out; + 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; + double aber[4]; + double gamm[6]; + dcrawImage_t image; + ushort white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4]; + float bright, user_mul[4], threshold; + + int half_size, four_color_rgb, document_mode, highlight; + int verbose, use_auto_wb, use_camera_wb, use_camera_matrix; + int output_color, output_bps, output_tiff, med_passes; + int no_auto_bright; + unsigned greybox[4] ; + + float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4]; + + int histogram[4][0x2000]; + void (DCraw::*write_thumb)(), (DCraw::*write_fun)(); + void (DCraw::*load_raw)(), (DCraw::*thumb_load_raw)(); + jmp_buf failure; + + unsigned huff[1024]; // static inside foveon_decoder + + struct decode { + struct decode *branch[2]; + int leaf; + } first_decode[2048], *second_decode, *free_decode; + + struct tiff_ifd { + int width, height, bps, comp, phint, offset, flip, samples, bytes; + } tiff_ifd[10]; + + struct ph1 { + int format, key_off, black, black_off, split_col, tag_21a; + float tag_210; + } ph1; + + struct jhead { + int bits, high, wide, clrs, sraw, psv, restart, vpred[6]; + ushort *huff[6], *free[4], *row; + }; + + struct tiff_tag { + ushort tag, type; + int count; + union { char c[4]; short s[2]; int i; } val; + }; + + struct tiff_hdr { + ushort order, magic; + int ifd; + ushort pad, ntag; + struct tiff_tag tag[23]; + int nextifd; + ushort pad2, nexif; + struct tiff_tag exif[4]; + ushort pad3, ngps; + struct tiff_tag gpst[10]; + short bps[4]; + int rat[10]; + unsigned gps[26]; + char desc[512], make[64], model[64], soft[32], date[20], artist[64]; + }; +protected: + +int fc (int row, int col); +void merror (void *ptr, const char *where); +void derror(); +ushort sget2 (uchar *s); +ushort get2(); +unsigned sget4 (uchar *s); +unsigned get4(); +unsigned getint (int type); +float int_to_float (int i); +double getreal (int type); +void read_shorts (ushort *pixel, int count); +void canon_600_fixed_wb (int temp); +int canon_600_color (int ratio[2], int mar); +void canon_600_auto_wb(); +void canon_600_coeff(); +void canon_600_load_raw(); +void remove_zeroes(); +int canon_s2is(); + +// getbithuff(int nbits, ushort *huff); +class getbithuff_t +{ +public: + getbithuff_t(DCraw *p,IMFILE *&i, unsigned &z):parent(p),bitbuf(0),vbits(0),reset(0),ifp(i),zero_after_ff(z){} + unsigned operator()(int nbits, ushort *huff); + +private: + void derror(){ + parent->derror(); + } + DCraw *parent; + unsigned bitbuf; + int vbits, reset; + IMFILE *&ifp; + unsigned &zero_after_ff; +}; +getbithuff_t getbithuff; + +ushort * make_decoder_ref (const uchar **source); +ushort * make_decoder (const uchar *source); +void crw_init_tables (unsigned table, ushort *huff[2]); +int canon_has_lowbits(); +void canon_compressed_load_raw(); +int ljpeg_start (struct jhead *jh, int info_only); +void ljpeg_end (struct jhead *jh); +int ljpeg_diff (ushort *huff); +ushort * ljpeg_row (int jrow, struct jhead *jh); +void lossless_jpeg_load_raw(); + +void canon_sraw_load_raw(); +void adobe_copy_pixel (int row, int col, ushort **rp); +void adobe_dng_load_raw_lj(); +void adobe_dng_load_raw_nc(); +void pentax_load_raw(); +void nikon_compressed_load_raw(); +int nikon_is_compressed(); +int nikon_e995(); +int nikon_e2100(); +void nikon_3700(); +int minolta_z2(); +void fuji_load_raw(); +void ppm_thumb(); +void layer_thumb(); +void rollei_thumb(); +void rollei_load_raw(); +int bayer (unsigned row, unsigned col); +void phase_one_flat_field (int is_float, int nc); +void phase_one_correct(); +void phase_one_load_raw(); + +// ph1_bithuff(int nbits, ushort *huff); +class ph1_bithuff_t { +public: + ph1_bithuff_t(DCraw *p,IMFILE *&i,short &o):parent(p),bitbuf(0),vbits(0),ifp(i),order(o){} + unsigned operator()(int nbits, ushort *huff); +private: + unsigned get4(){ + return parent->get4(); + } + DCraw *parent; + short ℴ + IMFILE *&ifp; + UINT64 bitbuf; + int vbits; +}; +ph1_bithuff_t ph1_bithuff; + +void phase_one_load_raw_c(); +void hasselblad_load_raw(); +void leaf_hdr_load_raw(); +void unpacked_load_raw(); +void sinar_4shot_load_raw(); +void imacon_full_load_raw(); +void packed_load_raw(); +void nokia_load_raw(); + +// pana_bits(int nbits); +class pana_bits_t{ +public: + pana_bits_t(IMFILE *&i,unsigned &u):ifp(i),load_flags(u){} + unsigned operator()(int nbits); +private: + IMFILE *&ifp; + unsigned &load_flags; + uchar buf[0x4000]; + int vbits; +}; +pana_bits_t pana_bits; + +void panasonic_load_raw(); +void olympus_load_raw(); +void minolta_rd175_load_raw(); +void quicktake_100_load_raw(); +void kodak_radc_load_raw(); + +void kodak_jpeg_load_raw(); +void kodak_dc120_load_raw(); +void eight_bit_load_raw(); +void kodak_yrgb_load_raw(); +void kodak_262_load_raw(); +int kodak_65000_decode (short *out, int bsize); +void kodak_65000_load_raw(); +void kodak_ycbcr_load_raw(); +void kodak_rgb_load_raw(); +void kodak_thumb_load_raw(); + +// sony_decrypt(unsigned *data, int len, int start, int key); +class sony_decrypt_t{ +public: + void operator()(unsigned *data, int len, int start, int key); +private: + unsigned pad[128], p; +}; +sony_decrypt_t sony_decrypt; + +void sony_load_raw(); +void sony_arw_load_raw(); +void sony_arw2_load_raw(); +void smal_decode_segment (unsigned seg[2][2], int holes); +void smal_v6_load_raw(); + +int median4 (int *p); +void fill_holes (int holes); +void smal_v9_load_raw(); + +void foveon_decoder (unsigned size, unsigned code); +void foveon_thumb(); +void foveon_load_camf(); +void foveon_load_raw(); +const char * foveon_camf_param (const char *block, const char *param); +void *foveon_camf_matrix (unsigned dim[3], const char *name); +int foveon_fixed (void *ptr, int size, const char *name); +float foveon_avg (short *pix, int range[2], float cfilt); +short *foveon_make_curve (double max, double mul, double filt); +void foveon_make_curves(short **curvep, float dq[3], float div[3], float filt); +int foveon_apply_curve (short *curve, int i); +void foveon_interpolate(); + +void bad_pixels (const char *cfname); +void subtract (const char *fname); +void gamma_curve (double pwr, double ts, int mode, int imax); +void pseudoinverse (double (*in)[3], double (*out)[3], int size); +void cam_xyz_coeff (double cam_xyz[4][3]); +void hat_transform (float *temp, float *base, int st, int size, int sc); +void wavelet_denoise(); +void scale_colors(); +void pre_interpolate(); +void border_interpolate (int border); +void lin_interpolate(); +void vng_interpolate(); +void ppg_interpolate(); +void ahd_interpolate(); +void median_filter(); +void blend_highlights(); +void recover_highlights(); + +void tiff_get (unsigned base, unsigned *tag, unsigned *type, unsigned *len, unsigned *save); +void parse_thumb_note (int base, unsigned toff, unsigned tlen); +int parse_tiff_ifd (int base); +void parse_makernote (int base, int uptag); +void get_timestamp (int reversed); +void parse_exif (int base); +void parse_gps (int base); +void romm_coeff (float romm_cam[3][3]); +void parse_mos (int offset); +void linear_table (unsigned len); +void parse_kodak_ifd (int base); + +void parse_minolta (int base); +int parse_tiff (int base); +void apply_tiff(); +void parse_external_jpeg(); +void ciff_block_1030(); +void parse_ciff (int offset, int length); +void parse_rollei(); +void parse_sinar_ia(); +void parse_phase_one (int base); +void parse_fuji (int offset); +int parse_jpeg (int offset); +void parse_riff(); +void parse_smal (int offset, int fsize); +void parse_cine(); +char *foveon_gets (int offset, char *str, int len); +void parse_foveon(); + +void adobe_coeff (const char *make, const char *model); +void simple_coeff (int index); +short guess_byte_order (int words); +float find_green (int bps, int bite, int off0, int off1); +void identify(); +void apply_profile (const char *input, const char *output); +void convert_to_rgb(); +void fuji_rotate(); +void stretch(); +int flip_index (int row, int col); +void tiff_set (ushort *ntag,ushort tag, ushort type, int count, int val); +void tiff_head (struct tiff_hdr *th, int full); +void jpeg_thumb(); +void write_ppm_tiff(); + +}; + + +#endif //DCRAW_H diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc index d00fec93a..cf7f1c576 100644 --- a/rtengine/dfmanager.cc +++ b/rtengine/dfmanager.cc @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -117,6 +117,7 @@ void dfInfo::updateRawImage() delete ri; ri=NULL; }else{ + ri->compress_image(); int rSize = W*(ri->isBayer()?1:3); acc_t **acc = new acc_t*[H]; for( int row=0; rowloadRaw(true)){ + temp->compress_image(); //\ TODO would be better working on original, because is temporary nFiles++; if( ri->isBayer() ){ for( int row=0; rowloadRaw(true)){ delete ri; ri=NULL; - } + }else + ri->compress_image(); } } diff --git a/rtengine/dfmanager.h b/rtengine/dfmanager.h index 73f5ba822..16b9d4e88 100644 --- a/rtengine/dfmanager.h +++ b/rtengine/dfmanager.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include namespace rtengine{ diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index e00457fb4..c453ae353 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -20,7 +20,7 @@ #define __IMAGEDATA_H__ #include -#include +#include #include #include #include diff --git a/rtengine/init.cc b/rtengine/init.cc index eca8ed7ff..b340a4efa 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -36,8 +36,6 @@ int init (const Settings* s) { iccStore->parseDir (s->iccDirectory); CurveFactory::init (); ImProcFunctions::initCache (); - delete dcrMutex; - dcrMutex = new Glib::Mutex; delete lcmsMutex; lcmsMutex = new Glib::Mutex; dfm.init( s->darkFramesPath ); diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc new file mode 100644 index 000000000..6c2158464 --- /dev/null +++ b/rtengine/rawimage.cc @@ -0,0 +1,245 @@ +/* + * This file is part of RawTherapee. + * + * Created on: 20/nov/2010 + */ + +#include +#include +#include +#include + + +namespace rtengine{ + +extern Settings* settings; + +RawImage::RawImage( const Glib::ustring name ) +:allocation(NULL) +,data(NULL) +,profile_data(NULL) +,filename(name) +,prefilters(0) +{ +} + +RawImage::~RawImage() +{ + if(ifp) + fclose(ifp); + if( image ) + free(image); + if(allocation){ delete [] allocation; allocation=NULL;} + if(data){ delete [] data; data=NULL;} + if(profile_data){ delete [] profile_data; profile_data=NULL;} +} + +/* Similar to dcraw scale_colors for coeff. calculation, but without actual pixels scaling. + * need pixels in data[][] available + */ +int RawImage::get_colorsCoeff( float *pre_mul_, float *scale_mul_, int *cblack_ ) +{ + unsigned row, col, ur, uc, i, x, y, c, sum[8]; + unsigned W = this->get_width(); + unsigned H = this->get_height(); + int val, dark, sat; + double dsum[8], dmin, dmax; + + for (int c = 0; c < 4; c++){ + cblack_[c] = this->get_cblack(c) + this->get_black(); + pre_mul_[c] = this->get_pre_mul(c); + } + + if ( this->get_cam_mul(0) == -1 ) { + memset(dsum, 0, sizeof dsum); + for (row = 0; row < H; row += 8) + for (col = 0; col < W ; col += 8) { + memset(sum, 0, sizeof sum); + for (y = row; y < row + 8 && y < H; y++) + for (x = col; x < col + 8 && x < W; x++) + for (int c = 0; c < 3; c++) { + if (this->isBayer()) { + c = FC(y, x); + val = data[y][x]; + } else + val = data[y][3*x+c]; + if (val > this->get_white() - 25) + goto skip_block; + if ((val -= cblack_[c]) < 0) + val = 0; + sum[c] += val; + sum[c + 4]++; + if ( this->isBayer()) + break; + } + for (c = 0; c < 8; c++) + dsum[c] += sum[c]; +skip_block: ; + } + for (int c = 0; c < 4; c++) + if (dsum[c]) + pre_mul_[c] = dsum[c + 4] / dsum[c]; + }else{ + memset(sum, 0, sizeof sum); + for (row = 0; row < 8; row++) + for (col = 0; col < 8; col++) { + int c = FC(row, col); + if ((val = white[row][col] - cblack_[c]) > 0) + sum[c] += val; + sum[c + 4]++; + } + if (sum[0] && sum[1] && sum[2] && sum[3]) + for (int c = 0; c < 4; c++) + pre_mul_[c] = (float) sum[c + 4] / sum[c]; + else if (this->get_cam_mul(0) && this->get_cam_mul(2)){ + pre_mul_[0] = this->get_cam_mul(0); + pre_mul_[1] = this->get_cam_mul(1); + pre_mul_[2] = this->get_cam_mul(2); + pre_mul_[3] = this->get_cam_mul(3); + }else + fprintf(stderr, "Cannot use camera white balance.\n"); + } + if (pre_mul_[3] == 0) + pre_mul_[3] = this->get_colors() < 4 ? pre_mul_[1] : 1; + dark = this->get_black(); + sat = this->get_white(); + sat -= this->get_black(); + for (dmin = DBL_MAX, dmax = c = 0; c < 4; c++) { + if (dmin > pre_mul_[c]) + dmin = pre_mul_[c]; + if (dmax < pre_mul_[c]) + dmax = pre_mul_[c]; + } + + for (c = 0; c < 4; c++) + scale_mul_[c] = (pre_mul_[c] /= dmax) * 65535.0 / sat; + if (settings->verbose) { + fprintf(stderr,"Scaling with darkness %d, saturation %d, and\nmultipliers", dark, sat); + for (c = 0; c < 4; c++) + fprintf(stderr, " %f", pre_mul[c]); + fputc('\n', stderr); + } +} + +int RawImage::loadRaw (bool loadData, bool closeFile) +{ + ifname = filename.c_str(); + image = NULL; + verbose = settings->verbose; + oprof = NULL; + + ifp = gfopen (filename.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); + ifp=NULL; + return 2; + } + + 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; + + if( loadData ){ + + use_camera_wb = 1; + shrink = 0; + if (settings->verbose) printf ("Loading %s %s image from %s...\n", make, model, filename.c_str()); + iheight = height; + iwidth = width; + + // dcraw needs this global variable to hold pixel data + image = (dcrawImage_t)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); + (this->*load_raw)(); + + // Load embedded profile + if (profile_length) { + profile_data = new char[profile_length]; + fseek ( ifp, profile_offset, SEEK_SET); + fread ( profile_data, 1, profile_length, ifp); + } + + // Setting the black 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; + } + if( closeFile ){ + fclose(ifp); + ifp=NULL; + } + return 0; +} + +unsigned short** RawImage::compress_image() +{ + if( !image ) + return NULL; + if (filters) { + if (!allocation) { + allocation = new unsigned short[height * width]; + data = new unsigned short*[height]; + for (int i = 0; i < height; i++) + data[i] = allocation + i * width; + } + } else { + if (!allocation) { + allocation = new unsigned short[3 * height * width]; + data = new unsigned short*[height]; + for (int i = 0; i < height; i++) + data[i] = allocation + 3 * i * width; + } + } + + // copy pixel raw data: the compressed format earns space + if (filters != 0) { + 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 + image=NULL; + return data; +} + +}; //namespace rtengine diff --git a/rtengine/common.h b/rtengine/rawimage.h similarity index 68% rename from rtengine/common.h rename to rtengine/rawimage.h index 528b4bf36..a95178298 100644 --- a/rtengine/common.h +++ b/rtengine/rawimage.h @@ -16,11 +16,12 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#ifndef _COMMON_ -#define _COMMON_ +#ifndef __RAWIMAGE_H +#define __RAWIMAGE_H #include #include +#include namespace rtengine { @@ -31,47 +32,38 @@ struct badPix badPix( int xc, int yc ):x(xc),y(yc){} }; -struct RawImage { - - unsigned filters; // \TODO problem in pre_interpolate() - int prefilters; +class RawImage: public DCraw +{ +public: + RawImage( const Glib::ustring name ); + ~RawImage(); + int loadRaw (bool loadData=true, bool closeFile=true); + int get_colorsCoeff( float *pre_mul, float *scale_mul, int *cblack ); + void set_prefilters(){ + if (isBayer() && get_colors() == 3) { + prefilters = filters; + filters &= ~((filters & 0x55555555) << 1); + } + } + dcrawImage_t get_image() { return image; } + unsigned short** compress_image(); // revert to compressed pixels format and release image data unsigned short** data; // holds pixel values, data[i][j] corresponds to the ith row and jth column - + unsigned prefilters; // original filters saved ( used for 4 color processing ) protected: Glib::ustring filename; // complete filename - int width; // with of the image as reported by dcraw - int height; // height of the image as reported by dcraw - int fuji_width; - int colors; // Number of colors of bayer filter (3 or 4) - int black; // Black offset taken from dslr info by dcraw - int cblack[4]; // Black for each color. - int maximum; // White (maximum) point taken from dslr info int rotate_deg; // 0,90,180,270 degree of rotation: info taken by dcraw from exif - double iso_speed; - double shutter; - time_t timestamp; - char *make, *model; - unsigned short white[8][8]; // square of white registered by camera - float cam_mul[4]; // Camera color multiplier taken from exif by dcraw - float pre_mul[4]; - float coeff[3][3]; // rgb_cam coeff. - - int exifbase, ciff_base, ciff_len; - int profile_len; char* profile_data; // Embedded ICC color profile - unsigned short* allocation; // pointer to allocated memory + public: - RawImage( const Glib::ustring name); - ~RawImage(); - int loadRaw (bool loadData=true); - void allocData(); + std::string get_filename() const { return filename;} int get_width() const { return width; } int get_height() const { return height; } int get_FujiWidth() const { return fuji_width; } bool isBayer() const { return filters!=0; } + unsigned get_filters() const { return filters; } int get_colors() const { return colors;} int get_black() const { return black;} int get_cblack(int i) const {return cblack[i];} @@ -87,21 +79,29 @@ public: float get_cam_mul(int c )const {return cam_mul[c];} float get_pre_mul(int c )const {return pre_mul[c];} - float get_rgb_cam( int r, int c) const { return coeff[r][c];} + float get_rgb_cam( int r, int c) const { return rgb_cam[r][c];} - int get_exifBase() const {return exifbase; } + int get_exifBase() const {return exif_base; } int get_ciffBase() const {return ciff_base; } int get_ciffLen() const {return ciff_len; } - int get_profileLen() const {return profile_len;} + int get_profileLen() const {return profile_length;} char* get_profile() const { return profile_data;} + IMFILE *get_file() { return ifp; } + int get_thumbOffset(){ return int(thumb_offset);} + unsigned get_thumbLength(){ return thumb_length;} +public: + // dcraw functions + void scale_colors(){ DCraw::scale_colors(); } + void pre_interpolate() { DCraw::pre_interpolate(); } public: bool ISRED (unsigned row, unsigned col) const { return ((filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==0);} bool ISGREEN(unsigned row, unsigned col) const { return ((filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==1);} bool ISBLUE (unsigned row, unsigned col) const { return ((filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==2);} + unsigned FC (unsigned row, unsigned col) const { return (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3); } }; } -#endif +#endif // __RAWIMAGE_H diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index f290f3c47..0f8303dad 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -731,6 +731,7 @@ int RawImageSource::load (Glib::ustring fname, bool batch) { int res = ri->loadRaw (); if (res) return res; + ri->compress_image(); if (plistener) { plistener->setProgress (0.8); } @@ -851,11 +852,7 @@ skip_block: ; wb = ColorTemp (cam_r, cam_g, cam_b); - // ---------------- preinterpolate - if (ri->isBayer() && ri->get_colors() == 3) { - ri->prefilters = ri->filters; - ri->filters &= ~((ri->filters & 0x55555555) << 1); - } + ri->set_prefilters(); //Load complete Exif informations RawMetaDataLocation rml; @@ -2469,15 +2466,11 @@ void RawImageSource::vng4_demosaic () { free (image); } -//#define ABS(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31)) -//#define MIN(a,b) ((a) < (b) ? (a) : (b)) -//#define MAX(a,b) ((a) > (b) ? (a) : (b)) -//#define LIM(x,min,max) MAX(min,MIN(x,max)) -//#define CLIP(x) LIM(x,0,65535) -#undef fc + +/*#undef fc #define fc(row,col) \ (ri->filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) -#define FC(x,y) fc(x,y) +#define FC(x,y) fc(x,y)*/ #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)) diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 8c90af40f..774f9c6a9 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -106,7 +106,7 @@ class RawImageSource : public ImageSource { void updateHLRecoveryMap (std::string method, double rm, double gm, double bm); void updateHLRecoveryMap_ColorPropagation (); void HLRecovery_ColorPropagation (unsigned short* red, unsigned short* green, unsigned short* blue, int i, int sx1, int width, int skip); - int FC(int row, int col){ return (ri->prefilters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3); } + unsigned FC(int row, int col){ return ri->FC(row,col); } public: RawImageSource (); ~RawImageSource (); diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 860d5c206..55a7f84ff 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -304,17 +304,6 @@ namespace rtengine { * @param s is a struct of basic settings */ int init (const Settings* s); -/** Checks if a raw file is supported - * @param fname the name of the file - * @param rml is a struct constaining informations on the location of the metadata in the raw file - * @param rotation is the default angle of rotation (0, 90, 180, 270) - * @param thumbWidth is the width of the embedded thumbnail file - * @param thumbHeight is the height of the embedded thumbnail file - * @param thumbOffset is the offset of the embedded thumbnail in the raw file - * @param thumbType is the type of the embedded thumbnail (=0: no thumbnail, =1: jpeg format, =2: simple continuous image data in rgbrgb... order) - * @return =0 if not supported */ - int getRawFileBasicInfo (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int& rotation, int& thumbWidth, int& thumbHeight, int& thumbOffset, int& thumbType); - /** Returns the available output profile names * @return a vector of the available output profile names */ std::vector getOutputProfiles (); diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 87ef8ec6d..ac269569d 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -33,6 +33,7 @@ #include #include #include +#include extern "C" { #include @@ -195,6 +196,288 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, return tpp; } +Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh) +{ + RawImage *ri= new RawImage(fname); + int r = ri->loadRaw(false,false); + if( r ) return NULL; + + rml.exifBase = ri->get_exifBase(); + rml.ciffBase = ri->get_ciffBase(); + rml.ciffLength = ri->get_ciffLen(); + + Thumbnail* tpp = Thumbnail::loadFromMemory(fdata(ri->get_thumbOffset(),ri->get_file()),ri->get_thumbLength(),w,h,fixwh); + + if ( tpp == 0 ) + { + printf("DCRAW: failed4\n"); + return NULL; + } + + if (ri->get_rotateDegree() > 0) { + Image16* rot = tpp->thumbImg->rotate(ri->get_rotateDegree()); + delete tpp->thumbImg; + tpp->thumbImg = rot; + } + + delete ri; + + return tpp; +} + +#define FISRED(filter,row,col) \ + ((filter >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==0 || !filter) +#define FISGREEN(filter,row,col) \ + ((filter >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==1 || !filter) +#define FISBLUE(filter,row,col) \ + ((filter >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3)==2 || !filter) + +Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh) +{ + RawImage *ri= new RawImage (fname); + int r = ri->loadRaw(); + if( r ){ + delete ri; + return NULL; + } + int width = ri->get_width(); + int height = ri->get_height(); + rtengine::Thumbnail* tpp = new rtengine::Thumbnail; + + tpp->isRaw = true; + tpp->embProfile = NULL; + tpp->embProfileData = NULL; + tpp->embProfileLength = ri->get_profileLen(); + if (ri->get_profileLen()) + tpp->embProfile = cmsOpenProfileFromMem(ri->get_profile(), + ri->get_profileLen()); //\ TODO check if mutex is needed + + tpp->redMultiplier = ri->get_pre_mul(0); + tpp->greenMultiplier = ri->get_pre_mul(1); + tpp->blueMultiplier = ri->get_pre_mul(2); + + float pre_mul[4], scale_mul[4]; + int cblack[4]; + + ri->scale_colors(); + ri->pre_interpolate(); + + rml.exifBase = ri->get_exifBase(); + rml.ciffBase = ri->get_ciffBase(); + rml.ciffLength = ri->get_ciffLen(); + + tpp->camwbRed = tpp->redMultiplier / ri->get_pre_mul(0); + tpp->camwbGreen = tpp->greenMultiplier / ri->get_pre_mul(1); + tpp->camwbBlue = tpp->blueMultiplier / ri->get_pre_mul(2); + tpp->defGain= 1.0/ MIN(MIN(ri->get_pre_mul(0),ri->get_pre_mul(1)),ri->get_pre_mul(2)); + tpp->gammaCorrected = true; + + unsigned filter = ri->get_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 = (ri->get_height() - firstgreen - 1) / h; + else + skip = (ri->get_width() - firstgreen - 1) / w; + if (skip % 2) + skip--; + if (skip < 1) + skip = 1; + + int hskip = skip, vskip = skip; + if (!ri->get_model().compare("D1X")) + hskip *= 2; + + int ix = 0; + int rofs = 0; + int tmpw = (width - 2) / hskip; + int tmph = (height - 2) / vskip; + + DCraw::dcrawImage_t image = ri->get_image(); + + Image16* tmpImg = new Image16(tmpw, tmph); + if (ri->isBayer()) { + 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 (ri->get_FujiWidth() != 0) { + int fw = ri->get_FujiWidth() / 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 (ri->get_FujiWidth() != 0) + tpp->scale = (double) (height - ri->get_FujiWidth()) / sqrt(0.5) / h; + else + tpp->scale = (double) height / h; + + // 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 (ri->get_FujiWidth() != 0) { + int fw = ri->get_FujiWidth(); + 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; + } + + // 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 (ri->get_FujiWidth() != 0) { + int fw = ri->get_FujiWidth(); + 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 = ri->get_rgb_cam(0, 0) * reds + ri->get_rgb_cam(0, 1) * greens + ri->get_rgb_cam(0, 2) * blues; + double gm = ri->get_rgb_cam(1, 0) * reds + ri->get_rgb_cam(1, 1) * greens + ri->get_rgb_cam(1, 2) * blues; + double bm = ri->get_rgb_cam(2, 0) * reds + ri->get_rgb_cam(2, 1) * greens + ri->get_rgb_cam(2, 2) * blues; + + ColorTemp::mul2temp(rm, gm, bm, tpp->autowbTemp, tpp->autowbGreen); + + if (ri->get_rotateDegree() > 0) { + Image16* rot = tpp->thumbImg->rotate(ri->get_rotateDegree()); + delete tpp->thumbImg; + tpp->thumbImg = rot; + } + + for (int a = 0; a < 3; a++) + for (int b = 0; b < 3; b++) + tpp->colorMatrix[a][b] = ri->get_rgb_cam(a, b); + + tpp->init(); + delete ri; + return tpp; +} +#undef FISRED +#undef FISGREEN +#undef FISBLUE + + void Thumbnail::init () { RawImageSource::inverse33 (colorMatrix, iColorMatrix);