diff --git a/rtdata/options/options.lin b/rtdata/options/options.lin index 1d2f9faac..580390b28 100644 --- a/rtdata/options/options.lin +++ b/rtdata/options/options.lin @@ -12,8 +12,8 @@ MultiUser=true [File Browser] # Image filename extensions to be looked for, and their corresponding search state (0/1 -> skip/include) -ParseExtensions=3fr;arw;arq;cr2;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f; -ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1; +ParseExtensions=3fr;arw;arq;cr2;cr3;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f; +ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1; [Output] PathTemplate=%p1/converted/%f diff --git a/rtdata/options/options.osx b/rtdata/options/options.osx index 11c5da4c8..58e0a5604 100644 --- a/rtdata/options/options.osx +++ b/rtdata/options/options.osx @@ -12,8 +12,8 @@ MultiUser=true [File Browser] # Image filename extensions to be looked for, and their corresponding search state (0/1 -> skip/include) -ParseExtensions=3fr;arw;arq;cr2;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f; -ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1; +ParseExtensions=3fr;arw;arq;cr2;cr3;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f; +ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1; [Output] PathTemplate=%p1/converted/%f diff --git a/rtdata/options/options.win b/rtdata/options/options.win index a4a767bf4..a54e021b1 100644 --- a/rtdata/options/options.win +++ b/rtdata/options/options.win @@ -14,8 +14,8 @@ UseSystemTheme=false [File Browser] # Image filename extensions to be looked for, and their corresponding search state (0/1 -> skip/include) -ParseExtensions=3fr;arw;arq;cr2;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f; -ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1; +ParseExtensions=3fr;arw;arq;cr2;cr3;crf;crw;dcr;dng;fff;iiq;jpg;jpeg;kdc;mef;mos;mrw;nef;nrw;orf;pef;png;raf;raw;rw2;rwl;rwz;sr2;srf;srw;tif;tiff;x3f; +ParseExtensionsEnabled=1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;1;0;1;1;1;1;1;1;1;1;1;1;1; [Output] PathTemplate=%p1/converted/%f diff --git a/rtdata/profiles/Pixel Shift/PS ISO Low.pp3 b/rtdata/profiles/Pixel Shift/PS ISO Low.pp3 index 5587b19e0..286b5a289 100644 --- a/rtdata/profiles/Pixel Shift/PS ISO Low.pp3 +++ b/rtdata/profiles/Pixel Shift/PS ISO Low.pp3 @@ -1,18 +1,8 @@ [Sharpening] -Enabled=true -Contrast=5 -Method=rld -DeconvRadius=0.75 -DeconvAmount=100 -DeconvDamping=0 -DeconvIterations=30 +Enabled=false [SharpenMicro] -Enabled=true -Contrast=15 -Matrix=false -Strength=20 -Uniformity=5 +Enabled=false [RAW] CA=true @@ -38,3 +28,6 @@ pixelShiftBlur=true pixelShiftSmoothFactor=0.69999999999999996 pixelShiftLmmse=false pixelShiftNonGreenCross=true + +[PostDemosaicSharpening] +Enabled=true diff --git a/rtdata/profiles/Pixel Shift/PS No Motion.pp3 b/rtdata/profiles/Pixel Shift/PS No Motion.pp3 index f1d889f97..0975251e2 100644 --- a/rtdata/profiles/Pixel Shift/PS No Motion.pp3 +++ b/rtdata/profiles/Pixel Shift/PS No Motion.pp3 @@ -1,18 +1,8 @@ [Sharpening] -Enabled=true -Contrast=5 -Method=rld -DeconvRadius=0.75 -DeconvAmount=100 -DeconvDamping=0 -DeconvIterations=30 +Enabled=false [SharpenMicro] -Enabled=true -Contrast=15 -Matrix=false -Strength=20 -Uniformity=5 +Enabled=false [RAW] CA=true @@ -22,3 +12,6 @@ Method=pixelshift PixelShiftMotion=0 PixelShiftMotionCorrection=5 PixelShiftMotionCorrectionMethod=0 + +[PostDemosaicSharpening] +Enabled=true diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index c37341c8b..f58afde5e 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -34,6 +34,7 @@ set(RTENGINESOURCEFILES amaze_demosaic_RT.cc badpixels.cc boxblur.cc + canon_cr3_decoder.cc CA_correct_RT.cc calc_distort.cc camconst.cc diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index ea0565b21..121c8189d 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -1599,9 +1599,9 @@ BENCHFUN Color::Lab2RGBLimit(labdn->L[i1], labdn->a[i1], labdn->b[i1], labdn->L[i1], labdn->a[i1], labdn->b[i1], wip, 9000000.f, 1.f + qhighFactor * realred, 1.f + qhighFactor * realblue, width); for (int j = tileleft; j < tileright; ++j) { int j1 = j - tileleft; - float r_ = labdn->L[i1][j1]; - float g_ = labdn->a[i1][j1]; - float b_ = labdn->b[i1][j1]; + float r_ = std::max(0.f, labdn->L[i1][j1]); + float g_ = std::max(0.f, labdn->a[i1][j1]); + float b_ = std::max(0.f, labdn->b[i1][j1]); //inverse gamma standard (slider) r_ = r_ < 32768.f ? igamcurve[r_] : (Color::gammanf(r_ / 32768.f, igam) * 65535.f); g_ = g_ < 32768.f ? igamcurve[g_] : (Color::gammanf(g_ / 32768.f, igam) * 65535.f); diff --git a/rtengine/badpixels.cc b/rtengine/badpixels.cc index 2710cb28d..0ae63a618 100644 --- a/rtengine/badpixels.cc +++ b/rtengine/badpixels.cc @@ -22,12 +22,39 @@ #include "pixelsmap.h" #include "rawimage.h" #include "rawimagesource.h" +//#define BENCHMARK +#include "StopWatch.h" namespace { unsigned fc(const unsigned int cfa[2][2], int r, int c) { return cfa[r & 1][c & 1]; } + +inline void sum5x5(const array2D& in, int col, float &sum) { +#ifdef __SSE2__ + // sum up 5*4 = 20 values using SSE + // 10 fabs function calls and 10 float additions with SSE + const vfloat sumv = (vabsf(LVFU(in[0][col])) + vabsf(LVFU(in[1][col]))) + + (vabsf(LVFU(in[2][col])) + vabsf(LVFU(in[3][col]))) + + vabsf(LVFU(in[4][col])); + // horizontally add the values and add the result to hfnbrave + sum += vhadd(sumv); + + // add remaining 5 values of last column + sum += (fabsf(in[0][col + 4]) + fabsf(in[1][col + 4])) + + (fabsf(in[2][col + 4]) + fabsf(in[3][col + 4])) + + fabsf(in[4][col + 4]); +#else + // 25 fabs function calls and 25 float additions without SSE + for (int nn = col; nn < col + 5; ++nn) { + sum += (fabsf(in[0][nn]) + fabsf(in[1][nn])) + + (fabsf(in[2][nn]) + fabsf(in[3][nn])) + + fabsf(in[4][nn]); + } +#endif + +} } namespace rtengine @@ -445,126 +472,124 @@ int RawImageSource::interpolateBadPixelsXtrans(const PixelsMap &bitmapBads) /* Search for hot or dead pixels in the image and update the map * For each pixel compare its value to the average of similar color surrounding * (Taken from Emil Martinec idea) - * (Optimized by Ingo Weyrich 2013 and 2015) - */ + * (Optimized by Ingo Weyrich 2013, 2015, and 2019) +*/ int RawImageSource::findHotDeadPixels(PixelsMap &bpMap, const float thresh, const bool findHotPixels, const bool findDeadPixels) const { + BENCHFUN const float varthresh = (20.0 * (thresh / 100.0) + 1.0) / 24.f; - // allocate temporary buffer - float* cfablur = new float[H * W]; - // counter for dead or hot pixels int counter = 0; #ifdef _OPENMP - #pragma omp parallel + #pragma omp parallel reduction(+:counter) #endif { + array2D cfablur(W, 5, ARRAY2D_CLEAR_DATA); + int firstRow = -1; + int lastRow = -1; + #ifdef _OPENMP - #pragma omp for schedule(dynamic,16) nowait + // note, static scheduling is important in this implementation + #pragma omp for schedule(static) nowait #endif - for (int i = 2; i < H - 2; i++) { - for (int j = 2; j < W - 2; j++) { + for (int i = 2; i < H - 2; ++i) { + if (firstRow == -1) { + firstRow = i; + if (firstRow > 2) { + for (int row = firstRow - 2; row < firstRow; ++row) { + const int destRow = row % 5; + for (int j = 2; j < W - 2; ++j) { + const float temp = median(rawData[row - 2][j - 2], rawData[row - 2][j], rawData[row - 2][j + 2], + rawData[row][j - 2], rawData[row][j], rawData[row][j + 2], + rawData[row + 2][j - 2], rawData[row + 2][j], rawData[row + 2][j + 2]); + cfablur[destRow][j] = rawData[row][j] - temp; + } + } + } + } + lastRow = i; + const int destRow = i % 5; + for (int j = 2; j < W - 2; ++j) { const float temp = median(rawData[i - 2][j - 2], rawData[i - 2][j], rawData[i - 2][j + 2], rawData[i][j - 2], rawData[i][j], rawData[i][j + 2], rawData[i + 2][j - 2], rawData[i + 2][j], rawData[i + 2][j + 2]); - cfablur[i * W + j] = rawData[i][j] - temp; + cfablur[destRow][j] = rawData[i][j] - temp; + } + + if (i - 1 > firstRow) { + const int rr = i - 2; + const int rr0 = rr % 5; + for (int cc = 2; cc < W - 2; ++cc) { + //evaluate pixel for heat/death + float pixdev = cfablur[rr0][cc]; + + if (!findDeadPixels && pixdev <= 0.f) { + continue; + } + + if (!findHotPixels && pixdev >= 0.f) { + continue; + } + + pixdev = fabsf(pixdev); + float hfnbrave = -pixdev; + sum5x5(cfablur, cc - 2, hfnbrave); + if (pixdev > varthresh * hfnbrave) { + // mark the pixel as "bad" + bpMap.set(cc, rr); + ++counter; + } + } //end of pixel evaluation } } - // process borders. Former version calculated the median using mirrored border which does not make sense because the original pixel loses weight - // Setting the difference between pixel and median for border pixels to zero should do the job not worse then former version -#ifdef _OPENMP - #pragma omp single -#endif - { - for (int i = 0; i < 2; ++i) { - for (int j = 0; j < W; ++j) { - cfablur[i * W + j] = 0.f; - } - } - - for (int i = 2; i < H - 2; ++i) { - for (int j = 0; j < 2; ++j) { - cfablur[i * W + j] = 0.f; - } - - for (int j = W - 2; j < W; ++j) { - cfablur[i * W + j] = 0.f; - } - } - - for (int i = H - 2; i < H; ++i) { - for (int j = 0; j < W; ++j) { - cfablur[i * W + j] = 0.f; - } - } - } - -#ifdef _OPENMP - #pragma omp barrier // barrier because of nowait clause above - - #pragma omp for reduction(+:counter) schedule(dynamic,16) -#endif - - //cfa pixel heat/death evaluation - for (int rr = 2; rr < H - 2; ++rr) { - for (int cc = 2, rrmWpcc = rr * W + 2; cc < W - 2; ++cc, ++rrmWpcc) { - //evaluate pixel for heat/death - float pixdev = cfablur[rrmWpcc]; - - if (pixdev == 0.f) { - continue; - } - - if ((!findDeadPixels) && pixdev < 0) { - continue; - } - - if ((!findHotPixels) && pixdev > 0) { - continue; - } - - pixdev = fabsf(pixdev); - float hfnbrave = -pixdev; - -#ifdef __SSE2__ - // sum up 5*4 = 20 values using SSE - // 10 fabs function calls and 10 float additions with SSE - vfloat sum = vabsf(LVFU(cfablur[(rr - 2) * W + cc - 2])) + vabsf(LVFU(cfablur[(rr - 1) * W + cc - 2])); - sum += vabsf(LVFU(cfablur[(rr) * W + cc - 2])); - sum += vabsf(LVFU(cfablur[(rr + 1) * W + cc - 2])); - sum += vabsf(LVFU(cfablur[(rr + 2) * W + cc - 2])); - // horizontally add the values and add the result to hfnbrave - hfnbrave += vhadd(sum); - - // add remaining 5 values of last column - for (int mm = rr - 2; mm <= rr + 2; ++mm) { - hfnbrave += fabsf(cfablur[mm * W + cc + 2]); - } - -#else - - // 25 fabs function calls and 25 float additions without SSE - for (int mm = rr - 2; mm <= rr + 2; ++mm) { - for (int nn = cc - 2; nn <= cc + 2; ++nn) { - hfnbrave += fabsf(cfablur[mm * W + nn]); + if (lastRow > 0 && lastRow < H - 2) { + //cfa pixel heat/death evaluation + for (int rr = lastRow - 1; rr < lastRow + 1; ++rr) { + const int i = rr + 2; + const int destRow = i % 5; + if (i >= H - 2) { + for (int j = 2; j < W - 2; j++) { + cfablur[destRow][j] = 0.f; + } + } else { + for (int j = 2; j < W - 2; ++j) { + const float temp = median(rawData[i - 2][j - 2], rawData[i - 2][j], rawData[i - 2][j + 2], + rawData[i][j - 2], rawData[i][j], rawData[i][j + 2], + rawData[i + 2][j - 2], rawData[i + 2][j], rawData[i + 2][j + 2]); + cfablur[destRow][j] = rawData[i][j] - temp; } } -#endif + const int rr0 = rr % 5; + for (int cc = 2; cc < W - 2; ++cc) { + //evaluate pixel for heat/death + float pixdev = cfablur[rr0][cc]; - if (pixdev > varthresh * hfnbrave) { - // mark the pixel as "bad" - bpMap.set(cc, rr); - counter++; - } - }//end of pixel evaluation + if (!findDeadPixels && pixdev <= 0.f) { + continue; + } + + if (!findHotPixels && pixdev >= 0.f) { + continue; + } + + pixdev = fabsf(pixdev); + float hfnbrave = -pixdev; + sum5x5(cfablur, cc - 2, hfnbrave); + if (pixdev > varthresh * hfnbrave) { + // mark the pixel as "bad" + bpMap.set(cc, rr); + ++counter; + } + }//end of pixel evaluation + } } }//end of parallel processing - delete [] cfablur; + return counter; } diff --git a/rtengine/boxblur.cc b/rtengine/boxblur.cc index 491ffae14..045c7ac3f 100644 --- a/rtengine/boxblur.cc +++ b/rtengine/boxblur.cc @@ -33,6 +33,7 @@ void boxblur(float** src, float** dst, int radius, int W, int H, bool multiThrea { //box blur using rowbuffers and linebuffers instead of a full size buffer + radius = rtengine::min(radius, W - 1, H - 1); if (radius == 0) { if (src != dst) { #ifdef _OPENMP diff --git a/rtengine/cJSON.c b/rtengine/cJSON.c index fb8ce27e8..130c8e2a5 100644 --- a/rtengine/cJSON.c +++ b/rtengine/cJSON.c @@ -445,9 +445,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) p->buffer = NULL; return NULL; - } - if (newbuffer) - { + } else { memcpy(newbuffer, p->buffer, p->offset + 1); } p->hooks.deallocate(p->buffer); @@ -1436,7 +1434,7 @@ fail: static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) { unsigned char *output_pointer = NULL; - size_t length = 0; + size_t length; cJSON *current_element = item->child; if (output_buffer == NULL) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index f2db455a3..c0d833db7 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1138,6 +1138,16 @@ Camera constants: } }, + { // Quality C, only raw crop + "make_model": [ "Canon EOS M6 Mark II", "Canon EOS 90D" ], + "raw_crop": [ 144, 72, 6984, 4660 ] + }, + + { // Quality C, only raw crop + "make_model": [ "Canon EOS R" ], + "raw_crop": [ 144, 46, 6744, 4500 ] + }, + // Canon Powershot { // Quality C, CHDK DNGs, raw frame correction "make_model": "Canon PowerShot A3100 IS", @@ -2506,7 +2516,7 @@ Camera constants: { // Quality C, "make_model": "Sony ILCE-7RM4", - "raw_crop": [ 0, 0, 9568, 0 ] // full raw frame 9600x6376 - 32 rightmost columns are garbage + "raw_crop": [ 0, 0, -32, 0 ] // full raw frame 9600x6376 - 32 rightmost columns are garbage. Using -32 instead of 9568 to support also 16-shot pixelshift files }, { // Quality B, color matrix copied from a7rm2 diff --git a/rtengine/canon_cr3_decoder.cc b/rtengine/canon_cr3_decoder.cc new file mode 100644 index 000000000..359243ed5 --- /dev/null +++ b/rtengine/canon_cr3_decoder.cc @@ -0,0 +1,3116 @@ +/* -*- C++ -*- + * + * This file is part of ART. + * + * ART 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. + * + * ART 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 ART. If not, see . +*/ + +#include +#include "dcraw.h" +#ifdef __GNUC__ // silence warning +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wunused-variable" +#pragma GCC diagnostic ignored "-Wunused-but-set-variable" +#endif + +// Code adapted from libraw +/* -*- C++ -*- + * Copyright 2019 LibRaw LLC (info@libraw.org) + * + LibRaw is free software; you can redistribute it and/or modify + it under the terms of the one of two licenses as you choose: + +1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1 + (See file LICENSE.LGPL provided in LibRaw distribution archive for details). + +2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0 + (See file LICENSE.CDDL provided in LibRaw distribution archive for details). + +*/ + + +void DCraw::parse_canon_cr3() +{ + int err; + unsigned long long szAtomList; + short nesting = -1; + short nTrack = -1; + short TrackType; + char AtomNameStack[128]; + strcpy(make, "Canon"); + + szAtomList = ifp->size; + err = parseCR3(0ULL, szAtomList, nesting, AtomNameStack, nTrack, TrackType); + if ((err == 0 || err == -14) && + nTrack >= 0) // no error, or too deep nesting + selectCRXTrack(nTrack); +} + +#define LIBRAW_CRXTRACKS_MAXCOUNT RT_canon_CR3_data.CRXTRACKS_MAXCOUNT + +void DCraw::selectCRXTrack(short maxTrack) +{ + if (maxTrack < 0) + return; + INT64 bitcounts[LIBRAW_CRXTRACKS_MAXCOUNT], maxbitcount = 0; + uint32_t maxjpegbytes = 0; + memset(bitcounts, 0, sizeof(bitcounts)); + for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++) + { + CanonCR3Data::crx_data_header_t *d = &RT_canon_CR3_data.crx_header[i]; + if (d->MediaType == 1) // RAW + { + bitcounts[i] = INT64(d->nBits) * INT64(d->f_width) * INT64(d->f_height); + if (bitcounts[i] > maxbitcount) + maxbitcount = bitcounts[i]; + } + else if (d->MediaType == 2) // JPEG + { + if (d->MediaSize > maxjpegbytes) + { + maxjpegbytes = d->MediaSize; + thumb_offset = d->MediaOffset; + thumb_length = d->MediaSize; + } + } + } + if (maxbitcount < 8) + return; + int framei = -1, framecnt = 0; + for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++) + { + if (bitcounts[i] == maxbitcount) + { + if (framecnt <= shot_select) + framei = i; + framecnt++; + } + } + is_raw = framecnt; + if (framei >= 0 && framei < LIBRAW_CRXTRACKS_MAXCOUNT) + { + CanonCR3Data::crx_data_header_t *d = + &RT_canon_CR3_data.crx_header[framei]; + data_offset = d->MediaOffset; + //data_size = d->MediaSize; + raw_width = d->f_width; + raw_height = d->f_height; + load_raw = &DCraw::crxLoadRaw; + switch (d->cfaLayout) + { + case 0: + filters = 0x94949494; + break; + case 1: + filters = 0x61616161; + break; + case 2: + filters = 0x49494949; + break; + case 3: + filters = 0x16161616; + break; + } + + RT_canon_CR3_data.crx_track_selected = framei; + + int tiff_idx = -1; + INT64 tpixels = 0; + for (int i = 0; i < tiff_nifds; i++) + if (INT64(tiff_ifd[i].height) * INT64(tiff_ifd[i].height) > tpixels) + { + tpixels = INT64(tiff_ifd[i].height) * INT64(tiff_ifd[i].height); + tiff_idx = i; + } + if (tiff_idx >= 0) + flip = tiff_ifd[tiff_idx].flip; + } +} + +#define FORC4 for (c=0; c < 4; c++) + +#define bad_hdr \ + (((order != 0x4d4d) && (order != 0x4949)) || (get2() != 0x002a) || \ + (get4() != 0x00000008)) +int DCraw::parseCR3(unsigned long long oAtomList, + unsigned long long szAtomList, short &nesting, + char *AtomNameStack, short &nTrack, short &TrackType) +{ + /* + Atom starts with 4 bytes for Atom size and 4 bytes containing Atom name + Atom size includes the length of the header and the size of all "contained" + Atoms if Atom size == 1, Atom has the extended size stored in 8 bytes located + after the Atom name if Atom size == 0, it is the last top-level Atom extending + to the end of the file Atom name is often a 4 symbol mnemonic, but can be a + 4-byte integer + */ + const char UIID_Canon[17] = + "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48"; + const char UIID_Preview[17] = + "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16"; + + /* + AtomType = 0 - unknown: "unk." + AtomType = 1 - container atom: "cont" + AtomType = 2 - leaf atom: "leaf" + AtomType = 3 - can be container, can be leaf: "both" + */ + const char sAtomeType[4][5] = {"unk.", "cont", "leaf", "both"}; + short AtomType; + static const struct + { + char AtomName[5]; + short AtomType; + } AtomNamesList[] = { + {"dinf", 1}, + {"edts", 1}, + {"fiin", 1}, + {"ipro", 1}, + {"iprp", 1}, + {"mdia", 1}, + {"meco", 1}, + {"mere", 1}, + {"mfra", 1}, + {"minf", 1}, + {"moof", 1}, + {"moov", 1}, + {"mvex", 1}, + {"paen", 1}, + {"schi", 1}, + {"sinf", 1}, + {"skip", 1}, + {"stbl", 1}, + {"stsd", 1}, + {"strk", 1}, + {"tapt", 1}, + {"traf", 1}, + {"trak", 1}, + + {"cdsc", 2}, + {"colr", 2}, + {"dimg", 2}, + // {"dref", 2}, + {"free", 2}, + {"frma", 2}, + {"ftyp", 2}, + {"hdlr", 2}, + {"hvcC", 2}, + {"iinf", 2}, + {"iloc", 2}, + {"infe", 2}, + {"ipco", 2}, + {"ipma", 2}, + {"iref", 2}, + {"irot", 2}, + {"ispe", 2}, + {"meta", 2}, + {"mvhd", 2}, + {"pitm", 2}, + {"pixi", 2}, + {"schm", 2}, + {"thmb", 2}, + {"tkhd", 2}, + {"url ", 2}, + {"urn ", 2}, + + {"CCTP", 1}, + {"CRAW", 1}, + + {"JPEG", 2}, + {"CDI1", 2}, + {"CMP1", 2}, + + {"CNCV", 2}, + {"CCDT", 2}, + {"CTBO", 2}, + {"CMT1", 2}, + {"CMT2", 2}, + {"CMT3", 2}, + {"CMT4", 2}, + {"THMB", 2}, + {"co64", 2}, + {"mdat", 2}, + {"mdhd", 2}, + {"nmhd", 2}, + {"stsc", 2}, + {"stsz", 2}, + {"stts", 2}, + {"vmhd", 2}, + + {"dref", 3}, + {"uuid", 3}, + }; + + const char sHandlerType[5][5] = {"unk.", "soun", "vide", "hint", "meta"}; + + int c, err = 0; + + ushort tL; // Atom length represented in 4 or 8 bytes + char nmAtom[5]; // Atom name + unsigned long long oAtom, szAtom; // Atom offset and Atom size + unsigned long long oAtomContent, + szAtomContent; // offset and size of Atom content + unsigned long long lHdr; + + char UIID[16]; + uchar CMP1[36]; + char HandlerType[5], MediaFormatID[5]; + unsigned ImageWidth, ImageHeight; + long relpos_inDir, relpos_inBox; + unsigned szItem, Tag, lTag; + ushort tItem; + + nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0'; + strcpy(HandlerType, sHandlerType[0]); + ImageWidth = ImageHeight = 0U; + oAtom = oAtomList; + nesting++; + if (nesting > 31) + return -14; // too deep nesting + short s_order = order; + + while ((oAtom + 8ULL) <= (oAtomList + szAtomList)) + { + lHdr = 0ULL; + err = 0; + order = 0x4d4d; + fseek(ifp, oAtom, SEEK_SET); + szAtom = get4(); + FORC4 nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp); + AtomNameStack[(nesting + 1) * 4] = '\0'; + tL = 4; + AtomType = 0; + + for (c = 0; c < sizeof AtomNamesList / sizeof *AtomNamesList; c++) + if (!strcmp(nmAtom, AtomNamesList[c].AtomName)) + { + AtomType = AtomNamesList[c].AtomType; + break; + } + + if (!AtomType) + { + err = 1; + } + + if (szAtom == 0ULL) + { + if (nesting != 0) + { + err = -2; + goto fin; + } + szAtom = szAtomList - oAtom; + oAtomContent = oAtom + 8ULL; + szAtomContent = szAtom - 8ULL; + } + else if (szAtom == 1ULL) + { + if ((oAtom + 16ULL) > (oAtomList + szAtomList)) + { + err = -3; + goto fin; + } + tL = 8; + szAtom = (((unsigned long long)get4()) << 32) | get4(); + oAtomContent = oAtom + 16ULL; + szAtomContent = szAtom - 16ULL; + } + else + { + oAtomContent = oAtom + 8ULL; + szAtomContent = szAtom - 8ULL; + } + + if (!strcmp(nmAtom, "trak")) + { + nTrack++; + TrackType = 0; + if (nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT) + break; + } + if (!strcmp(AtomNameStack, "moovuuid")) + { + lHdr = 16ULL; + fread(UIID, 1, lHdr, ifp); + if (!strncmp(UIID, UIID_Canon, lHdr)) + { + AtomType = 1; + } + else + fseek(ifp, -lHdr, SEEK_CUR); + } + else if (!strcmp(AtomNameStack, "moovuuidCCTP")) + { + lHdr = 12ULL; + } + else if (!strcmp(AtomNameStack, "moovuuidCMT1")) + { + short q_order = order; + order = get2(); + if ((tL != 4) || bad_hdr) + { + err = -4; + goto fin; + } + parse_tiff_ifd(oAtomContent); + order = q_order; + } + else if (!strcmp(AtomNameStack, "moovuuidCMT2")) + { + short q_order = order; + order = get2(); + if ((tL != 4) || bad_hdr) + { + err = -5; + goto fin; + } + parse_exif(oAtomContent); + order = q_order; + } + else if (!strcmp(AtomNameStack, "moovuuidCMT3")) + { + short q_order = order; + order = get2(); + if ((tL != 4) || bad_hdr) + { + err = -6; + goto fin; + } + fseek(ifp, -12L, SEEK_CUR); + parse_makernote(oAtomContent, 0); + order = q_order; + } + else if (!strcmp(AtomNameStack, "moovuuidCMT4")) + { + short q_order = order; + order = get2(); + if ((tL != 4) || bad_hdr) + { + err = -6; + goto fin; + } + INT64 off = ftell(ifp); + parse_gps(oAtomContent); + fseek(ifp, off, SEEK_SET); +// parse_gps_libraw(oAtomContent); + order = q_order; + } + else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr")) + { + fseek(ifp, 8L, SEEK_CUR); + FORC4 HandlerType[c] = fgetc(ifp); + for (c = 1; c < sizeof sHandlerType / sizeof *sHandlerType; c++) + if (!strcmp(HandlerType, sHandlerType[c])) + { + TrackType = c; + break; + } + } + else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd")) + { + if (szAtomContent >= 16) + { + fseek(ifp, 12L, SEEK_CUR); + lHdr = 8; + } + else + { + err = -7; + goto fin; + } + FORC4 MediaFormatID[c] = fgetc(ifp); + if ((TrackType == 2) && (!strcmp(MediaFormatID, "CRAW"))) + { + if (szAtomContent >= 44) + fseek(ifp, 24L, SEEK_CUR); + else + { + err = -8; + goto fin; + } + } + else + { + AtomType = 2; // only continue for CRAW + lHdr = 0; + } +#define current_track RT_canon_CR3_data.crx_header[nTrack] + + ImageWidth = get2(); + ImageHeight = get2(); + } + else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW")) + { + lHdr = 82; + } + else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCMP1")) + { + if (szAtomContent >= 40) + fread(CMP1, 1, 36, ifp); + else + { + err = -7; + goto fin; + } + if (!crxParseImageHeader(CMP1, nTrack)) + current_track.MediaType = 1; + } + else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG")) + { + current_track.MediaType = 2; + } + else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz")) + { + if (szAtomContent == 12) + fseek(ifp, 4L, SEEK_CUR); + else if (szAtomContent == 16) + fseek(ifp, 12L, SEEK_CUR); + else + { + err = -9; + goto fin; + } + current_track.MediaSize = get4(); + } + else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64")) + { + if (szAtomContent == 16) + fseek(ifp, 8L, SEEK_CUR); + else + { + err = -10; + goto fin; + } + current_track.MediaOffset = (((unsigned long long)get4()) << 32) | get4(); + } + + if (current_track.MediaSize && current_track.MediaOffset && + ((oAtom + szAtom) >= (oAtomList + szAtomList)) && + !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20)) + { + if ((TrackType == 4) && (!strcmp(MediaFormatID, "CTMD"))) + { + order = 0x4949; + relpos_inDir = 0L; + while (relpos_inDir + 6 < current_track.MediaSize) + { + fseek(ifp, current_track.MediaOffset + relpos_inDir, SEEK_SET); + szItem = get4(); + tItem = get2(); + if ((relpos_inDir + szItem) > current_track.MediaSize) + { + err = -11; + goto fin; + } + if ((tItem == 7) || (tItem == 8) || (tItem == 9)) + { + relpos_inBox = relpos_inDir + 12L; + while (relpos_inBox + 8 < relpos_inDir + szItem) + { + fseek(ifp, current_track.MediaOffset + relpos_inBox, SEEK_SET); + lTag = get4(); + Tag = get4(); + if (lTag < 8) + { + err = -12; + goto fin; + } + else if ((relpos_inBox + lTag) > (relpos_inDir + szItem)) + { + err = -11; + goto fin; + } + if ((Tag == 0x927c) && ((tItem == 7) || (tItem == 8))) + { + fseek(ifp, current_track.MediaOffset + relpos_inBox + 8L, + SEEK_SET); + short q_order = order; + order = get2(); + if (bad_hdr) + { + err = -13; + goto fin; + } + fseek(ifp, -8L, SEEK_CUR); + RT_canon_CR3_data.CR3_CTMDtag = 1; + parse_makernote(current_track.MediaOffset + relpos_inBox + 8, + 0); + RT_canon_CR3_data.CR3_CTMDtag = 0; + order = q_order; + } + relpos_inBox += lTag; + } + } + relpos_inDir += szItem; + } + order = 0x4d4d; + } + } +#undef current_track + if (AtomType == 1) + { + err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting, + AtomNameStack, nTrack, TrackType); + if (err) + goto fin; + } + oAtom += szAtom; + } + +fin: + nesting--; + if (nesting >= 0) + AtomNameStack[nesting * 4] = '\0'; + order = s_order; + return err; +} +#undef bad_hdr + + +//----------------------------------------------------------------------------- + +#ifdef _abs +#undef _abs +#undef _min +#undef _constrain +#endif +#define _abs(x) (((x) ^ ((int32_t)(x) >> 31)) - ((int32_t)(x) >> 31)) +#define _min(a, b) ((a) < (b) ? (a) : (b)) +#define _constrain(x, l, u) ((x) < (l) ? (l) : ((x) > (u) ? (u) : (x))) + +#if defined(__clang__) || defined(__GNUG__) +#define libraw_inline inline __attribute__((always_inline)) +#elif defined(_MSC_VER) && _MSC_VER > 1400 +#define libraw_inline __forceinline +#else +#define libraw_inline inline +#endif + +namespace { + +static unsigned sgetn (int n, unsigned char *s) +{ + unsigned result = 0; + + while (n-- > 0) { + result = (result << 8) | (*s++); + } + + return result; +} + +// this should be divisible by 4 +#define CRX_BUF_SIZE 0x10000 +#if !defined(_WIN32) || (defined (__GNUC__) && !defined(__INTRINSIC_SPECIAL__BitScanReverse)) +/* __INTRINSIC_SPECIAL__BitScanReverse found in MinGW32-W64 v7.30 headers, may be there is a better solution? */ +typedef uint32_t DWORD; +typedef uint8_t byte; +libraw_inline void _BitScanReverse(DWORD *Index, unsigned long Mask) +{ + *Index = sizeof(unsigned long) * 8 - 1 - __builtin_clzl(Mask); +} +#define _byteswap_ulong(x) __builtin_bswap32(x) +#endif + + +#define LIBRAW_EXCEPTION_IO_EOF std::exception() + +struct LibRaw_abstract_datastream { + IMFILE *ifp; + + void lock() {} + void unlock() {} + void seek(int p, int how) { fseek(ifp, p, how); } + int read(void* dst, int es, int count) + { return fread(dst, es, count, ifp); } +}; + +struct CrxBitstream +{ + uint8_t mdatBuf[CRX_BUF_SIZE]; + uint64_t mdatSize; + uint64_t curBufOffset; + uint32_t curPos; + uint32_t curBufSize; + uint32_t bitData; + int32_t bitsLeft; + LibRaw_abstract_datastream *input; +}; + +struct CrxBandParam +{ + CrxBitstream bitStream; + int16_t subbandWidth; + int16_t subbandHeight; + int32_t roundedBitsMask; + int32_t roundedBits; + int16_t curLine; + int32_t *lineBuf0; + int32_t *lineBuf1; + int32_t *lineBuf2; + int32_t sParam; + int32_t kParam; + int32_t *paramData; + int32_t *nonProgrData; + int8_t supportsPartial; +}; + +struct CrxWaveletTransform +{ + int32_t *subband0Buf; + int32_t *subband1Buf; + int32_t *subband2Buf; + int32_t *subband3Buf; + int32_t *lineBuf[8]; + int16_t curLine; + int16_t curH; + int8_t fltTapH; + int16_t height; + int16_t width; +}; + +struct CrxSubband +{ + CrxBandParam *bandParam; + uint64_t mdatOffset; + uint8_t *bandBuf; + int32_t bandSize; + uint64_t dataSize; + int8_t supportsPartial; + int32_t quantValue; + uint16_t width; + uint16_t height; + int32_t paramK; + int64_t dataOffset; +}; + +struct CrxPlaneComp +{ + byte *compBuf; + CrxSubband *subBands; + CrxWaveletTransform *waveletTransform; + int8_t compNumber; + int64_t dataOffset; + int32_t compSize; + int8_t supportsPartial; + int32_t roundedBitsMask; + int8_t tileFlag; +}; + +struct CrxTile +{ + CrxPlaneComp *comps; + int8_t tileFlag; + int8_t tileNumber; + int64_t dataOffset; + int32_t tileSize; + uint16_t width; + uint16_t height; +}; + +struct CrxImage +{ + uint8_t nPlanes; + uint16_t planeWidth; + uint16_t planeHeight; + uint8_t samplePrecision; + uint8_t subbandCount; + uint8_t levels; + uint8_t nBits; + uint8_t encType; + uint8_t tileCols; + uint8_t tileRows; + CrxTile *tiles; + uint64_t mdatOffset; + uint64_t mdatSize; + int16_t *outBufs[4]; // one per plane + int16_t *planeBuf; + LibRaw_abstract_datastream *input; +}; + +enum TileFlags +{ + E_HAS_TILES_ON_THE_RIGHT = 1, + E_HAS_TILES_ON_THE_LEFT = 2, + E_HAS_TILES_ON_THE_BOTTOM = 4, + E_HAS_TILES_ON_THE_TOP = 8 +}; + +int32_t exCoefNumTbl[0x120] = { + // level 1 + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + // level 2 + 1, 1, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 3, 2, 1, 0, 1, 0, 0, 0, 0, 0, 1, + 2, 4, 4, 2, 1, 2, 1, 0, 0, 0, 0, 1, 1, 4, 3, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 3, 2, 1, 0, 1, 0, 0, 0, 0, 0, 1, 2, 4, + 4, 2, 1, 2, 1, 0, 0, 0, 0, 1, 1, 4, 3, 1, 1, 1, 1, 0, 0, 0, 0, + + // level 3 + 1, 1, 7, 7, 1, 1, 3, 3, 1, 1, 1, 1, 1, 0, 7, 6, 1, 0, 3, 2, 1, 0, 1, 0, 1, + 2, 10, 10, 2, 2, 5, 4, 2, 1, 2, 1, 1, 1, 10, 9, 1, 2, 4, 4, 2, 1, 2, 1, 1, + 1, 9, 9, 1, 2, 4, 4, 2, 1, 2, 1, 1, 0, 9, 8, 1, 1, 4, 3, 1, 1, 1, 1, 1, 2, + 8, 8, 2, 1, 4, 3, 1, 1, 1, 1, 1, 1, 8, 7, 1, 1, 3, 3, 1, 1, 1, 1}; + +uint32_t JS[32] = {1, 1, 1, 1, 2, 2, 2, 2, + 4, 4, 4, 4, 8, 8, 8, 8, + 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, + 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000}; + +uint32_t J[32] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, + 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 9, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; + +static inline void crxFillBuffer(CrxBitstream *bitStrm) +{ + if (bitStrm->curPos >= bitStrm->curBufSize && bitStrm->mdatSize) + { + bitStrm->curPos = 0; + bitStrm->curBufOffset += bitStrm->curBufSize; +#ifdef _OPENMP +#pragma omp critical +#endif + { +#ifndef _OPENMP + bitStrm->input->lock(); +#endif + bitStrm->input->seek(bitStrm->curBufOffset, SEEK_SET); + bitStrm->curBufSize = bitStrm->input->read( + bitStrm->mdatBuf, 1, _min(bitStrm->mdatSize, CRX_BUF_SIZE)); +#ifndef _OPENMP + bitStrm->input->unlock(); +#endif + if (bitStrm->curBufSize < 1) // nothing read + throw LIBRAW_EXCEPTION_IO_EOF; + bitStrm->mdatSize -= bitStrm->curBufSize; + } + } +} + +libraw_inline int crxBitstreamGetZeros(CrxBitstream *bitStrm) +{ + uint32_t bitData = bitStrm->bitData; + uint32_t nonZeroBit = 0; + uint64_t nextData = 0; + int32_t result = 0; + + if (bitStrm->bitData) + { + _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)bitStrm->bitData); + result = 31 - nonZeroBit; + bitStrm->bitData <<= 32 - nonZeroBit; + bitStrm->bitsLeft -= 32 - nonZeroBit; + } + else + { + uint32_t bitsLeft = bitStrm->bitsLeft; + while (1) + { + while (bitStrm->curPos + 4 <= bitStrm->curBufSize) + { + nextData = + _byteswap_ulong(*(uint32_t *)(bitStrm->mdatBuf + bitStrm->curPos)); + bitStrm->curPos += 4; + crxFillBuffer(bitStrm); + if (nextData) + { + _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)nextData); + result = bitsLeft + 31 - nonZeroBit; + bitStrm->bitData = nextData << (32 - nonZeroBit); + bitStrm->bitsLeft = nonZeroBit; + return result; + } + bitsLeft += 32; + } + if (bitStrm->curBufSize < bitStrm->curPos + 1) + break; // error + nextData = bitStrm->mdatBuf[bitStrm->curPos++]; + crxFillBuffer(bitStrm); + if (nextData) + break; + bitsLeft += 8; + } + _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)nextData); + result = (uint32_t)(bitsLeft + 7 - nonZeroBit); + bitStrm->bitData = nextData << (32 - nonZeroBit); + bitStrm->bitsLeft = nonZeroBit; + } + return result; +} + +libraw_inline uint32_t crxBitstreamGetBits(CrxBitstream *bitStrm, int bits) +{ + int bitsLeft = bitStrm->bitsLeft; + uint32_t bitData = bitStrm->bitData; + uint32_t nextWord; + uint8_t nextByte; + uint32_t result; + + if (bitsLeft < bits) + { + // get them from stream + if (bitStrm->curPos + 4 <= bitStrm->curBufSize) + { + nextWord = + _byteswap_ulong(*(uint32_t *)(bitStrm->mdatBuf + bitStrm->curPos)); + bitStrm->curPos += 4; + crxFillBuffer(bitStrm); + bitStrm->bitsLeft = 32 - (bits - bitsLeft); + result = ((nextWord >> bitsLeft) | bitData) >> (32 - bits); + bitStrm->bitData = nextWord << (bits - bitsLeft); + return result; + } + // less than a word left - read byte at a time + do + { + if (bitStrm->curPos >= bitStrm->curBufSize) + break; // error + bitsLeft += 8; + nextByte = bitStrm->mdatBuf[bitStrm->curPos++]; + crxFillBuffer(bitStrm); + bitData |= nextByte << (32 - bitsLeft); + } while (bitsLeft < bits); + } + result = bitData >> (32 - bits); // 32-bits + bitStrm->bitData = bitData << bits; + bitStrm->bitsLeft = bitsLeft - bits; + return result; +} + +libraw_inline int crxPredictKParameter(int32_t prevK, int32_t bitCode, + int32_t maxVal = 0) +{ + int32_t newKParam = prevK - (bitCode < (1 << prevK >> 1)) + + ((bitCode >> prevK) > 2) + ((bitCode >> prevK) > 5); + + return !maxVal || newKParam < maxVal ? newKParam : maxVal; +} + +libraw_inline void crxDecodeSymbolL1(CrxBandParam *param, + int32_t doMedianPrediction, + int32_t notEOL = 0) +{ + if (doMedianPrediction) + { + int32_t symb[4]; + + int32_t delta = param->lineBuf0[1] - param->lineBuf0[0]; + symb[2] = param->lineBuf1[0]; + symb[0] = symb[1] = delta + symb[2]; + symb[3] = param->lineBuf0[1]; + + param->lineBuf1[1] = + symb[(((param->lineBuf0[0] < param->lineBuf1[0]) ^ (delta < 0)) << 1) + + ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (delta < 0))]; + } + else + param->lineBuf1[1] = param->lineBuf0[1]; + + // get next error symbol + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + + // add converted (+/-) error code to predicted value + param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); + + // for not end of the line - use one symbol ahead to estimate next K + if (notEOL) + { + int32_t nextDelta = (param->lineBuf0[2] - param->lineBuf0[1]) << 1; + bitCode = (bitCode + _abs(nextDelta)) >> 1; + ++param->lineBuf0; + } + + // update K parameter + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + + ++param->lineBuf1; +} + +int crxDecodeLine(CrxBandParam *param) +{ + int length = param->subbandWidth; + + param->lineBuf1[0] = param->lineBuf0[1]; + for (; length > 1; --length) + { + if (param->lineBuf1[0] != param->lineBuf0[1] || + param->lineBuf1[0] != param->lineBuf0[2]) + { + crxDecodeSymbolL1(param, 1, 1); + } + else + { + int nSyms = 0; + if (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms = 1; + while (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms += JS[param->sParam]; + if (nSyms > length) + { + nSyms = length; + break; + } + if (param->sParam < 31) + ++param->sParam; + if (nSyms == length) + break; + } + + if (nSyms < length) + { + if (J[param->sParam]) + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + if (param->sParam > 0) + --param->sParam; + if (nSyms > length) + return -1; + } + + length -= nSyms; + + // copy symbol nSyms times + param->lineBuf0 += nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) + { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + } + + if (length > 0) + crxDecodeSymbolL1(param, 0, (length > 1)); + } + } + + if (length == 1) + crxDecodeSymbolL1(param, 1, 0); + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return 0; +} + +libraw_inline void crxDecodeSymbolL1Rounded(CrxBandParam *param, + int32_t doSym = 1, + int32_t doCode = 1) +{ + int32_t sym = param->lineBuf0[1]; + + if (doSym) + { + // calculate the next symbol gradient + int32_t symb[4]; + int32_t deltaH = param->lineBuf0[1] - param->lineBuf0[0]; + symb[2] = param->lineBuf1[0]; + symb[0] = symb[1] = deltaH + symb[2]; + symb[3] = param->lineBuf0[1]; + sym = + symb[(((param->lineBuf0[0] < param->lineBuf1[0]) ^ (deltaH < 0)) << 1) + + ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (deltaH < 0))]; + } + + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + int32_t code = -(bitCode & 1) ^ (bitCode >> 1); + param->lineBuf1[1] = param->roundedBitsMask * 2 * code + (code >> 31) + sym; + + if (doCode) + { + if (param->lineBuf0[2] > param->lineBuf0[1]) + code = (param->lineBuf0[2] - param->lineBuf0[1] + param->roundedBitsMask - + 1) >> + param->roundedBits; + else + code = -( + (param->lineBuf0[1] - param->lineBuf0[2] + param->roundedBitsMask) >> + param->roundedBits); + + param->kParam = crxPredictKParameter(param->kParam, + (bitCode + 2 * _abs(code)) >> 1, 15); + } + else + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + + ++param->lineBuf1; +} + +int crxDecodeLineRounded(CrxBandParam *param) +{ + int32_t valueReached = 0; + + param->lineBuf0[0] = param->lineBuf0[1]; + param->lineBuf1[0] = param->lineBuf0[1]; + int32_t length = param->subbandWidth; + + for (; length > 1; --length) + { + if (_abs(param->lineBuf0[2] - param->lineBuf0[1]) > param->roundedBitsMask) + { + crxDecodeSymbolL1Rounded(param); + ++param->lineBuf0; + valueReached = 1; + } + else if (valueReached || _abs(param->lineBuf0[0] - param->lineBuf1[0]) > + param->roundedBitsMask) + { + crxDecodeSymbolL1Rounded(param); + ++param->lineBuf0; + valueReached = 0; + } + else + { + int nSyms = 0; + if (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms = 1; + while (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms += JS[param->sParam]; + if (nSyms > length) + { + nSyms = length; + break; + } + if (param->sParam < 31) + ++param->sParam; + if (nSyms == length) + break; + } + if (nSyms < length) + { + if (J[param->sParam]) + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + if (param->sParam > 0) + --param->sParam; + } + if (nSyms > length) + return -1; + } + length -= nSyms; + + // copy symbol nSyms times + param->lineBuf0 += nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) + { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + + if (length > 1) + { + crxDecodeSymbolL1Rounded(param, 0); + ++param->lineBuf0; + valueReached = _abs(param->lineBuf0[1] - param->lineBuf0[0]) > + param->roundedBitsMask; + } + else if (length == 1) + crxDecodeSymbolL1Rounded(param, 0, 0); + } + } + if (length == 1) + crxDecodeSymbolL1Rounded(param, 1, 0); + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return 0; +} + +int crxDecodeLineNoRefPrevLine(CrxBandParam *param) +{ + int32_t i = 0; + + for (; i < param->subbandWidth - 1; i++) + { + if (param->lineBuf0[i + 2] | param->lineBuf0[i + 1] | param->lineBuf1[i]) + { + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode); + if (param->lineBuf2[i + 1] - param->kParam <= 1) + { + if (param->kParam >= 15) + param->kParam = 15; + } + else + ++param->kParam; + } + else + { + int nSyms = 0; + if (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms = 1; + if (i != param->subbandWidth - 1) + { + while (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms += JS[param->sParam]; + if (i + nSyms > param->subbandWidth) + { + nSyms = param->subbandWidth - i; + break; + } + if (param->sParam < 31) + ++param->sParam; + if (i + nSyms == param->subbandWidth) + break; + } + if (i + nSyms < param->subbandWidth) + { + if (J[param->sParam]) + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + if (param->sParam > 0) + --param->sParam; + } + if (i + nSyms > param->subbandWidth) + return -1; + } + } + else if (i > param->subbandWidth) + return -1; + + if (nSyms > 0) + { + memset(param->lineBuf1 + i + 1, 0, nSyms * sizeof(int32_t)); + memset(param->lineBuf2 + i, 0, nSyms * sizeof(int32_t)); + i += nSyms; + } + + if (i >= param->subbandWidth - 1) + { + if (i == param->subbandWidth - 1) + { + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + param->lineBuf2[i] = param->kParam; + } + continue; + } + else + { + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode); + if (param->lineBuf2[i + 1] - param->kParam <= 1) + { + if (param->kParam >= 15) + param->kParam = 15; + } + else + ++param->kParam; + } + } + param->lineBuf2[i] = param->kParam; + } + if (i == param->subbandWidth - 1) + { + int32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + param->lineBuf2[i] = param->kParam; + } + + return 0; +} + +int crxDecodeTopLine(CrxBandParam *param) +{ + param->lineBuf1[0] = 0; + + int32_t length = param->subbandWidth; + + // read the line from bitstream + for (; length > 1; --length) + { + if (param->lineBuf1[0]) + param->lineBuf1[1] = param->lineBuf1[0]; + else + { + int nSyms = 0; + if (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms = 1; + while (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms += JS[param->sParam]; + if (nSyms > length) + { + nSyms = length; + break; + } + if (param->sParam < 31) + ++param->sParam; + if (nSyms == length) + break; + } + if (nSyms < length) + { + if (J[param->sParam]) + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + if (param->sParam > 0) + --param->sParam; + if (nSyms > length) + return -1; + } + + length -= nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) + { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + + if (length <= 0) + break; + } + + param->lineBuf1[1] = 0; + } + + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; + } + + if (length == 1) + { + param->lineBuf1[1] = param->lineBuf1[0]; + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; + } + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return 0; +} + +int crxDecodeTopLineRounded(CrxBandParam *param) +{ + param->lineBuf1[0] = 0; + + int32_t length = param->subbandWidth; + + // read the line from bitstream + for (; length > 1; --length) + { + if (_abs(param->lineBuf1[0]) > param->roundedBitsMask) + param->lineBuf1[1] = param->lineBuf1[0]; + else + { + int nSyms = 0; + if (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms = 1; + while (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms += JS[param->sParam]; + if (nSyms > length) + { + nSyms = length; + break; + } + if (param->sParam < 31) + ++param->sParam; + if (nSyms == length) + break; + } + if (nSyms < length) + { + if (J[param->sParam]) + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + if (param->sParam > 0) + --param->sParam; + if (nSyms > length) + return -1; + } + } + + length -= nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) + { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + + if (length <= 0) + break; + + param->lineBuf1[1] = 0; + } + + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + + int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1); + param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; + } + + if (length == 1) + { + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1); + param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; + } + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return 0; +} + +int crxDecodeTopLineNoRefPrevLine(CrxBandParam *param) +{ + param->lineBuf0[0] = 0; + param->lineBuf1[0] = 0; + int32_t length = param->subbandWidth; + for (; length > 1; --length) + { + if (param->lineBuf1[0]) + { + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + } + else + { + int nSyms = 0; + if (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms = 1; + while (crxBitstreamGetBits(¶m->bitStream, 1)) + { + nSyms += JS[param->sParam]; + if (nSyms > length) + { + nSyms = length; + break; + } + if (param->sParam < 31) + ++param->sParam; + if (nSyms == length) + break; + } + if (nSyms < length) + { + if (J[param->sParam]) + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + if (param->sParam > 0) + --param->sParam; + if (nSyms > length) + return -1; + } + } + + length -= nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) + { + param->lineBuf2[0] = 0; + param->lineBuf1[1] = 0; + ++param->lineBuf1; + ++param->lineBuf2; + } + + if (length <= 0) + break; + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + } + param->lineBuf2[0] = param->kParam; + ++param->lineBuf2; + ++param->lineBuf1; + } + + if (length == 1) + { + uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + if (bitCode >= 41) + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + else if (param->kParam) + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | + (bitCode << param->kParam); + param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + param->lineBuf2[0] = param->kParam; + ++param->lineBuf1; + } + + param->lineBuf1[1] = 0; + + return 0; +} + +int crxDecodeLine(CrxBandParam *param, uint8_t *bandBuf) +{ + if (!param || !bandBuf) + return -1; + if (param->curLine >= param->subbandHeight) + return -1; + + if (param->curLine == 0) + { + int32_t lineLength = param->subbandWidth + 2; + + param->sParam = 0; + param->kParam = 0; + if (param->supportsPartial) + { + if (param->roundedBitsMask <= 0) + { + param->lineBuf0 = (int32_t *)param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + int32_t *lineBuf = param->lineBuf1 + 1; + if (crxDecodeTopLine(param)) + return -1; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); + ++param->curLine; + } + else + { + param->roundedBits = 1; + if (param->roundedBitsMask & ~1) + { + while (param->roundedBitsMask >> param->roundedBits) + ++param->roundedBits; + } + param->lineBuf0 = (int32_t *)param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + int32_t *lineBuf = param->lineBuf1 + 1; + if (crxDecodeTopLineRounded(param)) + return -1; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); + ++param->curLine; + } + } + else + { + param->lineBuf2 = (int32_t *)param->nonProgrData; + param->lineBuf0 = (int32_t *)param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + int32_t *lineBuf = param->lineBuf1 + 1; + if (crxDecodeTopLineNoRefPrevLine(param)) + return -1; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); + ++param->curLine; + } + } + else if (!param->supportsPartial) + { + int32_t lineLength = param->subbandWidth + 2; + param->lineBuf2 = (int32_t *)param->nonProgrData; + if (param->curLine & 1) + { + param->lineBuf1 = (int32_t *)param->paramData; + param->lineBuf0 = param->lineBuf1 + lineLength; + } + else + { + param->lineBuf0 = (int32_t *)param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + } + int32_t *lineBuf = param->lineBuf1 + 1; + if (crxDecodeLineNoRefPrevLine(param)) + return -1; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); + ++param->curLine; + } + else if (param->roundedBitsMask <= 0) + { + int32_t lineLength = param->subbandWidth + 2; + if (param->curLine & 1) + { + param->lineBuf1 = (int32_t *)param->paramData; + param->lineBuf0 = param->lineBuf1 + lineLength; + } + else + { + param->lineBuf0 = (int32_t *)param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + } + int32_t *lineBuf = param->lineBuf1 + 1; + if (crxDecodeLine(param)) + return -1; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); + ++param->curLine; + } + else + { + int32_t lineLength = param->subbandWidth + 2; + if (param->curLine & 1) + { + param->lineBuf1 = (int32_t *)param->paramData; + param->lineBuf0 = param->lineBuf1 + lineLength; + } + else + { + param->lineBuf0 = (int32_t *)param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + } + int32_t *lineBuf = param->lineBuf1 + 1; + if (crxDecodeLineRounded(param)) + return -1; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); + ++param->curLine; + } + return 0; +} + +int crxDecodeLineWithIQuantization(CrxSubband *subband) +{ + int32_t q_step_tbl[6] = {0x28, 0x2D, 0x33, 0x39, 0x40, 0x48}; + + if (!subband->dataSize) + { + memset(subband->bandBuf, 0, subband->bandSize); + return 0; + } + + if (subband->supportsPartial) + { + uint32_t bitCode = crxBitstreamGetZeros(&subband->bandParam->bitStream); + if (bitCode >= 23) + bitCode = crxBitstreamGetBits(&subband->bandParam->bitStream, 8); + else if (subband->paramK) + bitCode = + crxBitstreamGetBits(&subband->bandParam->bitStream, subband->paramK) | + (bitCode << subband->paramK); + + subband->quantValue += + -(bitCode & 1) ^ (bitCode >> 1); // converting encoded to signed integer + subband->paramK = crxPredictKParameter(subband->paramK, bitCode); + if (subband->paramK > 7) + return -1; + } + if (crxDecodeLine(subband->bandParam, subband->bandBuf)) + return -1; + + if (subband->width <= 0) + return 0LL; + + // update subband buffers + int32_t *bandBuf = (int32_t *)subband->bandBuf; + int32_t qScale = + q_step_tbl[subband->quantValue % 6] >> (6 - subband->quantValue / 6); + if (subband->quantValue / 6 >= 6) + qScale = q_step_tbl[subband->quantValue % 6] * + (1 << (subband->quantValue / 6 + 26)); + + if (qScale != 1) + for (int32_t i = 0; i < subband->width; i++) + bandBuf[i] *= qScale; + + return 0; +} + +void crxHorizontal53(int32_t *lineBufLA, int32_t *lineBufLB, + CrxWaveletTransform *wavelet, uint32_t tileFlag) +{ + int32_t *band0Buf = wavelet->subband0Buf; + int32_t *band1Buf = wavelet->subband1Buf; + int32_t *band2Buf = wavelet->subband2Buf; + int32_t *band3Buf = wavelet->subband3Buf; + + if (wavelet->width <= 1) + { + lineBufLA[0] = band0Buf[0]; + lineBufLB[0] = band2Buf[0]; + } + else + { + if (tileFlag & E_HAS_TILES_ON_THE_LEFT) + { + lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + ++band1Buf; + ++band3Buf; + } + else + { + lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } + ++band0Buf; + ++band2Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufLA[1] = band1Buf[0] + ((delta + lineBufLA[0]) >> 1); + lineBufLA[2] = delta; + + delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufLB[1] = band3Buf[0] + ((delta + lineBufLB[0]) >> 1); + lineBufLB[2] = delta; + + ++band0Buf; + ++band1Buf; + ++band2Buf; + ++band3Buf; + lineBufLA += 2; + lineBufLB += 2; + } + if (tileFlag & E_HAS_TILES_ON_THE_RIGHT) + { + int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufLA[1] = band1Buf[0] + ((deltaA + lineBufLA[0]) >> 1); + + int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufLB[1] = band3Buf[0] + ((deltaB + lineBufLB[0]) >> 1); + + if (wavelet->width & 1) + { + lineBufLA[2] = deltaA; + lineBufLB[2] = deltaB; + } + } + else if (wavelet->width & 1) + { + lineBufLA[1] = + band1Buf[0] + + ((lineBufLA[0] + band0Buf[0] - ((band1Buf[0] + 1) >> 1)) >> 1); + lineBufLA[2] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + + lineBufLB[1] = + band3Buf[0] + + ((lineBufLB[0] + band2Buf[0] - ((band3Buf[0] + 1) >> 1)) >> 1); + lineBufLB[2] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } + else + { + lineBufLA[1] = lineBufLA[0] + band1Buf[0]; + lineBufLB[1] = lineBufLB[0] + band3Buf[0]; + } + } +} + +int32_t *crxIdwt53FilterGetLine(CrxPlaneComp *comp, int32_t level) +{ + int32_t *result = comp->waveletTransform[level] + .lineBuf[(comp->waveletTransform[level].fltTapH - + comp->waveletTransform[level].curH + 5) % + 5 + + 3]; + comp->waveletTransform[level].curH--; + return result; +} + +int crxIdwt53FilterDecode(CrxPlaneComp *comp, int32_t level) +{ + if (comp->waveletTransform[level].curH) + return 0; + + CrxSubband *sband = comp->subBands + 3 * level; + + if (comp->waveletTransform[level].height - 3 <= + comp->waveletTransform[level].curLine && + !(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) + { + if (comp->waveletTransform[level].height & 1) + { + if (level) + { + if (crxIdwt53FilterDecode(comp, level - 1)) + return -1; + } + else if (crxDecodeLineWithIQuantization(sband)) + return -1; + + if (crxDecodeLineWithIQuantization(sband + 1)) + return -1; + } + } + else + { + if (level) + { + if (crxIdwt53FilterDecode(comp, level - 1)) + return -1; + } + else if (crxDecodeLineWithIQuantization(sband)) // LL band + return -1; + + if (crxDecodeLineWithIQuantization(sband + 1) || // HL band + crxDecodeLineWithIQuantization(sband + 2) || // LH band + crxDecodeLineWithIQuantization(sband + 3)) // HH band + return -1; + } + + return 0; +} + +int crxIdwt53FilterTransform(CrxPlaneComp *comp, uint32_t level) +{ + CrxWaveletTransform *wavelet = comp->waveletTransform + level; + + if (wavelet->curH) + return 0; + + if (wavelet->curLine >= wavelet->height - 3) + { + if (!(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) + { + if (wavelet->height & 1) + { + if (level) + { + if (!wavelet[-1].curH) + if (crxIdwt53FilterTransform(comp, level - 1)) + return -1; + wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1); + } + int32_t *band0Buf = wavelet->subband0Buf; + int32_t *band1Buf = wavelet->subband1Buf; + int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; + int32_t *lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3]; + + int32_t *lineBufL0 = wavelet->lineBuf[0]; + int32_t *lineBufL1 = wavelet->lineBuf[1]; + wavelet->lineBuf[1] = wavelet->lineBuf[2]; + wavelet->lineBuf[2] = lineBufL1; + + // process L bands + if (wavelet->width <= 1) + { + lineBufL0[0] = band0Buf[0]; + } + else + { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) + { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + ++band1Buf; + } + else + { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + } + ++band0Buf; + for (int i = 0; i < wavelet->width - 3; i += 2) + { + int32_t delta = + band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); + lineBufL0[2] = delta; + ++band0Buf; + ++band1Buf; + lineBufL0 += 2; + } + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) + { + int32_t delta = + band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); + if (wavelet->width & 1) + lineBufL0[2] = delta; + } + else if (wavelet->width & 1) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); + lineBufL0[2] = delta; + } + else + lineBufL0[1] = band1Buf[0] + lineBufL0[0]; + } + + // process H bands + lineBufL0 = wavelet->lineBuf[0]; + lineBufL1 = wavelet->lineBuf[1]; + for (int32_t i = 0; i < wavelet->width; i++) + { + int32_t delta = lineBufL0[i] - ((lineBufL1[i] + 1) >> 1); + lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1); + lineBufH2[i] = delta; + } + wavelet->curH += 3; + wavelet->curLine += 3; + wavelet->fltTapH = (wavelet->fltTapH + 3) % 5; + } + else + { + int32_t *lineBufL2 = wavelet->lineBuf[2]; + int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; + wavelet->lineBuf[1] = lineBufL2; + wavelet->lineBuf[2] = wavelet->lineBuf[1]; + + for (int32_t i = 0; i < wavelet->width; i++) + lineBufH1[i] = lineBufH0[i] + lineBufL2[i]; + + wavelet->curH += 2; + wavelet->curLine += 2; + wavelet->fltTapH = (wavelet->fltTapH + 2) % 5; + } + } + } + else + { + if (level) + { + if (!wavelet[-1].curH && crxIdwt53FilterTransform(comp, level - 1)) + return -1; + wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1); + } + + int32_t *band0Buf = wavelet->subband0Buf; + int32_t *band1Buf = wavelet->subband1Buf; + int32_t *band2Buf = wavelet->subband2Buf; + int32_t *band3Buf = wavelet->subband3Buf; + + int32_t *lineBufL0 = wavelet->lineBuf[0]; + int32_t *lineBufL1 = wavelet->lineBuf[1]; + int32_t *lineBufL2 = wavelet->lineBuf[2]; + int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; + int32_t *lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3]; + + wavelet->lineBuf[1] = wavelet->lineBuf[2]; + wavelet->lineBuf[2] = lineBufL1; + + // process L bands + if (wavelet->width <= 1) + { + lineBufL0[0] = band0Buf[0]; + lineBufL1[0] = band2Buf[0]; + } + else + { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) + { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + ++band1Buf; + ++band3Buf; + } + else + { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } + ++band0Buf; + ++band2Buf; + for (int i = 0; i < wavelet->width - 3; i += 2) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1); + lineBufL0[2] = delta; + + delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1); + lineBufL1[2] = delta; + + ++band0Buf; + ++band1Buf; + ++band2Buf; + ++band3Buf; + lineBufL0 += 2; + lineBufL1 += 2; + } + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) + { + int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((deltaA + lineBufL0[0]) >> 1); + + int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL1[1] = band3Buf[0] + ((deltaB + lineBufL1[0]) >> 1); + + if (wavelet->width & 1) + { + lineBufL0[2] = deltaA; + lineBufL1[2] = deltaB; + } + } + else if (wavelet->width & 1) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1); + lineBufL0[2] = delta; + + delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1); + lineBufL1[2] = delta; + } + else + { + lineBufL0[1] = lineBufL0[0] + band1Buf[0]; + lineBufL1[1] = lineBufL1[0] + band3Buf[0]; + } + } + + // process H bands + lineBufL0 = wavelet->lineBuf[0]; + lineBufL1 = wavelet->lineBuf[1]; + lineBufL2 = wavelet->lineBuf[2]; + for (int32_t i = 0; i < wavelet->width; i++) + { + int32_t delta = lineBufL0[i] - ((lineBufL2[i] + lineBufL1[i] + 2) >> 2); + lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1); + lineBufH2[i] = delta; + } + if (wavelet->curLine >= wavelet->height - 3 && wavelet->height & 1) + { + wavelet->curH += 3; + wavelet->curLine += 3; + wavelet->fltTapH = (wavelet->fltTapH + 3) % 5; + } + else + { + wavelet->curH += 2; + wavelet->curLine += 2; + wavelet->fltTapH = (wavelet->fltTapH + 2) % 5; + } + } + + return 0; +} + +int crxIdwt53FilterInitialize(CrxPlaneComp *comp, int32_t prevLevel) +{ + if (prevLevel < 0) + return 0; + + for (int curLevel = 0, curBand = 0; curLevel < prevLevel + 1; + curLevel++, curBand += 3) + { + CrxWaveletTransform *wavelet = comp->waveletTransform + curLevel; + if (curLevel) + wavelet[0].subband0Buf = crxIdwt53FilterGetLine(comp, curLevel - 1); + else if (crxDecodeLineWithIQuantization(comp->subBands + curBand)) + return -1; + + int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + if (wavelet->height > 1) + { + if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 1) || + crxDecodeLineWithIQuantization(comp->subBands + curBand + 2) || + crxDecodeLineWithIQuantization(comp->subBands + curBand + 3)) + return -1; + + int32_t *lineBufL0 = wavelet->lineBuf[0]; + int32_t *lineBufL1 = wavelet->lineBuf[1]; + int32_t *lineBufL2 = wavelet->lineBuf[2]; + + if (comp->tileFlag & E_HAS_TILES_ON_THE_TOP) + { + crxHorizontal53(lineBufL0, wavelet->lineBuf[1], wavelet, + comp->tileFlag); + if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 3) || + crxDecodeLineWithIQuantization(comp->subBands + curBand + 2)) + return -1; + + int32_t *band2Buf = wavelet->subband2Buf; + int32_t *band3Buf = wavelet->subband3Buf; + + // process L band + if (wavelet->width <= 1) + lineBufL2[0] = band2Buf[0]; + else + { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) + { + lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + ++band3Buf; + } + else + lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + + ++band2Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) + { + int32_t delta = + band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); + lineBufL2[2] = delta; + + ++band2Buf; + ++band3Buf; + lineBufL2 += 2; + } + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) + { + int32_t delta = + band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); + if (wavelet->width & 1) + lineBufL2[2] = delta; + } + else if (wavelet->width & 1) + { + int32_t delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + + lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); + lineBufL2[2] = delta; + } + else + { + lineBufL2[1] = band3Buf[0] + lineBufL2[0]; + } + } + + // process H band + for (int32_t i = 0; i < wavelet->width; i++) + lineBufH0[i] = + lineBufL0[i] - ((lineBufL1[i] + lineBufL2[i] + 2) >> 2); + } + else + { + crxHorizontal53(lineBufL0, wavelet->lineBuf[2], wavelet, + comp->tileFlag); + for (int i = 0; i < wavelet->width; i++) + lineBufH0[i] = lineBufL0[i] - ((lineBufL2[i] + 1) >> 1); + } + + if (crxIdwt53FilterDecode(comp, curLevel) || + crxIdwt53FilterTransform(comp, curLevel)) + return -1; + } + else + { + if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 1)) + return -1; + + int32_t *band0Buf = wavelet->subband0Buf; + int32_t *band1Buf = wavelet->subband1Buf; + + // process H band + if (wavelet->width <= 1) + lineBufH0[0] = band0Buf[0]; + else + { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) + { + lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + ++band1Buf; + } + else + lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + + ++band0Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); + lineBufH0[2] = delta; + + ++band0Buf; + ++band1Buf; + lineBufH0 += 2; + } + + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); + lineBufH0[2] = delta; + } + else if (wavelet->width & 1) + { + int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); + lineBufH0[2] = delta; + } + else + { + lineBufH0[1] = band1Buf[0] + lineBufH0[0]; + } + } + ++wavelet->curLine; + ++wavelet->curH; + wavelet->fltTapH = (wavelet->fltTapH + 1) % 5; + } + } + + return 0; +} + +void crxFreeSubbandData(CrxImage *image, CrxPlaneComp *comp) +{ + if (comp->compBuf) + { + free(comp->compBuf); + comp->compBuf = 0; + } + + if (!comp->subBands) + return; + + for (int32_t i = 0; i < image->subbandCount; i++) + { + if (comp->subBands[i].bandParam) + { + free(comp->subBands[i].bandParam); + comp->subBands[i].bandParam = 0LL; + } + comp->subBands[i].bandBuf = 0; + comp->subBands[i].bandSize = 0; + } +} + +void crxConvertPlaneLine(CrxImage *img, int imageRow, int imageCol = 0, + int plane = 0, int32_t *lineData = 0, + int lineLength = 0) +{ + if (lineData) + { + uint64_t rawOffset = 4 * img->planeWidth * imageRow + 2 * imageCol; + if (img->encType == 1) + { + int32_t maxVal = 1 << (img->nBits - 1); + int32_t minVal = -maxVal; + --maxVal; + for (int i = 0; i < lineLength; i++) + img->outBufs[plane][rawOffset + 2 * i] = + _constrain(lineData[i], minVal, maxVal); + } + else if (img->encType == 3) + { + // copy to intermediate planeBuf + rawOffset = plane * img->planeWidth * img->planeHeight + + img->planeWidth * imageRow + imageCol; + for (int i = 0; i < lineLength; i++) + img->planeBuf[rawOffset + i] = lineData[i]; + } + else if (img->nPlanes == 4) + { + int32_t median = 1 << (img->nBits - 1); + int32_t maxVal = (1 << img->nBits) - 1; + for (int i = 0; i < lineLength; i++) + img->outBufs[plane][rawOffset + 2 * i] = + _constrain(median + lineData[i], 0, maxVal); + } + else if (img->nPlanes == 1) + { + int32_t maxVal = (1 << img->nBits) - 1; + int32_t median = 1 << (img->nBits - 1); + rawOffset = img->planeWidth * imageRow + imageCol; + for (int i = 0; i < lineLength; i++) + img->outBufs[0][rawOffset + i] = + _constrain(median + lineData[i], 0, maxVal); + } + } + else if (img->encType == 3 && img->planeBuf) + { + int32_t planeSize = img->planeWidth * img->planeHeight; + int16_t *plane0 = img->planeBuf + imageRow * img->planeWidth; + int16_t *plane1 = plane0 + planeSize; + int16_t *plane2 = plane1 + planeSize; + int16_t *plane3 = plane2 + planeSize; + + int32_t median = 1 << (img->nBits - 1) << 10; + int32_t maxVal = (1 << img->nBits) - 1; + uint32_t rawLineOffset = 4 * img->planeWidth * imageRow; + + // for this stage - all except imageRow is ignored + for (int i = 0; i < img->planeWidth; i++) + { + int32_t gr = + median + (plane0[i] << 10) - 168 * plane1[i] - 585 * plane3[i]; + int32_t val = 0; + if (gr < 0) + gr = -(((_abs(gr) + 512) >> 9) & ~1); + else + gr = ((_abs(gr) + 512) >> 9) & ~1; + + // Essentially R = round(median + P0 + 1.474*P3) + val = (median + (plane0[i] << 10) + 1510 * plane3[i] + 512) >> 10; + img->outBufs[0][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); + // Essentially G1 = round(median + P0 + P2 - 0.164*P1 - 0.571*P3) + val = (plane2[i] + gr + 1) >> 1; + img->outBufs[1][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); + // Essentially G1 = round(median + P0 - P2 - 0.164*P1 - 0.571*P3) + val = (gr - plane2[i] + 1) >> 1; + img->outBufs[2][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); + // Essentially B = round(median + P0 + 1.881*P1) + val = (median + (plane0[i] << 10) + 1927 * plane1[i] + 512) >> 10; + img->outBufs[3][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); + } + } +} + +int crxParamInit(CrxBandParam **param, uint64_t subbandMdatOffset, + uint64_t subbandDataSize, uint32_t subbandWidth, + uint32_t subbandHeight, int32_t supportsPartial, + uint32_t roundedBitsMask, LibRaw_abstract_datastream *input) +{ + int32_t progrDataSize = supportsPartial ? 0 : sizeof(int32_t) * subbandWidth; + int32_t paramLength = 2 * subbandWidth + 4; + uint8_t *paramBuf = (uint8_t *)calloc( + 1, sizeof(CrxBandParam) + sizeof(int32_t) * paramLength + progrDataSize); + + if (!paramBuf) + return -1; + + *param = (CrxBandParam *)paramBuf; + + paramBuf += sizeof(CrxBandParam); + + (*param)->paramData = (int32_t *)paramBuf; + (*param)->nonProgrData = + progrDataSize ? (*param)->paramData + paramLength : 0; + (*param)->subbandWidth = subbandWidth; + (*param)->subbandHeight = subbandHeight; + (*param)->roundedBits = 0; + (*param)->curLine = 0; + (*param)->roundedBitsMask = roundedBitsMask; + (*param)->supportsPartial = supportsPartial; + (*param)->bitStream.bitData = 0; + (*param)->bitStream.bitsLeft = 0; + (*param)->bitStream.mdatSize = subbandDataSize; + (*param)->bitStream.curPos = 0; + (*param)->bitStream.curBufSize = 0; + (*param)->bitStream.curBufOffset = subbandMdatOffset; + (*param)->bitStream.input = input; + + crxFillBuffer(&(*param)->bitStream); + + return 0; +} + +int crxSetupSubbandData(CrxImage *img, CrxPlaneComp *planeComp, + const CrxTile *tile, uint32_t mdatOffset) +{ + long compDataSize = 0; + long waveletDataOffset = 0; + long compCoeffDataOffset = 0; + int32_t toSubbands = 3 * img->levels + 1; + int32_t transformWidth = 0; + + CrxSubband *subbands = planeComp->subBands; + + // calculate sizes + for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++) + { + subbands[subbandNum].bandSize = + subbands[subbandNum].width * sizeof(int32_t); // 4bytes + compDataSize += subbands[subbandNum].bandSize; + } + + if (img->levels) + { + int32_t encLevels = img->levels ? img->levels : 1; + waveletDataOffset = (compDataSize + 7) & ~7; + compDataSize = + (sizeof(CrxWaveletTransform) * encLevels + waveletDataOffset + 7) & ~7; + compCoeffDataOffset = compDataSize; + + // calc wavelet line buffer sizes (always at one level up from current) + for (int level = 0; level < img->levels; ++level) + if (level < img->levels - 1) + compDataSize += 8 * sizeof(int32_t) * + planeComp->subBands[3 * (level + 1) + 2].width; + else + compDataSize += 8 * sizeof(int32_t) * tile->width; + } + + // buffer allocation + planeComp->compBuf = (uint8_t *)malloc(compDataSize); + if (!planeComp->compBuf) + return -1; + + // subbands buffer and sizes initialisation + uint64_t subbandMdatOffset = img->mdatOffset + mdatOffset; + uint8_t *subbandBuf = planeComp->compBuf; + + for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++) + { + subbands[subbandNum].bandBuf = subbandBuf; + subbandBuf += subbands[subbandNum].bandSize; + subbands[subbandNum].mdatOffset = + subbandMdatOffset + subbands[subbandNum].dataOffset; + } + + // wavelet data initialisation + if (img->levels) + { + CrxWaveletTransform *waveletTransforms = + (CrxWaveletTransform *)(planeComp->compBuf + waveletDataOffset); + int32_t *paramData = (int32_t *)(planeComp->compBuf + compCoeffDataOffset); + + planeComp->waveletTransform = waveletTransforms; + waveletTransforms[0].subband0Buf = (int32_t *)subbands->bandBuf; + + for (int level = 0; level < img->levels; ++level) + { + int32_t band = 3 * level + 1; + + if (level >= img->levels - 1) + { + waveletTransforms[level].height = tile->height; + transformWidth = tile->width; + } + else + { + waveletTransforms[level].height = subbands[band + 3].height; + transformWidth = subbands[band + 4].width; + } + waveletTransforms[level].width = transformWidth; + waveletTransforms[level].lineBuf[0] = paramData; + waveletTransforms[level].lineBuf[1] = + waveletTransforms[level].lineBuf[0] + transformWidth; + waveletTransforms[level].lineBuf[2] = + waveletTransforms[level].lineBuf[1] + transformWidth; + waveletTransforms[level].lineBuf[3] = + waveletTransforms[level].lineBuf[2] + transformWidth; + waveletTransforms[level].lineBuf[4] = + waveletTransforms[level].lineBuf[3] + transformWidth; + waveletTransforms[level].lineBuf[5] = + waveletTransforms[level].lineBuf[4] + transformWidth; + waveletTransforms[level].lineBuf[6] = + waveletTransforms[level].lineBuf[5] + transformWidth; + waveletTransforms[level].lineBuf[7] = + waveletTransforms[level].lineBuf[6] + transformWidth; + waveletTransforms[level].curLine = 0; + waveletTransforms[level].curH = 0; + waveletTransforms[level].fltTapH = 0; + waveletTransforms[level].subband1Buf = (int32_t *)subbands[band].bandBuf; + waveletTransforms[level].subband2Buf = + (int32_t *)subbands[band + 1].bandBuf; + waveletTransforms[level].subband3Buf = + (int32_t *)subbands[band + 2].bandBuf; + + paramData = waveletTransforms[level].lineBuf[7] + transformWidth; + } + } + + // decoding params and bitstream initialisation + for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++) + { + if (subbands[subbandNum].dataSize) + { + int32_t supportsPartial = 0; + uint32_t roundedBitsMask = 0; + + if (planeComp->supportsPartial && subbandNum == 0) + { + roundedBitsMask = planeComp->roundedBitsMask; + supportsPartial = 1; + } + if (crxParamInit(&subbands[subbandNum].bandParam, + subbands[subbandNum].mdatOffset, + subbands[subbandNum].dataSize, + subbands[subbandNum].width, subbands[subbandNum].height, + supportsPartial, roundedBitsMask, img->input)) + return -1; + } + } + + return 0; +} + +} // namespace + + +int DCraw::crxDecodePlane(void *p, uint32_t planeNumber) +{ + CrxImage *img = (CrxImage *)p; + int imageRow = 0; + for (int tRow = 0; tRow < img->tileRows; tRow++) + { + int imageCol = 0; + for (int tCol = 0; tCol < img->tileCols; tCol++) + { + CrxTile *tile = img->tiles + tRow * img->tileRows + tCol; + CrxPlaneComp *planeComp = tile->comps + planeNumber; + uint64_t tileMdatOffset = tile->dataOffset + planeComp->dataOffset; + + // decode single tile + if (crxSetupSubbandData(img, planeComp, tile, tileMdatOffset)) + return -1; + + if (img->levels) + { + if (crxIdwt53FilterInitialize(planeComp, img->levels - 1)) + return -1; + for (int i = 0; i < tile->height; ++i) + { + if (crxIdwt53FilterDecode(planeComp, img->levels - 1) || + crxIdwt53FilterTransform(planeComp, img->levels - 1)) + return -1; + int32_t *lineData = + crxIdwt53FilterGetLine(planeComp, img->levels - 1); + crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, + lineData, tile->width); + } + } + else + { + // we have the only subband in this case + if (!planeComp->subBands->dataSize) + { + memset(planeComp->subBands->bandBuf, 0, + planeComp->subBands->bandSize); + return 0; + } + + for (int i = 0; i < tile->height; ++i) + { + if (crxDecodeLine(planeComp->subBands->bandParam, + planeComp->subBands->bandBuf)) + return -1; + int32_t *lineData = (int32_t *)planeComp->subBands->bandBuf; + crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, + lineData, tile->width); + } + } + imageCol += tile->width; + } + imageRow += img->tiles[tRow * img->tileRows].height; + } + + return 0; +} + + +namespace { + +typedef DCraw::CanonCR3Data::crx_data_header_t crx_data_header_t; + + +int crxReadSubbandHeaders(crx_data_header_t *hdr, CrxImage *img, CrxTile *tile, + CrxPlaneComp *comp, uint8_t **subbandMdatPtr, + uint32_t *mdatSize) +{ + CrxSubband *band = comp->subBands + img->subbandCount - 1; // set to last band + uint32_t bandHeight = tile->height; + uint32_t bandWidth = tile->width; + int32_t bandWidthExCoef = 0; + int32_t bandHeightExCoef = 0; + if (img->levels) + { + // Build up subband sequences to crxDecode to a level in a header + + // Coefficient structure is a bit unclear and convoluted: + // 3 levels max - 8 groups (for tile width rounded to 8 bytes) + // of 3 band per level 4 sets of coefficients for each + int32_t *rowExCoef = + exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->width & 7); + int32_t *colExCoef = + exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->height & 7); + for (int level = 0; level < img->levels; ++level) + { + int32_t widthOddPixel = bandWidth & 1; + int32_t heightOddPixel = bandHeight & 1; + bandWidth = (widthOddPixel + bandWidth) >> 1; + bandHeight = (heightOddPixel + bandHeight) >> 1; + + int32_t bandWidthExCoef0 = 0; + int32_t bandWidthExCoef1 = 0; + int32_t bandHeightExCoef0 = 0; + int32_t bandHeightExCoef1 = 0; + if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) + { + bandWidthExCoef0 = rowExCoef[0]; + bandWidthExCoef1 = rowExCoef[1]; + } + if (tile->tileFlag & E_HAS_TILES_ON_THE_LEFT) + ++bandWidthExCoef0; + if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) + { + bandHeightExCoef0 = colExCoef[0]; + bandHeightExCoef1 = colExCoef[1]; + } + if (tile->tileFlag & E_HAS_TILES_ON_THE_TOP) + ++bandHeightExCoef0; + + band[0].width = bandWidth + bandWidthExCoef0 - widthOddPixel; + band[0].height = bandHeight + bandHeightExCoef0 - heightOddPixel; + + band[-1].width = bandWidth + bandWidthExCoef1; + band[-1].height = bandHeight + bandHeightExCoef0 - heightOddPixel; + + band[-2].width = bandWidth + bandWidthExCoef0 - widthOddPixel; + band[-2].height = bandHeight + bandHeightExCoef1; + + rowExCoef += 4; + colExCoef += 4; + band -= 3; + } + bandWidthExCoef = bandHeightExCoef = 0; + if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) + bandWidthExCoef = + exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->width & 7) + + 4 * (img->levels - 1) + 1]; + if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) + bandHeightExCoef = + exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->height & 7) + + 4 * (img->levels - 1) + 1]; + } + band->width = bandWidthExCoef + bandWidth; + band->height = bandHeightExCoef + bandHeight; + + if (!img->subbandCount) + return 0; + int32_t curSubband = 0; + int32_t subbandOffset = 0; + band = comp->subBands; + for (int curSubband = 0; curSubband < img->subbandCount; curSubband++, band++) + { + if (*mdatSize < 0xC) + return -1; + + if (sgetn(2, *subbandMdatPtr) != 0xFF03) + return -1; + + uint32_t bitData = sgetn(4, *subbandMdatPtr + 8); + uint32_t subbandSize = sgetn(4, *subbandMdatPtr + 4); + + if (curSubband != bitData >> 28) + { + band->dataSize = subbandSize; + return -1; + } + band->dataSize = subbandSize - (bitData & 0x7FF); + band->supportsPartial = bitData & 0x8000 ? 1 : 0; + band->dataOffset = subbandOffset; + band->quantValue = (bitData >> 19) & 0xFF; + band->paramK = 0; + band->bandParam = 0; + band->bandBuf = 0; + band->bandSize = 0; + + subbandOffset += subbandSize; + + *subbandMdatPtr += 0xC; + *mdatSize -= 0xC; + } + return 0; +} + +int crxReadImageHeaders(crx_data_header_t *hdr, CrxImage *img, uint8_t *mdatPtr, + uint32_t mdatSize) +{ + int nTiles = img->tileRows * img->tileCols; + + if (!nTiles) + return -1; + + if (!img->tiles) + { + img->tiles = (CrxTile *)malloc( + sizeof(CrxTile) * nTiles + + sizeof(CrxPlaneComp) * nTiles * img->nPlanes + + sizeof(CrxSubband) * nTiles * img->nPlanes * img->subbandCount); + if (!img->tiles) + return -1; + + // memory areas in allocated chunk + CrxTile *tile = img->tiles; + CrxPlaneComp *comps = (CrxPlaneComp *)(tile + nTiles); + CrxSubband *bands = (CrxSubband *)(comps + img->nPlanes * nTiles); + + for (int curTile = 0; curTile < nTiles; curTile++, tile++) + { + tile->tileFlag = 0; // tile neighbouring flags + tile->tileNumber = curTile; + tile->tileSize = 0; + tile->comps = comps + curTile * img->nPlanes; + + if ((curTile + 1) % img->tileCols) + { + // not the last tile in a tile row + tile->width = hdr->tileWidth; + if (img->tileCols > 1) + { + tile->tileFlag = E_HAS_TILES_ON_THE_RIGHT; + if (curTile % img->tileCols) + // not the first tile in tile row + tile->tileFlag |= E_HAS_TILES_ON_THE_LEFT; + } + } + else + { + // last tile in a tile row + tile->width = img->planeWidth - hdr->tileWidth * (img->tileCols - 1); + if (img->tileCols > 1) + tile->tileFlag = E_HAS_TILES_ON_THE_LEFT; + } + if (curTile < nTiles - img->tileCols) + { + // in first tile row + tile->height = hdr->tileHeight; + if (img->tileRows > 1) + { + tile->tileFlag |= E_HAS_TILES_ON_THE_BOTTOM; + if (curTile >= img->tileCols) + tile->tileFlag |= E_HAS_TILES_ON_THE_TOP; + } + } + else + { + // non first tile row + tile->height = img->planeHeight - hdr->tileHeight * (img->tileRows - 1); + if (img->tileRows > 1) + tile->tileFlag |= E_HAS_TILES_ON_THE_TOP; + } + if (img->nPlanes) + { + CrxPlaneComp *comp = tile->comps; + CrxSubband *band = bands + curTile * img->nPlanes * img->subbandCount; + + for (int curComp = 0; curComp < img->nPlanes; curComp++, comp++) + { + comp->compNumber = curComp; + comp->supportsPartial = 1; + comp->tileFlag = tile->tileFlag; + comp->subBands = band; + comp->compBuf = 0; + comp->waveletTransform = 0; + if (img->subbandCount) + { + for (int curBand = 0; curBand < img->subbandCount; + curBand++, band++) + { + band->supportsPartial = 0; + band->quantValue = 4; + band->bandParam = 0; + band->dataSize = 0; + } + } + } + } + } + } + + uint32_t tileOffset = 0; + uint32_t dataSize = mdatSize; + uint8_t *dataPtr = mdatPtr; + CrxTile *tile = img->tiles; + + for (int curTile = 0; curTile < nTiles; curTile++, tile++) + { + if (dataSize < 0xC) + return -1; + + if (sgetn(2, dataPtr) != 0xFF01) + return -1; + if (sgetn(2, dataPtr + 8) != curTile) + return -1; + + dataSize -= 0xC; + + tile->tileSize = sgetn(4, dataPtr + 4); + tile->dataOffset = tileOffset; + + int32_t hdrExtraBytes = sgetn(2, dataPtr + 2) - 8; + tileOffset += tile->tileSize; + dataPtr += hdrExtraBytes + 0xC; + dataSize -= hdrExtraBytes; + + uint32_t compOffset = 0; + CrxPlaneComp *comp = tile->comps; + + for (int compNum = 0; compNum < img->nPlanes; compNum++, comp++) + { + if (dataSize < 0xC) + return -1; + + if (sgetn(2, dataPtr) != 0xFF02) + return -1; + if (compNum != dataPtr[8] >> 4) + return -1; + + comp->compSize = sgetn(4, dataPtr + 4); + + int32_t compHdrRoundedBits = (dataPtr[8] >> 1) & 3; + comp->supportsPartial = (dataPtr[8] & 8) != 0; + + comp->dataOffset = compOffset; + comp->tileFlag = tile->tileFlag; + + compOffset += comp->compSize; + dataSize -= 0xC; + dataPtr += 0xC; + + comp->roundedBitsMask = 0; + + if (compHdrRoundedBits) + { + if (img->levels || !comp->supportsPartial) + return -1; + + comp->roundedBitsMask = 1 << (compHdrRoundedBits - 1); + } + + if (crxReadSubbandHeaders(hdr, img, tile, comp, &dataPtr, &dataSize)) + return -1; + } + } + return 0; +} + +int crxSetupImageData(crx_data_header_t *hdr, CrxImage *img, int16_t *outBuf, + uint64_t mdatOffset, uint32_t mdatSize, + uint8_t *mdatHdrPtr) +{ + int IncrBitTable[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, + 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0}; + + img->planeWidth = hdr->f_width; + img->planeHeight = hdr->f_height; + + if (hdr->tileWidth < 0x16 || hdr->tileHeight < 0x16 || + img->planeWidth > 0x7FFF || img->planeHeight > 0x7FFF) + return -1; + + img->tileCols = (img->planeWidth + hdr->tileWidth - 1) / hdr->tileWidth; + img->tileRows = (img->planeHeight + hdr->tileHeight - 1) / hdr->tileHeight; + + if (img->tileCols > 0xFF || img->tileRows > 0xFF || + img->planeWidth - hdr->tileWidth * (img->tileCols - 1) < 0x16 || + img->planeHeight - hdr->tileHeight * (img->tileRows - 1) < 0x16) + return -1; + + img->tiles = 0; + img->levels = hdr->imageLevels; + img->subbandCount = 3 * img->levels + 1; // 3 bands per level + one last LL + img->nPlanes = hdr->nPlanes; + img->nBits = hdr->nBits; + img->encType = hdr->encType; + img->samplePrecision = hdr->nBits + IncrBitTable[4 * hdr->encType + 2] + 1; + img->mdatOffset = mdatOffset + hdr->mdatHdrSize; + img->mdatSize = mdatSize; + img->planeBuf = 0; + img->outBufs[0] = img->outBufs[1] = img->outBufs[2] = img->outBufs[3] = 0; + + // The encoding type 3 needs all 4 planes to be decoded to generate row of + // RGGB values. It seems to be using some other colour space for raw encoding + // It is a massive buffer so ideallly it will need a different approach: + // decode planes line by line and convert single line then without + // intermediate plane buffer. At the moment though it's too many changes so + // left as is. + if (img->encType == 3 && img->nPlanes == 4 && img->nBits > 8) + { + img->planeBuf = + (int16_t *)malloc(img->planeHeight * img->planeWidth * img->nPlanes * + ((img->samplePrecision + 7) >> 3)); + if (!img->planeBuf) + return -1; + } + + int32_t rowSize = 2 * img->planeWidth; + + if (img->nPlanes == 1) + img->outBufs[0] = outBuf; + else + switch (hdr->cfaLayout) + { + case 0: + // R G + // G B + img->outBufs[0] = outBuf; + img->outBufs[1] = outBuf + 1; + img->outBufs[2] = outBuf + rowSize; + img->outBufs[3] = img->outBufs[2] + 1; + break; + case 1: + // G R + // B G + img->outBufs[1] = outBuf; + img->outBufs[0] = outBuf + 1; + img->outBufs[3] = outBuf + rowSize; + img->outBufs[2] = img->outBufs[3] + 1; + break; + case 2: + // G B + // R G + img->outBufs[2] = outBuf; + img->outBufs[3] = outBuf + 1; + img->outBufs[0] = outBuf + rowSize; + img->outBufs[1] = img->outBufs[0] + 1; + break; + case 3: + // B G + // G R + img->outBufs[3] = outBuf; + img->outBufs[2] = outBuf + 1; + img->outBufs[1] = outBuf + rowSize; + img->outBufs[0] = img->outBufs[1] + 1; + break; + } + + // read header + return crxReadImageHeaders(hdr, img, mdatHdrPtr, mdatSize); +} + +int crxFreeImageData(CrxImage *img) +{ + CrxTile *tile = img->tiles; + int nTiles = img->tileRows * img->tileCols; + + if (img->tiles) + { + for (int32_t curTile = 0; curTile < nTiles; curTile++, tile++) + if (tile[curTile].comps) + for (int32_t curPlane = 0; curPlane < img->nPlanes; curPlane++) + crxFreeSubbandData(img, tile[curTile].comps + curPlane); + free(img->tiles); + img->tiles = 0; + } + + if (img->planeBuf) + { + free(img->planeBuf); + img->planeBuf = 0; + } + + return 0; +} + +} // namespace + +void DCraw::crxLoadDecodeLoop(void *img, int nPlanes) +{ +#ifdef _OPENMP + int results[4]; // nPlanes is always <= 4 +#pragma omp parallel for + for (int32_t plane = 0; plane < nPlanes; ++plane) + results[plane] = crxDecodePlane(img, plane); + + for (int32_t plane = 0; plane < nPlanes; ++plane) + if (results[plane]) + derror(); +#else + for (int32_t plane = 0; plane < nPlanes; ++plane) + if (crxDecodePlane(img, plane)) + derror(); +#endif +} + +void DCraw::crxConvertPlaneLineDf(void *p, int imageRow) +{ + crxConvertPlaneLine((CrxImage *)p, imageRow); +} + +void DCraw::crxLoadFinalizeLoopE3(void *p, int planeHeight) +{ +#ifdef _OPENMP +#pragma omp parallel for +#endif + for (int i = 0; i < planeHeight; ++i) + crxConvertPlaneLineDf(p, i); +} + +void DCraw::crxLoadRaw() +{ + CrxImage img; + if (RT_canon_CR3_data.crx_track_selected < 0 || + RT_canon_CR3_data.crx_track_selected >= + LIBRAW_CRXTRACKS_MAXCOUNT) + derror(); + crx_data_header_t hdr = + RT_canon_CR3_data + .crx_header[RT_canon_CR3_data.crx_track_selected]; + + LibRaw_abstract_datastream input = { ifp }; + img.input = &input; //libraw_internal_data.internal_data.input; + + // update sizes for the planes + if (hdr.nPlanes == 4) + { + hdr.f_width >>= 1; + hdr.f_height >>= 1; + hdr.tileWidth >>= 1; + hdr.tileHeight >>= 1; + } + +// /*imgdata.color.*/maximum = (1 << hdr.nBits) - 1; + + uint8_t *hdrBuf = (uint8_t *)malloc(hdr.mdatHdrSize); + + // read image header +#ifdef _OPENMP +#pragma omp critical +#endif + { +#ifndef _OPENMP + /*libraw_internal_data.internal_data.input->*/input.lock(); +#endif + /*libraw_internal_data.internal_data.input->*/input.seek( + data_offset, SEEK_SET); + /*libraw_internal_data.internal_data.input->*/input.read(hdrBuf, 1, hdr.mdatHdrSize); +#ifndef _OPENMP + /*libraw_internal_data.internal_data.input->*/input.unlock(); +#endif + } + + // parse and setup the image data + if (crxSetupImageData(&hdr, &img, (int16_t *)raw_image, + hdr.MediaOffset/*data_offset*/, + hdr.MediaSize/*RT_canon_CR3_data.data_size*/, hdrBuf)) + derror(); + free(hdrBuf); + + crxLoadDecodeLoop(&img, hdr.nPlanes); + + if (img.encType == 3) + crxLoadFinalizeLoopE3(&img, img.planeHeight); + + crxFreeImageData(&img); +} + +int DCraw::crxParseImageHeader(uchar *cmp1TagData, int nTrack) +{ + if (nTrack < 0 || nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT) + return -1; + if (!cmp1TagData) + return -1; + + crx_data_header_t *hdr = + &RT_canon_CR3_data.crx_header[nTrack]; + + hdr->version = sgetn(2, cmp1TagData + 4); + hdr->f_width = sgetn(4, cmp1TagData + 8); + hdr->f_height = sgetn(4, cmp1TagData + 12); + hdr->tileWidth = sgetn(4, cmp1TagData + 16); + hdr->tileHeight = sgetn(4, cmp1TagData + 20); + hdr->nBits = cmp1TagData[24]; + hdr->nPlanes = cmp1TagData[25] >> 4; + hdr->cfaLayout = cmp1TagData[25] & 0xF; + hdr->encType = cmp1TagData[26] >> 4; + hdr->imageLevels = cmp1TagData[26] & 0xF; + hdr->hasTileCols = cmp1TagData[27] >> 7; + hdr->hasTileRows = (cmp1TagData[27] >> 6) & 1; + hdr->mdatHdrSize = sgetn(4, cmp1TagData + 28); + + // validation + if (hdr->version != 0x100 || !hdr->mdatHdrSize) + return -1; + if (hdr->encType == 1) + { + if (hdr->nBits > 15) + return -1; + } + else + { + if (hdr->encType && hdr->encType != 3) + return -1; + if (hdr->nBits > 14) + return -1; + } + + if (hdr->nPlanes == 1) + { + if (hdr->cfaLayout || hdr->encType) + return -1; + if (hdr->nBits != 8) + return -1; + } + else if (hdr->nPlanes != 4 || hdr->f_width & 1 || hdr->f_height & 1 || + hdr->tileWidth & 1 || hdr->tileHeight & 1 || hdr->cfaLayout > 3u || + (hdr->encType && hdr->encType != 1 && hdr->encType != 3) || + hdr->nBits == 8) + return -1; + + if (hdr->tileWidth > hdr->f_width || hdr->tileHeight > hdr->f_height) + return -1; + + if (hdr->imageLevels > 3 || hdr->hasTileCols > 1 || hdr->hasTileRows > 1) + return -1; + return 0; +} + +#undef _abs +#undef _min +#undef _constrain +#undef libraw_inline +#undef LIBRAW_CRXTRACKS_MAXCOUNT + +#ifdef __GNUC__ // silence warning +#pragma GCC diagnostic pop +#endif diff --git a/rtengine/capturesharpening.cc b/rtengine/capturesharpening.cc index 2866839bf..e8770f95a 100644 --- a/rtengine/capturesharpening.cc +++ b/rtengine/capturesharpening.cc @@ -409,92 +409,88 @@ float calcRadiusXtrans(const float * const *rawData, int W, int H, float lowerLi #ifdef _OPENMP #pragma omp parallel for reduction(max:maxRatio) schedule(dynamic, 16) #endif - for (int row = starty + 3; row < H - 4; row += 3) { - for (int col = startx + 3; col < W - 4; col += 3) { - const float valtl = rawData[row][col]; - const float valtr = rawData[row][col + 1]; - const float valbl = rawData[row + 1][col]; - const float valbr = rawData[row + 1][col + 1]; - if (valtl > 1.f) { - const float maxValtltr = std::max(valtl, valtr); - if (valtr > 1.f && maxValtltr > lowerLimit) { - const float minVal = std::min(valtl, valtr); - if (UNLIKELY(maxValtltr > maxRatio * minVal)) { - bool clipped = false; - if (maxValtltr == valtl) { // check for influence by clipped green in neighborhood - if (rtengine::max(rawData[row - 1][col - 1], valtr, valbl, valbr) >= upperLimit) { - clipped = true; + for (int row = starty + 2; row < H - 4; row += 3) { + for (int col = startx + 2; col < W - 4; col += 3) { + const float valp1p1 = rawData[row + 1][col + 1]; + const bool squareClipped = rtengine::max(valp1p1, rawData[row + 1][col + 2], rawData[row + 2][col + 1], rawData[row + 2][col + 2]) >= upperLimit; + const float greenSolitary = rawData[row][col]; + if (greenSolitary > 1.f && std::max(rawData[row - 1][col - 1], rawData[row - 1][col + 1]) < upperLimit) { + if (greenSolitary < upperLimit) { + const float valp1m1 = rawData[row + 1][col - 1]; + if (valp1m1 > 1.f && rtengine::max(rawData[row + 1][col - 2], valp1m1, rawData[row + 2][col - 2], rawData[row + 1][col - 1]) < upperLimit) { + const float maxVal = std::max(greenSolitary, valp1m1); + if (maxVal > lowerLimit) { + const float minVal = std::min(greenSolitary, valp1m1); + if (UNLIKELY(maxVal > maxRatio * minVal)) { + maxRatio = maxVal / minVal; } - } else { // check for influence by clipped green in neighborhood - if (rtengine::max(rawData[row - 1][col + 2], valtl, valbl, valbr) >= upperLimit) { - clipped = true; - } - } - if (!clipped) { - maxRatio = maxValtltr / minVal; } } - } - const float maxValtlbl = std::max(valtl, valbl); - if (valbl > 1.f && maxValtlbl > lowerLimit) { - const float minVal = std::min(valtl, valbl); - if (UNLIKELY(maxValtlbl > maxRatio * minVal)) { - bool clipped = false; - if (maxValtlbl == valtl) { // check for influence by clipped green in neighborhood - if (rtengine::max(rawData[row - 1][col - 1], valtr, valbl, valbr) >= upperLimit) { - clipped = true; + if (valp1p1 > 1.f && !squareClipped) { + const float maxVal = std::max(greenSolitary, valp1p1); + if (maxVal > lowerLimit) { + const float minVal = std::min(greenSolitary, valp1p1); + if (UNLIKELY(maxVal > maxRatio * minVal)) { + maxRatio = maxVal / minVal; } - } else { // check for influence by clipped green in neighborhood - if (rtengine::max(valtl, valtr, rawData[row + 2][col - 1], valbr) >= upperLimit) { - clipped = true; - } - } - if (!clipped) { - maxRatio = maxValtlbl / minVal; } } } } - if (valbr > 1.f) { - const float maxValblbr = std::max(valbl, valbr); - if (valbl > 1.f && maxValblbr > lowerLimit) { - const float minVal = std::min(valbl, valbr); - if (UNLIKELY(maxValblbr > maxRatio * minVal)) { - bool clipped = false; - if (maxValblbr == valbr) { // check for influence by clipped green in neighborhood - if (rtengine::max(valtl, valtr, valbl, rawData[row + 2][col + 2]) >= upperLimit) { - clipped = true; - } - } else { // check for influence by clipped green in neighborhood - if (rtengine::max(valtl, valtr, rawData[row + 2][col - 1], valbr) >= upperLimit) { - clipped = true; + if (!squareClipped) { + const float valp2p2 = rawData[row + 2][col + 2]; + if (valp2p2 > 1.f) { + if (valp1p1 > 1.f) { + const float maxVal = std::max(valp1p1, valp2p2); + if (maxVal > lowerLimit) { + const float minVal = std::min(valp1p1, valp2p2); + if (UNLIKELY(maxVal > maxRatio * minVal)) { + maxRatio = maxVal / minVal; } } - if (!clipped) { - maxRatio = maxValblbr / minVal; + } + const float greenSolitaryRight = rawData[row + 3][col + 3]; + if (rtengine::max(greenSolitaryRight, rawData[row + 4][col + 2], rawData[row + 4][col + 4]) < upperLimit) { + if (greenSolitaryRight > 1.f) { + const float maxVal = std::max(greenSolitaryRight, valp2p2); + if (maxVal > lowerLimit) { + const float minVal = std::min(greenSolitaryRight, valp2p2); + if (UNLIKELY(maxVal > maxRatio * minVal)) { + maxRatio = maxVal / minVal; + } + } } } } - const float maxValtrbr = std::max(valtr, valbr); - if (valtr > 1.f && maxValtrbr > lowerLimit) { - const float minVal = std::min(valtr, valbr); - if (UNLIKELY(maxValtrbr > maxRatio * minVal)) { - if (maxValtrbr == valbr) { // check for influence by clipped green in neighborhood - if (rtengine::max(valtl, valtr, valbl, rawData[row + 2][col + 2]) >= upperLimit) { - continue; - } - } else { // check for influence by clipped green in neighborhood - if (rtengine::max(rawData[row - 1][col + 2], valtl, valbl, valbr) >= upperLimit) { - continue; + const float valp1p2 = rawData[row + 1][col + 2]; + const float valp2p1 = rawData[row + 2][col + 1]; + if (valp2p1 > 1.f) { + if (valp1p2 > 1.f) { + const float maxVal = std::max(valp1p2, valp2p1); + if (maxVal > lowerLimit) { + const float minVal = std::min(valp1p2, valp2p1); + if (UNLIKELY(maxVal > maxRatio * minVal)) { + maxRatio = maxVal / minVal; + } + } + } + const float greenSolitaryLeft = rawData[row + 3][col]; + if (rtengine::max(greenSolitaryLeft, rawData[row + 4][col - 1], rawData[row + 4][col + 1]) < upperLimit) { + if (greenSolitaryLeft > 1.f) { + const float maxVal = std::max(greenSolitaryLeft, valp2p1); + if (maxVal > lowerLimit) { + const float minVal = std::min(greenSolitaryLeft, valp2p1); + if (UNLIKELY(maxVal > maxRatio * minVal)) { + maxRatio = maxVal / minVal; + } } } - maxRatio = maxValtrbr / minVal; } } } } } - return std::sqrt((1.f / (std::log(1.f / maxRatio))) / -2.f); + return std::sqrt((1.f / (std::log(1.f / maxRatio) / 2.f)) / -2.f); } bool checkForStop(float** tmpIThr, float** iterCheck, int fullTileSize, int border) @@ -537,8 +533,8 @@ BENCHFUN } constexpr int tileSize = 32; - constexpr int border = 5; - constexpr int fullTileSize = tileSize + 2 * border; + const int border = iterations <= 30 ? 5 : 7; + const int fullTileSize = tileSize + 2 * border; const float cornerRadius = std::min(1.15f, sigma + sigmaCornerOffset); const float cornerDistance = sqrt(rtengine::SQR(W * 0.5f) + rtengine::SQR(H * 0.5f)); const float distanceFactor = (cornerRadius - sigma) / cornerDistance; @@ -573,10 +569,10 @@ BENCHFUN } } } - for (int k = 0, ii = endOfCol ? H - fullTileSize : i; k < fullTileSize; ++k, ++ii) { - for (int l = 0, jj = endOfRow ? W - fullTileSize : j; l < fullTileSize; ++l, ++jj) { - tmpIThr[k][l] = oldLuminance[ii - border][jj - border]; - lumThr[k][l] = oldLuminance[ii - border][jj - border]; + for (int k = 0, ii = endOfCol ? H - fullTileSize : i - border; k < fullTileSize; ++k, ++ii) { + for (int l = 0, jj = endOfRow ? W - fullTileSize : j - border; l < fullTileSize; ++l, ++jj) { + tmpIThr[k][l] = oldLuminance[ii][jj]; + lumThr[k][l] = oldLuminance[ii][jj]; } } } else { @@ -618,14 +614,27 @@ BENCHFUN const float distance = sqrt(rtengine::SQR(i + tileSize / 2 - H / 2) + rtengine::SQR(j + tileSize / 2 - W / 2)); const float sigmaTile = static_cast(sigma) + distanceFactor * distance; if (sigmaTile >= 0.4f) { - float lkernel7[7][7]; - compute7x7kernel(static_cast(sigma) + distanceFactor * distance, lkernel7); - for (int k = 0; k < iterations && !stopped; ++k) { - // apply 7x7 gaussian blur and divide luminance by result of gaussian blur - gauss7x7div(tmpIThr, tmpThr, lumThr, fullTileSize, lkernel7); - gauss7x7mult(tmpThr, tmpIThr, fullTileSize, lkernel7); - if (checkIterStop) { - stopped = checkForStop(tmpIThr, iterCheck, fullTileSize, border); + if (sigmaTile > 0.84) { // have to use 7x7 kernel + float lkernel7[7][7]; + compute7x7kernel(static_cast(sigma) + distanceFactor * distance, lkernel7); + for (int k = 0; k < iterations && !stopped; ++k) { + // apply 7x7 gaussian blur and divide luminance by result of gaussian blur + gauss7x7div(tmpIThr, tmpThr, lumThr, fullTileSize, lkernel7); + gauss7x7mult(tmpThr, tmpIThr, fullTileSize, lkernel7); + if (checkIterStop) { + stopped = checkForStop(tmpIThr, iterCheck, fullTileSize, border); + } + } + } else { // can use 5x5 kernel + float lkernel7[5][5]; + compute5x5kernel(static_cast(sigma) + distanceFactor * distance, lkernel7); + for (int k = 0; k < iterations && !stopped; ++k) { + // apply 7x7 gaussian blur and divide luminance by result of gaussian blur + gauss5x5div(tmpIThr, tmpThr, lumThr, fullTileSize, lkernel7); + gauss5x5mult(tmpThr, tmpIThr, fullTileSize, lkernel7); + if (checkIterStop) { + stopped = checkForStop(tmpIThr, iterCheck, fullTileSize, border); + } } } } @@ -642,8 +651,8 @@ BENCHFUN } if (endOfRow || endOfCol) { // special handling for small tiles at end of row or column - for (int k = border, ii = endOfCol ? H - fullTileSize - border : i - border; k < fullTileSize - border; ++k) { - for (int l = border, jj = endOfRow ? W - fullTileSize - border : j - border; l < fullTileSize - border; ++l) { + for (int k = border, ii = endOfCol ? H - fullTileSize : i - border; k < fullTileSize - border; ++k) { + for (int l = border, jj = endOfRow ? W - fullTileSize : j - border; l < fullTileSize - border; ++l) { luminance[ii + k][jj + l] = rtengine::intp(blend[ii + k][jj + l], std::max(tmpIThr[k][l], 0.0f), luminance[ii + k][jj + l]); } } diff --git a/rtengine/ciecam02.cc b/rtengine/ciecam02.cc index 8314e5e8f..c7e49b2ed 100644 --- a/rtengine/ciecam02.cc +++ b/rtengine/ciecam02.cc @@ -404,7 +404,7 @@ void Ciecam02::calculate_abfloat ( vfloat &aa, vfloat &bb, vfloat h, vfloat e, v #endif void Ciecam02::initcam1float (float yb, float pilotd, float f, float la, float xw, float yw, float zw, float &n, float &d, float &nbb, float &ncb, - float &cz, float &aw, float &wh, float &pfl, float &fl, float &c) + float &cz, float &aw, float &wh, float &pfl, float &fl, float c) { n = yb / yw; diff --git a/rtengine/ciecam02.h b/rtengine/ciecam02.h index 8b532fba0..75ccfaa8c 100644 --- a/rtengine/ciecam02.h +++ b/rtengine/ciecam02.h @@ -84,7 +84,7 @@ public: * Forward transform from XYZ to CIECAM02 JCh. */ static void initcam1float (float yb, float pilotd, float f, float la, float xw, float yw, float zw, float &n, float &d, float &nbb, float &ncb, - float &cz, float &aw, float &wh, float &pfl, float &fl, float &c); + float &cz, float &aw, float &wh, float &pfl, float &fl, float c); static void initcam2float (float yb, float pilotd, float f, float la, float xw, float yw, float zw, float &n, float &d, float &nbb, float &ncb, float &cz, float &aw, float &fl); diff --git a/rtengine/cplx_wavelet_level.h b/rtengine/cplx_wavelet_level.h index 8664606c6..09b4e4a88 100644 --- a/rtengine/cplx_wavelet_level.h +++ b/rtengine/cplx_wavelet_level.h @@ -272,7 +272,7 @@ template void wavelet_level::SynthesisFilterHaarVertical (const T #pragma omp for nowait #endif - for(int i = 0; i < skip; i++) + for(int i = 0; i < std::min(skip, height); i++) { for(int j = 0; j < width; j++) { dst[width * i + j] = (srcLo[i * width + j] + srcHi[i * width + j]); diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index b81594dc4..d5348286c 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -5595,13 +5595,26 @@ nf: order = 0x4949; else if (!strcmp (buf,"AOC") || !strcmp (buf,"QVC")) fseek (ifp, -4, SEEK_CUR); + // ALB -- taken from LibRaw ------------------------------------------------ + else if (!strncmp(buf, "CMT3", 4)) + { + order = sget2((uchar *)(buf + 4)); + fseek(ifp, 2L, SEEK_CUR); + } + else if (RT_canon_CR3_data.CR3_CTMDtag) + { + order = sget2((uchar *)buf); + fseek(ifp, -2L, SEEK_CUR); + } + // ------------------------------------------------------------------------- + else { fseek (ifp, -10, SEEK_CUR); if (!strncmp(make,"SAMSUNG",7)) base = ftell(ifp); } entries = get2(); - if (entries > 1000) return; + if (entries > 2000) return; morder = order; while (entries--) { order = morder; @@ -5806,16 +5819,335 @@ get2_256: parse_thumb_note (base, 136, 137); } if (tag == 0x4001 && len > 500) { - i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126; - fseek (ifp, i, SEEK_CUR); - FORC4 cam_mul[c ^ (c >> 1)] = get2(); - for (i+=18; i <= len; i+=10) { - get2(); - FORC4 sraw_mul[c ^ (c >> 1)] = get2(); - if (sraw_mul[1] == 1170) break; + // i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126; + // fseek (ifp, i, SEEK_CUR); + // FORC4 cam_mul[c ^ (c >> 1)] = get2(); + // for (i+=18; i <= len; i+=10) { + // get2(); + // FORC4 sraw_mul[c ^ (c >> 1)] = get2(); + // if (sraw_mul[1] == 1170) break; + // } + // -- ALB -- adapted from LibRaw -------------------------------------- + int bls = 0; + long int offsetChannelBlackLevel = 0L; + long int offsetChannelBlackLevel2 = 0L; + long int offsetWhiteLevels = 0L; + struct { + int AverageBlackLevel; + int ColorDataSubVer; + int NormalWhiteLevel; + int SpecularWhiteLevel; + } imCanon = { 0, 0, 0, 0 }; + long int save1 = ftell(ifp); + + switch (len) + { + + case 582: + // imCanon.ColorDataVer = 1; // 20D / 350D + + fseek(ifp, save1 + (0x0019 << 1), SEEK_SET); + FORC4 cam_mul[c ^ (c >> 1)] = (float)get2(); + // fseek(ifp, save1 + (0x001e << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0041 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom1][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0046 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom2][c ^ (c >> 1)] = get2(); + + // fseek(ifp, save1 + (0x0023 << 1), SEEK_SET); + // Canon_WBpresets(2, 2); + // fseek(ifp, save1 + (0x004b << 1), SEEK_SET); + // Canon_WBCTpresets(1); // ABCT + offsetChannelBlackLevel = save1 + (0x00a6 << 1); + break; + + case 653: + // imCanon.ColorDataVer = 2; // 1Dmk2 / 1DsMK2 + + // fseek(ifp, save1 + (0x0018 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2(); + fseek(ifp, save1 + (0x0022 << 1), SEEK_SET); + FORC4 cam_mul[c ^ (c >> 1)] = (float)get2(); + // fseek(ifp, save1 + (0x0090 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom1][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0095 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom2][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x009a << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom3][c ^ (c >> 1)] = get2(); + + // fseek(ifp, save1 + (0x0027 << 1), SEEK_SET); + // Canon_WBpresets(2, 12); + // fseek(ifp, save1 + (0x00a4 << 1), SEEK_SET); + // Canon_WBCTpresets(1); // ABCT + offsetChannelBlackLevel = save1 + (0x011e << 1); + break; + + case 796: + // imCanon.ColorDataVer = 3; // 1DmkIIN / 5D / 30D / 400D + // imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x003f << 1), SEEK_SET); + FORC4 cam_mul[c ^ (c >> 1)] = (float)get2(); + // fseek(ifp, save1 + (0x0044 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0049 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0071 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom1][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0076 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom2][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x007b << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom3][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0080 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Custom][c ^ (c >> 1)] = get2(); + + // fseek(ifp, save1 + (0x004e << 1), SEEK_SET); + // Canon_WBpresets(2, 12); + // fseek(ifp, save1 + (0x0085 << 1), SEEK_SET); + // Canon_WBCTpresets(0); // BCAT + offsetChannelBlackLevel = save1 + (0x00c4 << 1); + break; + + // 1DmkIII / 1DSmkIII / 1DmkIV / 5DmkII + // 7D / 40D / 50D / 60D / 450D / 500D + // 550D / 1000D / 1100D + case 674: + case 692: + case 702: + case 1227: + case 1250: + case 1251: + case 1337: + case 1338: + case 1346: + // imCanon.ColorDataVer = 4; + imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x003f << 1), SEEK_SET); + FORC4 cam_mul[c ^ (c >> 1)] = (float)get2(); + // fseek(ifp, save1 + (0x0044 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0049 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = get2(); + + fseek(ifp, save1 + (0x004e << 1), SEEK_SET); + FORC4 sraw_mul[c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0053 << 1), SEEK_SET); + // Canon_WBpresets(2, 12); + // fseek(ifp, save1 + (0x00a8 << 1), SEEK_SET); + // Canon_WBCTpresets(0); // BCAT + + if ((imCanon.ColorDataSubVer == 4) || + (imCanon.ColorDataSubVer == 5)) + { + offsetChannelBlackLevel = save1 + (0x02b4 << 1); + offsetWhiteLevels = save1 + (0x02b8 << 1); } + else if ((imCanon.ColorDataSubVer == 6) || + (imCanon.ColorDataSubVer == 7)) + { + offsetChannelBlackLevel = save1 + (0x02cb << 1); + offsetWhiteLevels = save1 + (0x02cf << 1); + } + else if (imCanon.ColorDataSubVer == 9) + { + offsetChannelBlackLevel = save1 + (0x02cf << 1); + offsetWhiteLevels = save1 + (0x02d3 << 1); + } + else + offsetChannelBlackLevel = save1 + (0x00e7 << 1); + break; + + case 5120: // PowerShot G10, G12, G5 X, G7 X, G9 X, EOS M3, EOS M5, EOS M6 + // imCanon.ColorDataVer = 5; + imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x0047 << 1), SEEK_SET); + FORC4 cam_mul[c ^ (c >> 1)] = (float)get2(); + + if (imCanon.ColorDataSubVer == 0xfffc) + { // -4: G7 X Mark II, G9 X Mark II, G1 X Mark III, M5, M100, M6 + // fseek(ifp, save1 + (0x004f << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2(); + // fseek(ifp, 8, SEEK_CUR); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = + // get2(); + // fseek(ifp, 8, SEEK_CUR); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Other][c ^ (c >> 1)] = get2(); + // fseek(ifp, 8, SEEK_CUR); + // Canon_WBpresets(8, 24); + // fseek(ifp, 168, SEEK_CUR); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_FL_WW][c ^ (c >> 1)] = get2(); + // fseek(ifp, 24, SEEK_CUR); + // Canon_WBCTpresets(2); // BCADT + offsetChannelBlackLevel = save1 + (0x014d << 1); + offsetWhiteLevels = save1 + (0x0569 << 1); + } + else if (imCanon.ColorDataSubVer == 0xfffd) + { // -3: M10/M3/G1 X/G1 X II/G10/G11/G12/G15/G16/G3 X/G5 X/G7 X/G9 + // X/S100/S110/S120/S90/S95/SX1 IX/SX50 HS/SX60 HS + // fseek(ifp, save1 + (0x004c << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2(); + // get2(); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = + // get2(); + // get2(); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Other][c ^ (c >> 1)] = get2(); + // get2(); + // Canon_WBpresets(2, 12); + // fseek(ifp, save1 + (0x00ba << 1), SEEK_SET); + // Canon_WBCTpresets(2); // BCADT + offsetChannelBlackLevel = save1 + (0x0108 << 1); + } + break; + + case 1273: + case 1275: + // imCanon.ColorDataVer = 6; // 600D / 1200D + imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x003f << 1), SEEK_SET); + FORC4 cam_mul[c ^ (c >> 1)] = (float)get2(); + // fseek(ifp, save1 + (0x0044 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0049 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = get2(); + + fseek(ifp, save1 + (0x0062 << 1), SEEK_SET); + FORC4 sraw_mul[c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0067 << 1), SEEK_SET); + // Canon_WBpresets(2, 12); + // fseek(ifp, save1 + (0x00bc << 1), SEEK_SET); + // Canon_WBCTpresets(0); // BCAT + offsetChannelBlackLevel = save1 + (0x01df << 1); + offsetWhiteLevels = save1 + (0x01e3 << 1); + break; + + // 1DX / 5DmkIII / 6D / 100D / 650D / 700D / EOS M / 7DmkII / 750D / 760D + case 1312: + case 1313: + case 1316: + case 1506: + // imCanon.ColorDataVer = 7; + imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x003f << 1), SEEK_SET); + FORC4 cam_mul[c ^ (c >> 1)] = (float)get2(); + // fseek(ifp, save1 + (0x0044 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0049 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = get2(); + + fseek(ifp, save1 + (0x007b << 1), SEEK_SET); + FORC4 sraw_mul[c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0080 << 1), SEEK_SET); + // Canon_WBpresets(2, 12); + // fseek(ifp, save1 + (0x00d5 << 1), SEEK_SET); + // Canon_WBCTpresets(0); // BCAT + + if (imCanon.ColorDataSubVer == 10) + { + offsetChannelBlackLevel = save1 + (0x01f8 << 1); + offsetWhiteLevels = save1 + (0x01fc << 1); + } + else if (imCanon.ColorDataSubVer == 11) + { + offsetChannelBlackLevel = save1 + (0x02d8 << 1); + offsetWhiteLevels = save1 + (0x02dc << 1); + } + break; + + // 5DS / 5DS R / 80D / 1300D / 1500D / 3000D / 5D4 / 800D / 77D / 6D II / + // 200D + case 1560: + case 1592: + case 1353: + case 1602: + // imCanon.ColorDataVer = 8; + imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x003f << 1), SEEK_SET); + FORC4 cam_mul[c ^ (c >> 1)] = (float)get2(); + // fseek(ifp, save1 + (0x0044 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0049 << 1), SEEK_SET); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = get2(); + + fseek(ifp, save1 + (0x0080 << 1), SEEK_SET); + FORC4 sraw_mul[c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0085 << 1), SEEK_SET); + // Canon_WBpresets(2, 12); + // fseek(ifp, save1 + (0x0107 << 1), SEEK_SET); + // Canon_WBCTpresets(0); // BCAT + + if (imCanon.ColorDataSubVer == 14) + { // 1300D / 1500D / 3000D + offsetChannelBlackLevel = save1 + (0x022c << 1); + offsetWhiteLevels = save1 + (0x0230 << 1); + } + else + { + offsetChannelBlackLevel = save1 + (0x030a << 1); + offsetWhiteLevels = save1 + (0x030e << 1); + } + break; + + case 1820: // M50, ColorDataSubVer 16 + case 1824: // EOS R, SX740HS, ColorDataSubVer 17 + case 1816: // EOS RP, SX70HS, ColorDataSubVer 18; + // EOS M6 Mark II, EOS 90D, G7XmkIII, ColorDataSubVer 19 + // imCanon.ColorDataVer = 9; + imCanon.ColorDataSubVer = get2(); + + fseek(ifp, save1 + (0x0047 << 1), SEEK_SET); + FORC4 cam_mul[c ^ (c >> 1)] = (float)get2(); + // get2(); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Auto][c ^ (c >> 1)] = get2(); + // get2(); + // FORC4 imgdata.color.WB_Coeffs[LIBRAW_WBI_Measured][c ^ (c >> 1)] = get2(); + // fseek(ifp, save1 + (0x0088 << 1), SEEK_SET); + // Canon_WBpresets(2, 12); + // fseek(ifp, save1 + (0x010a << 1), SEEK_SET); + // Canon_WBCTpresets(0); + offsetChannelBlackLevel = save1 + (0x0318 << 1); + offsetChannelBlackLevel2 = save1 + (0x0149 << 1); + offsetWhiteLevels = save1 + (0x031c << 1); + break; } - if (tag == 0x4021 && get4() && get4()) + + if (offsetChannelBlackLevel) + { + fseek(ifp, offsetChannelBlackLevel, SEEK_SET); + FORC4 + bls += (cblack/*imCanon.ChannelBlackLevel*/[c ^ (c >> 1)] = get2()); + imCanon.AverageBlackLevel = bls / 4; + // RT_blacklevel_from_constant = ThreeValBool::F; + } + if (offsetWhiteLevels) + { + if ((offsetWhiteLevels - offsetChannelBlackLevel) != 8L) + fseek(ifp, offsetWhiteLevels, SEEK_SET); + imCanon.NormalWhiteLevel = get2(); + imCanon.SpecularWhiteLevel = get2(); + // FORC4 + // imgdata.color.linear_max[c] = imCanon.SpecularWhiteLevel; + maximum = imCanon.SpecularWhiteLevel; + // RT_whitelevel_from_constant = ThreeValBool::F; + } + + if(!imCanon.AverageBlackLevel && offsetChannelBlackLevel2) + { + fseek(ifp, offsetChannelBlackLevel2, SEEK_SET); + FORC4 + bls += (cblack/*imCanon.ChannelBlackLevel*/[c ^ (c >> 1)] = get2()); + imCanon.AverageBlackLevel = bls / 4; + // RT_blacklevel_from_constant = ThreeValBool::F; + } + fseek(ifp, save1, SEEK_SET); + + //--------------------------------------------------------------------- + } if (tag == 0x4021 && get4() && get4()) FORC4 cam_mul[c] = 1024; if (tag == 0xa021) FORC4 cam_mul[c ^ (c >> 1)] = get4(); @@ -6683,7 +7015,8 @@ int CLASS parse_tiff (int base) void CLASS apply_tiff() { - int max_samp=0, ties=0, os, ns, raw=-1, thm=-1, i; + int max_samp=0, ties=0, /*os, ns,*/ raw=-1, thm=-1, i; + uint64_t os, ns; // RT struct jhead jh; thumb_misc = 16; @@ -6713,6 +7046,7 @@ void CLASS apply_tiff() } if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) && (tiff_ifd[i].width | tiff_ifd[i].height) < 0x10000 && + (unsigned)tiff_ifd[i].bps < 33 && (unsigned)tiff_ifd[i].samples < 13 && // RT ns && ((ns > os && (ties = 1)) || (ns == os && shot_select == ties++))) { raw_width = tiff_ifd[i].width; @@ -6780,7 +7114,7 @@ void CLASS apply_tiff() load_raw = &CLASS olympus_load_raw; // ------- RT ------- if (!strncmp(make,"SONY",4) && - !strncmp(model,"ILCE-7RM3",9) && + (!strncmp(model,"ILCE-7RM3",9) || !strncmp(model,"ILCE-7RM4",9)) && tiff_samples == 4 && tiff_ifd[raw].bytes == raw_width*raw_height*tiff_samples*2) { load_raw = &CLASS sony_arq_load_raw; @@ -9313,6 +9647,11 @@ void CLASS identify() parse_foveon(); else if (!memcmp (head,"CI",2)) parse_cine(); + //--- RT ---------------------------------------------------------------- + else if (!memcmp(head + 4, "ftypcrx ", 8)) { + parse_canon_cr3(); + } + //------------------------------------------------------------------------- if (make[0] == 0) for (zero_fsize=i=0; i < sizeof table / sizeof *table; i++) if (fsize == table[i].fsize) { diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index 3d753d876..0265219c7 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -68,6 +68,7 @@ public: 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; + RT_canon_CR3_data.CR3_CTMDtag = 0; } protected: @@ -164,6 +165,35 @@ protected: PanasonicRW2Info(): bpp(0), encoding(0) {} }; PanasonicRW2Info RT_pana_info; +public: + struct CanonCR3Data { + // contents of tag CMP1 for relevant track in CR3 file + struct crx_data_header_t { + int32_t version; + int32_t f_width; + int32_t f_height; + int32_t tileWidth; + int32_t tileHeight; + int32_t nBits; + int32_t nPlanes; + int32_t cfaLayout; + int32_t encType; + int32_t imageLevels; + int32_t hasTileCols; + int32_t hasTileRows; + int32_t mdatHdrSize; + // Not from header, but from datastream + uint32_t MediaSize; + INT64 MediaOffset; + uint32_t MediaType; /* 1 -> /C/RAW, 2-> JPEG */ + }; + static constexpr size_t CRXTRACKS_MAXCOUNT = 16; + crx_data_header_t crx_header[CRXTRACKS_MAXCOUNT]; + int crx_track_selected; + short CR3_CTMDtag; + }; +protected: + CanonCR3Data RT_canon_CR3_data; float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4]; @@ -529,4 +559,20 @@ void shiftXtransMatrix( const int offsy, const int offsx) { void nikon_14bit_load_raw(); // ported from LibRaw +//----------------------------------------------------------------------------- +// Canon CR3 support ported from LibRaw +//----------------------------------------------------------------------------- +void parse_canon_cr3(); +void selectCRXTrack(short maxTrack); +int parseCR3(unsigned long long oAtomList, + unsigned long long szAtomList, short &nesting, + char *AtomNameStack, short &nTrack, short &TrackType); +int crxDecodePlane(void *p, uint32_t planeNumber); +void crxLoadDecodeLoop(void *img, int nPlanes); +void crxConvertPlaneLineDf(void *p, int imageRow); +void crxLoadFinalizeLoopE3(void *p, int planeHeight); +void crxLoadRaw(); +int crxParseImageHeader(uchar *cmp1TagData, int nTrack); +//----------------------------------------------------------------------------- + }; diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index edaa94d5d..1432fd726 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -196,18 +196,8 @@ void Crop::update(int todo) params.dirpyrDenoise.getCurves(noiseLCurve, noiseCCurve); - int tilesize; - int overlap; - - if (settings->leveldnti == 0) { - tilesize = 1024; - overlap = 128; - } - - if (settings->leveldnti == 1) { - tilesize = 768; - overlap = 96; - } + const int tilesize = settings->leveldnti == 0 ? 1024 : 768; + const int overlap = settings->leveldnti == 0 ? 128 : 96; int numtiles_W, numtiles_H, tilewidth, tileheight, tileWskip, tileHskip; diff --git a/rtengine/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc index b5839ee8b..69d1a189a 100644 --- a/rtengine/dual_demosaic_RT.cc +++ b/rtengine/dual_demosaic_RT.cc @@ -66,14 +66,9 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const procparams::RAWParams return; } - array2D redTmp(winw, winh); - array2D greenTmp(winw, winh); - array2D blueTmp(winw, winh); array2D L(winw, winh); if (isBayer) { - vng4_demosaic(rawData, redTmp, greenTmp, blueTmp); - if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::AMAZEVNG4) || raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::PIXELSHIFT)) { amaze_demosaic_RT(0, 0, winw, winh, rawData, red, green, blue, options.chunkSizeAMAZE, options.measure); } else if (raw.bayersensor.method == procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::DCBVNG4) ) { @@ -87,7 +82,6 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const procparams::RAWParams } else { xtrans_interpolate (1, false, options.chunkSizeXT, options.measure); } - fast_xtrans_interpolate(rawData, redTmp, greenTmp, blueTmp); } const float xyz_rgb[3][3] = { // XYZ from RGB @@ -114,6 +108,17 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const procparams::RAWParams buildBlendMask(L, blend, winw, winh, contrastf, 1.f, autoContrast); contrast = contrastf * 100.f; + array2D& redTmp = L; // L is not needed anymore => reuse it + array2D greenTmp(winw, winh); + array2D blueTmp(winw, winh); + + if (isBayer) { + vng4_demosaic(rawData, redTmp, greenTmp, blueTmp); + } else { + fast_xtrans_interpolate(rawData, redTmp, greenTmp, blueTmp); + } + + // the following is split into 3 loops intentionally to avoid cache conflicts on CPUs with only 4-way cache #ifdef _OPENMP #pragma omp parallel for diff --git a/rtengine/guidedfilter.h b/rtengine/guidedfilter.h index d66396c6a..2d8b70369 100644 --- a/rtengine/guidedfilter.h +++ b/rtengine/guidedfilter.h @@ -20,11 +20,12 @@ #pragma once -#include "array2D.h" +template class array2D; namespace rtengine { + void guidedFilter(const array2D &guide, const array2D &src, array2D &dst, int r, float epsilon, bool multithread, int subsampling=0); } // namespace rtengine diff --git a/rtengine/image8.cc b/rtengine/image8.cc index 3d0a8df06..66ad8b60f 100644 --- a/rtengine/image8.cc +++ b/rtengine/image8.cc @@ -233,10 +233,10 @@ void Image8::getStdImage (const ColorTemp &ctemp, int tran, Imagefloat* image, P lineB[dst_x] = CLIP(bm * btot); } else { // computing a special factor for this incomplete sub-region - float area = src_sub_width * src_sub_height; - lineR[dst_x] = CLIP(rm2 * rtot / area); - lineG[dst_x] = CLIP(gm2 * gtot / area); - lineB[dst_x] = CLIP(bm2 * btot / area); + float larea = src_sub_width * src_sub_height; + lineR[dst_x] = CLIP(rm2 * rtot / larea); + lineG[dst_x] = CLIP(gm2 * gtot / larea); + lineB[dst_x] = CLIP(bm2 * btot / larea); } } } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 6cec71006..a9f7135a6 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -231,9 +231,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) MyMutex::MyLock processingLock(mProcessing); - constexpr int numofphases = 14; - int readyphase = 0; - bool highDetailNeeded = options.prevdemo == PD_Sidecar ? true : (todo & M_HIGHQUAL); // Check if any detail crops need high detail. If not, take a fast path short cut @@ -274,8 +271,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) //rp.deadPixelFilter = rp.hotPixelFilter = false; } - progress("Applying white balance, color correction & sRGB conversion...", 100 * readyphase / numofphases); - if (frameCountListener) { frameCountListener->FrameCountChanged(imgsrc->getFrameCount(), params->raw.bayersensor.imageNum); } @@ -539,8 +534,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) ipf.firstAnalysis(orig_prev, *params, vhist16); } - readyphase++; - if ((todo & M_HDR) && (params->fattal.enabled || params->dehaze.enabled)) { if (fattal_11_dcrop_cache) { delete fattal_11_dcrop_cache; @@ -557,7 +550,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) oprevi = orig_prev; - progress("Rotate / Distortion...", 100 * readyphase / numofphases); // Remove transformation if unneeded bool needstransform = ipf.needsTransform(); @@ -583,11 +575,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) ipf.lab2rgb(labcbdl, *oprevi, params->icm.workingProfile); } - readyphase++; - progress("Preparing shadow/highlight map...", 100 * readyphase / numofphases); - - readyphase++; - if (todo & M_AUTOEXP) { if (params->toneCurve.autoexp) { LUTu aehist; @@ -624,8 +611,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } - progress("Exposure curve & CIELAB conversion...", 100 * readyphase / numofphases); - if (todo & (M_AUTOEXP | M_RGBCURVE)) { if (params->icm.workingTRC == "Custom") { //exec TRC IN free if (oprevi == orig_prev) { @@ -777,8 +762,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); } - readyphase++; - if (todo & (M_LUMACURVE | M_CROP)) { LUTu lhist16(32768); lhist16.clear(); @@ -821,8 +804,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (todo & (M_LUMINANCE + M_COLOR)) { nprevl->CopyFrom(oprevl); - progress("Applying Color Boost...", 100 * readyphase / numofphases); - histCCurve.clear(); histLCurve.clear(); ipf.chromiLuminanceCurve(nullptr, pW, nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, histCCurve, histLCurve); @@ -833,68 +814,20 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) ipf.EPDToneMap(nprevl, 0, scale); } - // for all treatments Defringe, Sharpening, Contrast detail , Microcontrast they are activated if "CIECAM" function are disabled - readyphase++; - - /* Issue 2785, disabled some 1:1 tools - if (scale==1) { - if((params->colorappearance.enabled && !settings->autocielab) || (!params->colorappearance.enabled)){ - progress ("Denoising luminance impulse...",100*readyphase/numofphases); - ipf.impulsedenoise (nprevl); - readyphase++; - } - if((params->colorappearance.enabled && !settings->autocielab) || (!params->colorappearance.enabled)){ - progress ("Defringing...",100*readyphase/numofphases); - ipf.defringe (nprevl); - readyphase++; - } - if (params->sharpenEdge.enabled) { - progress ("Edge sharpening...",100*readyphase/numofphases); - ipf.MLsharpen (nprevl); - readyphase++; - } - if (params->sharpenMicro.enabled) { - if(( params->colorappearance.enabled && !settings->autocielab) || (!params->colorappearance.enabled)){ - progress ("Microcontrast...",100*readyphase/numofphases); - ipf.MLmicrocontrast (nprevl); - readyphase++; - } - } - if(((params->colorappearance.enabled && !settings->autocielab) || (!params->colorappearance.enabled)) && params->sharpening.enabled) { - progress ("Sharpening...",100*readyphase/numofphases); - - float **buffer = new float*[pH]; - for (int i=0; idirpyrequalizer.cbdlMethod == "aft") { if (((params->colorappearance.enabled && !settings->autocielab) || (!params->colorappearance.enabled))) { - progress("Pyramid wavelet...", 100 * readyphase / numofphases); ipf.dirpyrequalizer(nprevl, scale); - //ipf.Lanczoslab (ip_wavelet(LabImage * lab, LabImage * dst, const procparams::EqualizerParams & eqparams), nprevl, 1.f/scale); - readyphase++; } } wavcontlutili = false; - //CurveFactory::curveWavContL ( wavcontlutili,params->wavelet.lcurve, wavclCurve, LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,int skip); CurveFactory::curveWavContL(wavcontlutili, params->wavelet.wavclCurve, wavclCurve, scale == 1 ? 1 : 16); if ((params->wavelet.enabled)) { WaveletParams WaveParams = params->wavelet; WaveParams.getCurves(wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); int kall = 0; - progress("Wavelet...", 100 * readyphase / numofphases); LabImage *unshar = nullptr; Glib::ustring provis; LabImage *provradius = nullptr; @@ -1109,7 +1042,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) ipf.softLight(nprevl); if (params->colorappearance.enabled) { - //L histo and Chroma histo for ciecam + // L histo and Chroma histo for ciecam // histogram well be for Lab (Lch) values, because very difficult to do with J,Q, M, s, C int x1, y1, x2, y2; params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); @@ -1190,8 +1123,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (params->colorappearance.autoybscen && acListener && params->colorappearance.enabled) { acListener->ybCamChanged((int) yb); //real value Yb scene } - - readyphase++; } else { // CIECAM is disabled, we free up its image buffer to save some space if (ncie) { @@ -1226,8 +1157,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } if (panningRelatedChange || (todo & M_MONITOR)) { - progress("Conversion to RGB...", 100 * readyphase / numofphases); - if ((todo != CROP && todo != MINUPDATE) || (todo & M_MONITOR)) { MyMutex::MyLock prevImgLock(previmg->getMutex()); @@ -1239,7 +1168,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) delete workimg; workimg = ipf.lab2rgb(nprevl, 0, 0, pW, pH, params->icm); } catch (char * str) { - progress("Error converting file...", 0); return; } } @@ -1258,8 +1186,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) imageListener->imageReady(params->crop); } - readyphase++; - if (hListener) { updateLRGBHistograms(); hListener->histogramChanged(histRed, histGreen, histBlue, histLuma, histToneCurve, histLCurve, histCCurve, /*histCLurve, histLLCurve,*/ histLCAM, histCCAM, histRedRaw, histGreenRaw, histBlueRaw, histChroma, histLRETI); @@ -1423,15 +1349,6 @@ void ImProcCoordinator::updateLRGBHistograms() } -void ImProcCoordinator::progress(Glib::ustring str, int pr) -{ - - /* if (plistener) { - plistener->setProgressStr (str); - plistener->setProgress ((double)pr / 100.0); - }*/ -} - bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, double tempBias) { diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index c27cfe76e..96d1f80ce 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -186,7 +186,6 @@ protected: MyMutex minit; // to gain mutually exclusive access to ... to what exactly? - void progress (Glib::ustring str, int pr); void reallocAll (); void updateLRGBHistograms (); void setScale (int prevscale); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 58258076d..f33c1c2c9 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -869,7 +869,9 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw mean = (sum / ((height) * width)) / 327.68f; //for Yb for all image...if one day "pipette" we can adapt Yb for each zone } } - +#ifdef _OPENMP + static_cast(numThreads); // to silence cppcheck warning +#endif //evaluate lightness, contrast } @@ -1469,8 +1471,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw if (ciedata) { //only with improccoordinator // Data for J Q M s and C histograms int posl, posc; - float brli = 327.f; - float chsacol = 327.f; + float brli; + float chsacol; float libr; float colch; @@ -2049,17 +2051,25 @@ filmlike_clip (float *r, float *g, float *b) } } -void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, - int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clToningcurve, LUTf & cl2Toningcurve, - const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfileApplyState &asIn, LUTu &histToneCurve, size_t chunkSize, bool measure) +void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, + int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, + const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, + const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, + double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfileApplyState& asIn, + LUTu& histToneCurve, size_t chunkSize, bool measure) { - rgbProc (working, lab, pipetteBuffer, hltonecurve, shtonecurve, tonecurve, sat, rCurve, gCurve, bCurve, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, dcpProf, asIn, histToneCurve, chunkSize, measure); + rgbProc(working, lab, pipetteBuffer, hltonecurve, shtonecurve, tonecurve, sat, rCurve, gCurve, bCurve, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, + clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, + params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, dcpProf, asIn, histToneCurve, chunkSize, measure); } // Process RGB image and convert to LAB space -void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, - int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clToningcurve, LUTf & cl2Toningcurve, - const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf, const DCPProfileApplyState &asIn, LUTu &histToneCurve, size_t chunkSize, bool measure) +void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, + int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, + const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, + const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, + double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, + DCPProfile *dcpProf, const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize, bool measure) { std::unique_ptr stop; @@ -3759,10 +3769,9 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go, float rlo; //0.4 0.5 float rlm; //1.1 float rlh; //1.1 - float rlob; //for BW old mode if (mode == 0) { //colour - rlo = rlob = strProtect; //0.5 ==> 0.75 + rlo = strProtect; //0.5 ==> 0.75 rlh = 2.2f * strProtect; rlm = 1.5f * strProtect; constexpr float v0 = 0.15f; @@ -3779,7 +3788,6 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go, } } else { //bw coefficient to preserve same results as before for satlimtopacity = 0.5 (default) rlo = strProtect * 0.8f; //0.4 - rlob = strProtect; //0.5 rlm = strProtect * 2.2f; //1.1 rlh = strProtect * 2.4f; //1.2 if (v > 0.15f) { @@ -4081,7 +4089,7 @@ void ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &g * @param iplow iphigh [0..1] luminance * @param wp wip 3x3 matrix and inverse conversion rgb XYZ **/ -void ImProcFunctions::labtoning (float r, float g, float b, float &ro, float &go, float &bo, int algm, int metchrom, int twoc, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, LUTf & clToningcurve, LUTf & cl2Toningcurve, float iplow, float iphigh, double wp[3][3], double wip[3][3] ) +void ImProcFunctions::labtoning (float r, float g, float b, float &ro, float &go, float &bo, int algm, int metchrom, int twoc, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, const LUTf & clToningcurve, const LUTf & cl2Toningcurve, float iplow, float iphigh, double wp[3][3], double wip[3][3] ) { ro = CLIP(r); go = CLIP(g); @@ -4140,7 +4148,7 @@ void ImProcFunctions::labtoning (float r, float g, float b, float &ro, float &go } -void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, LUTf & curve) +void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, const LUTf& curve) { int W = lold->W; @@ -4160,7 +4168,7 @@ void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, LUTf & cur -void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW, LabImage* lold, LabImage* lnew, LUTf & acurve, LUTf & bcurve, LUTf & satcurve, LUTf & lhskcurve, LUTf & clcurve, LUTf & curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histLCurve) +void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW, LabImage* lold, LabImage* lnew, const LUTf& acurve, const LUTf& bcurve, const LUTf& satcurve, const LUTf& lhskcurve, const LUTf& clcurve, LUTf & curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histLCurve) { int W = lold->W; @@ -5354,7 +5362,7 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double int imax = 65536 >> histcompr; int overex = 0; float sum = 0.f, hisum = 0.f, losum = 0.f; - float ave = 0.f, hidev = 0.f, lodev = 0.f; + float ave = 0.f; //find average luminance histogram.getSumAndAverage (sum, ave); @@ -5382,36 +5390,32 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double float octile[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}, ospread = 0.f; count = 0; - int i = 0; + int j = 0; - for (; i < min ((int)ave, imax); i++) { + for (; j < min ((int)ave, imax); ++j) { if (count < 8) { - octile[count] += histogram[i]; + octile[count] += histogram[j]; if (octile[count] > sum / 8.f || (count == 7 && octile[count] > sum / 16.f)) { - octile[count] = xlog (1. + (float)i) / log (2.f); + octile[count] = xlog (1. + j) / log (2.f); count++;// = min(count+1,7); } } - //lodev += SQR(ave-i)*histogram[i]; - lodev += (xlog (ave + 1.f) - xlog ((float)i + 1.)) * histogram[i]; - losum += histogram[i]; + losum += histogram[j]; } - for (; i < imax; i++) { + for (; j < imax; ++j) { if (count < 8) { - octile[count] += histogram[i]; + octile[count] += histogram[j]; if (octile[count] > sum / 8.f || (count == 7 && octile[count] > sum / 16.f)) { - octile[count] = xlog (1. + (float)i) / log (2.f); + octile[count] = xlog (1. + j) / log (2.f); count++;// = min(count+1,7); } } - //hidev += SQR(i-ave)*histogram[i]; - hidev += (xlog ((float)i + 1.) - xlog (ave + 1.f)) * histogram[i]; - hisum += histogram[i]; + hisum += histogram[j]; } diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 145639f57..93d582547 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -23,7 +23,6 @@ #include "coord2d.h" #include "gamutwarning.h" #include "pipettebuffer.h" -#include "shmap.h" template class LUT; @@ -125,14 +124,19 @@ public: void firstAnalysis(const Imagefloat* const working, const procparams::ProcParams ¶ms, LUTu & vhist16); void updateColorProfiles(const Glib::ustring& monitorProfile, RenderingIntent monitorIntent, bool softProof, bool gamutCheck); - void rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, - int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clcurve, LUTf & cl2curve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, - const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfileApplyState &asIn, LUTu &histToneCurve, size_t chunkSize = 1, bool measure = false); - void rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, - int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clcurve, LUTf & cl2curve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, - const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, - double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf, const DCPProfileApplyState &asIn, LUTu &histToneCurve, size_t chunkSize = 1, bool measure = false); - void labtoning(float r, float g, float b, float &ro, float &go, float &bo, int algm, int metchrom, int twoc, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, LUTf & clToningcurve, LUTf & cl2Toningcurve, float iplow, float iphigh, double wp[3][3], double wip[3][3]); + void rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, + int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve& ctColorCurve, + const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clcurve, const LUTf& cl2curve, const ToneCurve& customToneCurve1, + const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, + double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, + const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize = 1, bool measure = false); + void rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, + int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve& ctColorCurve, + const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clcurve, const LUTf& cl2curve, const ToneCurve& customToneCurve1, + const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, + double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, + int hlcomprthresh, DCPProfile *dcpProf, const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize = 1, bool measure = false); + void labtoning(float r, float g, float b, float &ro, float &go, float &bo, int algm, int metchrom, int twoc, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, const LUTf & clToningcurve, const LUTf & cl2Toningcurve, float iplow, float iphigh, double wp[3][3], double wip[3][3]); void toning2col(float r, float g, float b, float &ro, float &go, float &bo, float iplow, float iphigh, float rl, float gl, float bl, float rh, float gh, float bh, float SatLow, float SatHigh, float balanS, float balanH, float reducac, int mode, int preser, float strProtect); void toningsmh(float r, float g, float b, float &ro, float &go, float &bo, float RedLow, float GreenLow, float BlueLow, float RedMed, float GreenMed, float BlueMed, float RedHigh, float GreenHigh, float BlueHigh, float reducac, int mode, float strProtect); void toningsmh2(float r, float g, float b, float &ro, float &go, float &bo, float low[3], float satLow, float med[3], float satMed, float high[3], float satHigh, float reducac, int mode, int preser); @@ -142,12 +146,12 @@ public: void retreavergb(float &r, float &g, float &b); void moyeqt(Imagefloat* working, float &moyS, float &eqty); - void luminanceCurve(LabImage* lold, LabImage* lnew, LUTf &curve); + void luminanceCurve(LabImage* lold, LabImage* lnew, const LUTf &curve); void ciecam_02float(CieImage* ncie, float adap, int pW, int pwb, LabImage* lab, const procparams::ProcParams* params, const ColorAppearance & customColCurve1, const ColorAppearance & customColCurve, const ColorAppearance & customColCurve3, LUTu &histLCAM, LUTu &histCCAM, LUTf & CAMBrightCurveJ, LUTf & CAMBrightCurveQ, float &mean, int Iterates, int scale, bool execsharp, float &d, float &dj, float &yb, int rtt, bool showSharpMask = false); - void chromiLuminanceCurve(PipetteBuffer *pipetteBuffer, int pW, LabImage* lold, LabImage* lnew, LUTf &acurve, LUTf &bcurve, LUTf & satcurve, LUTf & satclcurve, LUTf &clcurve, LUTf &curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histLurve); + void chromiLuminanceCurve(PipetteBuffer *pipetteBuffer, int pW, LabImage* lold, LabImage* lnew, const LUTf& acurve, const LUTf& bcurve, const LUTf& satcurve, const LUTf& satclcurve, const LUTf& clcurve, LUTf &curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histLurve); void vibrance(LabImage* lab); //Jacques' vibrance // void colorCurve (LabImage* lold, LabImage* lnew); void sharpening(LabImage* lab, const procparams::SharpeningParams &sharpenParam, bool showMask = false); diff --git a/rtengine/iplabregions.cc b/rtengine/iplabregions.cc index 1768101c8..6526419f5 100644 --- a/rtengine/iplabregions.cc +++ b/rtengine/iplabregions.cc @@ -18,6 +18,7 @@ * along with RawTherapee. If not, see . */ +#include "array2D.h" #include "color.h" #include "curves.h" #include "guidedfilter.h" diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index b5d504a99..84f33482f 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -51,6 +51,7 @@ #include "procparams.h" #include "rawimagesource.h" #include "rtengine.h" +#include "shmap.h" #include "StopWatch.h" namespace diff --git a/rtengine/ipshadowshighlights.cc b/rtengine/ipshadowshighlights.cc index ae1fbadfa..f6656fbef 100644 --- a/rtengine/ipshadowshighlights.cc +++ b/rtengine/ipshadowshighlights.cc @@ -20,6 +20,7 @@ #include "improcfun.h" +#include "array2D.h" #include "color.h" #include "curves.h" #include "gauss.h" diff --git a/rtengine/iptransform.cc b/rtengine/iptransform.cc index a4f304413..b1531cc9c 100644 --- a/rtengine/iptransform.cc +++ b/rtengine/iptransform.cc @@ -220,7 +220,7 @@ bool ImProcFunctions::transCoord (int W, int H, const std::vector &src, blue.push_back (Coord2D (src[i].x, src[i].y)); } - return clipped; + return false; } double oW = W, oH = H; diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index 2c6d62844..f45b21f28 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -1205,7 +1205,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const b = 327.68f * Chprov * sincosv.x; //aply Munsell } else {//general case L = labco->L[i1][j1]; - const float Lin = labco->L[i1][j1]; + const float Lin = std::max(0.f, L); if (wavclCurve && cp.finena) { labco->L[i1][j1] = (0.5f * Lin + 1.5f * wavclCurve[Lin]) / 2.f; //apply contrast curve diff --git a/rtengine/lcp.cc b/rtengine/lcp.cc index 57a87c1f1..7fec79717 100644 --- a/rtengine/lcp.cc +++ b/rtengine/lcp.cc @@ -27,7 +27,6 @@ #ifdef WIN32 #include -#include #endif #include "lcp.h" diff --git a/rtengine/mytime.h b/rtengine/mytime.h index 80fb0899a..787fefcc3 100644 --- a/rtengine/mytime.h +++ b/rtengine/mytime.h @@ -19,7 +19,7 @@ #pragma once #ifdef WIN32 -#include +#include #elif defined __APPLE__ #include #else diff --git a/rtengine/panasonic_decoders.cc b/rtengine/panasonic_decoders.cc index 37f586a6b..bbbfb7c20 100644 --- a/rtengine/panasonic_decoders.cc +++ b/rtengine/panasonic_decoders.cc @@ -64,7 +64,7 @@ class pana_cs6_page_decoder unsigned char current, *buffer; public: pana_cs6_page_decoder(unsigned char *_buffer, unsigned int bsize) - : lastoffset(0), maxoffset(bsize), current(0), buffer(_buffer) + : pixelbuffer{}, lastoffset(0), maxoffset(bsize), current(0), buffer(_buffer) { } void read_page(); // will throw IO error if not enough space in buffer diff --git a/rtengine/pdaflinesfilter.cc b/rtengine/pdaflinesfilter.cc index 8ac0d3091..1eddbc1ea 100644 --- a/rtengine/pdaflinesfilter.cc +++ b/rtengine/pdaflinesfilter.cc @@ -206,7 +206,7 @@ std::unique_ptr PDAFLinesFilter::lineD } -int PDAFLinesFilter::markLine(array2D &rawData, PixelsMap &bpMap, int y) +int PDAFLinesFilter::markLine(const array2D &rawData, PixelsMap &bpMap, int y) { rowmap_.clear(); rowmap_.resize((W_+1)/2, false); @@ -258,7 +258,7 @@ int PDAFLinesFilter::markLine(array2D &rawData, PixelsMap &bpMap, int y) } -int PDAFLinesFilter::mark(array2D &rawData, PixelsMap &bpMap) +int PDAFLinesFilter::mark(const array2D &rawData, PixelsMap &bpMap) { if (pattern_.empty()) { diff --git a/rtengine/pdaflinesfilter.h b/rtengine/pdaflinesfilter.h index c3d8b47f4..707eb9371 100644 --- a/rtengine/pdaflinesfilter.h +++ b/rtengine/pdaflinesfilter.h @@ -36,12 +36,12 @@ public: explicit PDAFLinesFilter(RawImage *ri); ~PDAFLinesFilter(); - int mark(array2D &rawData, PixelsMap &bpMap); + int mark(const array2D &rawData, PixelsMap &bpMap); RawImageSource::GreenEqulibrateThreshold &greenEqThreshold(); std::unique_ptr lineDenoiseRowBlender(); private: - int markLine(array2D &rawData, PixelsMap &bpMap, int y); + int markLine(const array2D& rawData, PixelsMap &bpMap, int y); RawImage *ri_; int W_; diff --git a/rtengine/pipettebuffer.h b/rtengine/pipettebuffer.h index 79b6dd8c5..6f017a196 100644 --- a/rtengine/pipettebuffer.h +++ b/rtengine/pipettebuffer.h @@ -18,7 +18,6 @@ */ #pragma once -#include "array2D.h" #include "iimage.h" class EditDataProvider; diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index ff529697b..2e98b7b22 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -339,6 +339,8 @@ BENCHFUN lmmse_interpolate_omp(winw, winh, *(rawDataFrames[0]), red, green, blue, bayerParams.lmmse_iterations); } else if (bayerParams.pixelShiftDemosaicMethod == bayerParams.getPSDemosaicMethodString(procparams::RAWParams::BayerSensor::PSDemosaicMethod::AMAZEVNG4)) { dual_demosaic_RT (true, rawParamsIn, winw, winh, *(rawDataFrames[0]), red, green, blue, bayerParams.dualDemosaicContrast, true); + } else if (bayerParams.pixelShiftDemosaicMethod == bayerParams.getPSDemosaicMethodString(procparams::RAWParams::BayerSensor::PSDemosaicMethod::RCDVNG4)) { + dual_demosaic_RT (true, rawParamsIn, winw, winh, *(rawDataFrames[0]), red, green, blue, bayerParams.dualDemosaicContrast, true); } else { amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[0]), red, green, blue, options.chunkSizeAMAZE, options.measure); } @@ -351,6 +353,8 @@ BENCHFUN lmmse_interpolate_omp(winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i], bayerParams.lmmse_iterations); } else if (bayerParams.pixelShiftDemosaicMethod == bayerParams.getPSDemosaicMethodString(procparams::RAWParams::BayerSensor::PSDemosaicMethod::AMAZEVNG4)) { dual_demosaic_RT (true, rawParamsIn, winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i], bayerParams.dualDemosaicContrast, true); + } else if (bayerParams.pixelShiftDemosaicMethod == bayerParams.getPSDemosaicMethodString(procparams::RAWParams::BayerSensor::PSDemosaicMethod::RCDVNG4)) { + dual_demosaic_RT (true, rawParamsIn, winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i], bayerParams.dualDemosaicContrast, true); } else { amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i], options.chunkSizeAMAZE, options.measure); } @@ -380,6 +384,10 @@ BENCHFUN procparams::RAWParams rawParamsTmp = rawParamsIn; rawParamsTmp.bayersensor.method = procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::AMAZEVNG4); dual_demosaic_RT (true, rawParamsTmp, winw, winh, rawData, red, green, blue, bayerParams.dualDemosaicContrast, true); + } else if (bayerParams.pixelShiftDemosaicMethod == bayerParams.getPSDemosaicMethodString(procparams::RAWParams::BayerSensor::PSDemosaicMethod::RCDVNG4)) { + procparams::RAWParams rawParamsTmp = rawParamsIn; + rawParamsTmp.bayersensor.method = procparams::RAWParams::BayerSensor::getMethodString(procparams::RAWParams::BayerSensor::Method::RCDVNG4); + dual_demosaic_RT (true, rawParamsTmp, winw, winh, rawData, red, green, blue, bayerParams.dualDemosaicContrast, true); } else { amaze_demosaic_RT(winx, winy, winw, winh, rawData, red, green, blue, options.chunkSizeAMAZE, options.measure); } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index c1d4a9605..f92b40191 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2692,6 +2692,7 @@ const std::vector& RAWParams::BayerSensor::getPSDemosaicMethodStrin static const std::vector method_strings { "amaze", "amazevng4", + "rcdvng4", "lmmse" }; return method_strings; diff --git a/rtengine/procparams.h b/rtengine/procparams.h index d40a20074..839872e77 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1398,6 +1398,7 @@ struct RAWParams { enum class PSDemosaicMethod { AMAZE, AMAZEVNG4, + RCDVNG4, LMMSE }; diff --git a/rtengine/rtlensfun.cc b/rtengine/rtlensfun.cc index 665fbd199..7b959ce8b 100644 --- a/rtengine/rtlensfun.cc +++ b/rtengine/rtlensfun.cc @@ -500,6 +500,7 @@ std::unique_ptr LFDatabase::getModifier(const LFCamera &camera, cons return ret; } +std::set LFDatabase::notFound; std::unique_ptr LFDatabase::findModifier(const procparams::LensProfParams &lensProf, const FramesMetaData *idata, int width, int height, const procparams::CoarseTransformParams &coarse, int rawRotationDeg) { @@ -521,6 +522,11 @@ std::unique_ptr LFDatabase::findModifier(const procparams::LensProfP return nullptr; } + const std::string key = (make + model + lens).collate_key(); + if (notFound.find(key) != notFound.end()) { + // This combination was not found => do not search again + return nullptr; + } const LFDatabase *db = getInstance(); LFCamera c = db->findCamera(make, model); LFLens l = db->findLens(lensProf.lfAutoMatch() ? c : LFCamera(), lens); @@ -549,6 +555,10 @@ std::unique_ptr LFDatabase::findModifier(const procparams::LensProfP << (ret ? ret->getDisplayString() : "NONE") << std::endl; } + if (!ret) { + notFound.emplace(key); + } + return ret; } diff --git a/rtengine/rtlensfun.h b/rtengine/rtlensfun.h index 7dcd96007..573b93fca 100644 --- a/rtengine/rtlensfun.h +++ b/rtengine/rtlensfun.h @@ -21,6 +21,7 @@ #pragma once #include +#include #include #include @@ -135,6 +136,7 @@ private: mutable MyMutex lfDBMutex; static LFDatabase instance_; lfDatabase *data_; + static std::set notFound; }; } // namespace rtengine diff --git a/rtengine/shmap.cc b/rtengine/shmap.cc index 44096d965..abdcc42a4 100644 --- a/rtengine/shmap.cc +++ b/rtengine/shmap.cc @@ -351,7 +351,7 @@ void SHMap::forceStat (float max_, float min_, float avg_) avg = avg_; } -void SHMap::dirpyr_shmap(float ** data_fine, float ** data_coarse, int width, int height, LUTf & rangefn, int level, int scale) +void SHMap::dirpyr_shmap(float ** data_fine, float ** data_coarse, int width, int height, const LUTf& rangefn, int level, int scale) { //scale is spacing of directional averaging weights diff --git a/rtengine/shmap.h b/rtengine/shmap.h index 5373b8302..68e352b23 100644 --- a/rtengine/shmap.h +++ b/rtengine/shmap.h @@ -50,7 +50,7 @@ private: void fillLuminance( Imagefloat * img, float **luminance, double lumi[3] ); void fillLuminanceL( float ** L, float **luminance ); - void dirpyr_shmap(float ** data_fine, float ** data_coarse, int width, int height, LUTf & rangefn, int level, int scale); + void dirpyr_shmap(float ** data_fine, float ** data_coarse, int width, int height, const LUTf& rangefn, int level, int scale); }; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 88f24b7fd..1ed21aea0 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -810,17 +810,7 @@ private: void stage_denoise() { - procparams::ProcParams& params = job->pparams; - //ImProcFunctions ipf (¶ms, true); - ImProcFunctions &ipf = * (ipf_p.get()); - - // perform luma/chroma denoise -// CieImage *cieView; -// NoisCurve noiseLCurve; -// bool lldenoiseutili=false; -// Imagefloat *calclum ; -// params.dirpyrDenoise.getCurves(noiseLCurve, lldenoiseutili); -// if (params.dirpyrDenoise.enabled && lldenoiseutili) { + const procparams::ProcParams& params = job->pparams; DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise; // make a copy because we cheat here @@ -853,9 +843,7 @@ private: } if (denoiseParams.enabled) { - // CurveFactory::denoiseLL(lldenoiseutili, denoiseParams.lcurve, Noisecurve,1); - //denoiseParams.getCurves(noiseLCurve); -// ipf.RGB_denoise(baseImg, baseImg, calclum, imgsrc->isRAW(), denoiseParams, params.defringe, imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, lldenoiseutili); + ImProcFunctions &ipf = * (ipf_p.get()); float nresi, highresi; int kall = 2; ipf.RGB_denoise(kall, baseImg, baseImg, calclum, ch_M, max_r, max_b, imgsrc->isRAW(), denoiseParams, imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, noiseCCurve, nresi, highresi); @@ -877,7 +865,7 @@ private: void stage_transform() { - procparams::ProcParams& params = job->pparams; + const procparams::ProcParams& params = job->pparams; //ImProcFunctions ipf (¶ms, true); ImProcFunctions &ipf = * (ipf_p.get()); @@ -1095,13 +1083,10 @@ private: ipf.vibrance(labView); ipf.labColorCorrectionRegions(labView); - if ((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) { - ipf.impulsedenoise(labView); - } - // for all treatments Defringe, Sharpening, Contrast detail ,Microcontrast they are activated if "CIECAM" function are disabled if ((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) { + ipf.impulsedenoise (labView); ipf.defringe(labView); } diff --git a/rtgui/adjuster.cc b/rtgui/adjuster.cc index 302a2de00..2267a9fc1 100644 --- a/rtgui/adjuster.cc +++ b/rtgui/adjuster.cc @@ -246,7 +246,7 @@ void Adjuster::autoToggled () } if (adjusterListener != nullptr && !blocked) { - adjusterListener->adjusterAutoToggled(this, automatic->get_active()); + adjusterListener->adjusterAutoToggled(this); } } @@ -493,7 +493,7 @@ bool Adjuster::notifyListenerAutoToggled () { if (adjusterListener != nullptr && !blocked) { - adjusterListener->adjusterAutoToggled(this, automatic->get_active()); + adjusterListener->adjusterAutoToggled(this); } return false; diff --git a/rtgui/adjuster.h b/rtgui/adjuster.h index 9800dbac8..59250bc81 100644 --- a/rtgui/adjuster.h +++ b/rtgui/adjuster.h @@ -28,7 +28,7 @@ class AdjusterListener public: virtual ~AdjusterListener() = default; virtual void adjusterChanged (Adjuster* a, double newval) = 0; - virtual void adjusterAutoToggled (Adjuster* a, bool newval) {} + virtual void adjusterAutoToggled (Adjuster* a) {} }; typedef double(*double2double_fun)(double val); diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index afbec9efb..8b4583877 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -147,7 +147,7 @@ int BatchQueue::getThumbnailHeight () return std::max(std::min(options.thumbSizeQueue, 200), 10); } -void BatchQueue::rightClicked (ThumbBrowserEntryBase* entry) +void BatchQueue::rightClicked () { pmenu.popup (3, this->eventTime); } @@ -344,9 +344,8 @@ bool BatchQueue::loadBatchQueue () auto job = rtengine::ProcessingJob::create (source, thumb->getType () == FT_Raw, pparams, fast); - auto prevh = getMaxThumbnailHeight (); - auto prevw = prevh; - thumb->getThumbnailSize (prevw, prevh, &pparams); + const auto prevh = getMaxThumbnailHeight (); + const auto prevw = thumb->getThumbnailWidth(prevh, &pparams); auto entry = new BatchQueueEntry (job, pparams, source, prevw, prevh, thumb, options.overwriteOutputFile); thumb->decreaseRef (); // Removing the refCount acquired by cacheMgr->getEntry diff --git a/rtgui/batchqueue.h b/rtgui/batchqueue.h index f0289faa4..5cde37748 100644 --- a/rtgui/batchqueue.h +++ b/rtgui/batchqueue.h @@ -74,7 +74,7 @@ public: void error(const Glib::ustring& descr) override; rtengine::ProcessingJob* imageReady(rtengine::IImagefloat* img) override; - void rightClicked (ThumbBrowserEntryBase* entry) override; + void rightClicked () override; void doubleClicked (ThumbBrowserEntryBase* entry) override; bool keyPressed (GdkEventKey* event) override; void buttonPressed (LWButton* button, int actionCode, void* actionData) override; diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 9107aaaa8..f7a73a30b 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -18,7 +18,6 @@ */ #include "batchqueuepanel.h" #include "options.h" -#include "preferences.h" #include "multilangmgr.h" #include "rtwindow.h" #include "soundman.h" diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 4a57177e1..5b5cfe9c4 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -672,7 +672,7 @@ void BayerProcess::checkBoxToggled (CheckBox* c, CheckValue newval) } } -void BayerProcess::adjusterAutoToggled(Adjuster* a, bool newval) +void BayerProcess::adjusterAutoToggled(Adjuster* a) { if (multiImage) { if (dualDemosaicContrast->getAutoInconsistent()) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index 5c7498986..f8348e02b 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -88,7 +88,7 @@ public: void methodChanged(); void imageNumberChanged(); void adjusterChanged(Adjuster* a, double newval) override; - void adjusterAutoToggled (Adjuster* a, bool newval) override; + void adjusterAutoToggled (Adjuster* a) override; void checkBoxToggled(CheckBox* c, CheckValue newval) override; void pixelShiftMotionMethodChanged(); void pixelShiftDemosaicMethodChanged(); diff --git a/rtgui/cachemanager.cc b/rtgui/cachemanager.cc index 9f6e111e5..c37964e23 100644 --- a/rtgui/cachemanager.cc +++ b/rtgui/cachemanager.cc @@ -25,7 +25,7 @@ #include #ifdef WIN32 -#include +#include #endif #include "cachemanager.h" diff --git a/rtgui/colorappearance.cc b/rtgui/colorappearance.cc index 9a6bee524..62f6eee2c 100644 --- a/rtgui/colorappearance.cc +++ b/rtgui/colorappearance.cc @@ -1565,7 +1565,7 @@ void ColorAppearance::adjusterChanged(Adjuster* a, double newval) } } -void ColorAppearance::adjusterAutoToggled(Adjuster* a, bool newval) +void ColorAppearance::adjusterAutoToggled(Adjuster* a) { if (multiImage) { if (degree->getAutoInconsistent()) { diff --git a/rtgui/colorappearance.h b/rtgui/colorappearance.h index 170212ffe..c42bca774 100644 --- a/rtgui/colorappearance.h +++ b/rtgui/colorappearance.h @@ -47,7 +47,7 @@ public: void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; void setBatchMode (bool batchMode) override; void adjusterChanged (Adjuster* a, double newval) override; - void adjusterAutoToggled (Adjuster* a, bool newval) override; + void adjusterAutoToggled (Adjuster* a) override; // void adjusterAdapToggled (Adjuster* a, bool newval); void enabledChanged () override; void surroundChanged (); diff --git a/rtgui/crophandler.h b/rtgui/crophandler.h index d5da1cf6e..98c925b67 100644 --- a/rtgui/crophandler.h +++ b/rtgui/crophandler.h @@ -24,7 +24,6 @@ #include -#include "editbuffer.h" #include "lockablecolorpicker.h" #include "threadutils.h" diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index f44e78a56..b00032191 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -33,6 +33,7 @@ #include "editcallbacks.h" #include "editbuffer.h" #include "editwidgets.h" +#include "pointermotionlistener.h" #include "rtsurface.h" #include "../rtengine/dcrop.h" @@ -259,7 +260,7 @@ void CropWindow::getCropAnchorPosition (int& x, int& y) cropHandler.getAnchorPosition(x, y); } -void CropWindow::setCropAnchorPosition (int& x, int& y) +void CropWindow::setCropAnchorPosition (int x, int y) { cropHandler.setAnchorPosition(x, y); } diff --git a/rtgui/cropwindow.h b/rtgui/cropwindow.h index db44a2508..491124ad5 100644 --- a/rtgui/cropwindow.h +++ b/rtgui/cropwindow.h @@ -30,7 +30,6 @@ #include "editenums.h" #include "lwbutton.h" #include "lwbuttonset.h" -#include "pointermotionlistener.h" #include "../rtengine/noncopyable.h" @@ -42,6 +41,7 @@ struct Coord; } class CropWindow; +class PointerMotionListener; class CropWindowListener { @@ -224,7 +224,7 @@ public: void centerCrop (bool update = true); void getCropSize (int& w, int& h); void getCropAnchorPosition (int& w, int& h); - void setCropAnchorPosition (int& w, int& h); + void setCropAnchorPosition (int w, int h); // listeners void setCropGUIListener (CropGUIListener* cgl); diff --git a/rtgui/curveeditorgroup.h b/rtgui/curveeditorgroup.h index 7a5d3a074..5ef13656b 100644 --- a/rtgui/curveeditorgroup.h +++ b/rtgui/curveeditorgroup.h @@ -23,7 +23,6 @@ #include -#include "adjuster.h" #include "guiutils.h" #include "mycurve.h" #include "shcselector.h" diff --git a/rtgui/diagonalcurveeditorsubgroup.h b/rtgui/diagonalcurveeditorsubgroup.h index 184fa576f..a077da807 100644 --- a/rtgui/diagonalcurveeditorsubgroup.h +++ b/rtgui/diagonalcurveeditorsubgroup.h @@ -21,7 +21,7 @@ #include #include "curveeditorgroup.h" - +#include "adjuster.h" #include "../rtengine/noncopyable.h" class DiagonalCurveEditor; diff --git a/rtgui/dirbrowser.h b/rtgui/dirbrowser.h index fa526c3a6..6ead83919 100644 --- a/rtgui/dirbrowser.h +++ b/rtgui/dirbrowser.h @@ -23,10 +23,6 @@ #include "guiutils.h" -#ifdef WIN32 -#include "windows.h" -#endif - class DirBrowser : public Gtk::VBox { public: diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 87f4a0b94..1b5ed3fa7 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -28,9 +28,12 @@ #include "soundman.h" #include "rtimage.h" #include "rtwindow.h" +#include "filepanel.h" #include "guiutils.h" #include "popupbutton.h" #include "options.h" +#include "navigator.h" +#include "previewwindow.h" #include "progressconnector.h" #include "procparamchangers.h" #include "placesbrowser.h" @@ -38,6 +41,10 @@ #include "thumbnail.h" #include "toolpanelcoord.h" +#ifdef WIN32 +#include "windows.h" +#endif + using namespace rtengine::procparams; namespace diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index e348222a5..8993fea07 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -21,11 +21,9 @@ #include -#include "filepanel.h" #include "histogrampanel.h" #include "history.h" #include "imageareapanel.h" -#include "navigator.h" #include "profilepanel.h" #include "progressconnector.h" #include "saveasdlg.h" @@ -38,6 +36,7 @@ class BatchQueueEntry; class EditorPanel; class FilePanel; class MyProgressBar; +class Navigator; class Thumbnail; class ToolPanelCoordinator; diff --git a/rtgui/editwidgets.h b/rtgui/editwidgets.h index d31451ecb..55b4ca3cc 100644 --- a/rtgui/editwidgets.h +++ b/rtgui/editwidgets.h @@ -20,9 +20,9 @@ #ifdef GUIVERSION +#include #include -#include "editbuffer.h" #include "editcoordsys.h" #include "../rtengine/coord.h" @@ -285,7 +285,7 @@ public: rtengine::Coord end; Line (); - Line (rtengine::Coord& begin, rtengine::Coord& end); + Line (const rtengine::Coord& begin, const rtengine::Coord& end); Line (int beginX, int beginY, int endX, int endY); void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; @@ -532,7 +532,7 @@ inline Circle::Circle (int centerX, int centerY, int radius, bool filled, radiusInImageSpace) { } -inline Line::Line (rtengine::Coord& begin, rtengine::Coord& end) : +inline Line::Line (const rtengine::Coord& begin, const rtengine::Coord& end) : begin (begin), end (end) { } diff --git a/rtgui/editwindow.cc b/rtgui/editwindow.cc index 11c0be4e2..8841d3d42 100644 --- a/rtgui/editwindow.cc +++ b/rtgui/editwindow.cc @@ -16,13 +16,14 @@ */ #include "editwindow.h" +#include "editorpanel.h" +#include "filepanel.h" #include "../rtengine/procparams.h" #include "options.h" #include "preferences.h" #include "cursormanager.h" #include "rtwindow.h" #include -#include "rtimage.h" #include "threadutils.h" extern Glib::ustring argv0; diff --git a/rtgui/editwindow.h b/rtgui/editwindow.h index 08e8c0199..f4ada571d 100644 --- a/rtgui/editwindow.h +++ b/rtgui/editwindow.h @@ -20,10 +20,11 @@ #include -#include "editorpanel.h" -#include "filepanel.h" #include "rtimage.h" +class EditorPanel; +class RTWindow; + class EditWindow : public Gtk::Window { diff --git a/rtgui/exportpanel.h b/rtgui/exportpanel.h index f70e47386..7ae7e043c 100644 --- a/rtgui/exportpanel.h +++ b/rtgui/exportpanel.h @@ -21,7 +21,6 @@ #include -#include "adjuster.h" #include "guiutils.h" class ExportPanelListener diff --git a/rtgui/extprog.cc b/rtgui/extprog.cc index a7a757c1b..57d57ecd8 100644 --- a/rtgui/extprog.cc +++ b/rtgui/extprog.cc @@ -22,8 +22,8 @@ #include #ifdef WIN32 -#include #include +#include #endif #include @@ -145,20 +145,19 @@ bool ExtProgStore::searchProgram (const Glib::ustring& name, filePath = progFilesDir + "\\" + Glib::ustring::compose(exePath, ver); - if (Glib::file_test (filePath, Glib::FILE_TEST_EXISTS)) { + if (Glib::file_test(filePath, Glib::FILE_TEST_EXISTS)) { break; } - if (!exePath86.empty ()) { + if (!exePath86.empty()) { filePath = progFilesDirx86 + "\\" + Glib::ustring::compose(exePath86, ver); - if (Glib::file_test (filePath, Glib::FILE_TEST_EXISTS)) { + if (Glib::file_test(filePath, Glib::FILE_TEST_EXISTS)) { break; } } - - filePath.clear (); + filePath.clear(); } } else { @@ -166,21 +165,19 @@ bool ExtProgStore::searchProgram (const Glib::ustring& name, filePath = progFilesDir + "\\" + exePath; - if (Glib::file_test (filePath, Glib::FILE_TEST_EXISTS)) { + if (Glib::file_test(filePath, Glib::FILE_TEST_EXISTS)) { break; } - if (!exePath86.empty ()) { + if (!exePath86.empty()) { filePath = progFilesDirx86 + "\\" + exePath86; - if (Glib::file_test (filePath, Glib::FILE_TEST_EXISTS)) { + if (Glib::file_test(filePath, Glib::FILE_TEST_EXISTS)) { break; } } - - filePath.clear (); - + filePath.clear(); } while (false); } @@ -264,7 +261,7 @@ bool ExtProgStore::openInGimp (const Glib::ustring& fileName) #endif #ifdef WIN32 - if ((uintptr_t)success > 32) { + if (reinterpret_cast(success) > 32) { return true; } #else @@ -279,9 +276,9 @@ bool ExtProgStore::openInGimp (const Glib::ustring& fileName) for (auto ver = 12; ver >= 0; --ver) { executable = Glib::build_filename (options.gimpDir, "bin", Glib::ustring::compose (Glib::ustring("gimp-2.%1.exe"), ver)); - auto success = ShellExecute( NULL, "open", executable.c_str(), fileName.c_str(), NULL, SW_SHOWNORMAL ); + auto lsuccess = ShellExecute( NULL, "open", executable.c_str(), fileName.c_str(), NULL, SW_SHOWNORMAL ); - if ((uintptr_t)success > 32) { + if (reinterpret_cast(lsuccess) > 32) { return true; } } diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 3dcb573ca..caa60ebbc 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -90,41 +90,36 @@ ThumbBrowserEntryBase* selectOriginalEntry (ThumbBrowserEntryBase* original, Thu void findOriginalEntries (const std::vector& entries) { - typedef std::vector EntryVector; - typedef EntryVector::const_iterator EntryIterator; - typedef std::map BasenameMap; - typedef BasenameMap::const_iterator BasenameIterator; - // Sort all entries into buckets by basename without extension - BasenameMap byBasename; + std::map> byBasename; - for (EntryIterator entry = entries.begin (); entry != entries.end (); ++entry) { - const Glib::ustring basename = Glib::path_get_basename ((*entry)->filename.lowercase()); + for (const auto entry : entries) { + const auto basename = Glib::path_get_basename(entry->filename.lowercase()); - const Glib::ustring::size_type pos = basename.find_last_of ('.'); - if (pos >= basename.length () - 1) { - (*entry)->setOriginal (nullptr); + const auto pos = basename.find_last_of('.'); + if (pos >= basename.length() - 1) { + entry->setOriginal(nullptr); continue; } - const Glib::ustring withoutExtension = basename.substr (0, pos); + const auto withoutExtension = basename.substr(0, pos); - byBasename[withoutExtension].push_back (*entry); + byBasename[withoutExtension].push_back(entry); } // Find the original image for each bucket - for (BasenameIterator bucket = byBasename.begin (); bucket != byBasename.end (); ++bucket) { - const EntryVector& entries = bucket->second; + for (const auto& bucket : byBasename) { + const auto& lentries = bucket.second; ThumbBrowserEntryBase* original = nullptr; // Select the most likely original in a first pass... - for (EntryIterator entry = entries.begin (); entry != entries.end (); ++entry) { - original = selectOriginalEntry (original, *entry); + for (const auto entry : lentries) { + original = selectOriginalEntry(original, entry); } // ...and link all other images to it in a second pass. - for (EntryIterator entry = entries.begin (); entry != entries.end (); ++entry) { - (*entry)->setOriginal (*entry != original ? original : nullptr); + for (const auto entry : lentries) { + entry->setOriginal(entry != original ? original : nullptr); } } } @@ -487,7 +482,7 @@ FileBrowser::~FileBrowser () delete[] amiExtProg; } -void FileBrowser::rightClicked (ThumbBrowserEntryBase* entry) +void FileBrowser::rightClicked () { { diff --git a/rtgui/filebrowser.h b/rtgui/filebrowser.h index b941ea9df..86ab59395 100644 --- a/rtgui/filebrowser.h +++ b/rtgui/filebrowser.h @@ -23,7 +23,6 @@ #include #include "browserfilter.h" -#include "exiffiltersettings.h" #include "exportpanel.h" #include "extprog.h" #include "filebrowserentry.h" @@ -174,7 +173,7 @@ public: void buttonPressed (LWButton* button, int actionCode, void* actionData) override; void redrawNeeded (LWButton* button) override; bool checkFilter (ThumbBrowserEntryBase* entry) const override; - void rightClicked (ThumbBrowserEntryBase* entry) override; + void rightClicked () override; void doubleClicked (ThumbBrowserEntryBase* entry) override; bool keyPressed (GdkEventKey* event) override; diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc index 9da4044c1..3129e93e2 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -118,7 +118,7 @@ void FileBrowserEntry::calcThumbnailSize () { if (thumbnail) { - thumbnail->getThumbnailSize (prew, preh); + prew = thumbnail->getThumbnailWidth(preh); } } diff --git a/rtgui/filebrowserentry.h b/rtgui/filebrowserentry.h index 1bdbb2ecb..ea5140ed6 100644 --- a/rtgui/filebrowserentry.h +++ b/rtgui/filebrowserentry.h @@ -23,7 +23,6 @@ #include -#include "crophandler.h" #include "editenums.h" #include "filethumbnailbuttonset.h" #include "imageareatoollistener.h" diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index a2622e52c..109a1bb57 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -32,6 +32,7 @@ #include "rtimage.h" #include "cachemanager.h" #include "multilangmgr.h" +#include "coarsepanel.h" #include "filepanel.h" #include "renamedlg.h" #include "thumbimageupdater.h" @@ -40,6 +41,7 @@ #include "placesbrowser.h" #include "pathutils.h" #include "thumbnail.h" +#include "toolbar.h" using namespace std; @@ -1222,9 +1224,8 @@ void FileCatalog::developRequested(const std::vector& tbe, bo rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (fbe->filename, th->getType() == FT_Raw, params, fastmode && options.fastexport_use_fast_pipeline); - int pw; - int ph = BatchQueue::calcMaxThumbnailHeight(); - th->getThumbnailSize (pw, ph); + const int ph = BatchQueue::calcMaxThumbnailHeight(); + const int pw = th->getThumbnailWidth(ph); // processThumbImage is the processing intensive part, but adding to queue must be ordered //#pragma omp ordered diff --git a/rtgui/filecatalog.h b/rtgui/filecatalog.h index c71658cca..8f7e5618f 100644 --- a/rtgui/filecatalog.h +++ b/rtgui/filecatalog.h @@ -22,21 +22,21 @@ #include -#include "coarsepanel.h" #include "exiffiltersettings.h" #include "exportpanel.h" #include "filebrowser.h" #include "fileselectionchangelistener.h" #include "fileselectionlistener.h" #include "filterpanel.h" -#include "multilangmgr.h" #include "previewloader.h" #include "threadutils.h" -#include "toolbar.h" #include "../rtengine/noncopyable.h" class FilePanel; +class CoarsePanel; +class ToolBar; + /* * Class: * - handling the list of file (add/remove them) diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc index 8f45343de..1a66aed7c 100644 --- a/rtgui/filepanel.cc +++ b/rtgui/filepanel.cc @@ -18,6 +18,7 @@ */ #include "filepanel.h" +#include "dirbrowser.h" #include "batchtoolpanelcoord.h" #include "editorpanel.h" #include "rtwindow.h" @@ -25,6 +26,10 @@ #include "placesbrowser.h" #include "thumbnail.h" +#ifdef WIN32 +#include "windows.h" +#endif + FilePanel::FilePanel () : parent(nullptr), error(0) { diff --git a/rtgui/filepanel.h b/rtgui/filepanel.h index 9db9d99b7..cbfe8e53e 100644 --- a/rtgui/filepanel.h +++ b/rtgui/filepanel.h @@ -20,7 +20,6 @@ #include -#include "dirbrowser.h" #include "exportpanel.h" #include "filecatalog.h" #include "fileselectionlistener.h" @@ -35,6 +34,7 @@ class BatchToolPanelCoordinator; class RTWindow; +class DirBrowser; class FilePanel final : public Gtk::HPaned, diff --git a/rtgui/flatfield.cc b/rtgui/flatfield.cc index ff0c0f9dd..7433fd4de 100644 --- a/rtgui/flatfield.cc +++ b/rtgui/flatfield.cc @@ -252,7 +252,7 @@ void FlatField::adjusterChanged(Adjuster* a, double newval) } } -void FlatField::adjusterAutoToggled (Adjuster* a, bool newval) +void FlatField::adjusterAutoToggled (Adjuster* a) { if (multiImage) { if (flatFieldClipControl->getAutoInconsistent()) { diff --git a/rtgui/flatfield.h b/rtgui/flatfield.h index d20a96acd..5cbc49684 100644 --- a/rtgui/flatfield.h +++ b/rtgui/flatfield.h @@ -79,7 +79,7 @@ public: void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; void adjusterChanged (Adjuster* a, double newval) override; - void adjusterAutoToggled (Adjuster* a, bool newval) override; + void adjusterAutoToggled (Adjuster* a) override; void flatFieldFileChanged (); void flatFieldFile_Reset (); void flatFieldAutoSelectChanged (); diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index d6ede26da..02a28607f 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -946,22 +946,21 @@ bool MyScrolledWindow::on_scroll_event (GdkEventScroll* event) const double lowerBound = adjust->get_lower(); double value = adjust->get_value(); double step = adjust->get_step_increment(); - double value2 = 0.; if (event->direction == GDK_SCROLL_DOWN) { - value2 = rtengine::min(value + step, upperBound); + const double value2 = rtengine::min(value + step, upperBound); if (value2 != value) { scroll->set_value(value2); } } else if (event->direction == GDK_SCROLL_UP) { - value2 = rtengine::max(value - step, lowerBound); + const double value2 = rtengine::max(value - step, lowerBound); if (value2 != value) { scroll->set_value(value2); } } else if (event->direction == GDK_SCROLL_SMOOTH) { - value2 = rtengine::LIM(value + event->delta_y * step, lowerBound, upperBound); + const double value2 = rtengine::LIM(value + event->delta_y * step, lowerBound, upperBound); if (value2 != value) { scroll->set_value(value2); diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index ddf60ca75..dd0cbde46 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -983,7 +983,7 @@ void HistogramArea::on_realize () } void HistogramArea::drawCurve(Cairo::RefPtr &cr, - LUTu & data, double scale, int hsize, int vsize) + const LUTu & data, double scale, int hsize, int vsize) { double s = RTScalable::getScale(); @@ -1013,7 +1013,7 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, } void HistogramArea::drawMarks(Cairo::RefPtr &cr, - LUTu & data, double scale, int hsize, int & ui, int & oi) + const LUTu & data, double scale, int hsize, int & ui, int & oi) { int s = 8 * RTScalable::getScale(); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 23b065534..4fd21bcc2 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -165,8 +165,8 @@ public: type_signal_factor_changed signal_factor_changed(); private: - void drawCurve(Cairo::RefPtr &cr, LUTu & data, double scale, int hsize, int vsize); - void drawMarks(Cairo::RefPtr &cr, LUTu & data, double scale, int hsize, int & ui, int & oi); + void drawCurve(Cairo::RefPtr &cr, const LUTu & data, double scale, int hsize, int vsize); + void drawMarks(Cairo::RefPtr &cr, const LUTu & data, double scale, int hsize, int & ui, int & oi); Gtk::SizeRequestMode get_request_mode_vfunc () const override; void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const override; void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const override; diff --git a/rtgui/hsvequalizer.h b/rtgui/hsvequalizer.h index 987fd20b2..77c1ee1b0 100644 --- a/rtgui/hsvequalizer.h +++ b/rtgui/hsvequalizer.h @@ -20,7 +20,6 @@ #include -#include "adjuster.h" #include "colorprovider.h" #include "curvelistener.h" #include "guiutils.h" @@ -58,6 +57,5 @@ public: void autoOpenCurve () override; void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller) override; - //void adjusterChanged (Adjuster* a, double newval); void enabledChanged() override; }; diff --git a/rtgui/lockablecolorpicker.cc b/rtgui/lockablecolorpicker.cc index cb334c7e4..071847424 100644 --- a/rtgui/lockablecolorpicker.cc +++ b/rtgui/lockablecolorpicker.cc @@ -240,7 +240,7 @@ void LockableColorPicker::updateBackBuffer () } -void LockableColorPicker::draw (Cairo::RefPtr &cr) +void LockableColorPicker::draw (const Cairo::RefPtr &cr) { if (validity == Validity::OUTSIDE) { return; @@ -284,12 +284,12 @@ void LockableColorPicker::setRGB (const float R, const float G, const float B, c } } -void LockableColorPicker::getImagePosition (rtengine::Coord &imgPos) +void LockableColorPicker::getImagePosition (rtengine::Coord &imgPos) const { imgPos = position; } -void LockableColorPicker::getScreenPosition (rtengine::Coord &screenPos) +void LockableColorPicker::getScreenPosition (rtengine::Coord &screenPos) const { if (cropWindow) { cropWindow->imageCoordToScreen(position.x, position.y, screenPos.x, screenPos.y); @@ -328,7 +328,7 @@ void LockableColorPicker::setSize (Size newSize) } } -LockableColorPicker::Size LockableColorPicker::getSize () +LockableColorPicker::Size LockableColorPicker::getSize () const { return size; } diff --git a/rtgui/lockablecolorpicker.h b/rtgui/lockablecolorpicker.h index eadf71773..77d2e8e9f 100644 --- a/rtgui/lockablecolorpicker.h +++ b/rtgui/lockablecolorpicker.h @@ -74,14 +74,14 @@ public: LockableColorPicker (CropWindow* cropWindow, Glib::ustring *oProfile, Glib::ustring *wProfile); - void draw (Cairo::RefPtr &cr); + void draw (const Cairo::RefPtr &cr); // Used to update the RGB color, the HSV values will be updated accordingly void setPosition (const rtengine::Coord &newPos); void setRGB (const float R, const float G, const float B, const float previewR, const float previewG, const float previewB); - void getImagePosition (rtengine::Coord &imgPos); - void getScreenPosition (rtengine::Coord &screenPos); - Size getSize (); + void getImagePosition (rtengine::Coord &imgPos) const; + void getScreenPosition (rtengine::Coord &screenPos) const; + Size getSize () const; bool isOver (int x, int y); void setValidity (Validity isValid); void setSize (Size newSize); diff --git a/rtgui/lwbutton.cc b/rtgui/lwbutton.cc index c6c75584d..26d36f9e0 100644 --- a/rtgui/lwbutton.cc +++ b/rtgui/lwbutton.cc @@ -153,7 +153,7 @@ bool LWButton::releaseNotify (int x, int y) { bool in = inside (x, y); - State nstate = state; + State nstate; bool action = false; if (in && (state == Pressed_In || state == Pressed_Out)) { diff --git a/rtgui/main.cc b/rtgui/main.cc index ae34fc8d0..f669bcf4a 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -53,6 +53,7 @@ #else #include #include "conio.h" +#include "windows.h" #endif // Set this to 1 to make RT work when started with Eclipse and arguments, at least on Windows platform diff --git a/rtgui/mydiagonalcurve.cc b/rtgui/mydiagonalcurve.cc index 9aa52c67e..abd339ce0 100644 --- a/rtgui/mydiagonalcurve.cc +++ b/rtgui/mydiagonalcurve.cc @@ -592,7 +592,6 @@ bool MyDiagonalCurve::handleEvents (GdkEvent* event) curve.x.insert (itx, 0); curve.y.insert (ity, 0); - num++; // the graph is refreshed only if a new point is created curve.x.at(closest_point) = clampedX; @@ -1504,7 +1503,7 @@ void MyDiagonalCurve::setActiveParam (int ac) queue_draw (); } -void MyDiagonalCurve::updateBackgroundHistogram (LUTu & hist) +void MyDiagonalCurve::updateBackgroundHistogram (const LUTu & hist) { if (hist) { //memcpy (bghist, hist, 256*sizeof(unsigned int)); diff --git a/rtgui/mydiagonalcurve.h b/rtgui/mydiagonalcurve.h index a71c0565c..b38373006 100644 --- a/rtgui/mydiagonalcurve.h +++ b/rtgui/mydiagonalcurve.h @@ -85,7 +85,7 @@ public: bool handleEvents (GdkEvent* event) override; void setActiveParam (int ac); void reset (const std::vector &resetCurve, double identityValue = 0.5) override; - void updateBackgroundHistogram (LUTu & hist); + void updateBackgroundHistogram (const LUTu & hist); void pipetteMouseOver (CurveEditor *ce, EditDataProvider *provider, int modifierKey) override; bool pipetteButton1Pressed(EditDataProvider *provider, int modifierKey) override; diff --git a/rtgui/myflatcurve.cc b/rtgui/myflatcurve.cc index f01fb0066..362d34f35 100644 --- a/rtgui/myflatcurve.cc +++ b/rtgui/myflatcurve.cc @@ -653,7 +653,6 @@ bool MyFlatCurve::handleEvents (GdkEvent* event) curve.y.insert (ity, 0); curve.leftTangent.insert (itlt, 0); curve.rightTangent.insert (itrt, 0); - num++; if (mod_type & GDK_CONTROL_MASK) { clampedY = point.getVal01(clampedX); diff --git a/rtgui/navigator.cc b/rtgui/navigator.cc index 6a8137737..619ea0cfd 100644 --- a/rtgui/navigator.cc +++ b/rtgui/navigator.cc @@ -18,6 +18,7 @@ */ #include #include "navigator.h" +#include "previewwindow.h" #include "toolpanel.h" #include "../rtengine/color.h" #include "../rtengine/rt_math.h" diff --git a/rtgui/navigator.h b/rtgui/navigator.h index 953a0a44b..c1c23c6dc 100644 --- a/rtgui/navigator.h +++ b/rtgui/navigator.h @@ -22,7 +22,8 @@ #include "options.h" #include "pointermotionlistener.h" -#include "previewwindow.h" + +class PreviewWindow; class Navigator : public Gtk::Frame, diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index a7d2bd0d1..22f608ae4 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -136,6 +136,8 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren raw_ca_avoid_colourshift = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RAWCACORR_AVOIDCOLORSHIFT"))); //--- filmNegative = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FILMNEGATIVE")) ); + //--- + captureSharpening = Gtk::manage (new Gtk::CheckButton (M("TP_PDSHARPENING_LABEL")) ); Gtk::VBox* vboxes[8]; Gtk::HSeparator* hseps[8]; @@ -253,6 +255,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren vboxes[7]->pack_start (*raw_ca_avoid_colourshift, Gtk::PACK_SHRINK, 2); vboxes[7]->pack_start (*Gtk::manage (new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 0); vboxes[7]->pack_start (*filmNegative, Gtk::PACK_SHRINK, 2); + vboxes[7]->pack_start (*captureSharpening, Gtk::PACK_SHRINK, 2); Gtk::VBox* vbCol1 = Gtk::manage (new Gtk::VBox ()); Gtk::VBox* vbCol2 = Gtk::manage (new Gtk::VBox ()); @@ -402,6 +405,8 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren raw_ca_avoid_colourshiftconn = raw_ca_avoid_colourshift->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); //--- filmNegativeConn = filmNegative->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); + //--- + captureSharpeningConn = captureSharpening->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); add_button (M("GENERAL_OK"), Gtk::RESPONSE_OK); add_button (M("GENERAL_CANCEL"), Gtk::RESPONSE_CANCEL); @@ -474,6 +479,7 @@ void PartialPasteDlg::rawToggled () ConnectionBlocker raw_caredblueBlocker(raw_caredblueConn); ConnectionBlocker raw_ca_avoid_colourshiftBlocker(raw_ca_avoid_colourshiftconn); ConnectionBlocker filmNegativeBlocker(filmNegativeConn); + ConnectionBlocker captureSharpeningBlocker(captureSharpeningConn); raw->set_inconsistent (false); @@ -503,6 +509,7 @@ void PartialPasteDlg::rawToggled () raw_caredblue->set_active (raw->get_active ()); raw_ca_avoid_colourshift->set_active (raw->get_active ()); filmNegative->set_active (raw->get_active()); + captureSharpening->set_active (raw->get_active()); } void PartialPasteDlg::basicToggled () @@ -981,6 +988,17 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param filterPE.filmNegative.blueRatio = falsePE.filmNegative.blueRatio; } + if (!captureSharpening->get_active ()) { + filterPE.pdsharpening.enabled = falsePE.pdsharpening.enabled; + filterPE.pdsharpening.contrast = falsePE.pdsharpening.contrast; + filterPE.pdsharpening.autoContrast = falsePE.pdsharpening.autoContrast; + filterPE.pdsharpening.autoRadius = falsePE.pdsharpening.autoRadius; + filterPE.pdsharpening.deconvradius = falsePE.pdsharpening.deconvradius; + filterPE.pdsharpening.deconvradiusOffset = falsePE.pdsharpening.deconvradiusOffset; + filterPE.pdsharpening.deconviter = falsePE.pdsharpening.deconviter; + filterPE.pdsharpening.deconvitercheck = falsePE.pdsharpening.deconvitercheck; + } + if (dstPE) { *dstPE = filterPE; } diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index da6c9251a..1403e7c1b 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -141,6 +141,7 @@ public: Gtk::CheckButton* ff_ClipControl; Gtk::CheckButton* filmNegative; + Gtk::CheckButton* captureSharpening; sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaConn, rawConn, advancedConn; @@ -153,6 +154,7 @@ public: sigc::connection df_fileConn, df_AutoSelectConn, ff_fileConn, ff_AutoSelectConn, ff_BlurRadiusConn, ff_BlurTypeConn, ff_ClipControlConn; sigc::connection raw_caredblueConn, raw_ca_autocorrectConn, raw_ca_avoid_colourshiftconn, raw_hotpix_filtConn, raw_deadpix_filtConn, raw_pdaf_lines_filterConn, raw_linenoiseConn, raw_greenthreshConn, raw_ccStepsConn, raw_methodConn, raw_borderConn, raw_imagenumConn, raw_dcb_iterationsConn, raw_lmmse_iterationsConn, raw_pixelshiftConn, raw_dcb_enhanceConn, raw_exposConn, raw_blackConn; sigc::connection filmNegativeConn; + sigc::connection captureSharpeningConn; public: PartialPasteDlg (const Glib::ustring &title, Gtk::Window* parent); diff --git a/rtgui/pdsharpening.cc b/rtgui/pdsharpening.cc index 4f5416c82..18fa7aa2a 100644 --- a/rtgui/pdsharpening.cc +++ b/rtgui/pdsharpening.cc @@ -270,7 +270,7 @@ void PdSharpening::autoRadiusChanged(double autoRadius) ); } -void PdSharpening::adjusterAutoToggled(Adjuster* a, bool newval) +void PdSharpening::adjusterAutoToggled(Adjuster* a) { if (multiImage) { if (a->getAutoInconsistent()) { diff --git a/rtgui/pdsharpening.h b/rtgui/pdsharpening.h index 7d971eaee..eb0576ceb 100644 --- a/rtgui/pdsharpening.h +++ b/rtgui/pdsharpening.h @@ -59,7 +59,7 @@ public: void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; void setBatchMode (bool batchMode) override; - void adjusterAutoToggled (Adjuster* a, bool newval) override; + void adjusterAutoToggled (Adjuster* a) override; void adjusterChanged (Adjuster* a, double newval) override; void enabledChanged () override; diff --git a/rtgui/placesbrowser.h b/rtgui/placesbrowser.h index 78c94969f..d4640fff4 100644 --- a/rtgui/placesbrowser.h +++ b/rtgui/placesbrowser.h @@ -22,8 +22,6 @@ #include -#include "multilangmgr.h" - class PlacesBrowser : public Gtk::VBox { diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index b57956f30..083444342 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -128,7 +128,7 @@ Preferences::~Preferences () get_size (options.preferencesWidth, options.preferencesHeight); } -int Preferences::getThemeRowNumber (Glib::ustring& longThemeFName) +int Preferences::getThemeRowNumber (const Glib::ustring& longThemeFName) { if (regex->match (longThemeFName + ".css", matchInfo)) { diff --git a/rtgui/preferences.h b/rtgui/preferences.h index b4b90e669..76a104ffa 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -22,7 +22,6 @@ #include -#include "adjuster.h" #include "dynamicprofilepanel.h" #include "options.h" #include "../rtengine/profilestore.h" @@ -249,7 +248,7 @@ class Preferences : void switchFontTo (const Glib::ustring &newFontFamily, const int newFontSize); bool splashClosed (GdkEventAny* event); - int getThemeRowNumber (Glib::ustring& longThemeFName); + int getThemeRowNumber (const Glib::ustring& longThemeFName); void appendBehavList (Gtk::TreeModel::iterator& parent, Glib::ustring label, int id, bool set); diff --git a/rtgui/previewmodepanel.h b/rtgui/previewmodepanel.h index 98160a5e3..4121dfb92 100644 --- a/rtgui/previewmodepanel.h +++ b/rtgui/previewmodepanel.h @@ -19,8 +19,6 @@ #include -#include "adjuster.h" - class ImageArea; class PreviewModePanel : diff --git a/rtgui/previewwindow.cc b/rtgui/previewwindow.cc index 6268fe3d2..67fa87e0c 100644 --- a/rtgui/previewwindow.cc +++ b/rtgui/previewwindow.cc @@ -230,7 +230,7 @@ bool PreviewWindow::on_motion_notify_event (GdkEventMotion* event) if (x>imgX || y>imgY || w < imgW || h < imgH) { bool inside = event->x > x - 6 && event->x < x + w - 1 + 6 && event->y > y - 6 && event->y < y + h - 1 + 6; - CursorShape newType = cursor_type; + CursorShape newType; if (isMoving) { mainCropWin->remoteMove ((event->x - press_x) / zoom, (event->y - press_y) / zoom); diff --git a/rtgui/progressconnector.h b/rtgui/progressconnector.h index eb6eb3a66..f4d1d8f7e 100644 --- a/rtgui/progressconnector.h +++ b/rtgui/progressconnector.h @@ -79,9 +79,9 @@ class ProgressConnector static int emitEndSignalUI (void* data) { - sigc::signal0* opEnd = (sigc::signal0*) data; - int r = opEnd->emit (); - delete opEnd; + const sigc::signal0* lopEnd = reinterpret_cast*>(data); + const int r = lopEnd->emit (); + delete lopEnd; return r; } diff --git a/rtgui/recentbrowser.h b/rtgui/recentbrowser.h index 68a7962f9..bc8374087 100644 --- a/rtgui/recentbrowser.h +++ b/rtgui/recentbrowser.h @@ -21,7 +21,6 @@ #include #include "guiutils.h" -#include "multilangmgr.h" class RecentBrowser : public Gtk::VBox diff --git a/rtgui/rgbcurves.h b/rtgui/rgbcurves.h index 5ed2ea540..edc80eb41 100644 --- a/rtgui/rgbcurves.h +++ b/rtgui/rgbcurves.h @@ -20,7 +20,6 @@ #include -#include "adjuster.h" #include "colorprovider.h" #include "curvelistener.h" #include "toolpanel.h" diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index ae7072d88..5ab3ab85d 100644 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -44,14 +44,14 @@ extern unsigned char initialGdkScale; static gboolean osx_should_quit_cb (GtkosxApplication *app, gpointer data) { - RTWindow *rtWin = (RTWindow *)data; + RTWindow * const rtWin = static_cast(data); return rtWin->on_delete_event (0); } static void osx_will_quit_cb (GtkosxApplication *app, gpointer data) { - RTWindow *rtWin = (RTWindow *)data; + RTWindow *rtWin = static_cast(data); rtWin->on_delete_event (0); gtk_main_quit (); } @@ -75,7 +75,7 @@ bool RTWindow::osxFileOpenEvent (Glib::ustring path) static gboolean osx_open_file_cb (GtkosxApplication *app, gchar *path_, gpointer data) { - RTWindow *rtWin = (RTWindow *)data; + RTWindow *rtWin = static_cast(data); if (!argv1.empty()) { // skip handling if we have a file argument or else we get double open of same file @@ -232,13 +232,6 @@ RTWindow::RTWindow () } } -#ifndef NDEBUG - else if (!screen) { - printf ("ERROR: Can't get default screen!\n"); - } - -#endif - // ------- end loading theme files RTScalable::init(this); diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h index 39e1581e3..100ddf636 100644 --- a/rtgui/rtwindow.h +++ b/rtgui/rtwindow.h @@ -34,6 +34,7 @@ class BatchQueueEntry; class BatchQueuePanel; class EditorPanel; class FilePanel; +class PLDBridge; class RTWindow : public Gtk::Window, public rtengine::ProgressListener, diff --git a/rtgui/saveasdlg.h b/rtgui/saveasdlg.h index e4567f69b..448b37fd7 100644 --- a/rtgui/saveasdlg.h +++ b/rtgui/saveasdlg.h @@ -20,7 +20,6 @@ #include -#include "adjuster.h" #include "saveformatpanel.h" class SaveAsDialog : diff --git a/rtgui/thumbbrowserbase.cc b/rtgui/thumbbrowserbase.cc index c9329cf91..5f75ab413 100644 --- a/rtgui/thumbbrowserbase.cc +++ b/rtgui/thumbbrowserbase.cc @@ -967,7 +967,7 @@ void ThumbBrowserBase::buttonPressed (int x, int y, int button, GdkEventType typ } MYWRITERLOCK_RELEASE(l); - rightClicked (fileDescr); + rightClicked (); } } // end of MYWRITERLOCK(l, entryRW); diff --git a/rtgui/thumbbrowserbase.h b/rtgui/thumbbrowserbase.h index d6bafaf69..b4caac0a9 100644 --- a/rtgui/thumbbrowserbase.h +++ b/rtgui/thumbbrowserbase.h @@ -225,7 +225,7 @@ public: { return true; } - virtual void rightClicked (ThumbBrowserEntryBase* entry) {} + virtual void rightClicked () = 0; virtual void doubleClicked (ThumbBrowserEntryBase* entry) {} virtual bool keyPressed (GdkEventKey* event) { diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index cd7470263..bcf578143 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -590,10 +590,8 @@ void Thumbnail::decreaseRef () cachemgr->closeThumbnail (this); } -void Thumbnail::getThumbnailSize (int &w, int &h, const rtengine::procparams::ProcParams *pparams) +int Thumbnail::getThumbnailWidth (const int h, const rtengine::procparams::ProcParams *pparams) const { - MyMutex::MyLock lock(mutex); - int tw_ = tw; int th_ = th; float imgRatio_ = imgRatio; @@ -613,20 +611,17 @@ void Thumbnail::getThumbnailSize (int &w, int &h, const rtengine::procparams::Pr if (thisCoarse != ppCoarse) { // different orientation -> swapping width & height - int tmp = th_; - th_ = tw_; - tw_ = tmp; - + std::swap(th_, tw_); if (imgRatio_ >= 0.0001f) { imgRatio_ = 1.f / imgRatio_; } } } - if (imgRatio_ > 0.) { - w = (int)(imgRatio_ * (float)h); + if (imgRatio_ > 0.f) { + return imgRatio_ * h; } else { - w = tw_ * h / th_; + return tw_ * h / th_; } } diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index aee5ee0a6..c22c80cea 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -119,7 +119,7 @@ public: // unsigned char* getThumbnailImage (int &w, int &h, int fixwh=1); // fixwh = 0: fix w and calculate h, =1: fix h and calculate w rtengine::IImage8* processThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale); rtengine::IImage8* upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale); - void getThumbnailSize (int &w, int &h, const rtengine::procparams::ProcParams *pparams = nullptr); + int getThumbnailWidth (int h, const rtengine::procparams::ProcParams *pparams = nullptr) const; void getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h); void getOriginalSize (int& w, int& h); diff --git a/rtgui/toolbar.cc b/rtgui/toolbar.cc index 38ade6566..99c4196c6 100644 --- a/rtgui/toolbar.cc +++ b/rtgui/toolbar.cc @@ -20,6 +20,7 @@ #include "toolbar.h" #include "multilangmgr.h" #include "guiutils.h" +#include "lockablecolorpicker.h" #include "rtimage.h" ToolBar::ToolBar () : showColPickers(true), listener (nullptr), pickerListener(nullptr) diff --git a/rtgui/toolbar.h b/rtgui/toolbar.h index e6d99f819..8ec6bb615 100644 --- a/rtgui/toolbar.h +++ b/rtgui/toolbar.h @@ -20,10 +20,10 @@ #include -#include "lockablecolorpicker.h" #include "toolenum.h" class RTImage; +class LockablePickerToolListener; class ToolBarListener { diff --git a/rtgui/toolpanel.h b/rtgui/toolpanel.h index 0f002e048..aecf1f39f 100644 --- a/rtgui/toolpanel.h +++ b/rtgui/toolpanel.h @@ -22,7 +22,6 @@ #include -#include "editbuffer.h" #include "guiutils.h" #include "multilangmgr.h" #include "paramsedited.h" diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index a636994b2..57f61a09c 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -309,13 +309,17 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt { rawPanelSW->set_sensitive(true); sensorxtrans->FoldableToolPanel::hide(); + xtransprocess->FoldableToolPanel::hide(); + xtransrawexposure->FoldableToolPanel::hide(); sensorbayer->FoldableToolPanel::show(); + bayerprocess->FoldableToolPanel::show(); + bayerpreprocess->FoldableToolPanel::show(); + rawcacorrection->FoldableToolPanel::show(); preprocess->FoldableToolPanel::show(); flatfield->FoldableToolPanel::show(); filmNegative->FoldableToolPanel::show(); pdSharpening->FoldableToolPanel::show(); retinex->FoldableToolPanel::setGrayedOut(false); - return false; } ); @@ -326,13 +330,17 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt { rawPanelSW->set_sensitive(true); sensorxtrans->FoldableToolPanel::show(); + xtransprocess->FoldableToolPanel::show(); + xtransrawexposure->FoldableToolPanel::show(); sensorbayer->FoldableToolPanel::hide(); + bayerprocess->FoldableToolPanel::hide(); + bayerpreprocess->FoldableToolPanel::hide(); + rawcacorrection->FoldableToolPanel::hide(); preprocess->FoldableToolPanel::show(); flatfield->FoldableToolPanel::show(); filmNegative->FoldableToolPanel::show(); pdSharpening->FoldableToolPanel::show(); retinex->FoldableToolPanel::setGrayedOut(false); - return false; } ); @@ -343,13 +351,17 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt { rawPanelSW->set_sensitive(true); sensorbayer->FoldableToolPanel::hide(); + bayerprocess->FoldableToolPanel::hide(); + bayerpreprocess->FoldableToolPanel::hide(); + rawcacorrection->FoldableToolPanel::hide(); sensorxtrans->FoldableToolPanel::hide(); + xtransprocess->FoldableToolPanel::hide(); + xtransrawexposure->FoldableToolPanel::hide(); preprocess->FoldableToolPanel::hide(); flatfield->FoldableToolPanel::show(); filmNegative->FoldableToolPanel::hide(); pdSharpening->FoldableToolPanel::show(); retinex->FoldableToolPanel::setGrayedOut(false); - return false; } ); @@ -359,13 +371,17 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt { rawPanelSW->set_sensitive(true); sensorbayer->FoldableToolPanel::hide(); + bayerprocess->FoldableToolPanel::hide(); + bayerpreprocess->FoldableToolPanel::hide(); + rawcacorrection->FoldableToolPanel::hide(); sensorxtrans->FoldableToolPanel::hide(); + xtransprocess->FoldableToolPanel::hide(); + xtransrawexposure->FoldableToolPanel::hide(); preprocess->FoldableToolPanel::hide(); flatfield->FoldableToolPanel::hide(); filmNegative->FoldableToolPanel::hide(); pdSharpening->FoldableToolPanel::hide(); retinex->FoldableToolPanel::setGrayedOut(false); - return false; } ); @@ -375,10 +391,18 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt [this]() -> bool { rawPanelSW->set_sensitive(false); + sensorbayer->FoldableToolPanel::hide(); + bayerprocess->FoldableToolPanel::hide(); + bayerpreprocess->FoldableToolPanel::hide(); + rawcacorrection->FoldableToolPanel::hide(); + sensorxtrans->FoldableToolPanel::hide(); + xtransprocess->FoldableToolPanel::hide(); + xtransrawexposure->FoldableToolPanel::hide(); + preprocess->FoldableToolPanel::hide(); + flatfield->FoldableToolPanel::hide(); filmNegative->FoldableToolPanel::hide(); pdSharpening->FoldableToolPanel::hide(); retinex->FoldableToolPanel::setGrayedOut(true); - return false; } ); diff --git a/rtgui/xtransprocess.cc b/rtgui/xtransprocess.cc index 52c46be65..a371bad88 100644 --- a/rtgui/xtransprocess.cc +++ b/rtgui/xtransprocess.cc @@ -225,7 +225,7 @@ void XTransProcess::adjusterChanged(Adjuster* a, double newval) } } -void XTransProcess::adjusterAutoToggled(Adjuster* a, bool newval) +void XTransProcess::adjusterAutoToggled(Adjuster* a) { if (multiImage) { if (dualDemosaicContrast->getAutoInconsistent()) { diff --git a/rtgui/xtransprocess.h b/rtgui/xtransprocess.h index d6cb120e0..fc0dd7502 100644 --- a/rtgui/xtransprocess.h +++ b/rtgui/xtransprocess.h @@ -66,5 +66,5 @@ public: void autoContrastChanged (double autoContrast) override; void adjusterChanged(Adjuster* a, double newval) override; void checkBoxToggled(CheckBox* c, CheckValue newval) override; - void adjusterAutoToggled(Adjuster* a, bool newval) override; + void adjusterAutoToggled(Adjuster* a) override; };