From de5f92937857cccc45080c59c6236561416e5ece Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 31 Dec 2023 12:52:34 -0800 Subject: [PATCH] Squashed 'rtengine/libraw/' changes from cccb97647..1ef70158d 1ef70158d 0.21.2 release 62f042366 tag type => tag size mapping fixed ee087e3fe cubic_spline: better handling of non-integer data af755b991 extra metadata check in arq_load_raw 0fadd8819 Better incorrect data handling in cubic_spline d7fb66053 skip invalid pattern in xtrans_interpolate d059ed280 Check HL recovery coeffs before processing 104730519 limit wavelet denoise minimum size cae09838e raw-identify: use fallback if PATH_MAX not available d6c677608 additional check against corrupted ljpeg layout 1001a6ac1 Disable color conversion for Canon 16-bit thumbnails a5130b01b docs/changelog: explained the case when no thumbnail is found in specific file 600c0c63d rename swapXX to libraw_swapXX to avoid name conflict 299c8a11b Check against corrupted LJPEG header in Canon sRAW decoder ec8671ad9 Limit embedded color profile allocation/read size 5229d5942 Wrong alloc result check for 16-bit bitmap thumbnail b278b775f check pana_data/buffer offset before use 7f4b8d3af Check P1 quadrant linearization coeff[15] against zero e942a7db6 avoid integer overflow in buffer space check f6a57cfb8 prevent buffer overrun in buffer_datastream::scanf_one 3e62ed304 ensure correct T.tlength for 16b bitmap thumbnails(2) 8e52d81cd ensure correct T.tlength for 16b bitmap thumbnails 8e1af15e2 Do not run sraw decoder on (crafted) bayer files 0ace959c2 better striped thumbnails handling 477e0719f do not set shrink flag for 3/4 component images c8efae6c5 allow more decoders for fuji-rotated RAWs git-subtree-dir: rtengine/libraw git-subtree-split: 1ef70158d7fde1ced6aaddb0b9443c32a7121d3d --- Changelog.txt | 28 +++++++++++++- doc/API-datastruct.html | 6 +++ libraw/libraw_const.h | 4 ++ libraw/libraw_version.h | 2 +- samples/raw-identify.cpp | 4 ++ src/decoders/decoders_dcraw.cpp | 11 ++++++ src/decoders/decoders_libraw.cpp | 3 ++ src/decoders/fp_dng.cpp | 8 ++-- src/decoders/load_mfbacks.cpp | 13 +++++-- src/decoders/unpack_thumb.cpp | 23 +++++++----- src/demosaic/xtrans_demosaic.cpp | 4 ++ src/libraw_datastream.cpp | 2 +- src/metadata/fuji.cpp | 6 +-- src/postprocessing/postprocessing_aux.cpp | 7 ++++ src/preprocessing/raw2image.cpp | 2 + src/tables/wblists.cpp | 6 +-- src/utils/curves.cpp | 7 +++- src/utils/open.cpp | 17 +++++++-- src/utils/thumb_utils.cpp | 46 ++++++++++++++--------- 19 files changed, 150 insertions(+), 49 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 7534563b6..42c2bb2b5 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,25 @@ +2023-12-19 Alex Tutubalin + + LibRaw 0.21.2-Release + + * New compile-defined limit LIBRAW_MAX_PROFILE_SIZE_MB: + limits allocation/read size for embedded color profile (default: 256Mb) + + * Embedded color profile allocation/read size: limited by input file size. + + * Multiple fixes (mostly inspired by oss-fuzz) to improve library stability and/or input checks. + + * raw-identify: use fallback if PATH_MAX not available + + * Disabled color conversion for Canon 16-bit thumbnails + + * docs/changelog: explained the case when no thumbnail is found in specific file + + * swapXX renamed to libraw_swapXX to avoid name conflict + + * better striped thumbnails handling + + 2023-01-05 Alex Tutubalin LibRaw 0.21.1-Release * fixed typo in panasonic metadata parser @@ -52,7 +74,11 @@ Notes: - Only TIFF-based and CR3 files are parsed for thumbnail list, other formats will have - thumbcount = 1 (or 0 if no thumbnail found in file). + thumbcount = 1. + + - If no thumbnails are found in file: thumbcount will be set to 1 and + thumblist[0] will be initialized with data from thumbnail fields, + so LibRaw::unpack_thumb_ex(0) will do the same as LibRaw::unpack_thumb() - Thumbnail image size may be unknown (not recorded in metadata), in this case twidth and theight are zero. Usually small(er) thumbnails will always have twidth/theight filled, while largest one may have these fields set to zero. diff --git a/doc/API-datastruct.html b/doc/API-datastruct.html index 09c05ac76..5c2ddb3bf 100644 --- a/doc/API-datastruct.html +++ b/doc/API-datastruct.html @@ -427,6 +427,12 @@ +

+ Note: even if no thumbnails were found in TIFF/CR3 structure, the + thumbcount field will be initialized to 1 and thumblist[0] will be + initialized to thumbnail data from the thumbnail data, so + LibRaw::unpack_thumb_ex(0) will do the same as LibRaw::unpack_thumb(). +

Structure libraw_lensinfo_t: parsed lens data

The following parameters are extracted from Makernotes and EXIF, to help diff --git a/libraw/libraw_const.h b/libraw/libraw_const.h index 599306b6f..61f8028b2 100644 --- a/libraw/libraw_const.h +++ b/libraw/libraw_const.h @@ -24,6 +24,10 @@ it under the terms of the one of two licenses as you choose: #define LIBRAW_MAX_ALLOC_MB_DEFAULT 2048L #endif +#ifndef LIBRAW_MAX_PROFILE_SIZE_MB +#define LIBRAW_MAX_PROFILE_SIZE_MB 256LL +#endif + #ifndef LIBRAW_MAX_NONDNG_RAW_FILE_SIZE #define LIBRAW_MAX_NONDNG_RAW_FILE_SIZE 2147483647ULL #endif diff --git a/libraw/libraw_version.h b/libraw/libraw_version.h index 3845a5e46..c6f5c72a3 100644 --- a/libraw/libraw_version.h +++ b/libraw/libraw_version.h @@ -22,7 +22,7 @@ it under the terms of the one of two licenses as you choose: #define LIBRAW_MAJOR_VERSION 0 #define LIBRAW_MINOR_VERSION 21 -#define LIBRAW_PATCH_VERSION 1 +#define LIBRAW_PATCH_VERSION 2 #define LIBRAW_VERSION_TAIL Release #define LIBRAW_SHLIB_CURRENT 23 diff --git a/samples/raw-identify.cpp b/samples/raw-identify.cpp index ced518175..31c770d34 100644 --- a/samples/raw-identify.cpp +++ b/samples/raw-identify.cpp @@ -40,7 +40,11 @@ it under the terms of the one of two licenses as you choose: #include #include #ifndef MAX_PATH +#ifdef PATH_MAX #define MAX_PATH PATH_MAX +#else +#define MAX_PATH 4096 +#endif #endif #endif diff --git a/src/decoders/decoders_dcraw.cpp b/src/decoders/decoders_dcraw.cpp index 721d38577..090a6b726 100644 --- a/src/decoders/decoders_dcraw.cpp +++ b/src/decoders/decoders_dcraw.cpp @@ -577,6 +577,9 @@ void LibRaw::lossless_jpeg_load_raw() i = jidx / (cr2_slice[1] * raw_height); if ((j = i >= cr2_slice[0])) i = cr2_slice[0]; + if(!cr2_slice[1+j]) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + jidx -= i * (cr2_slice[1] * raw_height); row = jidx / cr2_slice[1 + j]; col = jidx % cr2_slice[1 + j] + i * cr2_slice[1]; @@ -609,10 +612,16 @@ void LibRaw::canon_sraw_load_raw() int saved_w = width, saved_h = height; char *cp; + if(!image) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + if (!ljpeg_start(&jh, 0) || jh.clrs < 4) return; jwide = (jh.wide >>= 1) * jh.clrs; + if (jwide < 32 || jwide > 65535) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + if (load_flags & 256) { width = raw_width; @@ -1170,6 +1179,8 @@ void LibRaw::panasonic_load_raw() } else { + if (load_flags >= 0x4000) + throw LIBRAW_EXCEPTION_IO_CORRUPT; for (row = 0; row < raw_height; row++) { checkCancel(); diff --git a/src/decoders/decoders_libraw.cpp b/src/decoders/decoders_libraw.cpp index 332e2af21..bc62a6c2d 100644 --- a/src/decoders/decoders_libraw.cpp +++ b/src/decoders/decoders_libraw.cpp @@ -22,6 +22,9 @@ void LibRaw::sony_arq_load_raw() { int row, col; + if (imgdata.idata.filters || imgdata.idata.colors < 3) + throw LIBRAW_EXCEPTION_IO_CORRUPT; + read_shorts(imgdata.rawdata.raw_image, imgdata.sizes.raw_width * imgdata.sizes.raw_height * 4); libraw_internal_data.internal_data.input->seek( diff --git a/src/decoders/fp_dng.cpp b/src/decoders/fp_dng.cpp index 0566ad2ca..72631dbbd 100644 --- a/src/decoders/fp_dng.cpp +++ b/src/decoders/fp_dng.cpp @@ -556,7 +556,7 @@ _forceinline #else inline #endif -void swap24(uchar *data, int len) +void libraw_swap24(uchar *data, int len) { for (int i = 0; i < len - 2; i += 3) { @@ -572,7 +572,7 @@ _forceinline #else inline #endif -void swap32(uchar *data, int len) +void libraw_swap32(uchar *data, int len) { unsigned *d = (unsigned*)data; for (int i = 0; i < len / 4; i++) @@ -646,9 +646,9 @@ void LibRaw::uncompressed_fp_dng_load_raw() if (bytesps == 2 && difford) libraw_swab(dst, fullrowbytes); else if (bytesps == 3 && (libraw_internal_data.unpacker_data.order == 0x4949)) // II-16bit - swap24(dst, fullrowbytes); + libraw_swap24(dst, fullrowbytes); if (bytesps == 4 && difford) - swap32(dst, fullrowbytes); + libraw_swap32(dst, fullrowbytes); float lmax = expandFloats( dst, diff --git a/src/decoders/load_mfbacks.cpp b/src/decoders/load_mfbacks.cpp index 493c7859f..cddc33ebc 100644 --- a/src/decoders/load_mfbacks.cpp +++ b/src/decoders/load_mfbacks.cpp @@ -352,10 +352,17 @@ int LibRaw::phase_one_correct() { /* Quadrant linearization */ ushort lc[2][2][16], ref[16]; int qr, qc; + bool baddiv = false; for (qr = 0; qr < 2; qr++) - for (qc = 0; qc < 2; qc++) - for (i = 0; i < 16; i++) - lc[qr][qc][i] = get4(); + for (qc = 0; qc < 2; qc++) + { + for (i = 0; i < 16; i++) + lc[qr][qc][i] = get4(); + if (lc[qr][qc][15] == 0) + baddiv = true; + } + if(baddiv) + continue; for (i = 0; i < 16; i++) { int v = 0; diff --git a/src/decoders/unpack_thumb.cpp b/src/decoders/unpack_thumb.cpp index 1f01ddc12..4298c3750 100644 --- a/src/decoders/unpack_thumb.cpp +++ b/src/decoders/unpack_thumb.cpp @@ -266,8 +266,9 @@ int LibRaw::unpack_thumb(void) tiff_ifd[pifd].strip_byte_counts_count) { // We found it, calculate final size - unsigned total_size = 0; - for (int i = 0; i < tiff_ifd[pifd].strip_byte_counts_count; i++) + INT64 total_size = 0; + for (int i = 0; i < tiff_ifd[pifd].strip_byte_counts_count + && i < tiff_ifd[pifd].strip_offsets_count; i++) total_size += tiff_ifd[pifd].strip_byte_counts[i]; if (total_size != (unsigned)t_length) // recalculate colors { @@ -284,15 +285,15 @@ int LibRaw::unpack_thumb(void) char *dest = T.thumb; INT64 pos = ID.input->tell(); + INT64 remain = T.tlength; for (int i = 0; i < tiff_ifd[pifd].strip_byte_counts_count && i < tiff_ifd[pifd].strip_offsets_count; i++) { - int remain = T.tlength; int sz = tiff_ifd[pifd].strip_byte_counts[i]; - int off = tiff_ifd[pifd].strip_offsets[i]; - if (off >= 0 && off + sz <= ID.input->size() && sz <= remain) + INT64 off = tiff_ifd[pifd].strip_offsets[i]; + if (off >= 0 && off + sz <= ID.input->size() && sz > 0 && INT64(sz) <= remain) { ID.input->seek(off, SEEK_SET); ID.input->read(dest, sz, 1); @@ -332,13 +333,13 @@ int LibRaw::unpack_thumb(void) int o_bps = (imgdata.rawparams.options & LIBRAW_RAWOPTIONS_USE_PPM16_THUMBS) ? 2 : 1; int o_length = T.twidth * T.theight * t_colors * o_bps; int i_length = T.twidth * T.theight * t_colors * 2; - if (!T.tlength) - T.tlength = o_length; - THUMB_SIZE_CHECKTNZ(o_length); + + THUMB_SIZE_CHECKTNZ(o_length); THUMB_SIZE_CHECKTNZ(i_length); - THUMB_SIZE_CHECKTNZ(T.tlength); ushort *t_thumb = (ushort *)calloc(i_length, 1); + if (!t_thumb) + throw LIBRAW_EXCEPTION_ALLOC; ID.input->read(t_thumb, 1, i_length); if ((libraw_internal_data.unpacker_data.order == 0x4949) == (ntohs(0x1234) == 0x1234)) @@ -350,14 +351,18 @@ int LibRaw::unpack_thumb(void) { T.thumb = (char *)t_thumb; T.tformat = LIBRAW_THUMBNAIL_BITMAP16; + T.tlength = i_length; } else { T.thumb = (char *)malloc(o_length); + if (!T.thumb) + throw LIBRAW_EXCEPTION_ALLOC; for (int i = 0; i < o_length; i++) T.thumb[i] = t_thumb[i] >> 8; free(t_thumb); T.tformat = LIBRAW_THUMBNAIL_BITMAP; + T.tlength = o_length; } SET_PROC_FLAG(LIBRAW_PROGRESS_THUMB_LOAD); return 0; diff --git a/src/demosaic/xtrans_demosaic.cpp b/src/demosaic/xtrans_demosaic.cpp index 5dbc3c3f6..2d96c62ef 100644 --- a/src/demosaic/xtrans_demosaic.cpp +++ b/src/demosaic/xtrans_demosaic.cpp @@ -265,6 +265,10 @@ void LibRaw::xtrans_interpolate(int passes) { rix = &rgb[0][row - top][col - left]; int h = fcol(row, col + 1); + + if (h == 1) // Incorrect pattern + break; + float diff[6]; memset(diff, 0, sizeof diff); for (int i = 1, d = 0; d < 6; d++, i ^= LIBRAW_AHD_TILE ^ 1, h ^= 2) diff --git a/src/libraw_datastream.cpp b/src/libraw_datastream.cpp index 898761de7..60593b42f 100644 --- a/src/libraw_datastream.cpp +++ b/src/libraw_datastream.cpp @@ -460,7 +460,7 @@ int LibRaw_buffer_datastream::scanf_one(const char *fmt, void *val) if (scanf_res > 0) { int xcnt = 0; - while (streampos < streamsize) + while (streampos < streamsize-1) { streampos++; xcnt++; diff --git a/src/metadata/fuji.cpp b/src/metadata/fuji.cpp index 4c9fe5025..feb394ef6 100644 --- a/src/metadata/fuji.cpp +++ b/src/metadata/fuji.cpp @@ -132,7 +132,7 @@ void LibRaw::parseAdobeRAFMakernote() } #define CHECKSPACE(s) \ - if (posPrivateMknBuf + (s) > PrivateMknLength) \ + if (INT64(posPrivateMknBuf) + INT64(s) > INT64(PrivateMknLength)) \ { \ free(PrivateMknBuf); \ return; \ @@ -209,7 +209,7 @@ void LibRaw::parseAdobeRAFMakernote() PrivateOrder = sget2(PrivateMknBuf); unsigned s, l; s = ifd_start = sget4(PrivateMknBuf +2)+6; - CHECKSPACE(ifd_start+4); + CHECKSPACE(INT64(ifd_start)+4LL); l = ifd_len = sget4(PrivateMknBuf +ifd_start); CHECKSPACE_ABS3(ifd_start, ifd_len, 4); @@ -767,7 +767,7 @@ void LibRaw::parseAdobeRAFMakernote() if (wb_section_offset) { - CHECKSPACE(wb_section_offset + 12); + CHECKSPACE(INT64(wb_section_offset) + 12LL); } if (wb_section_offset && diff --git a/src/postprocessing/postprocessing_aux.cpp b/src/postprocessing/postprocessing_aux.cpp index 57473400d..c8c53fa66 100644 --- a/src/postprocessing/postprocessing_aux.cpp +++ b/src/postprocessing/postprocessing_aux.cpp @@ -39,6 +39,7 @@ void LibRaw::wavelet_denoise() static const float noise[] = {0.8002f, 0.2735f, 0.1202f, 0.0585f, 0.0291f, 0.0152f, 0.0080f, 0.0044f}; + if (iwidth < 65 || iheight < 65) return; while (maximum << scale < 0x10000) scale++; @@ -135,6 +136,9 @@ void LibRaw::wavelet_denoise() static const float noise[] = {0.8002, 0.2735, 0.1202, 0.0585, 0.0291, 0.0152, 0.0080, 0.0044}; + if (iwidth < 65 || iheight < 65) + return; + while (maximum << scale < 0x10000) scale++; maximum <<= --scale; @@ -324,6 +328,9 @@ void LibRaw::recover_highlights() grow = pow(2.0, 4 - highlight); FORC(unsigned(colors)) hsat[c] = 32000 * pre_mul[c]; + FORC(unsigned(colors)) + if(hsat[c]<1) + return; for (kc = 0, c = 1; c < (unsigned)colors; c++) if (pre_mul[kc] < pre_mul[c]) kc = c; diff --git a/src/preprocessing/raw2image.cpp b/src/preprocessing/raw2image.cpp index e65e2ad73..702cf2902 100644 --- a/src/preprocessing/raw2image.cpp +++ b/src/preprocessing/raw2image.cpp @@ -43,6 +43,8 @@ void LibRaw::raw2image_start() // adjust for half mode! IO.shrink = + !imgdata.rawdata.color4_image && !imgdata.rawdata.color3_image && + !imgdata.rawdata.float4_image && !imgdata.rawdata.float3_image && P1.filters && (O.half_size || ((O.threshold || O.aber[0] != 1 || O.aber[2] != 1))); diff --git a/src/tables/wblists.cpp b/src/tables/wblists.cpp index f377cd3ec..1f8ae172b 100644 --- a/src/tables/wblists.cpp +++ b/src/tables/wblists.cpp @@ -17,15 +17,15 @@ #define _ARR_SZ(a) (sizeof(a)/sizeof(a[0])) -static const int _tagtype_dataunit_bytes [19] = { - 1, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4, 2, 8, 8, 8, 8 +static const int _tagtype_dataunit_bytes [20] = { + 1, 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8, 4, 2, 8, 8, 8, 8, 8 }; libraw_static_table_t LibRaw::tagtype_dataunit_bytes(_tagtype_dataunit_bytes, _ARR_SZ(_tagtype_dataunit_bytes)); int libraw_tagtype_dataunit_bytes(int tagtype) { - return _tagtype_dataunit_bytes[((unsigned)tagtype <= _ARR_SZ(_tagtype_dataunit_bytes)) ? tagtype : 0]; + return _tagtype_dataunit_bytes[((unsigned)tagtype < _ARR_SZ(_tagtype_dataunit_bytes)) ? tagtype : 0]; } diff --git a/src/utils/curves.cpp b/src/utils/curves.cpp index 03b1253bb..b14f19b79 100644 --- a/src/utils/curves.cpp +++ b/src/utils/curves.cpp @@ -37,8 +37,11 @@ void LibRaw::cubic_spline(const int *x_, const int *y_, const int len) } for (i = len - 1; i > 0; i--) { - b[i] = (y[i] - y[i - 1]) / (x[i] - x[i - 1]); - d[i - 1] = x[i] - x[i - 1]; + float _div = x[i] - x[i - 1]; + if (fabs(_div) < 1.0e-15) + _div = 1; + b[i] = (y[i] - y[i - 1]) / _div; + d[i - 1] = _div; } for (i = 1; i < len - 1; i++) { diff --git a/src/utils/open.cpp b/src/utils/open.cpp index 2adca43b5..12b0cb878 100644 --- a/src/utils/open.cpp +++ b/src/utils/open.cpp @@ -482,7 +482,10 @@ int LibRaw::open_datastream(LibRaw_abstract_datastream *stream) // Fuji layout files: either DNG or unpacked_load_raw should be used if (libraw_internal_data.internal_output_params.fuji_width || libraw_internal_data.unpacker_data.fuji_layout) { - if (!imgdata.idata.dng_version && load_raw != &LibRaw::unpacked_load_raw) + if (!imgdata.idata.dng_version && load_raw != &LibRaw::unpacked_load_raw + && load_raw != &LibRaw::unpacked_load_raw_FujiDBP + && load_raw != &LibRaw::unpacked_load_raw_fuji_f700s20 + ) return LIBRAW_FILE_UNSUPPORTED; } @@ -1200,9 +1203,15 @@ int LibRaw::open_datastream(LibRaw_abstract_datastream *stream) { if (C.profile) free(C.profile); - C.profile = malloc(C.profile_length); - ID.input->seek(ID.profile_offset, SEEK_SET); - ID.input->read(C.profile, C.profile_length, 1); + INT64 profile_sz = MIN(INT64(C.profile_length), ID.input->size() - ID.profile_offset); + if (profile_sz > 0LL && profile_sz < LIBRAW_MAX_PROFILE_SIZE_MB * 1024LL * 1024LL) + { + C.profile = malloc(size_t(profile_sz)); + ID.input->seek(ID.profile_offset, SEEK_SET); + ID.input->read(C.profile, size_t(profile_sz), 1); + } + else + C.profile = NULL; } SET_PROC_FLAG(LIBRAW_PROGRESS_IDENTIFY); diff --git a/src/utils/thumb_utils.cpp b/src/utils/thumb_utils.cpp index ffdb80247..b468b0b06 100644 --- a/src/utils/thumb_utils.cpp +++ b/src/utils/thumb_utils.cpp @@ -127,26 +127,36 @@ void LibRaw::kodak_thumb_loader() int(*t_hist)[LIBRAW_HISTOGRAM_SIZE] = (int(*)[LIBRAW_HISTOGRAM_SIZE])calloc(sizeof(*t_hist), 4); - float out[3], out_cam[3][4] = {{2.81761312f, -1.98369181f, 0.166078627f, 0}, - {-0.111855984f, 1.73688626f, -0.625030339f, 0}, - {-0.0379119813f, -0.891268849f, 1.92918086f, 0}}; - - for (img = imgdata.image[0], row = 0; row < S.height; row++) - for (col = 0; col < S.width; col++, img += 4) - { - out[0] = out[1] = out[2] = 0; - int c; - for (c = 0; c < 3; c++) + if (imgdata.idata.maker_index == LIBRAW_CAMERAMAKER_Canon) // Skip color conversion for canon PPM tiffs + { + for (img = imgdata.image[0], row = 0; row < S.height; row++) + for (col = 0; col < S.width; col++, img += 4) + for (int c = 0; c < P1.colors; c++) + t_hist[c][img[c] >> 3]++; + } + else + { + float out[3], out_cam[3][4] = {{2.81761312f, -1.98369181f, 0.166078627f, 0}, + {-0.111855984f, 1.73688626f, -0.625030339f, 0}, + {-0.0379119813f, -0.891268849f, 1.92918086f, 0}}; + + for (img = imgdata.image[0], row = 0; row < S.height; row++) + for (col = 0; col < S.width; col++, img += 4) { - out[0] += out_cam[0][c] * img[c]; - out[1] += out_cam[1][c] * img[c]; - out[2] += out_cam[2][c] * img[c]; + out[0] = out[1] = out[2] = 0; + int c; + for (c = 0; c < 3; c++) + { + out[0] += out_cam[0][c] * img[c]; + out[1] += out_cam[1][c] * img[c]; + out[2] += out_cam[2][c] * img[c]; + } + for (c = 0; c < 3; c++) + img[c] = CLIP((int)out[c]); + for (c = 0; c < P1.colors; c++) + t_hist[c][img[c] >> 3]++; } - for (c = 0; c < 3; c++) - img[c] = CLIP((int)out[c]); - for (c = 0; c < P1.colors; c++) - t_hist[c][img[c] >> 3]++; - } + } // from gamma_lut int(*save_hist)[LIBRAW_HISTOGRAM_SIZE] =