From c857bba95effed2bba4c69d7b072c0dce2ee64ad Mon Sep 17 00:00:00 2001 From: Beep6581 Date: Thu, 9 Jun 2016 22:36:59 +0200 Subject: [PATCH] Merged master into gtk3, fixed three conflicts. --- README.md | 2 +- rtengine/LUT.h | 284 ++- rtengine/camconst.json | 376 ++-- rtengine/ciecam02.cc | 94 +- rtengine/ciecam02.h | 4 +- rtengine/color.cc | 10 +- rtengine/colortemp.cc | 8 +- rtengine/colortemp.h | 22 +- rtengine/curves.cc | 945 +++----- rtengine/curves.h | 66 +- rtengine/dcp.cc | 2990 +++++++++++++------------- rtengine/dcp.h | 216 +- rtengine/dcraw.c | 572 +++-- rtengine/dcraw.cc | 437 ++-- rtengine/dcraw.h | 7 +- rtengine/dcraw.patch | 382 ++-- rtengine/dcrop.cc | 8 +- rtengine/demosaic_algos.cc | 5 +- rtengine/diagonalcurves.cc | 26 +- rtengine/flatcurves.cc | 31 +- rtengine/helpersse2.h | 3 + rtengine/iimage.h | 42 +- rtengine/imagesource.h | 14 +- rtengine/improccoordinator.cc | 176 +- rtengine/improccoordinator.h | 8 +- rtengine/improcfun.cc | 891 ++++---- rtengine/improcfun.h | 11 +- rtengine/init.cc | 2 +- rtengine/iplab2rgb.cc | 12 +- rtengine/ipvibrance.cc | 4 +- rtengine/previewimage.cc | 7 - rtengine/procparams.cc | 3794 +++++++++++++++++---------------- rtengine/procparams.h | 10 +- rtengine/rawimage.cc | 4 +- rtengine/rawimagesource.cc | 55 +- rtengine/rawimagesource.h | 22 +- rtengine/rtthumbnail.cc | 251 +-- rtengine/simpleprocess.cc | 114 +- rtengine/sleef.c | 8 +- rtengine/stdimagesource.cc | 10 +- rtengine/stdimagesource.h | 26 +- rtengine/utils.h | 12 +- rtgui/histogrampanel.cc | 64 +- rtgui/icmpanel.cc | 31 +- rtgui/lensgeom.cc | 32 + rtgui/lensgeom.h | 8 +- rtgui/lensprofile.cc | 14 +- rtgui/lensprofile.h | 6 + rtgui/myflatcurve.cc | 1 + rtgui/toolpanelcoord.cc | 1 + 50 files changed, 6109 insertions(+), 6009 deletions(-) diff --git a/README.md b/README.md index 9dfd4c324..e90807b73 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ RawTherapee is a powerful, cross-platform raw photo processing program, released ## Target audience -Rawtherapee is a [libre software](https://en.wikipedia.org/wiki/Free_software) designed for developing raw files from a broad range of digital cameras, as well as [HDR DNG](https://helpx.adobe.com/photoshop/digital-negative.html) files and non-raw image formats ([JPEG](https://en.wikipedia.org/wiki/JPEG), [TIFF](https://en.wikipedia.org/wiki/Tagged_Image_File_Format) and [PNG](https://en.wikipedia.org/wiki/Portable_Network_Graphics)). The target audience ranges from enthusiast newcomers who whish to broaden their understanding of how digital imaging works to semi-professional photographers. Knowledge in color science is not compulsory, but it is recommended that you are eager to learn and ready to read our documentation ([RawPedia](http://rawpedia.rawtherapee.com/)) as well as look up basic concepts which lie outside the scope of RawPedia, such as [color balance](https://en.wikipedia.org/wiki/Color_balance), elsewhere. +RawTherapee is a [libre software](https://en.wikipedia.org/wiki/Free_software) designed for developing raw files from a broad range of digital cameras, as well as [HDR DNG](https://helpx.adobe.com/photoshop/digital-negative.html) files and non-raw image formats ([JPEG](https://en.wikipedia.org/wiki/JPEG), [TIFF](https://en.wikipedia.org/wiki/Tagged_Image_File_Format) and [PNG](https://en.wikipedia.org/wiki/Portable_Network_Graphics)). The target audience ranges from enthusiast newcomers who wish to broaden their understanding of how digital imaging works to semi-professional photographers. Knowledge in color science is not compulsory, but it is recommended that you are eager to learn and ready to read our documentation ([RawPedia](http://rawpedia.rawtherapee.com/)) as well as look up basic concepts which lie outside the scope of RawPedia, such as [color balance](https://en.wikipedia.org/wiki/Color_balance), elsewhere. Of course, professionals may use RawTherapee too while enjoying complete freedom, but will probably lack some peripheral features such as [Digital Asset Management](https://en.wikipedia.org/wiki/Digital_asset_management), printing, uploading, etc. RawTherapee is not aimed at being an inclusive all-in-one program, and the [open-source community](https://en.wikipedia.org/wiki/Open-source_movement) is sufficiently developed by now to offer all those peripheral features in other specialized software. diff --git a/rtengine/LUT.h b/rtengine/LUT.h index 76bcf0ccd..24f883766 100644 --- a/rtengine/LUT.h +++ b/rtengine/LUT.h @@ -59,17 +59,8 @@ #ifndef LUT_H_ #define LUT_H_ -// bit representations of flags -#define LUT_CLIP_BELOW 1 -#define LUT_CLIP_ABOVE 2 - -#define LUTf LUT -#define LUTi LUT -#define LUTu LUT -#define LUTd LUT -#define LUTuc LUT - #include +#include #ifndef NDEBUG #include #include @@ -78,6 +69,21 @@ #include #include "rt_math.h" +// Bit representations of flags +enum { + LUT_CLIP_BELOW = 1 << 0, + LUT_CLIP_ABOVE = 1 << 1 +}; + +template +class LUT; + +using LUTf = LUT; +using LUTi = LUT; +using LUTu = LUT; +using LUTd = LUT; +using LUTuc = LUT; + template class LUT { @@ -155,41 +161,6 @@ public: #endif } - LUT(int s, T * source, int flags = 0xfffffff) - { -#ifndef NDEBUG - - if (s <= 0) { - printf("s<=0!\n"); - } - - assert (s > 0); - - if (!source) { - printf("source is NULL!\n"); - } - - assert (source != nullptr); -#endif - dirty = false; // Assumption - clip = flags; - data = new T[s]; - owner = 1; - size = s; - upperBound = size - 1; - maxs = size - 2; - maxsf = (float)maxs; -#if defined( __SSE2__ ) && defined( __x86_64__ ) - maxsv = F2V( size - 2); - sizeiv = _mm_set1_epi32( (int)(size - 1) ); - sizev = F2V( size - 1 ); -#endif - - for (int i = 0; i < s; i++) { - data[i] = source[i]; - } - } - LUT() { data = nullptr; @@ -215,7 +186,7 @@ public: * For a LUT(500), it will return 500 * @return number of element in the array */ - int getSize() + unsigned int getSize() const { return size; } @@ -224,7 +195,7 @@ public: * For a LUT(500), it will return 499, because 500 elements, starting from 0, goes up to 499 * @return number of element in the array */ - int getUpperBound() + unsigned int getUpperBound() const { return size > 0 ? upperBound : 0; } @@ -258,11 +229,12 @@ public: return *this; } - // handy to sum up per thread histograms. #pragma omp simd speeds up the loop by about factor 3 for LUTu (unsigned int). + // handy to sum up per thread histograms. #pragma omp simd speeds up the loop by about factor 3 for LUTu (uint32_t). + template::value>::type> LUT & operator+=(LUT &rhs) { if (rhs.size == this->size) { -#ifdef _OPENMP +#ifdef _RT_NESTED_OPENMP // temporary solution to fix Issue #3324 #pragma omp simd #endif @@ -274,6 +246,37 @@ public: return *this; } + // multiply all elements of LUT with a constant float value + template::value>::type> + LUT & operator*=(float factor) + { +#ifdef _RT_NESTED_OPENMP // temporary solution to fix Issue #3324 + #pragma omp simd +#endif + + for(unsigned int i = 0; i < this->size; i++) { + data[i] *= factor; + } + + return *this; + } + + // divide all elements of LUT by a constant float value + template::value>::type> + LUT & operator/=(float divisor) + { +#ifdef _RT_NESTED_OPENMP // temporary solution to fix Issue #3324 + #pragma omp simd +#endif + + for(unsigned int i = 0; i < this->size; i++) { + data[i] /= divisor; + } + + return *this; + } + + // use with integer indices T& operator[](int index) const { @@ -348,6 +351,7 @@ public: } */ #ifdef __SSE4_1__ + template::value>::type> vfloat operator[](vint idxv ) const { vfloat tempv, p1v; @@ -387,6 +391,7 @@ public: return p1v; } #else + template::value>::type> vfloat operator[](vint idxv ) const { vfloat tempv, p1v; @@ -431,6 +436,7 @@ public: #endif // use with float indices + template::value>::type> T operator[](float index) const { int idx = (int)index; // don't use floor! The difference in negative space is no problems here @@ -456,9 +462,10 @@ public: } // Return the value for "index" that is in the [0-1] range. + template::value>::type> T getVal01 (float index) const { - index *= float(upperBound); + index *= (float)upperBound; int idx = (int)index; // don't use floor! The difference in negative space is no problems here if (index < 0.f) { @@ -526,79 +533,122 @@ public: upperBound = 0; maxs = 0; } -}; - - -// TODO: HOMBRE: HueLUT is actually unused, could we delete this class now that LUT::getVal01 has been created? - - -/** @brief LUT subclass handling hue values specifically. - The array has a fixed size of float values and have to be in the [0.; 1.] range in both axis (no error checking implemented) */ -class HueLUT : public LUTf -{ -public: - HueLUT() : LUTf() {} - explicit HueLUT(bool createArray) : LUTf() + // create an identity LUT (LUT(x) = x) or a scaled identity LUT (LUT(x) = x / divisor) + template::value>::type> + void makeIdentity(float divisor = 1.f) { - if (createArray) { - this->operator () (501, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); - } - } - - void create() - { - this->operator () (501, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); - } - - // use with integer indices - float& operator[](int index) const - { - return data[ rtengine::LIM(index, 0, upperBound) ]; - } - - // use with float indices in the [0.;1.] range - float operator[](float index) const - { - int idx = int(index * 500.f); // don't use floor! The difference in negative space is no problems here - - if (index < 0.f) { - return data[0]; - } else if (index > 1.f) { - return data[upperBound]; - } - - float balance = index - float(idx / 500.f); - float h1 = data[idx]; - float h2 = data[idx + 1]; - - if (h1 == h2) { - return h1; - } - - if ((h1 > h2) && (h1 - h2 > 0.5f)) { - h1 -= 1.f; - float value = h1 + balance * (h2 - h1); - - if (value < 0.f) { - value += 1.f; + if(divisor == 1.f) { + for(unsigned int i = 0; i < size; i++) { + data[i] = i; } - - return value; - } else if (h2 - h1 > 0.5f) { - h2 -= 1.f; - float value = h1 + balance * (h2 - h1); - - if (value < 0.f) { - value += 1.f; - } - - return value; } else { - return h1 + balance * (h2 - h1); + for(unsigned int i = 0; i < size; i++) { + data[i] = i / divisor; + } } } -}; + // compress a LUT with size y into a LUT with size x (y>x) + template::value>::type> + void compressTo(LUT &dest, unsigned int numVals = 0) const + { + numVals = numVals == 0 ? size : numVals; + numVals = std::min(numVals, size); + float divisor = numVals - 1; + float mult = (dest.size - 1) / divisor; + + for (unsigned int i = 0; i < numVals; i++) { + int hi = (int)(mult * i); + dest.data[hi] += this->data[i] ; + } + } + + // compress a LUT with size y into a LUT with size x (y>x) by using the passTrough LUT to calculate indexes + template::value>::type> + void compressTo(LUT &dest, unsigned int numVals, const LUT &passThrough) const + { + if(passThrough) { + numVals = std::min(numVals, size); + numVals = std::min(numVals, passThrough.getSize()); + float mult = dest.size - 1; + + for (int i = 0; i < numVals; i++) { + int hi = (int)(mult * passThrough[i]); + dest[hi] += this->data[i] ; + } + } + } + + // compute sum and average of a LUT + template::value>::type> + void getSumAndAverage(float &sum, float &avg) const + { + sum = 0.f; + avg = 0.f; + int i = 0; +#ifdef __SSE2__ + vfloat iv = _mm_set_ps(3.f, 2.f, 1.f, 0.f); + vfloat fourv = F2V(4.f); + vint sumv = (vint)ZEROV; + vfloat avgv = ZEROV; + + for(; i < size - 3; i += 4) { + vint datav = _mm_loadu_si128((__m128i*)&data[i]); + sumv += datav; + avgv += iv * _mm_cvtepi32_ps(datav); + iv += fourv; + + } + + sum = vhadd(_mm_cvtepi32_ps(sumv)); + avg = vhadd(avgv); +#endif + + for (; i < size; i++) { + T val = data[i]; + sum += val; + avg += i * val; + } + + avg /= sum; + } + + + template::value>::type> + void makeConstant(float value, unsigned int numVals = 0) + { + numVals = numVals == 0 ? size : numVals; + numVals = std::min(numVals, size); + + for(unsigned int i = 0; i < numVals; i++) { + data[i] = value; + } + } + + // share the buffer with another LUT, handy for same data but different clip flags + void share(const LUT &source, int flags = 0xfffffff) + { + if (owner && data) { + delete[] data; + } + + dirty = false; // Assumption + clip = flags; + data = source.data; + owner = 0; + size = source.getSize(); + upperBound = size - 1; + maxs = size - 2; + maxsf = (float)maxs; +#if defined( __SSE2__ ) && defined( __x86_64__ ) + maxsv = F2V( size - 2); + sizeiv = _mm_set1_epi32( (int)(size - 1) ); + sizev = F2V( size - 1 ); +#endif + } + + +}; #endif /* LUT_H_ */ diff --git a/rtengine/camconst.json b/rtengine/camconst.json index d56eb05a6..c7bef9ee2 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -36,7 +36,7 @@ missing. That's why this file is needed. It's read once during startup, so if the file is updated you need to restart RawTherapee in order to take effect. The file is not intended for modification by the casual user, but advanced users can add missing camera information to this file. -If you do so please report at http://code.google.com/p/rawtherapee/issues so we can +If you do so please report at https://github.com/Beep6581/RawTherapee/issues so we can extend the distributed version of this file so your provided camera information becomes available to all. @@ -58,9 +58,20 @@ Examples: // make and model separated with single space, must match make // and model as provided by dcraw (case-insensitive). "make_model": "ManufacturerA ModelB", + Some Panasonics and some Canon Dslrs (of the low category like Canon 550D) exist + under alternate naming in various marketplaces (EOS 550D, EOS Rebel T2i, EOS Kiss X4). + For new models that are still not supported by the Dcraw version used in current RT, + we have to fill all the alternate names or else RT will not recognize the alternate model names + For models supported by Dcraw, filling the alternate names is simply desired (for better user info). + The format of multiple naming is to write all names in brackets i.e + instead of .. "make_model": "Canon EOS 550D", + type .. "make_model": [ "Canon EOS 550D", "Canon EOS Rebel T2i", "Canon EOS Kiss X4" ], // ColorMatrix with D65 Calibration Illuminant, in dcraw format "dcraw_matrix": [ 7530, -1942, -255, -4318, 11390, 3362, -926, 1694, 7649 ], // black level (or black offset if a base black is already extracted from exif by Dcraw, see Panasonic, resent Nikon ) + // For some rare cases where Dcraw detects wrong Black Level we need to correct it with absolute black i.e one that is not added up + // the detected. For this job we have to define "black" as 65535+desired_black. For example to correct a wrongly detected black level + of 9 instead of the correct 600 we define "black": 66135 i.e. 65535+600. // and white level same for all colors at all ISOs "ranges": { "black": 10, "white": 1000 }, // crop away masked sensor borders, 10 pixels left, 20 pixels top, resulting image width/height 4000x3000 @@ -68,14 +79,18 @@ Examples: that should be removed but keep in mind that sometimes after converting to DNG the borders are already cropped so the "negative number" way is not totally safe. "raw_crop": [ 10, 20, 4000, 3000 ], - // Almost same as MaskedAreas DNG tag, used for black level measuring here two areas defined - "masked_areas": [ 51, 2, 3804, 156, 51, 5794, 3804, 5792 ], - The difference here is the meaning of the numbers which here are expressing the absolute distance (in pixels) + // Almost same as MaskedAreas DNG tag, used for black level measuring. Here up to two areas can be defined + by tetrads of numbers + "masked_areas": [ 51, 2, 3804, 156, 51, 5794, 3804, 5792 ], // two tetrads define two areas + The difference vs "raw_crop" is the meaning of the numbers which here are expressing the absolute distance (in pixels) of each side of each rectangular "masked area" from the top and left side of the sensor - the first number is the distance of the top edge from the sensor's top - the second is the distance of the left side from the sensor's left - the third is the distance of the bottom side from the sensor's top - the fourth is the distance of the right side from the sensor's left + It is useful after detecting the masked areas, to not fully use these areas but leave a border of + 2-4 pixels instead, to take care of possible light leaks from the light sensing area to the optically + black (masked) area or sensor imperfections at the outer borders. }, { @@ -571,31 +586,6 @@ Quality X: unknown, ie we knowing to little about the camera properties to know } }, - { // Quality b, ISO and aperture WL data by ..... at RawTherapee forums, missing samples safely guessed - "make_model": "Canon EOS 550D", - "dcraw_matrix": [ 6941,-1164,-857,-3825,11597,2534,-416,1540,6039 ], // dcraw 550d - "ranges": { - "white": [ - { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13584 - { "iso": [ 160, 320, 640, 1250, 2500 ], "levels": 12550 }, // typical 12650 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 5000, 6400, 12800 ], "levels": 15200 } // typical 15304 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for f/1.2 and f/1.0 (no lenses to test with), but the - typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ - { "aperture": 1.4, "scale_factor": 1.250 }, // guessed - { "aperture": 1.6, "scale_factor": 1.150 }, // guessed - { "aperture": 1.8, "scale_factor": 1.110 }, // 15196/13584 - { "aperture": 2.0, "scale_factor": 1.080 }, // 14734/13584 - { "aperture": 2.2, "scale_factor": 1.050 }, // 14386/13584 - { "aperture": 2.5, "scale_factor": 1.040 }, // 14272/13584 - { "aperture": 2.8, "scale_factor": 1.030 }, // 14042/13584 - { "aperture": 3.2, "scale_factor": 1.015 }, // guessed - { "aperture": 3.5, "scale_factor": 1.000 } // guessed negligible - ] - } - }, { // Quality A, f/1.6 aperture scale factor missing but safely guessed, ISO and aperture data by charlyw at RT forums "make_model": "Canon EOS 7D Mark II", "dcraw_matrix": [ 7268,-1082,-969,-4186,11839,2663,-825,2029,5839 ], // dng_v8.7 d65 @@ -752,8 +742,65 @@ Quality X: unknown, ie we knowing to little about the camera properties to know } }, + { // Quality C, White Levels not properly indicated, aperture scaling..missing scaling factors are guessed + "make_model": "Canon EOS 80D", + "dcraw_matrix": [ 7457,-671,-937,-4849,12495,2643,-1213,2354,5492 ], // DNG_V9.5 D65 + "raw_crop": [ 264, 34, 6024, 4022 ], // full size 6288x4056, official crop 276,46,6275,4045 + "masked_areas": [ 40, 96, 4000, 260 ], + "ranges": { + "white": [ + { "iso": [ 100, 125, 200, 250 ], "levels": 16200 }, // nominal 16383, LENR blue 16243 + { "iso": [ 160 ], "levels": 13000 }, // nominal 13097, + { "iso": [ 320, 640, 1250, 2500, 5000, 10000 ], "levels": 13200 }, // G1,G2 13415 + { "iso": [ 400, 500, 800, 1000, 1600, 2000, 3200, 4000 ], "levels": 16150 }, // nominal 16383, LENR ISO3200 16150 + { "iso": [ 6400, 8000, 12800, 16000, 25600 ], "levels": 16000 } // R,G1,G2 16383, B 16243, LENR B 16000 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: need for more data to properly fill all scale factors */ + { "aperture": 1.4, "scale_factor": 1.200 }, // guessed + { "aperture": 1.6, "scale_factor": 1.080 }, // guessed + { "aperture": 1.8, "scale_factor": 1.055 }, // guessed + { "aperture": 2.0, "scale_factor": 1.030 }, // guessed + { "aperture": 2.2, "scale_factor": 1.025 }, // guessed + { "aperture": 2.5, "scale_factor": 1.020 }, // guessed + { "aperture": 2.8, "scale_factor": 1.000 }, // + { "aperture": 3.2, "scale_factor": 1.000 }, // + { "aperture": 3.5, "scale_factor": 1.000 } // + ] + } + }, + +// Canon Mid category DSLRs (Rebels) + + { // Quality b, ISO and aperture WL data by ..... at RawTherapee forums, missing samples safely guessed + "make_model": [ "Canon EOS 550D", "Canon EOS Rebel T2i", "Canon EOS Kiss X4" ], + "dcraw_matrix": [ 6941,-1164,-857,-3825,11597,2534,-416,1540,6039 ], // dcraw 550d + "ranges": { + "white": [ + { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13584 + { "iso": [ 160, 320, 640, 1250, 2500 ], "levels": 12550 }, // typical 12650 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 5000, 6400, 12800 ], "levels": 15200 } // typical 15304 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for f/1.2 and f/1.0 (no lenses to test with), but the + typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ + { "aperture": 1.4, "scale_factor": 1.250 }, // guessed + { "aperture": 1.6, "scale_factor": 1.150 }, // guessed + { "aperture": 1.8, "scale_factor": 1.110 }, // 15196/13584 + { "aperture": 2.0, "scale_factor": 1.080 }, // 14734/13584 + { "aperture": 2.2, "scale_factor": 1.050 }, // 14386/13584 + { "aperture": 2.5, "scale_factor": 1.040 }, // 14272/13584 + { "aperture": 2.8, "scale_factor": 1.030 }, // 14042/13584 + { "aperture": 3.2, "scale_factor": 1.015 }, // guessed + { "aperture": 3.5, "scale_factor": 1.000 } // guessed negligible + ] + } + }, + { // Quality b, scaling factors missing but guessed safely - "make_model": [ "Canon EOS 1200D", "Canon EOS Rebel T5", "Canon EOS 600D", "Canon EOS Rebel T3i" ], + "make_model": [ "Canon EOS 600D", "Canon EOS Rebel T3i", "Canon EOS Kiss X5", "Canon EOS 1200D", "Canon EOS Rebel T5", "Canon EOS Kiss X70" ], "dcraw_matrix": [ 6461,-907,-882,-4300,12184,2378,-819,1944,5931 ], // dcp D65 colormatrix2 "ranges": { "white": [ @@ -772,41 +819,13 @@ Quality X: unknown, ie we knowing to little about the camera properties to know { "aperture": 2.2, "scale_factor": 1.060 }, // 11971/11222 = 1.066 { "aperture": 2.5, "scale_factor": 1.050 }, // guessed { "aperture": 2.8, "scale_factor": 1.030 }, // iso100: 14042/13584=1.0336 - iso200 15820/15303 = 1.0348 - { "aperture": 3.2, "scale_factor": 1.000 }, // - { "aperture": 3.5, "scale_factor": 1.000 } // - ] - } - }, - - { // Quality B, .. integer ISOs measured, intermediate ISO samples missing, - // scaling factors safely guessed to be same as 1200D .. - "make_model": [ "Canon EOS 1300D", "Canon EOS Rebel T6" ], - "dcraw_matrix": [ 6939,-1016,-866,-4428,12473,2177,-1175,2178,6162 ], // Dcraw 9.27 - "ranges": { - "white": [ - { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13584 - { "iso": [ 160, 320, 640, 1250, 2500, 5000, 10000 ], "levels": 12550 }, // typical 12650 - { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000, 12800 ], "levels": 15200 } // typical 15303 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the - typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ - { "aperture": 1.4, "scale_factor": 1.290 }, // guessed from 60D data - { "aperture": 1.6, "scale_factor": 1.190 }, // guessed - { "aperture": 1.8, "scale_factor": 1.140 }, // guessed - { "aperture": 2.0, "scale_factor": 1.090 }, // 12293/11222 = 1.095 - { "aperture": 2.2, "scale_factor": 1.060 }, // 11971/11222 = 1.066 - { "aperture": 2.5, "scale_factor": 1.050 }, // guessed - { "aperture": 2.8, "scale_factor": 1.030 }, // iso100: 14042/13584=1.0336 - iso200 15820/15303 = 1.0348 - { "aperture": 3.2, "scale_factor": 1.000 }, // - { "aperture": 3.5, "scale_factor": 1.000 } // + { "aperture": 3.2, "scale_factor": 1.000 } // ] } }, { // Quality A, only one scaling factor missing and guessed safely, EOS 700D not tested but available samples look same as 650D - "make_model": [ "Canon EOS 650D", "Canon EOS Rebel T4i", "Canon EOS 700D", "Canon EOS Rebel T5i" ], + "make_model": [ "Canon EOS 650D", "Canon EOS Rebel T4i", "Canon EOS Kiss X6i", "Canon EOS 700D", "Canon EOS Rebel T5i", "Canon EOS Kiss X7i" ], "dcraw_matrix": [ 6602,-841,-939,-4472,12458,2247,-975,2039,6148 ], "ranges": { "white": [ @@ -826,14 +845,13 @@ Quality X: unknown, ie we knowing to little about the camera properties to know { "aperture": 2.2, "scale_factor": 1.025 }, // 13921/13583 { "aperture": 2.5, "scale_factor": 1.020 }, // { "aperture": 2.8, "scale_factor": 1.000 }, // - { "aperture": 3.2, "scale_factor": 1.000 }, // - { "aperture": 3.5, "scale_factor": 1.000 } // + { "aperture": 3.2, "scale_factor": 1.000 } // ] } }, { // Quality C, aperture scale factors and intermediate ISOs missing but safely guessed - "make_model": [ "Canon EOS 750D", "Canon EOS Rebel T6i", "Canon EOS 760D", "Canon EOS Rebel T6s" ], + "make_model": [ "Canon EOS 750D", "Canon EOS Rebel T6i", "Canon EOS Kiss X8i", "Canon EOS 760D", "Canon EOS Rebel T6s", "Canon EOS 8000D" ], "dcraw_matrix": [ 6362,-823,-847,-4426,12109,2616,-743,1857,5635 ], // dng_v9.0 d65 "raw_crop": [ 72, 34, 6024, 4022 ], // full size 6096x4056, official crop 84,46,6083,4045 "masked_areas": [ 40, 16, 4000, 54 ], @@ -861,6 +879,38 @@ Quality X: unknown, ie we knowing to little about the camera properties to know } }, +// Canon Low End DSLRs +// Canon EOS 1200D/Rebel T5/Kiss X70" is upper at the same item as 600D/T3i/X5 + + { // Quality B, integer ISOs measured, intermediate ISO samples missing, + // scaling factors safely guessed to be same as 1200D .. + "make_model": [ "Canon EOS 1300D", "Canon EOS Rebel T6", "Canon EOS Kiss X80" ], + "dcraw_matrix": [ 6939,-1016,-866,-4428,12473,2177,-1175,2178,6162 ], // Dcraw 9.27 + "ranges": { + "white": [ + { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13584 + { "iso": [ 160, 320, 640, 1250, 2500, 5000, 10000 ], "levels": 12550 }, // typical 12650 + { "iso": [ 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200, 4000, 6400, 8000, 12800 ], "levels": 15200 } // typical 15303 + ], + "white_max": 16383, + "aperture_scaling": [ + /* note: no scale factors known for f/1.2 and f/1.0 (had no lenses to test with), but the + typical 12650 white levels maxes out at "white_max" for f/1.4 and below anyway. */ + { "aperture": 1.4, "scale_factor": 1.290 }, // guessed from 60D data + { "aperture": 1.6, "scale_factor": 1.190 }, // guessed + { "aperture": 1.8, "scale_factor": 1.140 }, // guessed + { "aperture": 2.0, "scale_factor": 1.090 }, // 12293/11222 = 1.095 + { "aperture": 2.2, "scale_factor": 1.060 }, // 11971/11222 = 1.066 + { "aperture": 2.5, "scale_factor": 1.050 }, // guessed + { "aperture": 2.8, "scale_factor": 1.030 }, // iso100: 14042/13584=1.0336 - iso200 15820/15303 = 1.0348 + { "aperture": 3.2, "scale_factor": 1.000 }, // + { "aperture": 3.5, "scale_factor": 1.000 } // + ] + } + }, + +// Canon Mirrorless with Interchangable Lens + { // Quality B, missing scaling factors are guessed safely from 650D relative data "make_model": "Canon EOS M", "dcraw_matrix": [ 6602,-841,-939,-4472,12458,2247,-975,2039,6148 ], @@ -920,6 +970,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know ] } }, + { // Quality C, White Levels not properly indicated, aperture scaling..missing scaling factors are guessed "make_model": "Canon EOS M3", "dcraw_matrix": [ 6362,-823,-847,-4426,12109,2616,-743,1857,5635 ], // DNG_V8.8 D65 @@ -947,33 +998,16 @@ Quality X: unknown, ie we knowing to little about the camera properties to know ] } }, - { // Quality C, White Levels not properly indicated, aperture scaling..missing scaling factors are guessed - "make_model": "Canon EOS 80D", - "dcraw_matrix": [ 7457,-671,-937,-4849,12495,2643,-1213,2354,5492 ], // DNG_V9.5 D65 - "raw_crop": [ 264, 34, 6024, 4022 ], // full size 6288x4056, official crop 276,46,6275,4045 - "masked_areas": [ 40, 96, 4000, 260 ], - "ranges": { - "white": [ - { "iso": [ 100, 125, 200, 250 ], "levels": 16200 }, // nominal 16383, LENR blue 16243 - { "iso": [ 160 ], "levels": 13000 }, // nominal 13097, - { "iso": [ 320, 640, 1250, 2500, 5000, 10000 ], "levels": 13200 }, // G1,G2 13415 - { "iso": [ 400, 500, 800, 1000, 1600, 2000, 3200, 4000 ], "levels": 16150 }, // nominal 16383, LENR ISO3200 16150 - { "iso": [ 6400, 8000, 12800, 16000, 25600 ], "levels": 16000 } // R,G1,G2 16383, B 16243, LENR B 16000 - ], - "white_max": 16383, - "aperture_scaling": [ - /* note: need for more data to properly fill all scale factors */ - { "aperture": 1.4, "scale_factor": 1.200 }, // guessed - { "aperture": 1.6, "scale_factor": 1.080 }, // guessed - { "aperture": 1.8, "scale_factor": 1.055 }, // guessed - { "aperture": 2.0, "scale_factor": 1.030 }, // guessed - { "aperture": 2.2, "scale_factor": 1.025 }, // guessed - { "aperture": 2.5, "scale_factor": 1.020 }, // guessed - { "aperture": 2.8, "scale_factor": 1.000 }, // - { "aperture": 3.2, "scale_factor": 1.000 }, // - { "aperture": 3.5, "scale_factor": 1.000 } // - ] - } + +// Canon Powershot + + { // Quality C, CHDK DNGs, raw frame corrections, experimental infrared support commented out + "make_model": "Canon PowerShot A480", + "dcraw_matrix": [ 8275,-2905,-1261,-128,5305,505,52,482,2450 ], // DNG_CHDK_V1.3.0 Daylight + // "dcraw_matrix": [ 15906,-7425,-2014,-2010,5554,264,404,-265,2706 ], // Infrared guessed + "raw_crop": [ 6, 12, 3684, 2760 ], // full size 3720X2772, official Canon crop 3648x2736 + "masked_areas": [ 12, 3694, 2760, 3716 ], // only left side optically black area is considered + "ranges": { "white": 4080 } }, { // Quality B, experimental infrared support commented out @@ -984,17 +1018,17 @@ Quality X: unknown, ie we knowing to little about the camera properties to know // "dcraw_matrix": [ 13254,-6296,-1798,184,2753,90,1438,-566,1129 ], // Infrared guessed "ranges": { "white": 4080 } }, - { // Quality C, experimental infrared support commented out - "make_model": "Canon PowerShot A480", - "dcraw_matrix": [ 8275,-2905,-1261,-128,5305,505,52,482,2450 ], // DNG_CHDK_V1.3.0 Daylight - // "dcraw_matrix": [ 15906,-7425,-2014,-2010,5554,264,404,-265,2706 ], // Infrared guessed - "raw_crop": [ 6, 12, 3684, 2760 ], // full size 3720X2772, official Canon crop 3648x2736 - "masked_areas": [ 12, 3694, 2760, 3716 ], // only left side optically black area is considered - "ranges": { "white": 4080 } + + { // Quality A, changes for raw crop which is optimistic in Dcraw + "make_model": "Canon PowerShot G12", + "dcraw_matrix": [ 13244,-5501,-1248,-1508,9858,1935,-270,1083,4366 ], + // "raw_crop": [ 62, 18, 3666, 2748 ],// max usable + "raw_crop": [ 68, 20, 3656, 2744 ],// equal to official Canon frame, 72,24,3719,2759 = 3648x2736 + "masked_areas": [ 24, 40, 2770, 44 ],// as declared in maker data + "ranges": { "white": 4080 } // }, - - { /* Quality B, needs a way to auto apply 3/2 or 4/3 crops (read exif tags ..) to work better with auto distortion, + { /* Quality B, needs a way to auto apply 3/2 or 4/3 crops (read exif tags ..) to work better with auto distortion, for the moment just comment-uncomment the desired raw crop */ "make_model": "Canon PowerShot G1 X Mark II", "dcraw_matrix": [ 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 ], // D65 matrix from adobe dcp @@ -1006,6 +1040,14 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "ranges": { "white": 16300 } }, + { // Quality B, + "make_model": "Canon PowerShot G3 X", + "dcraw_matrix": [ 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 ], // DNG_V9.1.1 D65 + "raw_crop": [ 128, 36, 5480, 3656 ], // Default official 3/2 frame 5472X3648, 4pix borders, Left Border 132-4, Top border 40-4 + "masked_areas": [ 40, 4, 3680, 76 ], + "ranges": { "white": 16300 } + }, + { // Quality B, "make_model": "Canon PowerShot G7 X", "dcraw_matrix": [ 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 ], // DNG_V8.7 D65 @@ -1014,18 +1056,11 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "masked_areas": [ 40, 4, 3680, 76 ], "ranges": { "white": 4080 } }, - { // Quality B, - "make_model": [ "Canon PowerShot G9 X", "Canon PowerShot G5 X" ], - "dcraw_matrix": [ 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 ], // DNG_V8.7 D65 - // "raw_crop": [ 116, 24, 5504, 3680 ], // Sensor size 5632x3710. Largest useful frame 120-5616X28-3702 = 5504x3682, 4pix RTborders, Left Border 120-4, Top border 28-4 - "raw_crop": [ 128, 36, 5480, 3656 ], // Default official 3/2 frame 5472X3648, 4pix borders, Left Border 132-4, Top border 40-4 - "masked_areas": [ 40, 4, 3680, 76 ], - "ranges": { "white": 16300 } - }, { // Quality B, - "make_model": "Canon PowerShot G3 X", - "dcraw_matrix": [ 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 ], // DNG_V9.1.1 D65 + "make_model": [ "Canon PowerShot G5 X", "Canon PowerShot G9 X" ], + "dcraw_matrix": [ 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 ], // DNG_V8.7 D65 + // "raw_crop": [ 116, 24, 5504, 3680 ], // Sensor size 5632x3710. Largest useful frame 120-5616X28-3702 = 5504x3682, 4pix RTborders, Left Border 120-4, Top border 28-4 "raw_crop": [ 128, 36, 5480, 3656 ], // Default official 3/2 frame 5472X3648, 4pix borders, Left Border 132-4, Top border 40-4 "masked_areas": [ 40, 4, 3680, 76 ], "ranges": { "white": 16300 } @@ -1039,15 +1074,6 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "ranges": { "white": 4050 } }, - { // Quality A, changes for raw crop which is optimistic in Dcraw - "make_model": "Canon PowerShot G12", - "dcraw_matrix": [ 13244,-5501,-1248,-1508,9858,1935,-270,1083,4366 ], - // "raw_crop": [ 62, 18, 3666, 2748 ],// max usable - "raw_crop": [ 68, 20, 3656, 2744 ],// equal to official Canon frame, 72,24,3719,2759 = 3648x2736 - "masked_areas": [ 24, 40, 2770, 44 ],// as declared in maker data - "ranges": { "white": 4080 } // - }, - { // Quality B "make_model": "Canon PowerShot SX60 HS", "dcraw_matrix": [ 13161,-5451,-1344,-1989,10654,1531,-47,1271,4955 ], // DNG_V8.7 D65 @@ -1086,12 +1112,19 @@ Quality X: unknown, ie we knowing to little about the camera properties to know // "raw_crop": [ 4, 0, 4936, 3296 ], // full raw 4992,3296, fuji official 4936,3296 - experimental crop "ranges": { "white": 16100 } }, + { // Quality B "make_model": "FUJIFILM X-E2S", "dcraw_matrix": [ 11562,-5118,-961,-3022,11007,2311,-525,1569,6097 ], // DNG_v9.4 D65 "ranges": { "white": 16100 } }, + { // Quality B + "make_model": "FUJIFILM X-PRO1", + "dcraw_matrix": [ 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 ], // DNG_v9.4 D65 + "ranges": { "white": 4080 } + }, + { // Quality B "make_model": "FUJIFILM X-PRO2", "dcraw_matrix": [ 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 ], // DNG_v9.4 D65 @@ -1110,6 +1143,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "dcraw_matrix": [ 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 ], // DNG_v8.8 D65 "ranges": { "white": 4040 } }, + { // Quality B, Matrix from Adobe's dcp D65 instead of the internal in Leica's DNG "make_model": "LEICA Q (Typ 116)", "dcraw_matrix": [ 10068,-4043,-1068,-5319,14268,1044,-765,1701,6522 ], // DCP D65 @@ -1154,6 +1188,9 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "ranges": { "white": 4080 } // BL autodetected from exif }, +// For all Nikon Dslrs which have multiple bitdepth options (14 and 12 bit) we define the 14-bit value and RT adapts it to 12-bit +// when a 12-bit bitdepth is detected (WL12 = WL14*4095/16383) + { // quality B, samples by Johan Thor at RT.Issues, measures at long exposures with LENR are missing // but a safety margin is included - aperture scaling makes no significant difference "make_model": "Nikon D3S", @@ -1219,22 +1256,22 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "ranges": { "black": 0, "white": 16300 } // WL typical 16383 set to 16300 for safety }, - { // Quality B, aperture scaling used to scale WL at safer levels + { // Quality B "make_model": "Nikon D5300", "dcraw_matrix": [ 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 ], // adobe dng_v8.8 d65 - "ranges": { "white": 16300 } // attention.. WL value is for 14-bit files, has to be 4070 for 12-bit files. WL typical 16383 set to 16300 for safety + "ranges": { "white": 16300 } // WL value is for 14-bit files, RT auto adapts it for 12-bit files. WL typical 16383 set to 16300 for safety }, - { // Quality B, aperture scaling used to scale WL at safer levels + { // Quality B "make_model": "Nikon D5500", "dcraw_matrix": [ 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 ], // adobe dng_v9.0 d65 - "ranges": { "white": 16300 } // attention.. WL value is for 14-bit files, has to be 4070 for 12-bit files. WL typical 16383 set to 16300 for safety + "ranges": { "white": 16300 } // WL value is for 14-bit files, RT auto adapts it for 12-bit files. WL typical 16383 set to 16300 for safety }, - { // Quality B, color matrix from DNG_v9.0 instead of internal Dcraw_v9.25_r1.475, + { // Quality B "make_model": "Nikon D7200", "dcraw_matrix": [ 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 ], // adobe dng_v9.0 d65 - "ranges": { "white": 16300 } // attention.. WL values are for 14-bit files, has to be WL4070 for 12-bit files. WL typical 16383 set to 16300 for safety, + "ranges": { "white": 16300 } // WL value is for 14-bit files, RT auto adapts it for 12-bit files. WL typical 16383 set to 16300 for safety, }, { // quality B, samples by joachip at RT forums, are measures at long exposures with LongExposureNoiseReduction @@ -1252,12 +1289,12 @@ Quality X: unknown, ie we knowing to little about the camera properties to know ], "white_max": 16383 } - }, - { // quality B, lacks WL measures at intermediate ISOs (160-250-320 ..) and measures at long exposures with LongExposureNoiseReduction + }, + { // quality B, missing WL measures at intermediate ISOs (160-250-320 ..) and at long exposures with LongExposureNoiseReduction set to ON // aperture scaling known to exist, but little to gain as the levels are so close to white_max "make_model": "Nikon D610", "dcraw_matrix": [ 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 ], // dcp d65 - "raw_crop": [ 0, 0, 6034, 4028 ], // Dcraw has no raw crop for D610 + "raw_crop": [ 0, 0, 6034, 4028 ], "ranges": { "white": [ { "iso": [ 50, 100 ], "levels": [ 15800, 15700, 15800 ] }, // typical G1/G2 15778, R/B 15879 lowered to 15700, 15800 for possible WL distribution under LENR @@ -1267,25 +1304,24 @@ Quality X: unknown, ie we knowing to little about the camera properties to know ], "white_max": 16383 } - }, + }, - { // quality B; Data from RusselCottrell at RT forums. sensor is not uniform + { // quality B; Data from RusselCottrell at RT forums. sensor is not uniform "make_model": "Nikon D700", "dcraw_matrix": [ 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 ], - // "dcraw_matrix": [ 9336,-3405,14,-7321,14779,2764,-914,1171,8248 ], // illum a - // "raw_crop": [ 1400, 600, 1600, 1600 ], // experimental - Dcraw 2 0 4284 2844, + // "dcraw_matrix": [ 9336,-3405,14,-7321,14779,2764,-914,1171,8248 ], // illuminant A "ranges": { "white": [ 15500, 15500, 15500 ] } - // Non linearities start at 15750 (hi ISOs) 15850 (low ISOs) with long exposures (>2sec) and LENR ON .. nominal 15892 - // white 15750 is correct for 14-bit files, for 12-bit files RT auto_calculates it 15750*4095/16383=3936 - }, + // Non linearities start at 15500 (hi ISOs) 15850 (low ISOs) with long exposures (>2sec) and LENR ON .. nominal 15892 + // white 15500 is correct for 14-bit files, for 12-bit files RT auto_calculates it 15750*4095/16383=3936 + }, - { // Quality B, + { // Quality B, "make_model": "Nikon D750", "dcraw_matrix": [ 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 ], // adobe dcp d65 DNGv8.7 - "ranges": { "white": 16300 } // attention.. WL values are for 14-bit files, has to be WL4070 for 12-bit files. WL typical 16383 set to 16300 for safety - }, + "ranges": { "white": 16300 } // WL values for 14-bit files, RT auto adapts it for 12-bit files. TypicalWL 16383 set to 16300 for safety + }, - { // quality B; Data from RussellCottrell at RT forums. Largest aperture scale factor is 1.013, about 1/50th of a stop + { // quality B; Data from RussellCottrell at RT forums. Largest aperture scale factor is 1.013, about 1/50th of a stop "make_model": "Nikon D800E", "dcraw_matrix": [ 7866,-2108,-555,-4869,12483,2681,-1176,2069,7501 ], // D800/D800E from dcraw.c "ranges": { @@ -1295,17 +1331,18 @@ Quality X: unknown, ie we knowing to little about the camera properties to know { "iso": [ 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 16300 } // 16383 ] } - }, - { // quality B, WL set at 16300 from nominal 16380 for possible non linearities with LENR + }, + { // quality B, WL set at 16300 from nominal 16380 for possible non linearities with LENR "make_model": "Nikon D810", "dcraw_matrix": [ 9369,-3195,-791,-4488,12430,2301,-893,1796,6872 ], // dcp_v8.6 d65 "raw_crop": [ 0, 0, 7380, 4928 ], // Official raw crop 7380x4928, - "ranges": { "white": 16300 } // WL 16300 is for 14-bit raws, for 12-bit files RT auto calculates the correct WL. Typical WL at 16383 + "ranges": { "white": 16300 } // WL values for 14-bit files, RT auto adapts it for 12-bit files. Typical WL at 16383 }, + { // Quality b, 16Mp and 64Mp raw frames "make_model": "OLYMPUS E-M5MarkII", "dcraw_matrix": [ 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 ], // DNG_v8.8 D65 - "raw_crop": [ 0, 0, -6, -6 ], // largest valid, full 64Mp 9280x6938, official crop 0 0 9216 6912 - safe 5755 + "raw_crop": [ 0, 0, -6, -6 ], // largest valid, full 64Mp 9280x6938, official crop 0 0 9216 6912 "ranges": { "white": [ { "iso": [ 100, 200 ], "levels": 3950 }, // normal 4080-4095, HR Dpreview 4047, IR 3956 @@ -1317,7 +1354,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know { // Quality B, 20Mp and 80Mp raw frames "make_model": "OLYMPUS PEN-F", "dcraw_matrix": [ 9476,-3182,-765,-2613,10958,1893,-449,1315,5268 ], // dng_v9.5 D65 - // "raw_crop": [ 0, 0, 10372, -7780 ], // largest valid, full 80Mp 10400X7796, official crop 10 10 10368 7776 - + // "raw_crop": [ 0, 0, 10372, -7780 ], // Highres mode largest valid, full 80Mp 10400X7796, official crop 10 10 10368 7776 "ranges": { "white": [ { "iso": [ 100, 200 ], "levels": 3950 }, // normal 4080-4095, HR Dpreview 4047, IR 3956 @@ -1358,15 +1395,15 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "ranges": { "white": 4050 } // safe for worst case detected, nominal is 4093 }, - /* since Dcraw_v9.21 Panasonic base BL is read from exif (tags 0x001c BlackLevelRed15 is BL offstet. - Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset, 0x001d BlackLevelGreen, 0x001e BlackLevelBlue + /* since Dcraw_v9.21 Panasonic base BL is read from exif (tags 0x001c BlackLevelRed15 is BL offset. + Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset, 0x001d BlackLevelGreen, 0x001e BlackLevelBlue and we define here the needed offset of around 15. The total BL is base+offset */ { // Quality B, CameraPhone, some samples are missing but has the same sensor as FZ1000 .. "make_model": [ "Panasonic DMC-CM1", "Panasonic DMC-CM10" ], "dcraw_matrix": [ 8770,-3194,-820,-2871,11281,1803,-513,1552,4434 ], // dcp_v8.7 d65 "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 80, "levels": 3600 }, // exif:3277 distribution peak at 3700 up to +/- 100 { "iso": [ 100, 125, 200, 400, 800, 1600 ], "levels": 4050 }, // exif 4095 distribution 4050-4095 @@ -1378,20 +1415,20 @@ Quality X: unknown, ie we knowing to little about the camera properties to know { // Quality A , replicated from rawimage.cc "make_model": "Panasonic DMC-FZ150", "dcraw_matrix": [ 10435,-3208,-72,-2293,10506,2067,-486,1725,4682 ], // RT, copy from custom dcp d55 - "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "ranges": { "black": 15, "white": 4050 } // 15 is BL offset. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset }, { // Quality Β, "make_model": [ "Panasonic DMC-FZ300", "Panasonic DMC-FZ330" ], "dcraw_matrix": [ 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 ], // DNG-V9.1.1 - "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "ranges": { "black": 15, "white": 4050 } // 15 is BL offset. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset }, { // Quality A, samples by helices at Rt forums "make_model": [ "Panasonic DMC-FZ1000", "Leica V-LUX (Typ 114)" ], "dcraw_matrix": [ 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 ], // dcp_v8.6 d65 "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 80, "levels": 3600 }, // exif:3277 distribution peak at 3700 up to +/- 100 { "iso": [ 100, 125, 200, 400, 800, 1600 ], "levels": 4050 }, // exif 4095 distribution 4050-4095 @@ -1399,11 +1436,12 @@ Quality X: unknown, ie we knowing to little about the camera properties to know ] } }, - { // Quality A, samples by helices at Rt forums + { // Quality A, samples by helices at Rt forums and Chris Power at github "make_model": [ "Panasonic DMC-ZS100", "Panasonic DMC-ZS110", "Panasonic DMC-TZ100", "Panasonic DMC-TZ101", "Panasonic DMC-TZ110", "Panasonic DMC-TX1" ], "dcraw_matrix": [ 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 ], // dcp_v8.6 d65 + "raw_crop": [ 4, 4, -4, -4 ], // full raw frame 5488x3664 exif crop 5472X3648 with 8pixel borders. Set the borders at 4 pixels which added with RT's 4 pixels border gives exactly the official frame. "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 80, "levels": 3600 }, // exif:3277 distribution peak at 3700 up to +/- 100 { "iso": [ 100, 125, 200, 400, 800, 1600 ], "levels": 4050 }, // exif 4095 distribution 4050-4095 @@ -1414,13 +1452,13 @@ Quality X: unknown, ie we knowing to little about the camera properties to know { // Quality A "make_model": [ "Panasonic DMC-LF1", "Leica C (Typ 112)" ], "dcraw_matrix": [ 9379,-3267,-816,-3227,11560,1881,-926,1928,5340 ], - "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "ranges": { "black": 15, "white": 4050 } // 15 is BL offset. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset }, { // Quality A "make_model": [ "Panasonic DMC-TZ60", "Panasonic DMC-TZ61", "Panasonic DMC-ZS40", "Panasonic DMC-ZS41" ], "dcraw_matrix": [ 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 ], // matrix from Adobe dcp v8.4 "raw_crop": [ 8, 8, -8, -8 ], // crop according to exif 4896 X 3672 plus 4 pixels borders. RT's frame gets smaller than Dcraw but works better with auto distortion - "ranges": { "black": 14, "white": 4050 } // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "ranges": { "black": 14, "white": 4050 } // 15 is BL offset. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset }, { // Quality B, "make_model": [ "Panasonic DMC-TZ70", "Panasonic DMC-TZ71", "Panasonic DMC-ZS50", "Panasonic DMC-ZS51" ], @@ -1446,7 +1484,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "make_model": "Panasonic DMC-G1", "dcraw_matrix": [ 7477,-1615,-651,-5016,12769,2506,-1380,2475,7240 ], // Colin Walker "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": [ 100, 200, 400, 800 ], "levels": 3920 }, // exif:4095 distribution peak at 3977 +/- up to 50 { "iso": [ 1600, 3200 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 @@ -1457,21 +1495,21 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "make_model": "Panasonic DMC-G3", "dcraw_matrix": [ 6051,-1406,-671,-4015,11505,2868,-1654,2667,6219 ], // Colin Walker "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": 4060 } // exif:4095 normal distribution 4080-4095, 4070-4095 on long exposure NR }, { // Quality A, Replicated from rawimage.cc "make_model": "Panasonic DMC-G5", "dcraw_matrix": [ 7122,-2092,-419,-4643,11769,3283,-1363,2413,5944 ], // RT "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": 4060 } // exif:4095 normal distribution 4080-4095, 4070-4095 on long exposure NR }, { // Quality A, Replicated from rawimage.cc "make_model": "Panasonic DMC-GF1", "dcraw_matrix": [ 7863,-2080,-668,-4623,12331,2578,-1020,2066,7266 ], // Colin Walker "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": [ 100, 200, 400, 800 ], "levels": 3920 }, // exif:4095 distribution peak at 3977 +/- up to 50 { "iso": [ 1600, 3200 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 @@ -1483,21 +1521,21 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "make_model": "Panasonic DMC-GF2", "dcraw_matrix": [ 7694,-1791,-745,-4917,12818,2332,-1221,2322,7197 ], // Colin Walker "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": 4050 } // exif:4095 normal distribution 4080-4095, 4050-4095 on long exposure NR }, { // Quality A, Replicated from rawimage.cc "make_model": "Panasonic DMC-GF3", "dcraw_matrix": [ 8074,-1846,-861,-5026,12999,2239,-1320,2375,7422 ], // Colin Walker "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": 4050 } // exif:4095 normal distribution 4080-4095, 4050-4095 on long exposure NR }, { // Quality A, Replicated from rawimage.cc "make_model": "Panasonic DMC-GH1", "dcraw_matrix": [ 6360,-1557,-375,-4201,11504,3086,-1378,2518,5843 ], // Colin Walker "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": [ 100, 200, 400, 800 ], "levels": 3930 }, // exif:4095 distribution peak at 3982 +/- up to 50 { "iso": [ 1600, 3200 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 @@ -1509,7 +1547,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know // "dcraw_matrix": [ 6855,-1765,-456,-4223,11600,2996,-1450,2602,5761 ], // Colin Walker - disabled due to problems with underwater "dcraw_matrix": [ 7780,-2410,-806,-3913,11724,2484,-1018,2390,5298 ], // Dcraw d65 "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": [ 100, 200, 400, 800 ], "levels": 3930 }, // exif:4095 distribution peak at 3982 +/- up to 50 { "iso": [ 1600, 3200, 6400, 12800 ], "levels": 4060 } // exif 4095, histogram peak 4095 and distribution down to 4070 @@ -1521,7 +1559,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "make_model": "Panasonic DMC-GH3", "dcraw_matrix": [ 6559,-1752,-491,-3672,11407,2586,-962,1875,5130 ], // dcp d65 "ranges": { - "black": 16, // 16 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 16, // 16 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 125, "levels": 3500 }, // gaussian 3600-4095 { "iso": [ 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 @@ -1533,7 +1571,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "make_model": "Panasonic DMC-GH4", "dcraw_matrix": [ 7122,-2108,-512,-3155,11201,2231,-541,1423,5045 ], // dng_v8.5 d65 "ranges": { - "black": 16, // 16 is BL offstet. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 16, // 16 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 100, "levels": 2700 }, // gaussian center at 2870-2920 range +/- 150, exif 2111 { "iso": 125, "levels": 3100 }, // guessed @@ -1546,7 +1584,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "make_model": "Panasonic DMC-GM1", "dcraw_matrix": [ 6770,-1895,-744,-5232,13145,2303,-1664,2691,5703 ], "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 125, "levels": 3100 }, // bell shape 3150-3650 - exif 2616 { "iso": 160, "levels": 3600 }, // guessed from relative GX7 data @@ -1559,7 +1597,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "make_model": "Panasonic DMC-GM5", "dcraw_matrix": [ 8238,-3244,-679,-3921,11814,2384,-836,2022,5852 ], // dng_v8.7 d65 "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 100, "levels": 2800 }, // bell shape 2850-3250 - exif 2111 { "iso": [ 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 @@ -1570,7 +1608,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "make_model": [ "Panasonic DMC-GX7", "Panasonic DMC-GF7", "Panasonic DMC-GF8" ], "dcraw_matrix": [ 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 ], "ranges": { - "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 125, "levels": 3100 }, { "iso": 160, "levels": 3600 }, @@ -1583,7 +1621,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "make_model": [ "Panasonic DMC-G7", "Panasonic DMC-G70", "Panasonic DMC-GX80", "Panasonic DMC-GX85" ], "dcraw_matrix": [ 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 ],// DNG_v9.1 D65 "ranges": { - "black": 16, // 16 is BL offset. Dcraw/RT read the BLbase from exif and calculates total BL = BLbase+BLoffset + "black": 16, // 16 is BL offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 100, "levels": 2300 }, // gaussian 2300-2700 exif_linearitylimit 2111 { "iso": 125, "levels": 3180 }, // gaussian 3200-3600 exif_linearitylimit 2626 @@ -1595,7 +1633,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "make_model": "Panasonic DMC-GX8", "dcraw_matrix": [ 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 ], // DNG_v9.1.1 D65 "ranges": { - "black": 15, // 16 is BL offstet. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 16 is BL offset. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 100, "levels": 2800 }, // gaussian 2900-3200 exif_linearitylimit 2111 { "iso": 125, "levels": 3180 }, // guessed gaussian 3200-3600 exif_linearitylimit 2626 @@ -1608,7 +1646,7 @@ Quality X: unknown, ie we knowing to little about the camera properties to know "dcraw_matrix": [ 8844,-3538,-768,-3709,11762,2200,-698,1792,5220 ], // DNG_V8.7 d65 // "dcraw_matrix": [ 6538,-1614,-549,-5475,13096,2646,-1780,2799,5612 ], // calculated from DxO D50 "ranges": { - "black": 15, // 15 is BL offset calculated from exif data. + "black": 15, // 15 is BL offset. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset. "white": [ { "iso": 100, "levels": 2300 }, // gaussian 2400-2700 exif_linearitylimit 2111 { "iso": [ 160, 200, 250, 320, 400, 500, 640, 800, 1000, 1250, 1600, 2000, 2500, 3200, 4000, 5000, 6400, 12800, 25600 ], "levels": 4080 } // nominal 4095 diff --git a/rtengine/ciecam02.cc b/rtengine/ciecam02.cc index 83ff98f95..f10ae4b31 100644 --- a/rtengine/ciecam02.cc +++ b/rtengine/ciecam02.cc @@ -180,39 +180,36 @@ void Ciecam02::curveJ (double br, double contr, int db, LUTf & outCurve, LUTu & } } -void Ciecam02::curveJfloat (float br, float contr, int db, LUTf & outCurve, LUTu & histogram ) +void Ciecam02::curveJfloat (float br, float contr, const LUTu & histogram, LUTf & outCurve) { - LUTf dcurve(65536, 0); - int skip = 1; // check if brightness curve is needed if (br > 0.00001f || br < -0.00001f) { - std::vector brightcurvePoints; - brightcurvePoints.resize(9); - brightcurvePoints.at(0) = double(DCT_NURBS); + std::vector brightcurvePoints(9); + brightcurvePoints[0] = double(DCT_NURBS); - brightcurvePoints.at(1) = 0.f; // black point. Value in [0 ; 1] range - brightcurvePoints.at(2) = 0.f; // black point. Value in [0 ; 1] range + brightcurvePoints[1] = 0.f; // black point. Value in [0 ; 1] range + brightcurvePoints[2] = 0.f; // black point. Value in [0 ; 1] range if (br > 0) { - brightcurvePoints.at(3) = 0.1f; // toe point - brightcurvePoints.at(4) = 0.1f + br / 150.0f; //value at toe point + brightcurvePoints[3] = 0.1f; // toe point + brightcurvePoints[4] = 0.1f + br / 150.0f; //value at toe point - brightcurvePoints.at(5) = 0.7f; // shoulder point - brightcurvePoints.at(6) = min(1.0f, 0.7f + br / 300.0f); //value at shoulder point + brightcurvePoints[5] = 0.7f; // shoulder point + brightcurvePoints[6] = min(1.0f, 0.7f + br / 300.0f); //value at shoulder point } else { - brightcurvePoints.at(3) = 0.1f - br / 150.0f; // toe point - brightcurvePoints.at(4) = 0.1f; // value at toe point + brightcurvePoints[3] = 0.1f - br / 150.0f; // toe point + brightcurvePoints[4] = 0.1f; // value at toe point - brightcurvePoints.at(5) = min(1.0f, 0.7f - br / 300.0f); // shoulder point - brightcurvePoints.at(6) = 0.7f; // value at shoulder point + brightcurvePoints[5] = min(1.0f, 0.7f - br / 300.0f); // shoulder point + brightcurvePoints[6] = 0.7f; // value at shoulder point } - brightcurvePoints.at(7) = 1.f; // white point - brightcurvePoints.at(8) = 1.f; // value at white point + brightcurvePoints[7] = 1.f; // white point + brightcurvePoints[8] = 1.f; // value at white point - DiagonalCurve* brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS / skip); + DiagonalCurve brightcurve(brightcurvePoints, CURVES_MIN_POLY_POINTS); // Applying brightness curve for (int i = 0; i < 32768; i++) { @@ -221,67 +218,56 @@ void Ciecam02::curveJfloat (float br, float contr, int db, LUTf & outCurve, LUTu float val = (float)i / 32767.0f; // apply brightness curve - val = brightcurve->getVal (val); + val = brightcurve.getVal (val); - // store result in a temporary array - dcurve[i] = CLIPD(val); + // store result + outCurve[i] = CLIPD(val); } - delete brightcurve; } else { - // for (int i=0; i<32768; i++) { // L values range up to 32767, higher values are for highlight overflow - for (int i = 0; i < (32768 * db); i++) { // L values range up to 32767, higher values are for highlight overflow - - // set the identity curve in the temporary array - dcurve[i] = (float)i / (db * 32768.0f); - } + // set the identity curve + outCurve.makeIdentity(32767.f); } if (contr > 0.00001f || contr < -0.00001f) { // compute mean luminance of the image with the curve applied - int sum = 0; - float avg = 0; + float sum = 0.f; + float avg = 0.f; - //float sqavg = 0; for (int i = 0; i < 32768; i++) { - avg += dcurve[i] * histogram[i];//approximation for average : usage of L (lab) instead of J + avg += outCurve[i] * histogram[i];//approximation for average : usage of L (lab) instead of J sum += histogram[i]; } avg /= sum; - //printf("avg=%f\n",avg); - std::vector contrastcurvePoints; - contrastcurvePoints.resize(9); - contrastcurvePoints.at(0) = double(DCT_NURBS); + std::vector contrastcurvePoints(9); - contrastcurvePoints.at(1) = 0.f; // black point. Value in [0 ; 1] range - contrastcurvePoints.at(2) = 0.f; // black point. Value in [0 ; 1] range + contrastcurvePoints[0] = double(DCT_NURBS); - contrastcurvePoints.at(3) = avg - avg * (0.6f - contr / 250.0f); // toe point - contrastcurvePoints.at(4) = avg - avg * (0.6f + contr / 250.0f); // value at toe point + contrastcurvePoints[1] = 0.f; // black point. Value in [0 ; 1] range + contrastcurvePoints[2] = 0.f; // black point. Value in [0 ; 1] range - contrastcurvePoints.at(5) = avg + (1 - avg) * (0.6f - contr / 250.0f); // shoulder point - contrastcurvePoints.at(6) = avg + (1 - avg) * (0.6f + contr / 250.0f); // value at shoulder point + contrastcurvePoints[3] = avg - avg * (0.6f - contr / 250.0f); // toe point + contrastcurvePoints[4] = avg - avg * (0.6f + contr / 250.0f); // value at toe point - contrastcurvePoints.at(7) = 1.f; // white point - contrastcurvePoints.at(8) = 1.f; // value at white point + contrastcurvePoints[5] = avg + (1 - avg) * (0.6f - contr / 250.0f); // shoulder point + contrastcurvePoints[6] = avg + (1 - avg) * (0.6f + contr / 250.0f); // value at shoulder point - DiagonalCurve* contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS / skip); + contrastcurvePoints[7] = 1.f; // white point + contrastcurvePoints[8] = 1.f; // value at white point + + DiagonalCurve contrastcurve(contrastcurvePoints, CURVES_MIN_POLY_POINTS); // apply contrast enhancement - for (int i = 0; i < (32768 * db); i++) { - dcurve[i] = contrastcurve->getVal (dcurve[i]); + for (int i = 0; i < 32768; i++) { + outCurve[i] = contrastcurve.getVal(outCurve[i]); } - delete contrastcurve; } - // for (int i=0; i<32768; i++) outCurve[i] = 32768.0*dcurve[i]; - for (int i = 0; i < (db * 32768); i++) { - outCurve[i] = db * 32768.0f * dcurve[i]; - } + outCurve *= 32767.f; } /** @@ -857,7 +843,7 @@ void Ciecam02::xyz2jchqms_ciecam02( double &J, double &C, double &h, double &Q, h = myh; } -void Ciecam02::xyz2jchqms_ciecam02float( float &J, float &C, float &h, float &Q, float &M, float &s, float &aw, float &fl, float &wh, +void Ciecam02::xyz2jchqms_ciecam02float( float &J, float &C, float &h, float &Q, float &M, float &s, float aw, float fl, float wh, float x, float y, float z, float xw, float yw, float zw, float c, float nc, int gamu, float pow1, float nbb, float ncb, float pfl, float cz, float d) diff --git a/rtengine/ciecam02.h b/rtengine/ciecam02.h index e5b61d466..a551b2504 100644 --- a/rtengine/ciecam02.h +++ b/rtengine/ciecam02.h @@ -74,7 +74,7 @@ public: static void curvecolor(double satind, double satval, double &sres, double parsat); static void curvecolorfloat(float satind, float satval, float &sres, float parsat); static void curveJ (double br, double contr, int db, LUTf & outCurve , LUTu & histogram ) ; - static void curveJfloat (float br, float contr, int db, LUTf & outCurve , LUTu & histogram ) ; + static void curveJfloat (float br, float contr, const LUTu & histogram, LUTf & outCurve ) ; /** * Inverse transform from CIECAM02 JCh to XYZ. @@ -125,7 +125,7 @@ public: float c, float nc, float n, float nbb, float ncb, float cz, float d ); static void xyz2jchqms_ciecam02float( float &J, float &C, float &h, - float &Q, float &M, float &s, float &aw, float &fl, float &wh, + float &Q, float &M, float &s, float aw, float fl, float wh, float x, float y, float z, float xw, float yw, float zw, float c, float nc, int gamu, float n, float nbb, float ncb, float pfl, float cz, float d ); diff --git a/rtengine/color.cc b/rtengine/color.cc index 3684891df..4e180690e 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -139,7 +139,6 @@ void Color::init () constexpr auto maxindex = 65536; cachef(maxindex, LUT_CLIP_BELOW); - gamma2curve(maxindex, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); gammatab(maxindex, 0); gammatabThumb(maxindex, 0); @@ -185,11 +184,14 @@ void Color::init () #ifdef _OPENMP #pragma omp section #endif + { + for (int i = 0; i < maxindex; i++) + { + gammatab_srgb[i] = 65535.0 * gamma2(i / 65535.0); + } - for (int i = 0; i < maxindex; i++) { - gammatab_srgb[i] = gamma2curve[i] = 65535.0 * gamma2(i / 65535.0); // two lookup tables with same content but one clips and one does not clip + gamma2curve.share(gammatab_srgb, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); // shares the buffer with gammatab_srgb but has different clip flags } - #ifdef _OPENMP #pragma omp section #endif diff --git a/rtengine/colortemp.cc b/rtengine/colortemp.cc index 2ccbcba8d..c99e4bd41 100644 --- a/rtengine/colortemp.cc +++ b/rtengine/colortemp.cc @@ -70,7 +70,7 @@ static const double cie_colour_match_jd[97][3] = {//350nm to 830nm 5 nm J.Desm {0.000001251141, 0.00000045181, 0.000000} }; -ColorTemp::ColorTemp (double t, double g, double e, Glib::ustring m) : temp(t), green(g), equal(e), method(m) +ColorTemp::ColorTemp (double t, double g, double e, const Glib::ustring &m) : temp(t), green(g), equal(e), method(m) { clip (temp, green, equal); @@ -120,7 +120,7 @@ ColorTemp::ColorTemp (double mulr, double mulg, double mulb, double e) : equal(e mul2temp (mulr, mulg, mulb, equal, temp, green); } -void ColorTemp::mul2temp (const double rmul, const double gmul, const double bmul, const double equal, double& temp, double& green) +void ColorTemp::mul2temp (const double rmul, const double gmul, const double bmul, const double equal, double& temp, double& green) const { double maxtemp = double(MAXTEMP), mintemp = double(MINTEMP); @@ -849,7 +849,7 @@ const double ColorTemp::ColabSky42_0_m24_spect[97] = { /* LERP(a,b,c) = linear interpolation macro, is 'a' when c == 0.0 and 'b' when c == 1.0 */ #define LERP(a,b,c) (((b) - (a)) * (c) + (a)) -int ColorTemp::XYZtoCorColorTemp(double x0, double y0, double z0, double &temp) +int ColorTemp::XYZtoCorColorTemp(double x0, double y0, double z0, double &temp) const { typedef struct UVT { @@ -1128,7 +1128,7 @@ void ColorTemp::temp2mulxyz (double tem, double gree, std::string method , doubl //printf("Xxyz=%f Zxyz=%f\n",Xxyz,Zxyz); } -void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul, double& gmul, double& bmul) +void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul, double& gmul, double& bmul) const { clip (temp, green, equal); diff --git a/rtengine/colortemp.h b/rtengine/colortemp.h index c79ebb4bf..a1a805092 100644 --- a/rtengine/colortemp.h +++ b/rtengine/colortemp.h @@ -47,12 +47,14 @@ private: std::string method; static void clip (double &temp, double &green); static void clip (double &temp, double &green, double &equal); + int XYZtoCorColorTemp(double x0, double y0 , double z0, double &temp) const; + void temp2mul (double temp, double green, double equal, double& rmul, double& gmul, double& bmul) const; public: ColorTemp () : temp(-1.), green(-1.), equal (1.), method("Custom") {} ColorTemp (double e) : temp(-1.), green(-1.), equal (e), method("Custom") {} - ColorTemp (double t, double g, double e, Glib::ustring m); + ColorTemp (double t, double g, double e, const Glib::ustring &m); ColorTemp (double mulr, double mulg, double mulb, double e); void update (const double rmul, const double gmul, const double bmul, const double equal) @@ -67,42 +69,40 @@ public: this->equal = equal; } - inline std::string getMethod() + inline std::string getMethod() const { return method; } - inline double getTemp () + inline double getTemp () const { return temp; } - inline double getGreen () + inline double getGreen () const { return green; } - inline double getEqual () + inline double getEqual () const { return equal; } - void getMultipliers (double &mulr, double &mulg, double &mulb) + void getMultipliers (double &mulr, double &mulg, double &mulb) const { temp2mul (temp, green, equal, mulr, mulg, mulb); } - void mul2temp (const double rmul, const double gmul, const double bmul, const double equal, double& temp, double& green); - void temp2mul (double temp, double green, double equal, double& rmul, double& gmul, double& bmul); + void mul2temp (const double rmul, const double gmul, const double bmul, const double equal, double& temp, double& green) const; static void temp2mulxyz (double tem, double gree, std::string method, double &Xxyz, double &Zxyz); - int XYZtoCorColorTemp(double x0, double y0 , double z0, double &temp); static void cieCAT02(double Xw, double Yw, double Zw, double &CAM02BB00, double &CAM02BB01, double &CAM02BB02, double &CAM02BB10, double &CAM02BB11, double &CAM02BB12, double &CAM02BB20, double &CAM02BB21, double &CAM02BB22, double adap ); //static void CAT02 (Imagefloat* baseImg, const ProcParams* params); //static void ciecam_02 (LabImage* lab, const ProcParams* params); - bool operator== (const ColorTemp& other) + bool operator== (const ColorTemp& other) const { return fabs(temp - other.temp) < 1e-10 && fabs(green - other.green) < 1e-10; } - bool operator!= (const ColorTemp& other) + bool operator!= (const ColorTemp& other) const { return !(*this == other); } diff --git a/rtengine/curves.cc b/rtengine/curves.cc index 158086cfd..9b68cc9ee 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -16,12 +16,13 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include +#include +#include +#include +#include #include #include -#include -#include -#include -#include #ifdef _OPENMP #include #endif @@ -43,7 +44,7 @@ using namespace std; namespace rtengine { -Curve::Curve () : N(0), x(NULL), y(NULL), ypp(NULL), hashSize(1000 /* has to be initialized to the maximum value */ ) {} +Curve::Curve () : N(0), x(nullptr), y(nullptr), ypp(nullptr), hashSize(1000 /* has to be initialized to the maximum value */) {} void Curve::AddPolygons () { @@ -69,6 +70,18 @@ void Curve::AddPolygons () poly_y.push_back(y3); } +void Curve::fillDyByDx () +{ + dyByDx.resize(poly_x.size() - 1); + + for(unsigned int i = 0; i < poly_x.size() - 1; i++) { + double dx = poly_x[i + 1] - poly_x[i]; + double dy = poly_y[i + 1] - poly_y[i]; + dyByDx[i] = dy / dx; + + } +} + void Curve::fillHash() { hash.resize(hashSize + 2); @@ -155,11 +168,9 @@ void Curve::getControlPoint(int cpNum, double &x, double &y) const const double CurveFactory::sRGBGamma = 2.2; const double CurveFactory::sRGBGammaCurve = 2.4; -SSEFUNCTION void fillCurveArray(DiagonalCurve* diagCurve, LUTf &outCurve, int skip, bool needed) +void fillCurveArray(DiagonalCurve* diagCurve, LUTf &outCurve, int skip, bool needed) { - if (needed) { - LUTf lutCurve (65536); for (int i = 0; i <= 0xffff; i += i < 0xffff - skip ? skip : 1 ) { // change to [0,1] range @@ -167,353 +178,157 @@ SSEFUNCTION void fillCurveArray(DiagonalCurve* diagCurve, LUTf &outCurve, int sk // apply custom/parametric/NURBS curve, if any val = diagCurve->getVal (val); // store result in a temporary array - lutCurve[i] = (val); + outCurve[i] = val; } // if skip>1, let apply linear interpolation in the skipped points of the curve if (skip > 1) { - int prev = 0; + float skipmul = 1.f / (float) skip; - for (int i = 1; i <= 0xffff - skip; i++) { - if (i % skip == 0) { - prev += skip; - continue; + for (int i = 0; i <= 0x10000 - skip; i += skip) { + for(int j = 1; j < skip; j++) { + outCurve[i + j] = ( outCurve[i] * (skip - j) + outCurve[i + skip] * j ) * skipmul; } - - lutCurve[i] = ( lutCurve[prev] * (skip - i % skip) + lutCurve[prev + skip] * (i % skip) ) / skip; } } - for (int i = 0; i <= 0xffff; i++) { - outCurve[i] = (65535.f * lutCurve[i]); - } + outCurve *= 65535.f; } else { -#ifdef __SSE2__ - __m128 fourv = _mm_set1_ps(4.f); - __m128 iv = _mm_set_ps(3.f, 2.f, 1.f, 0.f); - - for (int i = 0; i <= 0xfffc; i += 4) { - _mm_storeu_ps(&outCurve[i], iv); - iv += fourv; - } - -#else - - for (int i = 0; i <= 0xffff; i++) { - outCurve[i] = (float)i; - } - -#endif - } - -} - -void CurveFactory::updatechroma ( - const std::vector& cccurvePoints, - LUTu & histogramC, LUTu & outBeforeCCurveHistogramC,//for chroma - int skip) -{ - LUTf dCcurve(65536, 0); - float val; - - for (int i = 0; i < 48000; i++) { //32768*1.414 + ... - val = (double)i / 47999.0; - dCcurve[i] = CLIPD(val); - } - - outBeforeCCurveHistogramC.clear(); - bool histNeededC = false; - - - if (!cccurvePoints.empty() && cccurvePoints[0] != 0) { - if (outBeforeCCurveHistogramC /*&& histogramCropped*/) { - histNeededC = true; - } - } - - for (int i = 0; i < 48000; i++) { //32768*1.414 + ... - float val; - - if (histNeededC) { - float hval = dCcurve[i]; - int hi = (int)(255.0 * CLIPD(hval)); // - outBeforeCCurveHistogramC[hi] += histogramC[i] ; - } + outCurve.makeIdentity(); } } - -void CurveFactory::curveLightBrightColor ( - procparams::ColorAppearanceParams::eTCModeId curveMode1, const std::vector& curvePoints1, - procparams::ColorAppearanceParams::eTCModeId curveMode2, const std::vector& curvePoints2, - procparams::ColorAppearanceParams::eCTCModeId curveMode3, const std::vector& curvePoints3, - LUTu & histogram, LUTu & histogramCropped, LUTu & outBeforeCCurveHistogram,//for Luminance - LUTu & histogramC, LUTu & outBeforeCCurveHistogramC,//for chroma - ColorAppearance & customColCurve1, - ColorAppearance & customColCurve2, - ColorAppearance & customColCurve3, - int skip) +void CurveFactory::curveLightBrightColor (const std::vector& curvePoints1, const std::vector& curvePoints2, const std::vector& curvePoints3, + const LUTu & histogram, LUTu & outBeforeCCurveHistogram,//for Luminance + const LUTu & histogramC, LUTu & outBeforeCCurveHistogramC,//for chroma + ColorAppearance & customColCurve1, ColorAppearance & customColCurve2, ColorAppearance & customColCurve3, int skip) { outBeforeCCurveHistogram.clear(); outBeforeCCurveHistogramC.clear(); - bool histNeededC = false; - bool histNeeded = false; - DiagonalCurve* tcurve = NULL; customColCurve3.Reset(); if (!curvePoints3.empty() && curvePoints3[0] > DCT_Linear && curvePoints3[0] < DCT_Unchanged) { - tcurve = new DiagonalCurve (curvePoints3, CURVES_MIN_POLY_POINTS / skip); + DiagonalCurve tcurve(curvePoints3, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogramC /*&& histogramCropped*/) { - histNeededC = true; + if (outBeforeCCurveHistogramC) { + histogramC.compressTo(outBeforeCCurveHistogramC, 48000); } - } - - if (tcurve) { - if (tcurve->isIdentity()) { - delete tcurve; - tcurve = NULL; - } else { + if (!tcurve.isIdentity()) { customColCurve3.Set(tcurve); } - - delete tcurve; - tcurve = NULL; } + customColCurve2.Reset(); if (!curvePoints2.empty() && curvePoints2[0] > DCT_Linear && curvePoints2[0] < DCT_Unchanged) { - tcurve = new DiagonalCurve (curvePoints2, CURVES_MIN_POLY_POINTS / skip); + DiagonalCurve tcurve(curvePoints2, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogram /*&& histogramCropped*/) { + if (outBeforeCCurveHistogram) { histNeeded = true; } - } - - if (tcurve) { - if (tcurve->isIdentity()) { - delete tcurve; - tcurve = NULL; - } else { + if (!tcurve.isIdentity()) { customColCurve2.Set(tcurve); } - - delete tcurve; - tcurve = NULL; } + // create first curve if needed customColCurve1.Reset(); if (!curvePoints1.empty() && curvePoints1[0] > DCT_Linear && curvePoints1[0] < DCT_Unchanged) { - tcurve = new DiagonalCurve (curvePoints1, CURVES_MIN_POLY_POINTS / skip); + DiagonalCurve tcurve(curvePoints1, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogram /*&& histogramCropped*/) { + if (outBeforeCCurveHistogram) { histNeeded = true; } - } - - if (tcurve) { - if (tcurve->isIdentity()) { - delete tcurve; - tcurve = NULL; - } else { + if (!tcurve.isIdentity()) { customColCurve1.Set(tcurve); - delete tcurve; - tcurve = NULL; } } if (histNeeded) { - for (int i = 0; i < 32768; i++) { - double hval = CLIPD((double)i / 32767.0); - int hi = (int)(255.0 * hval); - outBeforeCCurveHistogram[hi] += histogram[i] ; - } - } - - if (histNeededC) { - for (int i = 0; i < 48000; i++) { //32768*1.414 + ... - double hval = CLIPD((double)i / 47999.0); - int hi = (int)(255.0 * hval); // - outBeforeCCurveHistogramC[hi] += histogramC[i] ; - } - } - - if (tcurve) { - delete tcurve; - } - -} -// add curve Denoise : C=f(C) -void CurveFactory::denoiseCC ( bool & ccdenoiseutili, const std::vector& cccurvePoints, LUTf & NoiseCCcurve, int skip) -{ - bool needed; - DiagonalCurve* dCurve = NULL; - LUTf dCcurve(65536, 0); - - float val; - - for (int i = 0; i < 48000; i++) { - dCcurve[i] = (float)i / 47999.0; - } - - needed = false; - - if (!cccurvePoints.empty() && cccurvePoints[0] != 0) { - dCurve = new DiagonalCurve (cccurvePoints, CURVES_MIN_POLY_POINTS / skip); - - if (dCurve && !dCurve->isIdentity()) { - needed = true; - ccdenoiseutili = true; - } - } - - fillCurveArray(dCurve, NoiseCCcurve, skip, needed); - //NoiseCCcurve.dump("Noise"); - - if (dCurve) { - delete dCurve; - dCurve = NULL; + histogram.compressTo(outBeforeCCurveHistogram, 32768); } } - -void CurveFactory::curveBW ( - const std::vector& curvePointsbw, const std::vector& curvePointsbw2, - LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw,//for Luminance - ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip) +void CurveFactory::curveBW ( const std::vector& curvePointsbw, const std::vector& curvePointsbw2, + const LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw,//for Luminance + ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip) { + const float gamma_ = Color::sRGBGammaCurve; - const float start = expf(gamma_ * logf( -0.055 / ((1.0 / gamma_ - 1.0) * 1.055 ))); - const float slope = 1.055 * powf (start, 1.0 / gamma_ - 1) - 0.055 / start; - const float mul = 1.055; - const float add = 0.055; outBeforeCCurveHistogrambw.clear(); bool histNeeded = false; - DiagonalCurve* tcurve = NULL; customToneCurvebw2.Reset(); if (!curvePointsbw2.empty() && curvePointsbw2[0] > DCT_Linear && curvePointsbw2[0] < DCT_Unchanged) { - tcurve = new DiagonalCurve (curvePointsbw2, CURVES_MIN_POLY_POINTS / skip); + DiagonalCurve tcurve(curvePointsbw2, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogrambw /*&& histogramCropped*/) { + if (outBeforeCCurveHistogrambw) { histNeeded = true; } - } - - if (tcurve) { - if (!tcurve->isIdentity()) { - customToneCurvebw2.Set(tcurve, gamma_, start, slope, mul, add); + if (!tcurve.isIdentity()) { + customToneCurvebw2.Set(tcurve, gamma_); } - - delete tcurve; - tcurve = NULL; } + customToneCurvebw1.Reset(); if (!curvePointsbw.empty() && curvePointsbw[0] > DCT_Linear && curvePointsbw[0] < DCT_Unchanged) { - tcurve = new DiagonalCurve (curvePointsbw, CURVES_MIN_POLY_POINTS / skip); + DiagonalCurve tcurve(curvePointsbw, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogrambw /*&& histogramCropped*/) { + if (outBeforeCCurveHistogrambw ) { histNeeded = true; } - } - - if (tcurve) { - if (!tcurve->isIdentity()) { - customToneCurvebw1.Set(tcurve, gamma_, start, slope, mul, add); + if (!tcurve.isIdentity()) { + customToneCurvebw1.Set(tcurve, gamma_); } - - delete tcurve; - tcurve = NULL; } + // create first curve if needed if (histNeeded) { - LUTf dcurve(65536, 0); - - float val; - - for (int i = 0; i < 32768; i++) { - val = (float)i / 32767.f; - dcurve[i] = CLIPD(val); - } - - for (int i = 0; i < 32768; i++) { - float hval = dcurve[i]; - int hi = (int)(255.0 * CLIPD(hval)); - outBeforeCCurveHistogrambw[hi] += histogrambw[i] ; - } + histogrambw.compressTo(outBeforeCCurveHistogrambw, 32768); } - - if (tcurve) { - delete tcurve; - } - } + // add curve Lab : C=f(L) -void CurveFactory::curveCL ( bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, LUTu & histogramcl, LUTu & outBeforeCLurveHistogram, int skip) +void CurveFactory::curveCL ( bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, int skip) { - bool needed; - DiagonalCurve* dCurve = NULL; - - if (outBeforeCLurveHistogram) { - outBeforeCLurveHistogram.clear(); - } - - bool histNeededCL = false; - - needed = false; + clcutili = false; + std::unique_ptr dCurve; if (!clcurvePoints.empty() && clcurvePoints[0] != 0) { - dCurve = new DiagonalCurve (clcurvePoints, CURVES_MIN_POLY_POINTS / skip); - - if (outBeforeCLurveHistogram) { - histNeededCL = true; - } + dCurve = std::unique_ptr(new DiagonalCurve(clcurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { - needed = true; clcutili = true; } } - if(histNeededCL) - for (int i = 0; i < 50000; i++) { //32768*1.414 + ... - int hi = (int)(255.0 * CLIPD((float)i / 49999.0)); // - outBeforeCLurveHistogram[hi] += histogramcl[i] ; - } - - - fillCurveArray(dCurve, clCurve, skip, needed); - - if (dCurve) { - delete dCurve; - dCurve = NULL; - } + fillCurveArray(dCurve.get(), clCurve, skip, clcutili); } -void CurveFactory::mapcurve ( bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, LUTu & histogram, LUTu & outBeforeCurveHistogram) +void CurveFactory::mapcurve ( bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram) { bool needed = false; - DiagonalCurve* dCurve = NULL; + std::unique_ptr dCurve; outBeforeCurveHistogram.clear(); bool histNeeded = false; if (!mapcurvePoints.empty() && mapcurvePoints[0] != 0) { - dCurve = new DiagonalCurve (mapcurvePoints, CURVES_MIN_POLY_POINTS / skip); + dCurve = std::unique_ptr(new DiagonalCurve(mapcurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (outBeforeCurveHistogram) { histNeeded = true; @@ -526,33 +341,21 @@ void CurveFactory::mapcurve ( bool & mapcontlutili, const std::vector& m } if (histNeeded) { - for (int i = 0; i < 32768; i++) { - double hval = CLIPD((double)i / 32767.0); - int hi = (int)(255.0 * hval); - outBeforeCurveHistogram[hi] += histogram[i] ; - } + histogram.compressTo(outBeforeCurveHistogram, 32768); } - fillCurveArray(dCurve, mapcurve, skip, needed); - - if (dCurve) { - delete dCurve; - dCurve = NULL; - } + fillCurveArray(dCurve.get(), mapcurve, skip, needed); } - - - -void CurveFactory::curveDehaContL ( bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, LUTu & histogram, LUTu & outBeforeCurveHistogram) +void CurveFactory::curveDehaContL ( bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram) { bool needed = false; - DiagonalCurve* dCurve = NULL; + std::unique_ptr dCurve; outBeforeCurveHistogram.clear(); bool histNeeded = false; if (!dehaclcurvePoints.empty() && dehaclcurvePoints[0] != 0) { - dCurve = new DiagonalCurve (dehaclcurvePoints, CURVES_MIN_POLY_POINTS / skip); + dCurve = std::unique_ptr(new DiagonalCurve(dehaclcurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (outBeforeCurveHistogram) { histNeeded = true; @@ -565,37 +368,20 @@ void CurveFactory::curveDehaContL ( bool & dehacontlutili, const std::vector& wavclcurvePoints, LUTf & wavclCurve, /*LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,*/int skip) { - bool needed; - DiagonalCurve* dCurve = NULL; - - // if (outBeforeWavCLurveHistogram) - // outBeforeWavCLurveHistogram.clear(); - bool histNeededCL = false; - - needed = false; + bool needed = false; + std::unique_ptr dCurve; if (!wavclcurvePoints.empty() && wavclcurvePoints[0] != 0) { - dCurve = new DiagonalCurve (wavclcurvePoints, CURVES_MIN_POLY_POINTS / skip); - // if (outBeforeWavCLurveHistogram) - // histNeededCL = true; + dCurve = std::unique_ptr(new DiagonalCurve(wavclcurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { needed = true; @@ -603,212 +389,89 @@ void CurveFactory::curveWavContL ( bool & wavcontlutili, const std::vector& clcurvePoints, LUTf & clToningCurve, int skip) +// add curve Colortoning : C=f(L) and CLf(L) +void CurveFactory::curveToning ( const std::vector& curvePoints, LUTf & ToningCurve, int skip) { - bool needed; - DiagonalCurve* dCurve = NULL; + bool needed = false; + std::unique_ptr dCurve; - needed = false; - - if (!clcurvePoints.empty() && clcurvePoints[0] != 0) { - dCurve = new DiagonalCurve (clcurvePoints, CURVES_MIN_POLY_POINTS / skip); + if (!curvePoints.empty() && curvePoints[0] != 0) { + dCurve = std::unique_ptr(new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { needed = true; - clctoningutili = true; } } - fillCurveArray(dCurve, clToningCurve, skip, needed); - - // clToningCurve.dump("CLToning"); - if (dCurve) { - delete dCurve; - dCurve = NULL; - } + fillCurveArray(dCurve.get(), ToningCurve, skip, needed); } -// add curve Colortoning : CLf(L) -void CurveFactory::curveToningLL ( bool & llctoningutili, const std::vector& llcurvePoints, LUTf & llToningCurve, int skip) -{ - bool needed; - DiagonalCurve* dCurve = NULL; - - needed = false; - - if (!llcurvePoints.empty() && llcurvePoints[0] != 0) { - dCurve = new DiagonalCurve (llcurvePoints, CURVES_MIN_POLY_POINTS / skip); - - if (dCurve && !dCurve->isIdentity()) { - needed = true; - llctoningutili = true; - } - } - - fillCurveArray(dCurve, llToningCurve, skip, needed); -// llToningCurve.dump("LLToning"); - - if (dCurve) { - delete dCurve; - dCurve = NULL; - } -} //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void CurveFactory::complexsgnCurve (float adjustr, bool & autili, bool & butili, bool & ccutili, bool & cclutili, double saturation, double rstprotection, +void CurveFactory::complexsgnCurve (bool & autili, bool & butili, bool & ccutili, bool & cclutili, const std::vector& acurvePoints, const std::vector& bcurvePoints, const std::vector& cccurvePoints, const std::vector& lccurvePoints, LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, LUTf & lhskCurve, - LUTu & histogramC, LUTu & histogramLC, LUTu & outBeforeCCurveHistogram, LUTu & outBeforeLCurveHistogram, //for chroma int skip) { - - //----------------------------------------------------- - - bool needed; - DiagonalCurve* dCurve = NULL; - LUTf dCcurve(65536, 0); - int k = 48000; //32768*1.41 - - if(outBeforeCCurveHistogram || outBeforeLCurveHistogram) { - for (int i = 0; i < k * adjustr; i++) { //# 32768*1.414 approximation maxi for chroma - dCcurve[i] = (float)i / (k * adjustr - 1); - } - } - - if (outBeforeCCurveHistogram) { - outBeforeCCurveHistogram.clear(); - } - - bool histNeededC = false; - - if (outBeforeLCurveHistogram) { - outBeforeLCurveHistogram.clear(); - } - - bool histNeededLC = false; - - //----------------------------------------------------- - - needed = false; + autili = butili = ccutili = cclutili = false; + std::unique_ptr dCurve; // create a curve if needed if (!acurvePoints.empty() && acurvePoints[0] != 0) { - dCurve = new DiagonalCurve (acurvePoints, CURVES_MIN_POLY_POINTS / skip); + dCurve = std::unique_ptr(new DiagonalCurve(acurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { - needed = true; autili = true; } } - fillCurveArray(dCurve, aoutCurve, skip, needed); - //if(autili) aoutCurve.dump("acurve"); + fillCurveArray(dCurve.get(), aoutCurve, skip, autili); - if (dCurve) { - delete dCurve; - dCurve = NULL; - } + dCurve = nullptr; //----------------------------------------------------- - needed = false; - if (!bcurvePoints.empty() && bcurvePoints[0] != 0) { - dCurve = new DiagonalCurve (bcurvePoints, CURVES_MIN_POLY_POINTS / skip); + dCurve = std::unique_ptr(new DiagonalCurve(bcurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { - needed = true; butili = true; } } - fillCurveArray(dCurve, boutCurve, skip, needed); + fillCurveArray(dCurve.get(), boutCurve, skip, butili); - if (dCurve) { - delete dCurve; - dCurve = NULL; - } + dCurve = nullptr; //----------------------------------------------- - needed = false; if (!cccurvePoints.empty() && cccurvePoints[0] != 0) { - dCurve = new DiagonalCurve (cccurvePoints, CURVES_MIN_POLY_POINTS / skip); - - if (outBeforeCCurveHistogram /*&& histogramCropped*/) { - histNeededC = true; - } + dCurve = std::unique_ptr(new DiagonalCurve(cccurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { - needed = true; ccutili = true; } } - if (histNeededC) { - for (int i = 0; i < k * adjustr; i++) { //32768*1.414 + ... - float hval = dCcurve[i]; - int hi = (int)(255.0 * CLIPD(hval)); // - outBeforeCCurveHistogram[hi] += histogramC[i] ; - } - } + fillCurveArray(dCurve.get(), satCurve, skip, ccutili); - fillCurveArray(dCurve, satCurve, skip, needed); - - if (dCurve) { - delete dCurve; - dCurve = NULL; - } + dCurve = nullptr; //---------------------------- - needed = false; if (!lccurvePoints.empty() && lccurvePoints[0] != 0) { - dCurve = new DiagonalCurve (lccurvePoints, CURVES_MIN_POLY_POINTS / skip); - - if (outBeforeLCurveHistogram /*&& histogramCropped*/) { - histNeededLC = true; - } + dCurve = std::unique_ptr(new DiagonalCurve(lccurvePoints, CURVES_MIN_POLY_POINTS / skip)); if (dCurve && !dCurve->isIdentity()) { - needed = true; cclutili = true; } } - if (histNeededLC) { - for (int i = 0; i < k * adjustr; i++) { //32768*1.414 + ... - float hval = dCcurve[i]; - int hi = (int)(255.0 * CLIPD(hval)); // - outBeforeLCurveHistogram[hi] += histogramLC[i] ; - } - } - - - fillCurveArray(dCurve, lhskCurve, skip, needed); - - if (dCurve) { - delete dCurve; - dCurve = NULL; - } + fillCurveArray(dCurve.get(), lhskCurve, skip, cclutili); } @@ -820,7 +483,7 @@ SSEFUNCTION void CurveFactory::complexCurve (double ecomp, double black, double double shcompr, double br, double contr, procparams::ToneCurveParams::eTCModeId curveMode, const std::vector& curvePoints, procparams::ToneCurveParams::eTCModeId curveMode2, const std::vector& curvePoints2, - LUTu & histogram, LUTu & histogramCropped, + LUTu & histogram, LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, ToneCurve & customToneCurve1, @@ -846,36 +509,35 @@ SSEFUNCTION void CurveFactory::complexCurve (double ecomp, double black, double // tone curve base. a: slope (from exp.comp.), b: black, def_mul: max. x value (can be>1), hr,sr: highlight,shadow recovery //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - DiagonalCurve* brightcurve = NULL; + std::unique_ptr brightcurve; // check if brightness curve is needed if (br > 0.00001 || br < -0.00001) { - std::vector brightcurvePoints; - brightcurvePoints.resize(9); - brightcurvePoints.at(0) = double(DCT_NURBS); + std::vector brightcurvePoints(9); + brightcurvePoints[0] = DCT_NURBS; - brightcurvePoints.at(1) = 0.; //black point. Value in [0 ; 1] range - brightcurvePoints.at(2) = 0.; //black point. Value in [0 ; 1] range + brightcurvePoints[1] = 0.; //black point. Value in [0 ; 1] range + brightcurvePoints[2] = 0.; //black point. Value in [0 ; 1] range if(br > 0) { - brightcurvePoints.at(3) = 0.1; //toe point - brightcurvePoints.at(4) = 0.1 + br / 150.0; //value at toe point + brightcurvePoints[3] = 0.1; //toe point + brightcurvePoints[4] = 0.1 + br / 150.0; //value at toe point - brightcurvePoints.at(5) = 0.7; //shoulder point - brightcurvePoints.at(6) = min(1.0, 0.7 + br / 300.0); //value at shoulder point + brightcurvePoints[5] = 0.7; //shoulder point + brightcurvePoints[6] = min(1.0, 0.7 + br / 300.0); //value at shoulder point } else { - brightcurvePoints.at(3) = max(0.0, 0.1 - br / 150.0); //toe point - brightcurvePoints.at(4) = 0.1; //value at toe point + brightcurvePoints[3] = max(0.0, 0.1 - br / 150.0); //toe point + brightcurvePoints[4] = 0.1; //value at toe point - brightcurvePoints.at(5) = 0.7 - br / 300.0; //shoulder point - brightcurvePoints.at(6) = 0.7; //value at shoulder point + brightcurvePoints[5] = 0.7 - br / 300.0; //shoulder point + brightcurvePoints[6] = 0.7; //value at shoulder point } - brightcurvePoints.at(7) = 1.; // white point - brightcurvePoints.at(8) = 1.; // value at white point + brightcurvePoints[7] = 1.; // white point + brightcurvePoints[8] = 1.; // value at white point - brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS / skip); + brightcurve = std::unique_ptr(new DiagonalCurve(brightcurvePoints, CURVES_MIN_POLY_POINTS / skip)); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -885,26 +547,52 @@ SSEFUNCTION void CurveFactory::complexCurve (double ecomp, double black, double float scale = 65536.0; float comp = (max(0.0, ecomp) + 1.0) * hlcompr / 100.0; float shoulder = ((scale / max(1.0f, exp_scale)) * (hlcomprthresh / 200.0)) + 0.1; - //printf("shoulder = %e\n",shoulder); - //printf ("exp_scale= %f comp= %f def_mul=%f a= %f \n",exp_scale,comp,def_mul,a); - if (comp <= 0.0f) - for (int i = 0; i < 0x10000; i++) { - hlCurve[i] = exp_scale; - } - else { - for (int i = 0; i <= shoulder; i++) { - hlCurve[i] = exp_scale; - } + if (comp <= 0.0f) { + hlCurve.makeConstant(exp_scale); + } else { + hlCurve.makeConstant(exp_scale, shoulder + 1); float scalemshoulder = scale - shoulder; - for (int i = shoulder + 1; i < 0x10000; i++) { +#ifdef __SSE2__ + int i = shoulder + 1; + + if(i & 1) { // original formula, slower than optimized formulas below but only used once or none, so I let it as is for reference // change to [0,1] range float val = (float)i - shoulder; float R = val * comp / (scalemshoulder); hlCurve[i] = xlog(1.0 + R * exp_scale) / R; // don't use xlogf or 1.f here. Leads to errors caused by too low precision + i++; } + + vdouble onev = _mm_set1_pd(1.0); + vdouble Rv = _mm_set_pd((i + 1 - shoulder) * (double)comp / scalemshoulder, (i - shoulder) * (double)comp / scalemshoulder); + vdouble incrementv = _mm_set1_pd(2.0 * comp / scalemshoulder); + vdouble exp_scalev = _mm_set1_pd(exp_scale); + + for (; i < 0x10000; i += 2) { + // change to [0,1] range + vdouble resultv = xlog(onev + Rv * exp_scalev) / Rv; + vfloat resultfv = _mm_cvtpd_ps(resultv); + _mm_store_ss(&hlCurve[i], resultfv); + resultfv = PERMUTEPS(resultfv, _MM_SHUFFLE(1, 1, 1, 1)); + _mm_store_ss(&hlCurve[i + 1], resultfv); + Rv += incrementv; + } + +#else + float R = comp / scalemshoulder; + float increment = R; + + for (int i = shoulder + 1; i < 0x10000; i++) { + // change to [0,1] range + hlCurve[i] = xlog(1.0 + R * exp_scale) / R; // don't use xlogf or 1.f here. Leads to errors caused by too low precision + R += increment; + } + +#endif + } @@ -915,11 +603,11 @@ SSEFUNCTION void CurveFactory::complexCurve (double ecomp, double black, double // change to [0,1] range shCurve.setClip(LUT_CLIP_ABOVE); // used LUT_CLIP_ABOVE, because the curve converges to 1.0 at the upper end and we don't want to exceed this value. float val = 1.f / 65535.f; - float val2 = simplebasecurve (val, black, 0.015 * shcompr); + float val2 = simplebasecurve (val, black, 0.015 * shcompr); shCurve[0] = CLIPD(val2) / val; - val = 0.0; // gamma correction - val = gamma (val, gamma_, start, slope, mul, add); + + val = Color::gammatab_srgb[0] / 65535.f; // apply brightness curve if (brightcurve) { @@ -929,30 +617,25 @@ SSEFUNCTION void CurveFactory::complexCurve (double ecomp, double black, double // store result in a temporary array dcurve[0] = CLIPD(val); - #pragma omp parallel for - for (int i = 1; i < 0x10000; i++) { - float val; - val = (float)i / 65535.0f; + float val = i / 65535.f; float val2 = simplebasecurve (val, black, 0.015 * shcompr); - shCurve[i] = CLIPD(val2) / val; + shCurve[i] = val2 / val; // gamma correction - val = gamma (val, gamma_, start, slope, mul, add); + val = Color::gammatab_srgb[i] / 65535.f; // apply brightness curve if (brightcurve) { - val = brightcurve->getVal (val); // TODO: getVal(double) is very slow! Optimize with a LUTf + val = CLIPD(brightcurve->getVal (val)); // TODO: getVal(double) is very slow! Optimize with a LUTf } // store result in a temporary array - dcurve[i] = CLIPD(val); + dcurve[i] = val; } - if (brightcurve) { - delete brightcurve; - } + brightcurve = nullptr; //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -965,71 +648,57 @@ SSEFUNCTION void CurveFactory::complexCurve (double ecomp, double black, double unsigned int sum = 0; float avg = 0; - //double sqavg = 0; for (int i = 0; i <= 0xffff; i++) { - float fi = i; - fi *= hlCurve[i]; + float fi = i * hlCurve[i]; avg += dcurve[(int)(shCurve[fi] * fi)] * histogram[i]; - //sqavg += dcurve[i]*dcurve[i] * histogram[i]; sum += histogram[i]; } avg /= sum; - //sqavg /= sum; - //double stddev = sqrt(sqavg-avg*avg); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - std::vector contrastcurvePoints; - contrastcurvePoints.resize(9); - contrastcurvePoints.at(0) = double(DCT_NURBS); + std::vector contrastcurvePoints(9); + contrastcurvePoints[0] = DCT_NURBS; - contrastcurvePoints.at(1) = 0; //black point. Value in [0 ; 1] range - contrastcurvePoints.at(2) = 0; //black point. Value in [0 ; 1] range + contrastcurvePoints[1] = 0; //black point. Value in [0 ; 1] range + contrastcurvePoints[2] = 0; //black point. Value in [0 ; 1] range - contrastcurvePoints.at(3) = avg - avg * (0.6 - contr / 250.0); //toe point - contrastcurvePoints.at(4) = avg - avg * (0.6 + contr / 250.0); //value at toe point + contrastcurvePoints[3] = avg - avg * (0.6 - contr / 250.0); //toe point + contrastcurvePoints[4] = avg - avg * (0.6 + contr / 250.0); //value at toe point - contrastcurvePoints.at(5) = avg + (1 - avg) * (0.6 - contr / 250.0); //shoulder point - contrastcurvePoints.at(6) = avg + (1 - avg) * (0.6 + contr / 250.0); //value at shoulder point + contrastcurvePoints[5] = avg + (1 - avg) * (0.6 - contr / 250.0); //shoulder point + contrastcurvePoints[6] = avg + (1 - avg) * (0.6 + contr / 250.0); //value at shoulder point - contrastcurvePoints.at(7) = 1.; // white point - contrastcurvePoints.at(8) = 1.; // value at white point + contrastcurvePoints[7] = 1.; // white point + contrastcurvePoints[8] = 1.; // value at white point - DiagonalCurve* contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS / skip); + const DiagonalCurve contrastcurve(contrastcurvePoints, CURVES_MIN_POLY_POINTS / skip); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // apply contrast enhancement for (int i = 0; i <= 0xffff; i++) { - dcurve[i] = contrastcurve->getVal (dcurve[i]); + dcurve[i] = contrastcurve.getVal (dcurve[i]); } - - delete contrastcurve; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // create second curve if needed bool histNeeded = false; - DiagonalCurve* tcurve = NULL; customToneCurve2.Reset(); if (!curvePoints2.empty() && curvePoints2[0] > DCT_Linear && curvePoints2[0] < DCT_Unchanged) { - tcurve = new DiagonalCurve (curvePoints2, CURVES_MIN_POLY_POINTS / skip); + const DiagonalCurve tcurve(curvePoints2, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogram /*&& histogramCropped*/) { + if (!tcurve.isIdentity()) { + customToneCurve2.Set(tcurve, gamma_); + } + + if (outBeforeCCurveHistogram ) { histNeeded = true; } } - if (tcurve) { - if (!tcurve->isIdentity()) { - customToneCurve2.Set(tcurve, gamma_, start, slope, mul, add); - } - - delete tcurve; - tcurve = NULL; - } - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1038,90 +707,52 @@ SSEFUNCTION void CurveFactory::complexCurve (double ecomp, double black, double customToneCurve1.Reset(); if (!curvePoints.empty() && curvePoints[0] > DCT_Linear && curvePoints[0] < DCT_Unchanged) { - tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS / skip); + const DiagonalCurve tcurve(curvePoints, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogram /*&& histogramCropped*/) { + if (!tcurve.isIdentity()) { + customToneCurve1.Set(tcurve, gamma_); + } + + if (outBeforeCCurveHistogram) { histNeeded = true; } } - if (tcurve) { - if (!tcurve->isIdentity()) { - customToneCurve1.Set(tcurve, gamma_, start, slope, mul, add); - } + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - delete tcurve; - tcurve = NULL; +#ifdef __SSE2__ + vfloat gamma_v = F2V(gamma_); + vfloat startv = F2V(start); + vfloat slopev = F2V(slope); + vfloat mulv = F2V(mul); + vfloat addv = F2V(add); + vfloat c65535v = F2V(65535.f); + + for (int i = 0; i <= 0xffff; i += 4) { + vfloat valv = LVFU(dcurve[i]); + valv = igamma (valv, gamma_v, startv, slopev, mulv, addv); + STVFU(outCurve[i], c65535v * valv); } - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - // create curve bw - // curve 2 - /* DiagonalCurve* tbwcurve = NULL; - customToneCurvebw2.Reset(); - - if (!curvePointsbw2.empty() && curvePointsbw2[0]>DCT_Linear && curvePointsbw2[0]isIdentity()) { - delete tbwcurve; - tbwcurve = NULL; - } - else - customToneCurvebw2.Set(tbwcurve); - delete tbwcurve; - tbwcurve = NULL; - } - - customToneCurvebw1.Reset(); - - if (!curvePointsbw.empty() && curvePointsbw[0]>DCT_Linear && curvePointsbw[0]isIdentity()) { - delete tbwcurve; - tbwcurve = NULL; - } - else if (curveModeb != procparams::BlackWhiteParams::TC_MODE_STD_BW) { - customToneCurvebw1.Set(tbwcurve); - delete tbwcurve; - tbwcurve = NULL; - } - } - */ - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +#else for (int i = 0; i <= 0xffff; i++) { float val = dcurve[i]; - - if (histNeeded) { - float fi = i; - float hval = hlCurve[i] * fi; - hval = dcurve[shCurve[hval] * hval]; - //if (needigamma) - // hval = igamma2 (hval); - int hi = (int)(255.0 * (hval)); - outBeforeCCurveHistogram[hi] += histogram/*Cropped*/[i] ; - } - val = igamma (val, gamma_, start, slope, mul, add); outCurve[i] = (65535.f * val); } - if (tcurve) { - delete tcurve; - } +#endif - /*if (outBeforeCCurveHistogram) { - for (int i=0; i<256; i++) printf("i= %d bchist= %d \n",i,outBeforeCCurveHistogram[i]); - }*/ + if (histNeeded) { + for (int i = 0; i <= 0xffff; i++) { + float fi = i; + float hval = hlCurve[i] * fi; + hval = dcurve[shCurve[hval] * hval]; + int hi = (int)(255.f * (hval)); + outBeforeCCurveHistogram[hi] += histogram[i] ; + } + } } @@ -1130,13 +761,11 @@ SSEFUNCTION void CurveFactory::complexCurve (double ecomp, double black, double //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void CurveFactory::complexLCurve (double br, double contr, const std::vector& curvePoints, - LUTu & histogram, LUTu & histogramCropped, LUTf & outCurve, + const LUTu & histogram, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, int skip, bool & utili) { - // curve without contrast - LUTf dcurve(65536, 0); - + utili = false; // clear array that stores histogram valid before applying the custom curve if (outBeforeCCurveHistogram) { outBeforeCCurveHistogram.clear(); @@ -1174,7 +803,7 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vectorgetVal (val); + val = brightcurve.getVal (val); // store result in a temporary array - dcurve[i] = CLIPD(val); + outCurve[i] = CLIPD(val); } - delete brightcurve; } else { - for (int i = 0; i < 32768; i++) { // L values range up to 32767, higher values are for highlight overflow - // set the identity curve in the temporary array - dcurve[i] = (float)i / 32767.0; - } + outCurve.makeIdentity(32767.f); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1206,27 +831,21 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vector 0.00001 || contr < -0.00001) { utili = true; - DiagonalCurve* contrastcurve = NULL; - // compute mean luminance of the image with the curve applied int sum = 0; float avg = 0; - //float sqavg = 0; for (int i = 0; i < 32768; i++) { - avg += dcurve[i] * histogram[i]; - //sqavg += dcurve[i]*dcurve[i] * histogram[i]; + avg += outCurve[i] * histogram[i]; sum += histogram[i]; } + std::vector contrastcurvePoints; + if(sum) { avg /= sum; - //sqavg /= sum; - //float stddev = sqrt(sqavg-avg*avg); - // printf("avg=%f\n",avg); //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - std::vector contrastcurvePoints; contrastcurvePoints.resize(9); contrastcurvePoints.at(0) = double(DCT_NURBS); @@ -1242,12 +861,10 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vector contrastcurvePoints; contrastcurvePoints.resize(5); contrastcurvePoints.at(0) = double(DCT_NURBS); @@ -1257,35 +874,34 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vectorgetVal (dcurve[i]); + outCurve[i] = contrastcurve.getVal (outCurve[i]); } - delete contrastcurve; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // create a curve if needed - DiagonalCurve* tcurve = NULL; + std::unique_ptr tcurve; bool histNeeded = false; if (!curvePoints.empty() && curvePoints[0] != 0) { - tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS / skip); + tcurve = std::unique_ptr(new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS / skip)); - if (outBeforeCCurveHistogram /*&& histogramCropped*/) { + if (outBeforeCCurveHistogram) { histNeeded = true; } } if (tcurve && tcurve->isIdentity()) { - delete tcurve; - tcurve = NULL; + tcurve = nullptr; } if (tcurve) { @@ -1296,41 +912,32 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vectorgetVal (dcurve[i]); + val = tcurve->getVal (outCurve[i]); - outCurve[i] = (32767.0 * val); + outCurve[i] = (32767.f * val); } } else { + // Skip the slow getval method if no curve is used (or an identity curve) // L values go up to 32767, last stop is for highlight overflow - for (int i = 0; i < 32768; i++) { - if (histNeeded) { - float hval = dcurve[i]; - int hi = (int)(255.0 * CLIPD(hval)); - outBeforeCCurveHistogram[hi] += histogram/*Cropped*/[i] ; - } - - outCurve[i] = 32767.0 * dcurve[i]; + if(histNeeded) { + histogram.compressTo(outBeforeCCurveHistogram, 32768, outCurve); } + + outCurve *= 32767.f; + } - for (int i = 32768; i < 65536; i++) { + for (int i = 32768; i < 32770; i++) { // set last two elements of lut to 32768 and 32769 to allow linear interpolation outCurve[i] = (float)i; } - if (tcurve) { - delete tcurve; - } - - /*if (outBeforeCCurveHistogram) { - for (int i=0; i<256; i++) printf("i= %d bchist= %d \n",i,outBeforeCCurveHistogram[i]); - }*/ } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1340,19 +947,15 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vector& curvePoints, LUTf & outCurve, int skip) { - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // create a curve if needed - DiagonalCurve* tcurve = NULL; + std::unique_ptr tcurve; if (!curvePoints.empty() && curvePoints[0] != 0) { - tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS / skip); + tcurve = std::unique_ptr(new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); } if (tcurve && tcurve->isIdentity()) { - delete tcurve; - tcurve = NULL; + tcurve = nullptr; } if (tcurve) { @@ -1362,23 +965,14 @@ void CurveFactory::RGBCurve (const std::vector& curvePoints, LUTf & outC for (int i = 0; i < 65536; i++) { // apply custom/parametric/NURBS curve, if any - // RGB curves are defined with sRGB gamma, but operate on linear data - float val = float(i) / 65535.f; - val = CurveFactory::gamma2 (val); + float val = Color::gamma2curve[i] / 65535.f; val = tcurve->getVal(val); - val = CurveFactory::igamma2 (val); - //float val = tcurve->getVal ((float)i/65536.0f); - outCurve[i] = (65536.0f * val); + outCurve[i] = Color::igammatab_srgb[val * 65535.f]; } - - delete tcurve; - } - // let the LUTf empty for identity curves - else { + } else { // let the LUTf empty for identity curves outCurve.reset(); } - } @@ -1388,12 +982,12 @@ void ColorAppearance::Reset() } // Fill a LUT with X/Y, ranged 0xffff -void ColorAppearance::Set(Curve *pCurve) +void ColorAppearance::Set(const Curve &pCurve) { lutColCurve(65536); for (int i = 0; i < 65536; i++) { - lutColCurve[i] = pCurve->getVal(double(i) / 65535.) * 65535.; + lutColCurve[i] = pCurve.getVal(double(i) / 65535.) * 65535.; } } @@ -1469,20 +1063,34 @@ void ToneCurve::Reset() } // Fill a LUT with X/Y, ranged 0xffff -void ToneCurve::Set(Curve *pCurve, float gamma, float start, float slope, float mul, float add) +void ToneCurve::Set(const Curve &pCurve, float gamma) { lutToneCurve(65536); if (gamma <= 0.0 || gamma == 1.) { for (int i = 0; i < 65536; i++) { - lutToneCurve[i] = (float)pCurve->getVal(float(i) / 65535.f) * 65535.f; + lutToneCurve[i] = (float)pCurve.getVal(float(i) / 65535.f) * 65535.f; } + } else if(gamma == (float)Color::sRGBGammaCurve) { + // for sRGB gamma we can use luts, which is much faster + for (int i = 0; i < 65536; i++) { + float val = Color::gammatab_srgb[i] / 65535.f; + val = pCurve.getVal(val); + val = Color::igammatab_srgb[val * 65535.f]; + lutToneCurve[i] = val; + } + } else { + const float start = expf(gamma * logf( -0.055 / ((1.0 / gamma - 1.0) * 1.055 ))); + const float slope = 1.055 * powf (start, 1.0 / gamma - 1) - 0.055 / start; + const float mul = 1.055; + const float add = 0.055; + // apply gamma, that is 'pCurve' is defined with the given gamma and here we convert it to a curve in linear space for (int i = 0; i < 65536; i++) { float val = float(i) / 65535.f; val = CurveFactory::gamma (val, gamma, start, slope, mul, add); - val = pCurve->getVal(val); + val = pCurve.getVal(val); val = CurveFactory::igamma (val, gamma, start, slope, mul, add); lutToneCurve[i] = val * 65535.f; } @@ -1512,18 +1120,17 @@ void OpacityCurve::Set(const Curve *pCurve) void OpacityCurve::Set(const std::vector &curvePoints, bool &opautili) { - FlatCurve* tcurve = NULL; + std::unique_ptr tcurve; if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { - tcurve = new FlatCurve (curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + tcurve = std::unique_ptr(new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); tcurve->setIdentityValue(0.); } if (tcurve) { - Set(tcurve); + Set(tcurve.get()); opautili = true; - delete tcurve; - tcurve = NULL; + tcurve = nullptr; } } @@ -1896,16 +1503,14 @@ void ColorGradientCurve::SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], void ColorGradientCurve::SetXYZ(const std::vector &curvePoints, const double xyz_rgb[3][3], const double rgb_xyz[3][3], float satur, float lumin) { - FlatCurve* tcurve = NULL; + std::unique_ptr tcurve; if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { - tcurve = new FlatCurve (curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + tcurve = std::unique_ptr(new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); } if (tcurve) { - SetXYZ(tcurve, xyz_rgb, rgb_xyz, satur, lumin); - delete tcurve; - tcurve = NULL; + SetXYZ(tcurve.get(), xyz_rgb, rgb_xyz, satur, lumin); } } @@ -1997,16 +1602,14 @@ void ColorGradientCurve::SetRGB(const Curve *pCurve, const double xyz_rgb[3][3], void ColorGradientCurve::SetRGB(const std::vector &curvePoints, const double xyz_rgb[3][3], const double rgb_xyz[3][3]) { - FlatCurve* tcurve = NULL; + std::unique_ptr tcurve; if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { - tcurve = new FlatCurve (curvePoints, false, CURVES_MIN_POLY_POINTS / 2); + tcurve = std::unique_ptr(new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); } if (tcurve) { - SetRGB(tcurve, xyz_rgb, rgb_xyz); - delete tcurve; - tcurve = NULL; + SetRGB(tcurve.get(), xyz_rgb, rgb_xyz); } } diff --git a/rtengine/curves.h b/rtengine/curves.h index 0adc735be..a06502c71 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -159,7 +159,9 @@ protected: static inline double simplebasecurve (double x, double b, double sr) { // a = 1, D = 1, hr = 0 (unused for a = D = 1) - if (b < 0) { + if (b == 0.0) { + return x; + } else if (b < 0) { double m = 0.5;//midpoint double slope = 1.0 + b; //slope of straight line between (0,-b) and (1,1) double y = -b + m * slope; //value at midpoint @@ -175,7 +177,7 @@ protected: double y = (m - b) * slope; if (x <= m) { - return b == 0 ? x * slope : clower (x / m, slope * m / y, sr) * y; + return clower (x / m, slope * m / y, sr) * y; } else { return y + (x - m) * slope; } @@ -238,13 +240,18 @@ public: } static inline float gamma (float x, float gamma, float start, float slope, float mul, float add) { - return (x <= start ? x*slope : expf(logf(x) / gamma) * mul - add); + return (x <= start ? x*slope : xexpf(xlogf(x) / gamma) * mul - add); } static inline float igamma (float x, float gamma, float start, float slope, float mul, float add) { - return (x <= start * slope ? x / slope : expf(logf((x + add) / mul) * gamma) ); + return (x <= start * slope ? x / slope : xexpf(xlogf((x + add) / mul) * gamma) ); } - +#ifdef __SSE2__ + static inline vfloat igamma (vfloat x, vfloat gamma, vfloat start, vfloat slope, vfloat mul, vfloat add) + { + return (x <= start * slope ? x / slope : xexpf(xlogf((x + add) / mul) * gamma) ); + } +#endif static inline float hlcurve (const float exp_scale, const float comp, const float hlrange, float level) { if (comp > 0.0) { @@ -271,42 +278,31 @@ public: public: static void complexCurve (double ecomp, double black, double hlcompr, double hlcomprthresh, double shcompr, double br, double contr, procparams::ToneCurveParams::eTCModeId curveMode, const std::vector& curvePoints, procparams::ToneCurveParams::eTCModeId curveMode2, const std::vector& curvePoints2, - - LUTu & histogram, LUTu & histogramCropped, - LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, ToneCurve & outToneCurve, ToneCurve & outToneCurve2, + LUTu & histogram, LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, ToneCurve & outToneCurve, ToneCurve & outToneCurve2, int skip = 1); - static void curveBW (const std::vector& curvePointsbw, const std::vector& curvePointsbw2, LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw, + static void curveBW (const std::vector& curvePointsbw, const std::vector& curvePointsbw2, const LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw, ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip); - static void curveCL ( bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, LUTu & histogramcl, LUTu & outBeforeCLurveHistogram, int skip); + static void curveCL ( bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, int skip); static void curveWavContL ( bool & wavcontlutili, const std::vector& wavclcurvePoints, LUTf & wavclCurve,/* LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,*/int skip); - static void curveDehaContL ( bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, LUTu & histogram, LUTu & outBeforeCurveHistogram); - static void mapcurve ( bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, LUTu & histogram, LUTu & outBeforeCurveHistogram); + static void curveDehaContL ( bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram); + static void mapcurve ( bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram); - static void curveToningCL ( bool & clctoningutili, const std::vector& clcurvePoints, LUTf & clToningCurve, int skip); - static void curveToningLL ( bool & llctoningutili, const std::vector& llcurvePoints, LUTf & llToningCurve, int skip); - static void denoiseCC ( bool & ccdenoiseutili, const std::vector& cccurvePoints, LUTf & NoiseCCcurve, int skip); + static void curveToning ( const std::vector& curvePoints, LUTf & ToningCurve, int skip); - static void complexsgnCurve ( float adjustr, bool & autili, bool & butili, bool & ccutili, bool & clcutili, double saturation, double rstprotection, const std::vector& acurvePoints, + static void complexsgnCurve ( bool & autili, bool & butili, bool & ccutili, bool & clcutili, const std::vector& acurvePoints, const std::vector& bcurvePoints, const std::vector& cccurvePoints, const std::vector& lccurvePoints, LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, LUTf & lhskCurve, - LUTu & histogramC, LUTu & histogramLC, LUTu & outBeforeCCurveHistogram, LUTu & outBeforeLCurveHistogram, ///for chroma int skip = 1); - static void complexLCurve (double br, double contr, const std::vector& curvePoints, LUTu & histogram, LUTu & histogramCropped, - LUTf & outCurve, LUTu & outBeforeCCurveHistogram, int skip, bool & utili); - - static void updatechroma ( - const std::vector& cccurvePoints, - LUTu & histogramC, LUTu & outBeforeCCurveHistogramC,//for chroma - int skip = 1); + static void complexLCurve (double br, double contr, const std::vector& curvePoints, const LUTu & histogram, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, int skip, bool & utili); static void curveLightBrightColor ( - procparams::ColorAppearanceParams::eTCModeId curveMode, const std::vector& curvePoints, - procparams::ColorAppearanceParams::eTCModeId curveMode2, const std::vector& curvePoints2, - procparams::ColorAppearanceParams::eCTCModeId curveMode3, const std::vector& curvePoints3, - LUTu & histogram, LUTu & histogramCropped, LUTu & outBeforeCCurveHistogram, - LUTu & histogramC, LUTu & outBeforeCCurveHistogramC, + const std::vector& curvePoints, + const std::vector& curvePoints2, + const std::vector& curvePoints3, + const LUTu & histogram, LUTu & outBeforeCCurveHistogram, + const LUTu & histogramC, LUTu & outBeforeCCurveHistogramC, ColorAppearance & outColCurve1, ColorAppearance & outColCurve2, ColorAppearance & outColCurve3, @@ -337,6 +333,7 @@ protected: // end of variables used in Parametric curves only std::vector poly_x; // X points of the faceted curve std::vector poly_y; // Y points of the faceted curve + std::vector dyByDx; std::vector hash; unsigned short hashSize; // hash table's size, between [10, 100, 1000] @@ -358,11 +355,11 @@ protected: } static inline double p01 (double x, double prot) { - return x <= 0.5 ? CurveFactory::clower (x * 2, 2.0, prot) / 2.0 : 0.5 + CurveFactory::cupper ((x - 0.5) * 2, 2.0, prot) / 2.0; + return x <= 0.5 ? CurveFactory::clower (x * 2, 2.0, prot) * 0.5 : 0.5 + CurveFactory::cupper ((x - 0.5) * 2, 2.0, prot) * 0.5; } static inline double p10 (double x, double prot) { - return x <= 0.5 ? CurveFactory::cupper (x * 2, 2.0, prot) / 2.0 : 0.5 + CurveFactory::clower ((x - 0.5) * 2, 2.0, prot) / 2.0; + return x <= 0.5 ? CurveFactory::cupper (x * 2, 2.0, prot) * 0.5 : 0.5 + CurveFactory::clower ((x - 0.5) * 2, 2.0, prot) * 0.5; } static inline double pfull (double x, double prot, double sh, double hl) { @@ -370,6 +367,7 @@ protected: } void fillHash(); + void fillDyByDx(); public: Curve (); @@ -407,7 +405,7 @@ public: class FlatCurve : public Curve { -protected: +private: FlatCurveType kind; double* leftTangent; double* rightTangent; @@ -488,7 +486,7 @@ public: virtual ~ToneCurve() {}; void Reset(); - void Set(Curve *pCurve, float gamma = 0, float start = 0, float slope = 0, float mul = 0, float add = 0); + void Set(const Curve &pCurve, float gamma = 0); operator bool (void) const { return lutToneCurve; @@ -712,7 +710,7 @@ public: virtual ~ColorAppearance() {}; void Reset(); - void Set(Curve *pCurve); + void Set(const Curve &pCurve); operator bool (void) const { return lutColCurve; diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index c05230738..775428a4e 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ + #include #include "dcp.h" @@ -25,305 +26,46 @@ #include "improcfun.h" #include "rt_math.h" -using namespace std; using namespace rtengine; using namespace rtexif; -static const float adobe_camera_raw_default_curve[] = { - 0.00000f, 0.00078f, 0.00160f, 0.00242f, - 0.00314f, 0.00385f, 0.00460f, 0.00539f, - 0.00623f, 0.00712f, 0.00806f, 0.00906f, - 0.01012f, 0.01122f, 0.01238f, 0.01359f, - 0.01485f, 0.01616f, 0.01751f, 0.01890f, - 0.02033f, 0.02180f, 0.02331f, 0.02485f, - 0.02643f, 0.02804f, 0.02967f, 0.03134f, - 0.03303f, 0.03475f, 0.03648f, 0.03824f, - 0.04002f, 0.04181f, 0.04362f, 0.04545f, - 0.04730f, 0.04916f, 0.05103f, 0.05292f, - 0.05483f, 0.05675f, 0.05868f, 0.06063f, - 0.06259f, 0.06457f, 0.06655f, 0.06856f, - 0.07057f, 0.07259f, 0.07463f, 0.07668f, - 0.07874f, 0.08081f, 0.08290f, 0.08499f, - 0.08710f, 0.08921f, 0.09134f, 0.09348f, - 0.09563f, 0.09779f, 0.09996f, 0.10214f, - 0.10433f, 0.10652f, 0.10873f, 0.11095f, - 0.11318f, 0.11541f, 0.11766f, 0.11991f, - 0.12218f, 0.12445f, 0.12673f, 0.12902f, - 0.13132f, 0.13363f, 0.13595f, 0.13827f, - 0.14061f, 0.14295f, 0.14530f, 0.14765f, - 0.15002f, 0.15239f, 0.15477f, 0.15716f, - 0.15956f, 0.16197f, 0.16438f, 0.16680f, - 0.16923f, 0.17166f, 0.17410f, 0.17655f, - 0.17901f, 0.18148f, 0.18395f, 0.18643f, - 0.18891f, 0.19141f, 0.19391f, 0.19641f, - 0.19893f, 0.20145f, 0.20398f, 0.20651f, - 0.20905f, 0.21160f, 0.21416f, 0.21672f, - 0.21929f, 0.22185f, 0.22440f, 0.22696f, - 0.22950f, 0.23204f, 0.23458f, 0.23711f, - 0.23963f, 0.24215f, 0.24466f, 0.24717f, - 0.24967f, 0.25216f, 0.25465f, 0.25713f, - 0.25961f, 0.26208f, 0.26454f, 0.26700f, - 0.26945f, 0.27189f, 0.27433f, 0.27676f, - 0.27918f, 0.28160f, 0.28401f, 0.28641f, - 0.28881f, 0.29120f, 0.29358f, 0.29596f, - 0.29833f, 0.30069f, 0.30305f, 0.30540f, - 0.30774f, 0.31008f, 0.31241f, 0.31473f, - 0.31704f, 0.31935f, 0.32165f, 0.32395f, - 0.32623f, 0.32851f, 0.33079f, 0.33305f, - 0.33531f, 0.33756f, 0.33981f, 0.34205f, - 0.34428f, 0.34650f, 0.34872f, 0.35093f, - 0.35313f, 0.35532f, 0.35751f, 0.35969f, - 0.36187f, 0.36404f, 0.36620f, 0.36835f, - 0.37050f, 0.37264f, 0.37477f, 0.37689f, - 0.37901f, 0.38112f, 0.38323f, 0.38533f, - 0.38742f, 0.38950f, 0.39158f, 0.39365f, - 0.39571f, 0.39777f, 0.39982f, 0.40186f, - 0.40389f, 0.40592f, 0.40794f, 0.40996f, - 0.41197f, 0.41397f, 0.41596f, 0.41795f, - 0.41993f, 0.42191f, 0.42388f, 0.42584f, - 0.42779f, 0.42974f, 0.43168f, 0.43362f, - 0.43554f, 0.43747f, 0.43938f, 0.44129f, - 0.44319f, 0.44509f, 0.44698f, 0.44886f, - 0.45073f, 0.45260f, 0.45447f, 0.45632f, - 0.45817f, 0.46002f, 0.46186f, 0.46369f, - 0.46551f, 0.46733f, 0.46914f, 0.47095f, - 0.47275f, 0.47454f, 0.47633f, 0.47811f, - 0.47989f, 0.48166f, 0.48342f, 0.48518f, - 0.48693f, 0.48867f, 0.49041f, 0.49214f, - 0.49387f, 0.49559f, 0.49730f, 0.49901f, - 0.50072f, 0.50241f, 0.50410f, 0.50579f, - 0.50747f, 0.50914f, 0.51081f, 0.51247f, - 0.51413f, 0.51578f, 0.51742f, 0.51906f, - 0.52069f, 0.52232f, 0.52394f, 0.52556f, - 0.52717f, 0.52878f, 0.53038f, 0.53197f, - 0.53356f, 0.53514f, 0.53672f, 0.53829f, - 0.53986f, 0.54142f, 0.54297f, 0.54452f, - 0.54607f, 0.54761f, 0.54914f, 0.55067f, - 0.55220f, 0.55371f, 0.55523f, 0.55673f, - 0.55824f, 0.55973f, 0.56123f, 0.56271f, - 0.56420f, 0.56567f, 0.56715f, 0.56861f, - 0.57007f, 0.57153f, 0.57298f, 0.57443f, - 0.57587f, 0.57731f, 0.57874f, 0.58017f, - 0.58159f, 0.58301f, 0.58443f, 0.58583f, - 0.58724f, 0.58864f, 0.59003f, 0.59142f, - 0.59281f, 0.59419f, 0.59556f, 0.59694f, - 0.59830f, 0.59966f, 0.60102f, 0.60238f, - 0.60373f, 0.60507f, 0.60641f, 0.60775f, - 0.60908f, 0.61040f, 0.61173f, 0.61305f, - 0.61436f, 0.61567f, 0.61698f, 0.61828f, - 0.61957f, 0.62087f, 0.62216f, 0.62344f, - 0.62472f, 0.62600f, 0.62727f, 0.62854f, - 0.62980f, 0.63106f, 0.63232f, 0.63357f, - 0.63482f, 0.63606f, 0.63730f, 0.63854f, - 0.63977f, 0.64100f, 0.64222f, 0.64344f, - 0.64466f, 0.64587f, 0.64708f, 0.64829f, - 0.64949f, 0.65069f, 0.65188f, 0.65307f, - 0.65426f, 0.65544f, 0.65662f, 0.65779f, - 0.65897f, 0.66013f, 0.66130f, 0.66246f, - 0.66362f, 0.66477f, 0.66592f, 0.66707f, - 0.66821f, 0.66935f, 0.67048f, 0.67162f, - 0.67275f, 0.67387f, 0.67499f, 0.67611f, - 0.67723f, 0.67834f, 0.67945f, 0.68055f, - 0.68165f, 0.68275f, 0.68385f, 0.68494f, - 0.68603f, 0.68711f, 0.68819f, 0.68927f, - 0.69035f, 0.69142f, 0.69249f, 0.69355f, - 0.69461f, 0.69567f, 0.69673f, 0.69778f, - 0.69883f, 0.69988f, 0.70092f, 0.70196f, - 0.70300f, 0.70403f, 0.70506f, 0.70609f, - 0.70711f, 0.70813f, 0.70915f, 0.71017f, - 0.71118f, 0.71219f, 0.71319f, 0.71420f, - 0.71520f, 0.71620f, 0.71719f, 0.71818f, - 0.71917f, 0.72016f, 0.72114f, 0.72212f, - 0.72309f, 0.72407f, 0.72504f, 0.72601f, - 0.72697f, 0.72794f, 0.72890f, 0.72985f, - 0.73081f, 0.73176f, 0.73271f, 0.73365f, - 0.73460f, 0.73554f, 0.73647f, 0.73741f, - 0.73834f, 0.73927f, 0.74020f, 0.74112f, - 0.74204f, 0.74296f, 0.74388f, 0.74479f, - 0.74570f, 0.74661f, 0.74751f, 0.74842f, - 0.74932f, 0.75021f, 0.75111f, 0.75200f, - 0.75289f, 0.75378f, 0.75466f, 0.75555f, - 0.75643f, 0.75730f, 0.75818f, 0.75905f, - 0.75992f, 0.76079f, 0.76165f, 0.76251f, - 0.76337f, 0.76423f, 0.76508f, 0.76594f, - 0.76679f, 0.76763f, 0.76848f, 0.76932f, - 0.77016f, 0.77100f, 0.77183f, 0.77267f, - 0.77350f, 0.77432f, 0.77515f, 0.77597f, - 0.77680f, 0.77761f, 0.77843f, 0.77924f, - 0.78006f, 0.78087f, 0.78167f, 0.78248f, - 0.78328f, 0.78408f, 0.78488f, 0.78568f, - 0.78647f, 0.78726f, 0.78805f, 0.78884f, - 0.78962f, 0.79040f, 0.79118f, 0.79196f, - 0.79274f, 0.79351f, 0.79428f, 0.79505f, - 0.79582f, 0.79658f, 0.79735f, 0.79811f, - 0.79887f, 0.79962f, 0.80038f, 0.80113f, - 0.80188f, 0.80263f, 0.80337f, 0.80412f, - 0.80486f, 0.80560f, 0.80634f, 0.80707f, - 0.80780f, 0.80854f, 0.80926f, 0.80999f, - 0.81072f, 0.81144f, 0.81216f, 0.81288f, - 0.81360f, 0.81431f, 0.81503f, 0.81574f, - 0.81645f, 0.81715f, 0.81786f, 0.81856f, - 0.81926f, 0.81996f, 0.82066f, 0.82135f, - 0.82205f, 0.82274f, 0.82343f, 0.82412f, - 0.82480f, 0.82549f, 0.82617f, 0.82685f, - 0.82753f, 0.82820f, 0.82888f, 0.82955f, - 0.83022f, 0.83089f, 0.83155f, 0.83222f, - 0.83288f, 0.83354f, 0.83420f, 0.83486f, - 0.83552f, 0.83617f, 0.83682f, 0.83747f, - 0.83812f, 0.83877f, 0.83941f, 0.84005f, - 0.84069f, 0.84133f, 0.84197f, 0.84261f, - 0.84324f, 0.84387f, 0.84450f, 0.84513f, - 0.84576f, 0.84639f, 0.84701f, 0.84763f, - 0.84825f, 0.84887f, 0.84949f, 0.85010f, - 0.85071f, 0.85132f, 0.85193f, 0.85254f, - 0.85315f, 0.85375f, 0.85436f, 0.85496f, - 0.85556f, 0.85615f, 0.85675f, 0.85735f, - 0.85794f, 0.85853f, 0.85912f, 0.85971f, - 0.86029f, 0.86088f, 0.86146f, 0.86204f, - 0.86262f, 0.86320f, 0.86378f, 0.86435f, - 0.86493f, 0.86550f, 0.86607f, 0.86664f, - 0.86720f, 0.86777f, 0.86833f, 0.86889f, - 0.86945f, 0.87001f, 0.87057f, 0.87113f, - 0.87168f, 0.87223f, 0.87278f, 0.87333f, - 0.87388f, 0.87443f, 0.87497f, 0.87552f, - 0.87606f, 0.87660f, 0.87714f, 0.87768f, - 0.87821f, 0.87875f, 0.87928f, 0.87981f, - 0.88034f, 0.88087f, 0.88140f, 0.88192f, - 0.88244f, 0.88297f, 0.88349f, 0.88401f, - 0.88453f, 0.88504f, 0.88556f, 0.88607f, - 0.88658f, 0.88709f, 0.88760f, 0.88811f, - 0.88862f, 0.88912f, 0.88963f, 0.89013f, - 0.89063f, 0.89113f, 0.89163f, 0.89212f, - 0.89262f, 0.89311f, 0.89360f, 0.89409f, - 0.89458f, 0.89507f, 0.89556f, 0.89604f, - 0.89653f, 0.89701f, 0.89749f, 0.89797f, - 0.89845f, 0.89892f, 0.89940f, 0.89987f, - 0.90035f, 0.90082f, 0.90129f, 0.90176f, - 0.90222f, 0.90269f, 0.90316f, 0.90362f, - 0.90408f, 0.90454f, 0.90500f, 0.90546f, - 0.90592f, 0.90637f, 0.90683f, 0.90728f, - 0.90773f, 0.90818f, 0.90863f, 0.90908f, - 0.90952f, 0.90997f, 0.91041f, 0.91085f, - 0.91130f, 0.91173f, 0.91217f, 0.91261f, - 0.91305f, 0.91348f, 0.91392f, 0.91435f, - 0.91478f, 0.91521f, 0.91564f, 0.91606f, - 0.91649f, 0.91691f, 0.91734f, 0.91776f, - 0.91818f, 0.91860f, 0.91902f, 0.91944f, - 0.91985f, 0.92027f, 0.92068f, 0.92109f, - 0.92150f, 0.92191f, 0.92232f, 0.92273f, - 0.92314f, 0.92354f, 0.92395f, 0.92435f, - 0.92475f, 0.92515f, 0.92555f, 0.92595f, - 0.92634f, 0.92674f, 0.92713f, 0.92753f, - 0.92792f, 0.92831f, 0.92870f, 0.92909f, - 0.92947f, 0.92986f, 0.93025f, 0.93063f, - 0.93101f, 0.93139f, 0.93177f, 0.93215f, - 0.93253f, 0.93291f, 0.93328f, 0.93366f, - 0.93403f, 0.93440f, 0.93478f, 0.93515f, - 0.93551f, 0.93588f, 0.93625f, 0.93661f, - 0.93698f, 0.93734f, 0.93770f, 0.93807f, - 0.93843f, 0.93878f, 0.93914f, 0.93950f, - 0.93986f, 0.94021f, 0.94056f, 0.94092f, - 0.94127f, 0.94162f, 0.94197f, 0.94231f, - 0.94266f, 0.94301f, 0.94335f, 0.94369f, - 0.94404f, 0.94438f, 0.94472f, 0.94506f, - 0.94540f, 0.94573f, 0.94607f, 0.94641f, - 0.94674f, 0.94707f, 0.94740f, 0.94774f, - 0.94807f, 0.94839f, 0.94872f, 0.94905f, - 0.94937f, 0.94970f, 0.95002f, 0.95035f, - 0.95067f, 0.95099f, 0.95131f, 0.95163f, - 0.95194f, 0.95226f, 0.95257f, 0.95289f, - 0.95320f, 0.95351f, 0.95383f, 0.95414f, - 0.95445f, 0.95475f, 0.95506f, 0.95537f, - 0.95567f, 0.95598f, 0.95628f, 0.95658f, - 0.95688f, 0.95718f, 0.95748f, 0.95778f, - 0.95808f, 0.95838f, 0.95867f, 0.95897f, - 0.95926f, 0.95955f, 0.95984f, 0.96013f, - 0.96042f, 0.96071f, 0.96100f, 0.96129f, - 0.96157f, 0.96186f, 0.96214f, 0.96242f, - 0.96271f, 0.96299f, 0.96327f, 0.96355f, - 0.96382f, 0.96410f, 0.96438f, 0.96465f, - 0.96493f, 0.96520f, 0.96547f, 0.96574f, - 0.96602f, 0.96629f, 0.96655f, 0.96682f, - 0.96709f, 0.96735f, 0.96762f, 0.96788f, - 0.96815f, 0.96841f, 0.96867f, 0.96893f, - 0.96919f, 0.96945f, 0.96971f, 0.96996f, - 0.97022f, 0.97047f, 0.97073f, 0.97098f, - 0.97123f, 0.97149f, 0.97174f, 0.97199f, - 0.97223f, 0.97248f, 0.97273f, 0.97297f, - 0.97322f, 0.97346f, 0.97371f, 0.97395f, - 0.97419f, 0.97443f, 0.97467f, 0.97491f, - 0.97515f, 0.97539f, 0.97562f, 0.97586f, - 0.97609f, 0.97633f, 0.97656f, 0.97679f, - 0.97702f, 0.97725f, 0.97748f, 0.97771f, - 0.97794f, 0.97817f, 0.97839f, 0.97862f, - 0.97884f, 0.97907f, 0.97929f, 0.97951f, - 0.97973f, 0.97995f, 0.98017f, 0.98039f, - 0.98061f, 0.98082f, 0.98104f, 0.98125f, - 0.98147f, 0.98168f, 0.98189f, 0.98211f, - 0.98232f, 0.98253f, 0.98274f, 0.98295f, - 0.98315f, 0.98336f, 0.98357f, 0.98377f, - 0.98398f, 0.98418f, 0.98438f, 0.98458f, - 0.98478f, 0.98498f, 0.98518f, 0.98538f, - 0.98558f, 0.98578f, 0.98597f, 0.98617f, - 0.98636f, 0.98656f, 0.98675f, 0.98694f, - 0.98714f, 0.98733f, 0.98752f, 0.98771f, - 0.98789f, 0.98808f, 0.98827f, 0.98845f, - 0.98864f, 0.98882f, 0.98901f, 0.98919f, - 0.98937f, 0.98955f, 0.98973f, 0.98991f, - 0.99009f, 0.99027f, 0.99045f, 0.99063f, - 0.99080f, 0.99098f, 0.99115f, 0.99133f, - 0.99150f, 0.99167f, 0.99184f, 0.99201f, - 0.99218f, 0.99235f, 0.99252f, 0.99269f, - 0.99285f, 0.99302f, 0.99319f, 0.99335f, - 0.99351f, 0.99368f, 0.99384f, 0.99400f, - 0.99416f, 0.99432f, 0.99448f, 0.99464f, - 0.99480f, 0.99495f, 0.99511f, 0.99527f, - 0.99542f, 0.99558f, 0.99573f, 0.99588f, - 0.99603f, 0.99619f, 0.99634f, 0.99649f, - 0.99664f, 0.99678f, 0.99693f, 0.99708f, - 0.99722f, 0.99737f, 0.99751f, 0.99766f, - 0.99780f, 0.99794f, 0.99809f, 0.99823f, - 0.99837f, 0.99851f, 0.99865f, 0.99879f, - 0.99892f, 0.99906f, 0.99920f, 0.99933f, - 0.99947f, 0.99960f, 0.99974f, 0.99987f, - 1.00000f -}; +namespace +{ // This sRGB gamma is taken from DNG reference code, with the added linear extension past 1.0, as we run clipless here -static float sRGBGammaForward (const float x) +float srgbGammaForward(float x) { - if (x <= 0.0031308) { - return x * 12.92; - } else if (x > 1.0) { - return 1.0 + (x - 1.0) * (1.055 * (1.0 / 2.4)); // linear extension - } else { - return 1.055 * pow (x, 1.0 / 2.4) - 0.055; - } -} -static float sRGBGammaInverse (const float y) -{ - if (y <= 0.0031308 * 12.92) { - return y * (1.0 / 12.92); - } else if (y > 1.0) { - return 1.0 + (y - 1.0) / (1.055 * (1.0 / 2.4)); - } else { - return pow ((y + 0.055) * (1.0 / 1.055), 2.4); - } + return + x <= 0.0031308f + ? x * 12.92f + : x > 1.0f + ? 1.0f + (x - 1.0f) * (1.055f * (1.0f / 2.4f)) // Linear extension + : 1.055f * pow(x, 1.0f / 2.4f) - 0.055f; } -static void Invert3x3(const double (*A)[3], double (*B)[3]) +float srgbGammaInverse(float y) { + return + y <= 0.0031308f * 12.92f + ? y * (1.0f / 12.92f) + : y > 1.0f + ? 1.0f + (y - 1.0f) / (1.055f * (1.0f / 2.4f)) + : pow ((y + 0.055f) * (1.0f / 1.055f), 2.4f); +} - double a00 = A[0][0]; - double a01 = A[0][1]; - double a02 = A[0][2]; - double a10 = A[1][0]; - double a11 = A[1][1]; - double a12 = A[1][2]; - double a20 = A[2][0]; - double a21 = A[2][1]; - double a22 = A[2][2]; - double temp [3][3]; +void invert3x3(const DCPProfile::Matrix& a, DCPProfile::Matrix& b) +{ + const double& a00 = a[0][0]; + const double& a01 = a[0][1]; + const double& a02 = a[0][2]; + const double& a10 = a[1][0]; + const double& a11 = a[1][1]; + const double& a12 = a[1][2]; + const double& a20 = a[2][0]; + const double& a21 = a[2][1]; + const double& a22 = a[2][2]; + + double temp[3][3]; temp[0][0] = a11 * a22 - a21 * a12; temp[0][1] = a21 * a02 - a01 * a22; @@ -335,79 +77,79 @@ static void Invert3x3(const double (*A)[3], double (*B)[3]) temp[2][1] = a20 * a01 - a00 * a21; temp[2][2] = a00 * a11 - a10 * a01; - double det = a00 * temp[0][0] + a01 * temp[1][0] + a02 * temp[2][0]; + const double det = a00 * temp[0][0] + a01 * temp[1][0] + a02 * temp[2][0]; - if (fabs(det) < 1.0E-10) { - abort(); // can't be inverted, we shouldn't be dealing with such matrices + if (fabs(det) < 1.0e-10) { + abort(); // Can't be inverted, we shouldn't be dealing with such matrices } - for (int j = 0; j < 3; j++) { - for (int k = 0; k < 3; k++) { - B[j][k] = temp[j][k] / det; + for (int j = 0; j < 3; ++j) { + for (int k = 0; k < 3; ++k) { + b[j][k] = temp[j][k] / det; } } } -static void Multiply3x3(const double (*A)[3], const double (*B)[3], double (*C)[3]) +void multiply3x3(const DCPProfile::Matrix& a, const DCPProfile::Matrix& b, DCPProfile::Matrix& c) { + // Use temp to support having output same as input + DCPProfile::Matrix m; - // use temp to support having output same as input - double M[3][3]; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + m[i][j] = 0; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - M[i][j] = 0; - - for (int k = 0; k < 3; k++) { - M[i][j] += A[i][k] * B[k][j]; + for (int k = 0; k < 3; ++k) { + m[i][j] += a[i][k] * b[k][j]; } } } - memcpy(C, M, 3 * 3 * sizeof(double)); + c = m; } -static void Multiply3x3_v3(const double (*A)[3], const double B[3], double C[3]) +void multiply3x3_v3(const DCPProfile::Matrix& a, const DCPProfile::Triple& b, DCPProfile::Triple& c) { + // Use temp to support having output same as input + DCPProfile::Triple m = {}; - // use temp to support having output same as input - double M[3] = { 0, 0, 0 }; - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - M[i] += A[i][j] * B[j]; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + m[i] += a[i][j] * b[j]; } } - memcpy(C, M, 3 * sizeof(double)); + c = m; } -static void Mix3x3(const double (*A)[3], double mulA, const double (*B)[3], double mulB, double (*C)[3]) +void mix3x3(const DCPProfile::Matrix& a, double mul_a, const DCPProfile::Matrix& b, double mul_b, DCPProfile::Matrix& c) { + DCPProfile::Matrix m; - double M[3][3]; - - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - M[i][j] = A[i][j] * mulA + B[i][j] * mulB; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + m[i][j] = a[i][j] * mul_a + b[i][j] * mul_b; } } - memcpy(C, M, 3 * 3 * sizeof(double)); + c = m; } -static void MapWhiteMatrix(const double white1[3], const double white2[3], double (*B)[3]) +void mapWhiteMatrix(const DCPProfile::Triple& white1, const DCPProfile::Triple& white2, DCPProfile::Matrix& b) { + // Code adapted from dng_color_spec::MapWhiteMatrix - // code adapted from dng_color_spec::MapWhiteMatrix + // Use the linearized Bradford adaptation matrix + const DCPProfile::Matrix mb = {{ + { 0.8951, 0.2664, -0.1614 }, + { -0.7502, 1.7135, 0.0367 }, + { 0.0389, -0.0685, 1.0296 } + }}; - // Use the linearized Bradford adaptation matrix. - double Mb[3][3] = { { 0.8951, 0.2664, -0.1614 }, { -0.7502, 1.7135, 0.0367 }, { 0.0389, -0.0685, 1.0296 }}; - - double w1[3]; - Multiply3x3_v3(Mb, white1, w1); - double w2[3]; - Multiply3x3_v3(Mb, white2, w2); + DCPProfile::Triple w1; + multiply3x3_v3(mb, white1, w1); + DCPProfile::Triple w2; + multiply3x3_v3(mb, white2, w2); // Negative white coordinates are kind of meaningless. w1[0] = std::max(w1[0], 0.0); @@ -418,36 +160,34 @@ static void MapWhiteMatrix(const double white1[3], const double white2[3], doubl w2[2] = std::max(w2[2], 0.0); // Limit scaling to something reasonable. - double A[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - A[0][0] = std::max(0.1, std::min(w1[0] > 0.0 ? w2[0] / w1[0] : 10.0, 10.0)); - A[1][1] = std::max(0.1, std::min(w1[1] > 0.0 ? w2[1] / w1[1] : 10.0, 10.0)); - A[2][2] = std::max(0.1, std::min(w1[2] > 0.0 ? w2[2] / w1[2] : 10.0, 10.0)); + DCPProfile::Matrix a = {}; + a[0][0] = std::max(0.1, std::min(w1[0] > 0.0 ? w2[0] / w1[0] : 10.0, 10.0)); + a[1][1] = std::max(0.1, std::min(w1[1] > 0.0 ? w2[1] / w1[1] : 10.0, 10.0)); + a[2][2] = std::max(0.1, std::min(w1[2] > 0.0 ? w2[2] / w1[2] : 10.0, 10.0)); - double temp[3][3]; - Invert3x3(Mb, temp); - Multiply3x3(temp, A, temp); - Multiply3x3(temp, Mb, B); + DCPProfile::Matrix temp; + invert3x3(mb, temp); + multiply3x3(temp, a, temp); + multiply3x3(temp, mb, b); } -static void XYZtoXY(const double XYZ[3], double XY[2]) +void xyzToXy(const DCPProfile::Triple& xyz, double xy[2]) { - double X = XYZ[0]; - double Y = XYZ[1]; - double Z = XYZ[2]; - double total = X + Y + Z; + const double total = xyz[0] + xyz[1] + xyz[2]; if (total > 0.0) { - XY[0] = X / total; - XY[1] = Y / total; + xy[0] = xyz[0] / total; + xy[1] = xyz[1] / total; } else { - XY[0] = 0.3457; - XY[1] = 0.3585; + xy[0] = 0.3457; + xy[1] = 0.3585; } } -static void XYtoXYZ(const double XY[2], double XYZ[3]) +void xyToXyz(const double xy[2], DCPProfile::Triple& xyz) { - double temp[2] = { XY[0], XY[1] }; + double temp[2] = {xy[0], xy[1]}; + // Restrict xy coord to someplace inside the range of real xy coordinates. // This prevents math from doing strange things when users specify // extreme temperature/tint coordinates. @@ -460,106 +200,1209 @@ static void XYtoXYZ(const double XY[2], double XYZ[3]) temp[1] *= scale; } - XYZ[0] = temp[0] / temp[1]; - XYZ[1] = 1.0; - XYZ[2] = (1.0 - temp[0] - temp[1]) / temp[1]; + xyz[0] = temp[0] / temp[1]; + xyz[1] = 1.0; + xyz[2] = (1.0 - temp[0] - temp[1]) / temp[1]; } -enum dngCalibrationIlluminant { - lsUnknown = 0, - lsDaylight = 1, - lsFluorescent = 2, - lsTungsten = 3, - lsFlash = 4, - lsFineWeather = 9, - lsCloudyWeather = 10, - lsShade = 11, - lsDaylightFluorescent = 12, // D 5700 - 7100K - lsDayWhiteFluorescent = 13, // N 4600 - 5500K - lsCoolWhiteFluorescent = 14, // W 3800 - 4500K - lsWhiteFluorescent = 15, // WW 3250 - 3800K - lsWarmWhiteFluorescent = 16, // L 2600 - 3250K - lsStandardLightA = 17, - lsStandardLightB = 18, - lsStandardLightC = 19, - lsD55 = 20, - lsD65 = 21, - lsD75 = 22, - lsD50 = 23, - lsISOStudioTungsten = 24, - lsOther = 255 -}; - -// should probably be moved to colortemp.cc -static double calibrationIlluminantToTemperature(int light) +double calibrationIlluminantToTemperature(int light) { + enum class LightSource { + UNKNOWN = 0, + DAYLIGHT = 1, + FLUORESCENT = 2, + TUNGSTEN = 3, + FLASH = 4, + FINE_WEATHER = 9, + CLOUDY_WEATHER = 10, + SHADE = 11, + DAYLIGHT_FLUORESCENT = 12, // D 5700 - 7100K + DAYWHITE_FLUORESCENT = 13, // N 4600 - 5500K + COOL_WHITE_FLUORESCENT = 14, // W 3800 - 4500K + WHITE_FLUORESCENT = 15, // WW 3250 - 3800K + WARM_WHITE_FLUORESCENT = 16, // L 2600 - 3250K + STANDARD_LIGHT_A = 17, + STANDARD_LIGHT_B = 18, + STANDARD_LIGHT_C = 19, + D55 = 20, + D65 = 21, + D75 = 22, + D50 = 23, + ISO_STUDIO_TUNGSTEN = 24, + OTHER = 255 + }; - // these temperatures are those found in DNG SDK reference code. - switch (light) { - case lsStandardLightA: - case lsTungsten: - return 2850.0; + // These temperatures are those found in DNG SDK reference code + switch (LightSource(light)) { + case LightSource::STANDARD_LIGHT_A: + case LightSource::TUNGSTEN: { + return 2850.0; + } - case lsISOStudioTungsten: - return 3200.0; + case LightSource::ISO_STUDIO_TUNGSTEN: { + return 3200.0; + } - case lsD50: - return 5000.0; + case LightSource::D50: { + return 5000.0; + } - case lsD55: - case lsDaylight: - case lsFineWeather: - case lsFlash: - case lsStandardLightB: - return 5500.0; + case LightSource::D55: + case LightSource::DAYLIGHT: + case LightSource::FINE_WEATHER: + case LightSource::FLASH: + case LightSource::STANDARD_LIGHT_B: { + return 5500.0; + } - case lsD65: - case lsStandardLightC: - case lsCloudyWeather: - return 6500.0; + case LightSource::D65: + case LightSource::STANDARD_LIGHT_C: + case LightSource::CLOUDY_WEATHER: { + return 6500.0; + } - case lsD75: - case lsShade: - return 7500.0; + case LightSource::D75: + case LightSource::SHADE: { + return 7500.0; + } - case lsDaylightFluorescent: - return (5700.0 + 7100.0) * 0.5; + case LightSource::DAYLIGHT_FLUORESCENT: { + return (5700.0 + 7100.0) * 0.5; + } - case lsDayWhiteFluorescent: - return (4600.0 + 5500.0) * 0.5; + case LightSource::DAYWHITE_FLUORESCENT: { + return (4600.0 + 5500.0) * 0.5; + } - case lsCoolWhiteFluorescent: - case lsFluorescent: - return (3800.0 + 4500.0) * 0.5; + case LightSource::COOL_WHITE_FLUORESCENT: + case LightSource::FLUORESCENT: { + return (3800.0 + 4500.0) * 0.5; + } - case lsWhiteFluorescent: - return (3250.0 + 3800.0) * 0.5; + case LightSource::WHITE_FLUORESCENT: { + return (3250.0 + 3800.0) * 0.5; + } - case lsWarmWhiteFluorescent: - return (2600.0 + 3250.0) * 0.5; + case LightSource::WARM_WHITE_FLUORESCENT: { + return (2600.0 + 3250.0) * 0.5; + } - default: - return 0.0; + default: { + return 0.0; + } } } -void DCPProfile::MakeXYZCAM(ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const -{ - // code adapted from dng_color_spec::FindXYZtoCamera - // note that we do not support monochrome or colorplanes > 3 (no reductionMatrix support) - // we do not support cameracalibration either - double neutral[3]; // same as the DNG "AsShotNeutral" tag if white balance is Camera's own +void xyCoordToTemperature(const double white_xy[2], double* temp, double* tint) +{ + struct Ruvt { + double r; + double u; + double v; + double t; + }; + + static const Ruvt temp_table[] = { + { 0, 0.18006, 0.26352, -0.24341 }, + { 10, 0.18066, 0.26589, -0.25479 }, + { 20, 0.18133, 0.26846, -0.26876 }, + { 30, 0.18208, 0.27119, -0.28539 }, + { 40, 0.18293, 0.27407, -0.30470 }, + { 50, 0.18388, 0.27709, -0.32675 }, + { 60, 0.18494, 0.28021, -0.35156 }, + { 70, 0.18611, 0.28342, -0.37915 }, + { 80, 0.18740, 0.28668, -0.40955 }, + { 90, 0.18880, 0.28997, -0.44278 }, + { 100, 0.19032, 0.29326, -0.47888 }, + { 125, 0.19462, 0.30141, -0.58204 }, + { 150, 0.19962, 0.30921, -0.70471 }, + { 175, 0.20525, 0.31647, -0.84901 }, + { 200, 0.21142, 0.32312, -1.0182 }, + { 225, 0.21807, 0.32909, -1.2168 }, + { 250, 0.22511, 0.33439, -1.4512 }, + { 275, 0.23247, 0.33904, -1.7298 }, + { 300, 0.24010, 0.34308, -2.0637 }, + { 325, 0.24702, 0.34655, -2.4681 }, + { 350, 0.25591, 0.34951, -2.9641 }, + { 375, 0.26400, 0.35200, -3.5814 }, + { 400, 0.27218, 0.35407, -4.3633 }, + { 425, 0.28039, 0.35577, -5.3762 }, + { 450, 0.28863, 0.35714, -6.7262 }, + { 475, 0.29685, 0.35823, -8.5955 }, + { 500, 0.30505, 0.35907, -11.324 }, + { 525, 0.31320, 0.35968, -15.628 }, + { 550, 0.32129, 0.36011, -23.325 }, + { 575, 0.32931, 0.36038, -40.770 }, + { 600, 0.33724, 0.36051, -116.45 } + }; + + constexpr double tint_scale = -3000.0; + + double temperature = 0; + double computed_tint = 0; + + // Convert to uv space. + double u = 2.0 * white_xy[0] / (1.5 - white_xy[0] + 6.0 * white_xy[1]); + double v = 3.0 * white_xy[1] / (1.5 - white_xy[0] + 6.0 * white_xy[1]); + + // Search for line pair coordinate is between. + double last_dt = 0.0; + double last_dv = 0.0; + double last_du = 0.0; + + for (uint32_t index = 1; index <= 30; ++index) { + // Convert slope to delta-u and delta-v, with length 1. + double du = 1.0; + double dv = temp_table[index].t; + double len = sqrt(1.0 + dv * dv); + du /= len; + dv /= len; + + // Find delta from black body point to test coordinate. + double uu = u - temp_table[index].u; + double vv = v - temp_table[index].v; + + // Find distance above or below line. + double dt = -uu * dv + vv * du; + + // If below line, we have found line pair. + if (dt <= 0.0 || index == 30) { + // Find fractional weight of two lines. + if (dt > 0.0) { + dt = 0.0; + } + + dt = -dt; + + double f; + + if (index == 1) { + f = 0.0; + } else { + f = dt / (last_dt + dt); + } + + // Interpolate the temperature. + temperature = 1.0e6 / (temp_table[index - 1].r * f + temp_table[index].r * (1.0 - f)); + + // Find delta from black body point to test coordinate. + uu = u - (temp_table [index - 1].u * f + temp_table [index].u * (1.0 - f)); + vv = v - (temp_table [index - 1].v * f + temp_table [index].v * (1.0 - f)); + // Interpolate vectors along slope. + du = du * (1.0 - f) + last_du * f; + dv = dv * (1.0 - f) + last_dv * f; + len = sqrt (du * du + dv * dv); + du /= len; + dv /= len; + + // Find distance along slope. + computed_tint = (uu * du + vv * dv) * tint_scale; + break; + } + + // Try next line pair. + last_dt = dt; + last_du = du; + last_dv = dv; + } + + if (temp != nullptr) { + *temp = temperature; + } + + if (tint != nullptr) { + *tint = computed_tint; + } +} + +} + +struct DCPProfile::ApplyState::Data { + double pro_photo[3][3]; + double work[3][3]; + bool already_pro_photo; + bool use_tone_curve; + bool apply_look_table; + float bl_scale; +}; + +DCPProfile::ApplyState::ApplyState() : + data(new Data{}) +{ +} + +DCPProfile::ApplyState::~ApplyState() +{ +} + +DCPProfile::DCPProfile(const Glib::ustring& filename) : + has_color_matrix_1(false), + has_color_matrix_2(false), + has_forward_matrix_1(false), + has_forward_matrix_2(false), + has_tone_curve(false), + has_baseline_exposure_offset(false), + will_interpolate(false), + baseline_exposure_offset(0.0) +{ + constexpr int tiff_float_size = 4; + + enum class TagKey : int { + COLOR_MATRIX_1 = 50721, + COLOR_MATRIX_2 = 50722, + PROFILE_HUE_SAT_MAP_DIMS = 50937, + PROFILE_HUE_SAT_MAP_DATA_1 = 50938, + PROFILE_HUE_SAT_MAP_DATA_2 = 50939, + PROFILE_TONE_CURVE = 50940, + PROFILE_TONE_COPYRIGHT = 50942, + CALIBRATION_ILLUMINANT_1 = 50778, + CALIBRATION_ILLUMINANT_2 = 50779, + FORWARD_MATRIX_1 = 50964, + FORWARD_MATRIX_2 = 50965, + PROFILE_LOOK_TABLE_DIMS = 50981, // ProfileLookup is the low quality variant + PROFILE_LOOK_TABLE_DATA = 50982, + PROFILE_HUE_SAT_MAP_ENCODING = 51107, + PROFILE_LOOK_TABLE_ENCODING = 51108, + BASELINE_EXPOSURE_OFFSET = 51109 + }; + + static const float adobe_camera_raw_default_curve[] = { + 0.00000f, 0.00078f, 0.00160f, 0.00242f, + 0.00314f, 0.00385f, 0.00460f, 0.00539f, + 0.00623f, 0.00712f, 0.00806f, 0.00906f, + 0.01012f, 0.01122f, 0.01238f, 0.01359f, + 0.01485f, 0.01616f, 0.01751f, 0.01890f, + 0.02033f, 0.02180f, 0.02331f, 0.02485f, + 0.02643f, 0.02804f, 0.02967f, 0.03134f, + 0.03303f, 0.03475f, 0.03648f, 0.03824f, + 0.04002f, 0.04181f, 0.04362f, 0.04545f, + 0.04730f, 0.04916f, 0.05103f, 0.05292f, + 0.05483f, 0.05675f, 0.05868f, 0.06063f, + 0.06259f, 0.06457f, 0.06655f, 0.06856f, + 0.07057f, 0.07259f, 0.07463f, 0.07668f, + 0.07874f, 0.08081f, 0.08290f, 0.08499f, + 0.08710f, 0.08921f, 0.09134f, 0.09348f, + 0.09563f, 0.09779f, 0.09996f, 0.10214f, + 0.10433f, 0.10652f, 0.10873f, 0.11095f, + 0.11318f, 0.11541f, 0.11766f, 0.11991f, + 0.12218f, 0.12445f, 0.12673f, 0.12902f, + 0.13132f, 0.13363f, 0.13595f, 0.13827f, + 0.14061f, 0.14295f, 0.14530f, 0.14765f, + 0.15002f, 0.15239f, 0.15477f, 0.15716f, + 0.15956f, 0.16197f, 0.16438f, 0.16680f, + 0.16923f, 0.17166f, 0.17410f, 0.17655f, + 0.17901f, 0.18148f, 0.18395f, 0.18643f, + 0.18891f, 0.19141f, 0.19391f, 0.19641f, + 0.19893f, 0.20145f, 0.20398f, 0.20651f, + 0.20905f, 0.21160f, 0.21416f, 0.21672f, + 0.21929f, 0.22185f, 0.22440f, 0.22696f, + 0.22950f, 0.23204f, 0.23458f, 0.23711f, + 0.23963f, 0.24215f, 0.24466f, 0.24717f, + 0.24967f, 0.25216f, 0.25465f, 0.25713f, + 0.25961f, 0.26208f, 0.26454f, 0.26700f, + 0.26945f, 0.27189f, 0.27433f, 0.27676f, + 0.27918f, 0.28160f, 0.28401f, 0.28641f, + 0.28881f, 0.29120f, 0.29358f, 0.29596f, + 0.29833f, 0.30069f, 0.30305f, 0.30540f, + 0.30774f, 0.31008f, 0.31241f, 0.31473f, + 0.31704f, 0.31935f, 0.32165f, 0.32395f, + 0.32623f, 0.32851f, 0.33079f, 0.33305f, + 0.33531f, 0.33756f, 0.33981f, 0.34205f, + 0.34428f, 0.34650f, 0.34872f, 0.35093f, + 0.35313f, 0.35532f, 0.35751f, 0.35969f, + 0.36187f, 0.36404f, 0.36620f, 0.36835f, + 0.37050f, 0.37264f, 0.37477f, 0.37689f, + 0.37901f, 0.38112f, 0.38323f, 0.38533f, + 0.38742f, 0.38950f, 0.39158f, 0.39365f, + 0.39571f, 0.39777f, 0.39982f, 0.40186f, + 0.40389f, 0.40592f, 0.40794f, 0.40996f, + 0.41197f, 0.41397f, 0.41596f, 0.41795f, + 0.41993f, 0.42191f, 0.42388f, 0.42584f, + 0.42779f, 0.42974f, 0.43168f, 0.43362f, + 0.43554f, 0.43747f, 0.43938f, 0.44129f, + 0.44319f, 0.44509f, 0.44698f, 0.44886f, + 0.45073f, 0.45260f, 0.45447f, 0.45632f, + 0.45817f, 0.46002f, 0.46186f, 0.46369f, + 0.46551f, 0.46733f, 0.46914f, 0.47095f, + 0.47275f, 0.47454f, 0.47633f, 0.47811f, + 0.47989f, 0.48166f, 0.48342f, 0.48518f, + 0.48693f, 0.48867f, 0.49041f, 0.49214f, + 0.49387f, 0.49559f, 0.49730f, 0.49901f, + 0.50072f, 0.50241f, 0.50410f, 0.50579f, + 0.50747f, 0.50914f, 0.51081f, 0.51247f, + 0.51413f, 0.51578f, 0.51742f, 0.51906f, + 0.52069f, 0.52232f, 0.52394f, 0.52556f, + 0.52717f, 0.52878f, 0.53038f, 0.53197f, + 0.53356f, 0.53514f, 0.53672f, 0.53829f, + 0.53986f, 0.54142f, 0.54297f, 0.54452f, + 0.54607f, 0.54761f, 0.54914f, 0.55067f, + 0.55220f, 0.55371f, 0.55523f, 0.55673f, + 0.55824f, 0.55973f, 0.56123f, 0.56271f, + 0.56420f, 0.56567f, 0.56715f, 0.56861f, + 0.57007f, 0.57153f, 0.57298f, 0.57443f, + 0.57587f, 0.57731f, 0.57874f, 0.58017f, + 0.58159f, 0.58301f, 0.58443f, 0.58583f, + 0.58724f, 0.58864f, 0.59003f, 0.59142f, + 0.59281f, 0.59419f, 0.59556f, 0.59694f, + 0.59830f, 0.59966f, 0.60102f, 0.60238f, + 0.60373f, 0.60507f, 0.60641f, 0.60775f, + 0.60908f, 0.61040f, 0.61173f, 0.61305f, + 0.61436f, 0.61567f, 0.61698f, 0.61828f, + 0.61957f, 0.62087f, 0.62216f, 0.62344f, + 0.62472f, 0.62600f, 0.62727f, 0.62854f, + 0.62980f, 0.63106f, 0.63232f, 0.63357f, + 0.63482f, 0.63606f, 0.63730f, 0.63854f, + 0.63977f, 0.64100f, 0.64222f, 0.64344f, + 0.64466f, 0.64587f, 0.64708f, 0.64829f, + 0.64949f, 0.65069f, 0.65188f, 0.65307f, + 0.65426f, 0.65544f, 0.65662f, 0.65779f, + 0.65897f, 0.66013f, 0.66130f, 0.66246f, + 0.66362f, 0.66477f, 0.66592f, 0.66707f, + 0.66821f, 0.66935f, 0.67048f, 0.67162f, + 0.67275f, 0.67387f, 0.67499f, 0.67611f, + 0.67723f, 0.67834f, 0.67945f, 0.68055f, + 0.68165f, 0.68275f, 0.68385f, 0.68494f, + 0.68603f, 0.68711f, 0.68819f, 0.68927f, + 0.69035f, 0.69142f, 0.69249f, 0.69355f, + 0.69461f, 0.69567f, 0.69673f, 0.69778f, + 0.69883f, 0.69988f, 0.70092f, 0.70196f, + 0.70300f, 0.70403f, 0.70506f, 0.70609f, + 0.70711f, 0.70813f, 0.70915f, 0.71017f, + 0.71118f, 0.71219f, 0.71319f, 0.71420f, + 0.71520f, 0.71620f, 0.71719f, 0.71818f, + 0.71917f, 0.72016f, 0.72114f, 0.72212f, + 0.72309f, 0.72407f, 0.72504f, 0.72601f, + 0.72697f, 0.72794f, 0.72890f, 0.72985f, + 0.73081f, 0.73176f, 0.73271f, 0.73365f, + 0.73460f, 0.73554f, 0.73647f, 0.73741f, + 0.73834f, 0.73927f, 0.74020f, 0.74112f, + 0.74204f, 0.74296f, 0.74388f, 0.74479f, + 0.74570f, 0.74661f, 0.74751f, 0.74842f, + 0.74932f, 0.75021f, 0.75111f, 0.75200f, + 0.75289f, 0.75378f, 0.75466f, 0.75555f, + 0.75643f, 0.75730f, 0.75818f, 0.75905f, + 0.75992f, 0.76079f, 0.76165f, 0.76251f, + 0.76337f, 0.76423f, 0.76508f, 0.76594f, + 0.76679f, 0.76763f, 0.76848f, 0.76932f, + 0.77016f, 0.77100f, 0.77183f, 0.77267f, + 0.77350f, 0.77432f, 0.77515f, 0.77597f, + 0.77680f, 0.77761f, 0.77843f, 0.77924f, + 0.78006f, 0.78087f, 0.78167f, 0.78248f, + 0.78328f, 0.78408f, 0.78488f, 0.78568f, + 0.78647f, 0.78726f, 0.78805f, 0.78884f, + 0.78962f, 0.79040f, 0.79118f, 0.79196f, + 0.79274f, 0.79351f, 0.79428f, 0.79505f, + 0.79582f, 0.79658f, 0.79735f, 0.79811f, + 0.79887f, 0.79962f, 0.80038f, 0.80113f, + 0.80188f, 0.80263f, 0.80337f, 0.80412f, + 0.80486f, 0.80560f, 0.80634f, 0.80707f, + 0.80780f, 0.80854f, 0.80926f, 0.80999f, + 0.81072f, 0.81144f, 0.81216f, 0.81288f, + 0.81360f, 0.81431f, 0.81503f, 0.81574f, + 0.81645f, 0.81715f, 0.81786f, 0.81856f, + 0.81926f, 0.81996f, 0.82066f, 0.82135f, + 0.82205f, 0.82274f, 0.82343f, 0.82412f, + 0.82480f, 0.82549f, 0.82617f, 0.82685f, + 0.82753f, 0.82820f, 0.82888f, 0.82955f, + 0.83022f, 0.83089f, 0.83155f, 0.83222f, + 0.83288f, 0.83354f, 0.83420f, 0.83486f, + 0.83552f, 0.83617f, 0.83682f, 0.83747f, + 0.83812f, 0.83877f, 0.83941f, 0.84005f, + 0.84069f, 0.84133f, 0.84197f, 0.84261f, + 0.84324f, 0.84387f, 0.84450f, 0.84513f, + 0.84576f, 0.84639f, 0.84701f, 0.84763f, + 0.84825f, 0.84887f, 0.84949f, 0.85010f, + 0.85071f, 0.85132f, 0.85193f, 0.85254f, + 0.85315f, 0.85375f, 0.85436f, 0.85496f, + 0.85556f, 0.85615f, 0.85675f, 0.85735f, + 0.85794f, 0.85853f, 0.85912f, 0.85971f, + 0.86029f, 0.86088f, 0.86146f, 0.86204f, + 0.86262f, 0.86320f, 0.86378f, 0.86435f, + 0.86493f, 0.86550f, 0.86607f, 0.86664f, + 0.86720f, 0.86777f, 0.86833f, 0.86889f, + 0.86945f, 0.87001f, 0.87057f, 0.87113f, + 0.87168f, 0.87223f, 0.87278f, 0.87333f, + 0.87388f, 0.87443f, 0.87497f, 0.87552f, + 0.87606f, 0.87660f, 0.87714f, 0.87768f, + 0.87821f, 0.87875f, 0.87928f, 0.87981f, + 0.88034f, 0.88087f, 0.88140f, 0.88192f, + 0.88244f, 0.88297f, 0.88349f, 0.88401f, + 0.88453f, 0.88504f, 0.88556f, 0.88607f, + 0.88658f, 0.88709f, 0.88760f, 0.88811f, + 0.88862f, 0.88912f, 0.88963f, 0.89013f, + 0.89063f, 0.89113f, 0.89163f, 0.89212f, + 0.89262f, 0.89311f, 0.89360f, 0.89409f, + 0.89458f, 0.89507f, 0.89556f, 0.89604f, + 0.89653f, 0.89701f, 0.89749f, 0.89797f, + 0.89845f, 0.89892f, 0.89940f, 0.89987f, + 0.90035f, 0.90082f, 0.90129f, 0.90176f, + 0.90222f, 0.90269f, 0.90316f, 0.90362f, + 0.90408f, 0.90454f, 0.90500f, 0.90546f, + 0.90592f, 0.90637f, 0.90683f, 0.90728f, + 0.90773f, 0.90818f, 0.90863f, 0.90908f, + 0.90952f, 0.90997f, 0.91041f, 0.91085f, + 0.91130f, 0.91173f, 0.91217f, 0.91261f, + 0.91305f, 0.91348f, 0.91392f, 0.91435f, + 0.91478f, 0.91521f, 0.91564f, 0.91606f, + 0.91649f, 0.91691f, 0.91734f, 0.91776f, + 0.91818f, 0.91860f, 0.91902f, 0.91944f, + 0.91985f, 0.92027f, 0.92068f, 0.92109f, + 0.92150f, 0.92191f, 0.92232f, 0.92273f, + 0.92314f, 0.92354f, 0.92395f, 0.92435f, + 0.92475f, 0.92515f, 0.92555f, 0.92595f, + 0.92634f, 0.92674f, 0.92713f, 0.92753f, + 0.92792f, 0.92831f, 0.92870f, 0.92909f, + 0.92947f, 0.92986f, 0.93025f, 0.93063f, + 0.93101f, 0.93139f, 0.93177f, 0.93215f, + 0.93253f, 0.93291f, 0.93328f, 0.93366f, + 0.93403f, 0.93440f, 0.93478f, 0.93515f, + 0.93551f, 0.93588f, 0.93625f, 0.93661f, + 0.93698f, 0.93734f, 0.93770f, 0.93807f, + 0.93843f, 0.93878f, 0.93914f, 0.93950f, + 0.93986f, 0.94021f, 0.94056f, 0.94092f, + 0.94127f, 0.94162f, 0.94197f, 0.94231f, + 0.94266f, 0.94301f, 0.94335f, 0.94369f, + 0.94404f, 0.94438f, 0.94472f, 0.94506f, + 0.94540f, 0.94573f, 0.94607f, 0.94641f, + 0.94674f, 0.94707f, 0.94740f, 0.94774f, + 0.94807f, 0.94839f, 0.94872f, 0.94905f, + 0.94937f, 0.94970f, 0.95002f, 0.95035f, + 0.95067f, 0.95099f, 0.95131f, 0.95163f, + 0.95194f, 0.95226f, 0.95257f, 0.95289f, + 0.95320f, 0.95351f, 0.95383f, 0.95414f, + 0.95445f, 0.95475f, 0.95506f, 0.95537f, + 0.95567f, 0.95598f, 0.95628f, 0.95658f, + 0.95688f, 0.95718f, 0.95748f, 0.95778f, + 0.95808f, 0.95838f, 0.95867f, 0.95897f, + 0.95926f, 0.95955f, 0.95984f, 0.96013f, + 0.96042f, 0.96071f, 0.96100f, 0.96129f, + 0.96157f, 0.96186f, 0.96214f, 0.96242f, + 0.96271f, 0.96299f, 0.96327f, 0.96355f, + 0.96382f, 0.96410f, 0.96438f, 0.96465f, + 0.96493f, 0.96520f, 0.96547f, 0.96574f, + 0.96602f, 0.96629f, 0.96655f, 0.96682f, + 0.96709f, 0.96735f, 0.96762f, 0.96788f, + 0.96815f, 0.96841f, 0.96867f, 0.96893f, + 0.96919f, 0.96945f, 0.96971f, 0.96996f, + 0.97022f, 0.97047f, 0.97073f, 0.97098f, + 0.97123f, 0.97149f, 0.97174f, 0.97199f, + 0.97223f, 0.97248f, 0.97273f, 0.97297f, + 0.97322f, 0.97346f, 0.97371f, 0.97395f, + 0.97419f, 0.97443f, 0.97467f, 0.97491f, + 0.97515f, 0.97539f, 0.97562f, 0.97586f, + 0.97609f, 0.97633f, 0.97656f, 0.97679f, + 0.97702f, 0.97725f, 0.97748f, 0.97771f, + 0.97794f, 0.97817f, 0.97839f, 0.97862f, + 0.97884f, 0.97907f, 0.97929f, 0.97951f, + 0.97973f, 0.97995f, 0.98017f, 0.98039f, + 0.98061f, 0.98082f, 0.98104f, 0.98125f, + 0.98147f, 0.98168f, 0.98189f, 0.98211f, + 0.98232f, 0.98253f, 0.98274f, 0.98295f, + 0.98315f, 0.98336f, 0.98357f, 0.98377f, + 0.98398f, 0.98418f, 0.98438f, 0.98458f, + 0.98478f, 0.98498f, 0.98518f, 0.98538f, + 0.98558f, 0.98578f, 0.98597f, 0.98617f, + 0.98636f, 0.98656f, 0.98675f, 0.98694f, + 0.98714f, 0.98733f, 0.98752f, 0.98771f, + 0.98789f, 0.98808f, 0.98827f, 0.98845f, + 0.98864f, 0.98882f, 0.98901f, 0.98919f, + 0.98937f, 0.98955f, 0.98973f, 0.98991f, + 0.99009f, 0.99027f, 0.99045f, 0.99063f, + 0.99080f, 0.99098f, 0.99115f, 0.99133f, + 0.99150f, 0.99167f, 0.99184f, 0.99201f, + 0.99218f, 0.99235f, 0.99252f, 0.99269f, + 0.99285f, 0.99302f, 0.99319f, 0.99335f, + 0.99351f, 0.99368f, 0.99384f, 0.99400f, + 0.99416f, 0.99432f, 0.99448f, 0.99464f, + 0.99480f, 0.99495f, 0.99511f, 0.99527f, + 0.99542f, 0.99558f, 0.99573f, 0.99588f, + 0.99603f, 0.99619f, 0.99634f, 0.99649f, + 0.99664f, 0.99678f, 0.99693f, 0.99708f, + 0.99722f, 0.99737f, 0.99751f, 0.99766f, + 0.99780f, 0.99794f, 0.99809f, 0.99823f, + 0.99837f, 0.99851f, 0.99865f, 0.99879f, + 0.99892f, 0.99906f, 0.99920f, 0.99933f, + 0.99947f, 0.99960f, 0.99974f, 0.99987f, + 1.00000f + }; + + FILE* const file = g_fopen(filename.c_str(), "rb"); + + std::unique_ptr tagDir(ExifManager::parseTIFF(file, false)); + + Tag* tag = tagDir->getTag(toUnderlying(TagKey::CALIBRATION_ILLUMINANT_1)); + light_source_1 = + tag + ? tag->toInt(0, rtexif::SHORT) + : -1; + tag = tagDir->getTag(toUnderlying(TagKey::CALIBRATION_ILLUMINANT_2)); + light_source_2 = + tag + ? tag->toInt(0, rtexif::SHORT) + : -1; + temperature_1 = calibrationIlluminantToTemperature(light_source_1); + temperature_2 = calibrationIlluminantToTemperature(light_source_2); + + const bool has_second_hue_sat = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DATA_2)); // Some profiles have two matrices, but just one huesat + + // Fetch Forward Matrices, if any + tag = tagDir->getTag(toUnderlying(TagKey::FORWARD_MATRIX_1)); + + if (tag) { + has_forward_matrix_1 = true; + + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + forward_matrix_1[row][col] = tag->toDouble((col + row * 3) * 8); + } + } + } + + tag = tagDir->getTag(toUnderlying(TagKey::FORWARD_MATRIX_2)); + + if (tag) { + has_forward_matrix_2 = true; + + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + forward_matrix_2[row][col] = tag->toDouble((col + row * 3) * 8); + } + } + } + + // Color Matrix (one is always there) + tag = tagDir->getTag(toUnderlying(TagKey::COLOR_MATRIX_1)); + + if (!tag) { + // FIXME: better error handling + fprintf(stderr, "Bad DCP, no ColorMatrix1\n"); + abort(); + } + + has_color_matrix_1 = true; + + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + color_matrix_1[row][col] = tag->toDouble((col + row * 3) * 8); + } + } + + tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_LOOK_TABLE_DIMS)); + + if (tag) { + look_info.hue_divisions = tag->toInt(0); + look_info.sat_divisions = tag->toInt(4); + look_info.val_divisions = tag->toInt(8); + + tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_LOOK_TABLE_ENCODING)); + look_info.srgb_gamma = tag && tag->toInt(0); + + tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_LOOK_TABLE_DATA)); + look_info.array_count = tag->getCount() / 3; + + look_table.resize(look_info.array_count); + + for (unsigned int i = 0; i < look_info.array_count; i++) { + look_table[i].hue_shift = tag->toDouble((i * 3) * tiff_float_size); + look_table[i].sat_scale = tag->toDouble((i * 3 + 1) * tiff_float_size); + look_table[i].val_scale = tag->toDouble((i * 3 + 2) * tiff_float_size); + } + + // Precalculated constants for table application + look_info.pc.h_scale = + look_info.hue_divisions < 2 + ? 0.0f + : static_cast(look_info.hue_divisions) / 6.0f; + look_info.pc.s_scale = look_info.sat_divisions - 1; + look_info.pc.v_scale = look_info.val_divisions - 1; + look_info.pc.max_hue_index0 = look_info.hue_divisions - 1; + look_info.pc.max_sat_index0 = look_info.sat_divisions - 2; + look_info.pc.max_val_index0 = look_info.val_divisions - 2; + look_info.pc.hue_step = look_info.sat_divisions; + look_info.pc.val_step = look_info.hue_divisions * look_info.pc.hue_step; + } + + tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DIMS)); + + if (tag) { + delta_info.hue_divisions = tag->toInt(0); + delta_info.sat_divisions = tag->toInt(4); + delta_info.val_divisions = tag->toInt(8); + + tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_ENCODING)); + delta_info.srgb_gamma = tag && tag->toInt(0); + + tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DATA_1)); + delta_info.array_count = tag->getCount() / 3; + + deltas_1.resize(delta_info.array_count); + + for (unsigned int i = 0; i < delta_info.array_count; ++i) { + deltas_1[i].hue_shift = tag->toDouble((i * 3) * tiff_float_size); + deltas_1[i].sat_scale = tag->toDouble((i * 3 + 1) * tiff_float_size); + deltas_1[i].val_scale = tag->toDouble((i * 3 + 2) * tiff_float_size); + } + + delta_info.pc.h_scale = + delta_info.hue_divisions < 2 + ? 0.0f + : static_cast(delta_info.hue_divisions) / 6.0f; + delta_info.pc.s_scale = delta_info.sat_divisions - 1; + delta_info.pc.v_scale = delta_info.val_divisions - 1; + delta_info.pc.max_hue_index0 = delta_info.hue_divisions - 1; + delta_info.pc.max_sat_index0 = delta_info.sat_divisions - 2; + delta_info.pc.max_val_index0 = delta_info.val_divisions - 2; + delta_info.pc.hue_step = delta_info.sat_divisions; + delta_info.pc.val_step = delta_info.hue_divisions * delta_info.pc.hue_step; + } + + if (light_source_2 != -1) { + // Second matrix + has_color_matrix_2 = true; + + tag = tagDir->getTag(toUnderlying(TagKey::COLOR_MATRIX_2)); + + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + color_matrix_2[row][col] = + tag + ? tag->toDouble((col + row * 3) * 8) + : color_matrix_1[row][col]; + } + } + + // Second huesatmap + if (has_second_hue_sat) { + deltas_2.resize(delta_info.array_count); + + // Saturation maps. Need to be unwinded. + tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DATA_2)); + + for (int i = 0; i < delta_info.array_count; ++i) { + deltas_2[i].hue_shift = tag->toDouble((i * 3) * tiff_float_size); + deltas_2[i].sat_scale = tag->toDouble((i * 3 + 1) * tiff_float_size); + deltas_2[i].val_scale = tag->toDouble((i * 3 + 2) * tiff_float_size); + } + } + } + + tag = tagDir->getTag(toUnderlying(TagKey::BASELINE_EXPOSURE_OFFSET)); + + if (tag) { + has_baseline_exposure_offset = true; + baseline_exposure_offset = tag->toDouble(); + } + + // Read tone curve points, if any, but disable to RTs own profiles + tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_TONE_CURVE)); + + if (tag) { + std::vector curve_points = { + static_cast(DCT_Spline) // The first value is the curve type + }; + + // Push back each X/Y coordinates in a loop + bool curve_is_linear = true; + + for (int i = 0; i < tag->getCount(); i += 2) { + const double x = tag->toDouble((i + 0) * tiff_float_size); + const double y = tag->toDouble((i + 1) * tiff_float_size); + + if (x != y) { + curve_is_linear = false; + } + + curve_points.push_back(x); + curve_points.push_back(y); + } + + if (!curve_is_linear) { + // Create the curve + has_tone_curve = true; + tone_curve.Set(DiagonalCurve(curve_points, CURVES_MIN_POLY_POINTS)); + } + } else { + tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_TONE_COPYRIGHT)); + + if (tag && tag->valueToString().find("Adobe Systems") != std::string::npos) { + // An Adobe profile without tone curve is expected to have the Adobe Default Curve, we add that + std::vector curve_points = { + static_cast(DCT_Spline) + }; + + constexpr size_t tc_len = sizeof(adobe_camera_raw_default_curve) / sizeof(adobe_camera_raw_default_curve[0]); + + for (size_t i = 0; i < tc_len; ++i) { + const double x = static_cast(i) / (tc_len - 1); + const double y = adobe_camera_raw_default_curve[i]; + curve_points.push_back(x); + curve_points.push_back(y); + } + + has_tone_curve = true; + tone_curve.Set(DiagonalCurve(curve_points, CURVES_MIN_POLY_POINTS)); + } + } + + will_interpolate = false; + + if (has_forward_matrix_1) { + if (has_forward_matrix_2) { + if (forward_matrix_1 != forward_matrix_2) { + // Common that forward matrices are the same! + will_interpolate = true; + } + + if (!deltas_1.empty() && !deltas_2.empty()) { + // We assume tables are different + will_interpolate = true; + } + } + } + + if (has_color_matrix_1 && has_color_matrix_2) { + if (color_matrix_1 != color_matrix_2) { + will_interpolate = true; + } + + if (!deltas_1.empty() && !deltas_2.empty()) { + will_interpolate = true; + } + } + + if (file) { + fclose(file); + } +} + +DCPProfile::~DCPProfile() +{ +} + +bool DCPProfile::getHasToneCurve() const +{ + return has_tone_curve; +} + +bool DCPProfile::getHasLookTable() const +{ + return !look_table.empty(); +} + +bool DCPProfile::getHasHueSatMap() const +{ + return !deltas_1.empty(); +} + +bool DCPProfile::getHasBaselineExposureOffset() const +{ + return has_baseline_exposure_offset; +} + +DCPProfile::Illuminants DCPProfile::getIlluminants() const +{ + return { + light_source_1, + light_source_2, + temperature_1, + temperature_2, + will_interpolate + }; +} + +void DCPProfile::apply( + Imagefloat* img, + int preferred_illuminant, + const Glib::ustring& working_space, + const ColorTemp& white_balance, + const Triple& pre_mul, + const Matrix& cam_wb_matrix, + bool use_tone_curve, + bool apply_hue_sat_map, + bool apply_look_table +) const +{ + const TMatrix work_matrix = iccStore->workingSpaceInverseMatrix(working_space); + + Matrix xyz_cam; // Camera RGB to XYZ D50 matrix + makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant, xyz_cam); + + const std::vector delta_base = makeHueSatMap(white_balance, preferred_illuminant); + + if (delta_base.empty()) { + apply_hue_sat_map = false; + } + + if (look_table.empty()) { + apply_look_table = false; + } + + use_tone_curve = use_tone_curve && tone_curve; + + if (!apply_hue_sat_map && !apply_look_table && !use_tone_curve) { + // The fast path: No LUT and not tone curve --> Calculate matrix for direct conversion raw>working space + double mat[3][3] = {}; + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + for (int k = 0; k < 3; ++k) { + mat[i][j] += work_matrix[i][k] * xyz_cam[k][j]; + } + } + } + + // Apply the matrix part +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int y = 0; y < img->height; ++y) { + for (int x = 0; x < img->width; x++) { + const float& newr = mat[0][0] * img->r(y, x) + mat[0][1] * img->g(y, x) + mat[0][2] * img->b(y, x); + const float& newg = mat[1][0] * img->r(y, x) + mat[1][1] * img->g(y, x) + mat[1][2] * img->b(y, x); + const float& newb = mat[2][0] * img->r(y, x) + mat[2][1] * img->g(y, x) + mat[2][2] * img->b(y, x); + + img->r(y, x) = newr; + img->g(y, x) = newg; + img->b(y, x) = newb; + } + } + } else { + // LUT available --> Calculate matrix for conversion raw>ProPhoto + double pro_photo[3][3] = {}; + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + for (int k = 0; k < 3; ++k) { + pro_photo[i][j] += prophoto_xyz[i][k] * xyz_cam[k][j]; + } + } + } + + double work[3][3] = {}; + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + for (int k = 0; k < 3; ++k) { + work[i][j] += work_matrix[i][k] * xyz_prophoto[k][j]; + } + } + } + + // Convert to ProPhoto and apply LUT +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int y = 0; y < img->height; ++y) { + float h, s, v, hs, ss, vs; + + for (int x = 0; x < img->width; x++) { + float newr = pro_photo[0][0] * img->r(y, x) + pro_photo[0][1] * img->g(y, x) + pro_photo[0][2] * img->b(y, x); + float newg = pro_photo[1][0] * img->r(y, x) + pro_photo[1][1] * img->g(y, x) + pro_photo[1][2] * img->b(y, x); + float newb = pro_photo[2][0] * img->r(y, x) + pro_photo[2][1] * img->g(y, x) + pro_photo[2][2] * img->b(y, x); + + // If point is in negative area, just the matrix, but not the LUT + if ( + ( + apply_hue_sat_map + || apply_look_table + ) + && newr >= 0 + && newg >= 0 + && newb >= 0 + ) { + float h; + float s; + float v; + Color::rgb2hsv(newr, newg, newb, h , s, v); + h *= 6.0f; // RT calculates in [0,1] + + if (apply_hue_sat_map) { + hsdApply(delta_info, delta_base, h, s, v); + } + + if (apply_look_table) { + hsdApply(look_info, look_table, h, s, v); + } + + // RT range correction + if (h < 0.0f) { + h += 6.0f; + } + + if (h >= 6.0f) { + h -= 6.0f; + } + + h /= 6.f; + + Color::hsv2rgb(h, s, v, newr, newg, newb); + } + + if (use_tone_curve) { + tone_curve.Apply(newr, newg, newb); + } + + img->r(y, x) = work[0][0] * newr + work[0][1] * newg + work[0][2] * newb; + img->g(y, x) = work[1][0] * newr + work[1][1] * newg + work[1][2] * newb; + img->b(y, x) = work[2][0] * newr + work[2][1] * newg + work[2][2] * newb; + } + } + } +} + +void DCPProfile::setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, ApplyState& as_out) +{ + as_out.data->use_tone_curve = use_tone_curve; + as_out.data->apply_look_table = apply_look_table; + as_out.data->bl_scale = 1.0; + + if (look_table.empty()) { + as_out.data->apply_look_table = false; + } + + if (!has_tone_curve) { + as_out.data->use_tone_curve = false; + } + + if (has_baseline_exposure_offset && apply_baseline_exposure) { + as_out.data->bl_scale = powf(2, baseline_exposure_offset); + } + + if (working_space == "ProPhoto") { + as_out.data->already_pro_photo = true; + } else { + as_out.data->already_pro_photo = false; + TMatrix mWork; + + mWork = iccStore->workingSpaceMatrix (working_space); + memset(as_out.data->pro_photo, 0, sizeof(as_out.data->pro_photo)); + + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 3; k++) { + as_out.data->pro_photo[i][j] += prophoto_xyz[i][k] * mWork[k][j]; + } + + mWork = iccStore->workingSpaceInverseMatrix (working_space); + memset(as_out.data->work, 0, sizeof(as_out.data->work)); + + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + for (int k = 0; k < 3; k++) { + as_out.data->work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; + } + } +} + +void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int height, int tile_width, const ApplyState& as_in) const +{ + +#define FCLIP(a) ((a)>0.0?((a)<65535.5?(a):65535.5):0.0) +#define CLIP01(a) ((a)>0?((a)<1?(a):1):0) + + float exp_scale = 1.0; + exp_scale *= as_in.data->bl_scale; + + if (!as_in.data->use_tone_curve && !as_in.data->apply_look_table) { + if (exp_scale == 1.0) { + return; + } + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + rc[y * tile_width + x] *= exp_scale; + gc[y * tile_width + x] *= exp_scale; + bc[y * tile_width + x] *= exp_scale; + } + } + } else { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + float r = rc[y * tile_width + x]; + float g = gc[y * tile_width + x]; + float b = bc[y * tile_width + x]; + + if (exp_scale != 1.0) { + r *= exp_scale; + g *= exp_scale; + b *= exp_scale; + } + + float newr, newg, newb; + + if (as_in.data->already_pro_photo) { + newr = r; + newg = g; + newb = b; + } else { + newr = as_in.data->pro_photo[0][0] * r + as_in.data->pro_photo[0][1] * g + as_in.data->pro_photo[0][2] * b; + newg = as_in.data->pro_photo[1][0] * r + as_in.data->pro_photo[1][1] * g + as_in.data->pro_photo[1][2] * b; + newb = as_in.data->pro_photo[2][0] * r + as_in.data->pro_photo[2][1] * g + as_in.data->pro_photo[2][2] * b; + } + + // with looktable and tonecurve we need to clip + newr = FCLIP(newr); + newg = FCLIP(newg); + newb = FCLIP(newb); + + if (as_in.data->apply_look_table) { + float h, s, v; + Color::rgb2hsv(newr, newg, newb, h, s, v); + h *= 6.f; // RT calculates in [0,1] + + hsdApply(look_info, look_table, h, s, v); + s = CLIP01(s); + v = CLIP01(v); + + // RT range correction + if (h < 0.0f) { + h += 6.0f; + } + + if (h >= 6.0f) { + h -= 6.0f; + } + + h /= 6.f; + Color::hsv2rgb( h, s, v, newr, newg, newb); + } + + if (as_in.data->use_tone_curve) { + tone_curve.Apply(newr, newg, newb); + } + + if (as_in.data->already_pro_photo) { + rc[y * tile_width + x] = newr; + gc[y * tile_width + x] = newg; + bc[y * tile_width + x] = newb; + } else { + rc[y * tile_width + x] = as_in.data->work[0][0] * newr + as_in.data->work[0][1] * newg + as_in.data->work[0][2] * newb; + gc[y * tile_width + x] = as_in.data->work[1][0] * newr + as_in.data->work[1][1] * newg + as_in.data->work[1][2] * newb; + bc[y * tile_width + x] = as_in.data->work[2][0] * newr + as_in.data->work[2][1] * newg + as_in.data->work[2][2] * newb; + } + } + } + } +} + +void DCPProfile::findXyztoCamera(const double white_xy[2], int preferred_illuminant, Matrix& xyz_to_camera) const +{ + bool has_col_1 = has_color_matrix_1; + bool has_col_2 = has_color_matrix_2; + + if (preferred_illuminant == 1) { + if (has_col_1) { + has_col_2 = false; + } + } else if (preferred_illuminant == 2) { + if (has_col_2) { + has_col_1 = false; + } + } + + // Mix if we have two matrices + double mix; + Matrix col; + + if (has_col_1 && has_col_2) { + double wbtemp; + /* + Note: We're using DNG SDK reference code for XY to temperature translation to get the exact same mix as + the reference code does. + */ + xyCoordToTemperature(white_xy, &wbtemp, nullptr); + + if (wbtemp <= temperature_1) { + mix = 1.0; + } else if (wbtemp >= temperature_2) { + mix = 0.0; + } else { + const double invT = 1.0 / wbtemp; + mix = (invT - (1.0 / temperature_2)) / ((1.0 / temperature_1) - (1.0 / temperature_2)); + } + + // Interpolate + if (mix >= 1.0) { + col = color_matrix_1; + } else if (mix <= 0.0) { + col = color_matrix_2; + } else { + mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix, col); + } + } else if (has_col_1) { + col = color_matrix_1; + } else { + col = color_matrix_2; + } + + xyz_to_camera = col; +} + +void DCPProfile::neutralToXy(const Triple& neutral, int preferred_illuminant, double xy[2]) const +{ + enum { + MAX_PASSES = 30 + }; + + double last_xy[2] = {0.3457, 0.3585}; // D50 + + for (unsigned int pass = 0; pass < MAX_PASSES; ++pass) { + Matrix xyz_to_camera; + findXyztoCamera(last_xy, preferred_illuminant, xyz_to_camera); + + Matrix inv_m; + Triple next_xyz; + double next_xy[2]; + invert3x3(xyz_to_camera, inv_m); + multiply3x3_v3(inv_m, neutral, next_xyz); + xyzToXy(next_xyz, next_xy); + + if (fabs(next_xy[0] - last_xy[0]) + + fabs(next_xy[1] - last_xy[1]) < 0.0000001) { + xy[0] = next_xy[0]; + xy[1] = next_xy[1]; + return; + } + + // If we reach the limit without converging, we are most likely + // in a two value oscillation. So take the average of the last + // two estimates and give up. + if (pass == MAX_PASSES - 1) { + next_xy[0] = (last_xy[0] + next_xy[0]) * 0.5; + next_xy[1] = (last_xy[1] + next_xy[1]) * 0.5; + } + + last_xy[0] = next_xy[0]; + last_xy[1] = next_xy[1]; + } + + xy[0] = last_xy[0]; + xy[1] = last_xy[1]; +} + +void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, int preferred_illuminant, Matrix& xyz_cam) const +{ + // Code adapted from dng_color_spec::FindXYZtoCamera. + // Note that we do not support monochrome or colorplanes > 3 (no reductionMatrix support), + // we do not support cameracalibration either. + + Triple neutral; // Same as the DNG "AsShotNeutral" tag if white balance is Camera's own { /* A bit messy matrixing and conversions to get the neutral[] array from RT's own white balance which is stored in sRGB space, while the DCP code needs multipliers in CameraRGB space */ double r, g, b; - wb.getMultipliers(r, g, b); + white_balance.getMultipliers(r, g, b); // camWbMatrix == imatrices.xyz_cam - double cam_xyz[3][3]; - Invert3x3(camWbMatrix, cam_xyz); - double cam_rgb[3][3]; - Multiply3x3(cam_xyz, xyz_sRGB, cam_rgb); + Matrix cam_xyz; + invert3x3(cam_wb_matrix, cam_xyz); + Matrix cam_rgb; + constexpr Matrix xyz_srgb = {{ + {xyz_sRGB[0][0], xyz_sRGB[0][1], xyz_sRGB[0][2]}, + {xyz_sRGB[1][0], xyz_sRGB[1][1], xyz_sRGB[1][2]}, + {xyz_sRGB[2][0], xyz_sRGB[2][1], xyz_sRGB[2][2]} + }}; + multiply3x3(cam_xyz, xyz_srgb, cam_rgb); double camwb_red = cam_rgb[0][0] * r + cam_rgb[0][1] * g + cam_rgb[0][2] * b; double camwb_green = cam_rgb[1][0] * r + cam_rgb[1][1] * g + cam_rgb[1][2] * b; double camwb_blue = cam_rgb[2][0] * r + cam_rgb[2][1] * g + cam_rgb[2][2] * b; @@ -584,67 +1427,67 @@ void DCPProfile::MakeXYZCAM(ColorTemp &wb, double pre_mul[3], double camWbMatrix do it, which is a bit different from RT's own white balance model at the time of writing. When RT's white balance can make use of the DCP color matrices we could use that instead. */ double white_xy[2]; - dngref_NeutralToXY(neutral, preferredIlluminant, white_xy); + neutralToXy(neutral, preferred_illuminant, white_xy); - bool hasFwd1 = hasForwardMatrix1; - bool hasFwd2 = hasForwardMatrix2; - bool hasCol1 = hasColorMatrix1; - bool hasCol2 = hasColorMatrix2; + bool has_fwd_1 = has_forward_matrix_1; + bool has_fwd_2 = has_forward_matrix_2; + bool has_col_1 = has_color_matrix_1; + bool has_col_2 = has_color_matrix_2; - if (preferredIlluminant == 1) { - if (hasFwd1) { - hasFwd2 = false; + if (preferred_illuminant == 1) { + if (has_fwd_1) { + has_fwd_2 = false; } - if (hasCol1) { - hasCol2 = false; + if (has_col_1) { + has_col_2 = false; } - } else if (preferredIlluminant == 2) { - if (hasFwd2) { - hasFwd1 = false; + } else if (preferred_illuminant == 2) { + if (has_fwd_2) { + has_fwd_1 = false; } - if (hasCol2) { - hasCol1 = false; + if (has_col_2) { + has_col_1 = false; } } - // mix if we have two matrices + // Mix if we have two matrices double mix = 1.0; - if ((hasCol1 && hasCol2) || (hasFwd1 && hasFwd2)) { + if ((has_col_1 && has_col_2) || (has_fwd_1 && has_fwd_2)) { double wbtemp; /* DNG ref way to convert XY to temperature, which affect matrix mixing. A different model here typically does not affect the result too much, ie it's probably not strictly necessary to use the DNG reference code here, but we do it for now. */ - dngref_XYCoord2Temperature(white_xy, &wbtemp, NULL); + xyCoordToTemperature(white_xy, &wbtemp, nullptr); - if (wbtemp <= temperature1) { + if (wbtemp <= temperature_1) { mix = 1.0; - } else if (wbtemp >= temperature2) { + } else if (wbtemp >= temperature_2) { mix = 0.0; } else { double invT = 1.0 / wbtemp; - mix = (invT - (1.0 / temperature2)) / ((1.0 / temperature1) - (1.0 / temperature2)); + mix = (invT - (1.0 / temperature_2)) / ((1.0 / temperature_1) - (1.0 / temperature_2)); } } // Colormatrix - double mCol[3][3]; + Matrix color_matrix; - if (hasCol1 && hasCol2) { + if (has_col_1 && has_col_2) { // interpolate if (mix >= 1.0) { - memcpy(mCol, mColorMatrix1, sizeof(mCol)); + color_matrix = color_matrix_1; } else if (mix <= 0.0) { - memcpy(mCol, mColorMatrix2, sizeof(mCol)); + color_matrix = color_matrix_2; } else { - Mix3x3(mColorMatrix1, mix, mColorMatrix2, 1.0 - mix, mCol); + mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix, color_matrix); } - } else if (hasCol1) { - memcpy(mCol, mColorMatrix1, sizeof(mCol)); + } else if (has_col_1) { + color_matrix = color_matrix_1; } else { - memcpy(mCol, mColorMatrix2, sizeof(mCol)); + color_matrix = color_matrix_2; } /* @@ -655,49 +1498,53 @@ void DCPProfile::MakeXYZCAM(ColorTemp &wb, double pre_mul[3], double camWbMatrix will show incorrect color. */ - double white_xyz[3]; - XYtoXYZ(white_xy, white_xyz); + Triple white_xyz; + xyToXyz(white_xy, white_xyz); - double cam_xyz[3][3]; + Matrix cam_xyz; - if (hasFwd1 || hasFwd2) { - // always prefer ForwardMatrix ahead of ColorMatrix - double mFwd[3][3]; + if (has_fwd_1 || has_fwd_2) { + // Always prefer ForwardMatrix to ColorMatrix + Matrix fwd; - if (hasFwd1 && hasFwd2) { - // interpolate + if (has_fwd_1 && has_fwd_2) { + // Interpolate if (mix >= 1.0) { - memcpy(mFwd, mForwardMatrix1, sizeof(mFwd)); + fwd = forward_matrix_1; } else if (mix <= 0.0) { - memcpy(mFwd, mForwardMatrix2, sizeof(mFwd)); + fwd = forward_matrix_2; } else { - Mix3x3(mForwardMatrix1, mix, mForwardMatrix2, 1.0 - mix, mFwd); + mix3x3(forward_matrix_1, mix, forward_matrix_2, 1.0 - mix, fwd); } - } else if (hasFwd1) { - memcpy(mFwd, mForwardMatrix1, sizeof(mFwd)); + } else if (has_fwd_1) { + fwd = forward_matrix_1; } else { - memcpy(mFwd, mForwardMatrix2, sizeof(mFwd)); + fwd = forward_matrix_2; } // adapted from dng_color_spec::SetWhiteXY - double CameraWhite[3]; - Multiply3x3_v3(mCol, white_xyz, CameraWhite); + Triple camera_white; + multiply3x3_v3(color_matrix, white_xyz, camera_white); - double whiteDiag[3][3] = {{CameraWhite[0], 0, 0}, {0, CameraWhite[1], 0}, {0, 0, CameraWhite[2]}}; - double whiteDiagInv[3][3]; - Invert3x3(whiteDiag, whiteDiagInv); + const Matrix white_diag = {{ + {camera_white[0], 0, 0}, + {0, camera_white[1], 0}, + {0, 0, camera_white[2]} + }}; + Matrix white_diag_inv; + invert3x3(white_diag, white_diag_inv); - double xyz_cam[3][3]; - Multiply3x3(mFwd, whiteDiagInv, xyz_cam); - Invert3x3(xyz_cam, cam_xyz); + Matrix xyz_cam; + multiply3x3(fwd, white_diag_inv, xyz_cam); + invert3x3(xyz_cam, cam_xyz); } else { - double whiteMatrix[3][3]; - const double white_d50[3] = { 0.3457, 0.3585, 0.2958 }; // D50 - MapWhiteMatrix(white_d50, white_xyz, whiteMatrix); - Multiply3x3(mCol, whiteMatrix, cam_xyz); + Matrix white_matrix; + const Triple white_d50 = {0.3457, 0.3585, 0.2958}; // D50 + mapWhiteMatrix(white_d50, white_xyz, white_matrix); + multiply3x3(color_matrix, white_matrix, cam_xyz); } - // convert cam_xyz (XYZ D50 to CameraRGB, "PCS to Camera" in DNG terminology) to mXYZCAM + // Convert cam_xyz (XYZ D50 to CameraRGB, "PCS to Camera" in DNG terminology) to mXYZCAM { // This block can probably be simplified, seems unnecessary to pass through the sRGB matrix @@ -705,1085 +1552,342 @@ void DCPProfile::MakeXYZCAM(ColorTemp &wb, double pre_mul[3], double camWbMatrix int i, j, k; // Multiply out XYZ colorspace - double cam_rgb[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + double cam_rgb[3][3] = {}; - for (i = 0; i < 3; i++) - for (j = 0; j < 3; j++) - for (k = 0; k < 3; k++) { + for (i = 0; i < 3; ++i) { + for (j = 0; j < 3; ++j) { + for (k = 0; k < 3; ++k) { cam_rgb[i][j] += cam_xyz[i][k] * xyz_sRGB[k][j]; } + } + } - // Normalize cam_rgb so that: cam_rgb * (1,1,1) is (1,1,1,1) + // Normalize cam_rgb so that cam_rgb * (1,1,1) is (1,1,1,1) double num; - for (i = 0; i < 3; i++) { - for (num = j = 0; j < 3; j++) { + for (i = 0; i < 3; ++i) { + for (num = j = 0; j < 3; ++j) { num += cam_rgb[i][j]; } - for (j = 0; j < 3; j++) { + for (j = 0; j < 3; ++j) { cam_rgb[i][j] /= num; } } - double rgb_cam[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - RawImageSource::inverse33 (cam_rgb, rgb_cam); + double rgb_cam[3][3] = {}; + RawImageSource::inverse33(cam_rgb, rgb_cam); - for (i = 0; i < 3; i++) - for (j = 0; j < 3; j++) { - mXYZCAM[i][j] = 0; + for (i = 0; i < 3; ++i) { + for (j = 0; j < 3; ++j) { + xyz_cam[i][j] = 0; } + } - for (i = 0; i < 3; i++) - for (j = 0; j < 3; j++) - for (k = 0; k < 3; k++) { - mXYZCAM[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j]; + for (i = 0; i < 3; ++i) { + for (j = 0; j < 3; ++j) { + for (k = 0; k < 3; ++k) { + xyz_cam[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j]; } + } + } } } -const DCPProfile::HSBModify* DCPProfile::MakeHueSatMap(ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const +std::vector DCPProfile::makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const { - - *deleteHandle = NULL; - - if (!aDeltas1) { - return NULL; + if (deltas_1.empty()) { + return std::vector(); } - if (!aDeltas2) { - return aDeltas1; + if (deltas_2.empty()) { + return deltas_1; } - if (preferredIlluminant == 1) { - return aDeltas1; - } else if (preferredIlluminant == 2) { - return aDeltas2; + if (preferred_illuminant == 1) { + return deltas_1; + } else if (preferred_illuminant == 2) { + return deltas_2; } - // Interpolate based on color temperature. - if (temperature1 <= 0.0 || temperature2 <= 0.0 || temperature1 == temperature2) { - return aDeltas1; + // Interpolate based on color temperature + if ( + temperature_1 <= 0.0 + || temperature_2 <= 0.0 + || temperature_1 == temperature_2 + ) { + return deltas_1; } - bool reverseOrder = temperature1 > temperature2; - double t1, t2; - - if (reverseOrder) { - t1 = temperature2; - t2 = temperature1; - } else { - t1 = temperature1; - t2 = temperature2; - } + const bool reverse = temperature_1 > temperature_2; + const double t1 = + reverse + ? temperature_2 + : temperature_1; + const double t2 = + reverse + ? temperature_1 + : temperature_2; double mix; - - if (wb.getTemp() <= t1) { + if (white_balance.getTemp() <= t1) { mix = 1.0; - } else if (wb.getTemp() >= t2) { + } else if (white_balance.getTemp() >= t2) { mix = 0.0; } else { - double invT = 1.0 / wb.getTemp(); + const double invT = 1.0 / white_balance.getTemp(); mix = (invT - (1.0 / t2)) / ((1.0 / t1) - (1.0 / t2)); } - if (reverseOrder) { + if (reverse) { mix = 1.0 - mix; } if (mix >= 1.0) { - return aDeltas1; + return deltas_1; } else if (mix <= 0.0) { - return aDeltas2; + return deltas_2; } // Interpolate between the tables. - HSBModify *aDeltas = new HSBModify[DeltaInfo.iArrayCount]; - *deleteHandle = aDeltas; - float w1 = (float)mix; - float w2 = 1.0f - (float)mix; + std::vector res(delta_info.array_count); - for (int i = 0; i < DeltaInfo.iArrayCount; i++) { - aDeltas[i].fHueShift = w1 * aDeltas1[i].fHueShift + w2 * aDeltas2[i].fHueShift; - aDeltas[i].fSatScale = w1 * aDeltas1[i].fSatScale + w2 * aDeltas2[i].fSatScale; - aDeltas[i].fValScale = w1 * aDeltas1[i].fValScale + w2 * aDeltas2[i].fValScale; + const float w1 = mix; + const float w2 = 1.0f - w1; + + for (unsigned int i = 0; i < delta_info.array_count; ++i) { + res[i].hue_shift = w1 * deltas_1[i].hue_shift + w2 * deltas_2[i].hue_shift; + res[i].sat_scale = w1 * deltas_1[i].sat_scale + w2 * deltas_2[i].sat_scale; + res[i].val_scale = w1 * deltas_1[i].val_scale + w2 * deltas_2[i].val_scale; } - return aDeltas; + return res; } -DCPProfile::DCPProfile(Glib::ustring fname) +void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const { - const int TIFFFloatSize = 4; - const int TagColorMatrix1 = 50721, TagColorMatrix2 = 50722, TagProfileHueSatMapDims = 50937; - const int TagForwardMatrix1 = 50964, TagForwardMatrix2 = 50965; - const int TagProfileHueSatMapData1 = 50938, TagProfileHueSatMapData2 = 50939; - const int TagCalibrationIlluminant1 = 50778, TagCalibrationIlluminant2 = 50779; - const int TagProfileLookTableData = 50982, TagProfileLookTableDims = 50981; // ProfileLookup is the low quality variant - const int TagProfileHueSatMapEncoding = 51107, TagProfileLookTableEncoding = 51108; - const int TagProfileToneCurve = 50940, TagBaselineExposureOffset = 51109; - const int TagProfileCopyright = 50942; + // Apply the HueSatMap. Ported from Adobes reference implementation. + float hue_shift; + float sat_scale; + float val_scale; + float v_encoded = v; - aDeltas1 = aDeltas2 = aLookTable = NULL; + if (table_info.val_divisions < 2) { + // Optimize most common case of "2.5D" table + const float h_scaled = h * table_info.pc.h_scale; + const float s_scaled = s * table_info.pc.s_scale; - FILE *pFile = g_fopen(fname.c_str (), "rb"); + int h_index0 = max(h_scaled, 0); + const int s_index0 = std::max(std::min(s_scaled, table_info.pc.max_sat_index0), 0); - TagDirectory *tagDir = ExifManager::parseTIFF(pFile, false); + int h_index1 = h_index0 + 1; - Tag* tag = tagDir->getTag(TagCalibrationIlluminant1); - iLightSource1 = (tag != NULL ? tag->toInt(0, rtexif::SHORT) : -1); - tag = tagDir->getTag(TagCalibrationIlluminant2); - iLightSource2 = (tag != NULL ? tag->toInt(0, rtexif::SHORT) : -1); - temperature1 = calibrationIlluminantToTemperature(iLightSource1); - temperature2 = calibrationIlluminantToTemperature(iLightSource2); - - bool hasSecondHueSat = tagDir->getTag(TagProfileHueSatMapData2) != NULL; // some profiles have two matrices, but just one huesat - - // Fetch Forward Matrices, if any - hasForwardMatrix1 = false; - hasForwardMatrix2 = false; - hasColorMatrix1 = false; - hasColorMatrix2 = false; - hasToneCurve = false; - hasBaselineExposureOffset = false; - baselineExposureOffset = 0; - tag = tagDir->getTag(TagForwardMatrix1); - - if (tag) { - hasForwardMatrix1 = true; - - for (int row = 0; row < 3; row++) { - for (int col = 0; col < 3; col++) { - mForwardMatrix1[row][col] = (float)tag->toDouble((col + row * 3) * 8); - } - } - } - - tag = tagDir->getTag(TagForwardMatrix2); - - if (tag) { - hasForwardMatrix2 = true; - - for (int row = 0; row < 3; row++) { - for (int col = 0; col < 3; col++) { - mForwardMatrix2[row][col] = (float)tag->toDouble((col + row * 3) * 8); - } - } - } - - // Color Matrix (1 is always there) - tag = tagDir->getTag(TagColorMatrix1); - - if (!tag) { - // FIXME: better error handling - fprintf(stderr, "Bad DCP, no ColorMatrix1\n"); - abort(); - } - - hasColorMatrix1 = true; - - for (int row = 0; row < 3; row++) { - for (int col = 0; col < 3; col++) { - mColorMatrix1[row][col] = (float)tag->toDouble((col + row * 3) * 8); - } - } - - tag = tagDir->getTag(TagProfileLookTableDims); - - if (tag != NULL) { - LookInfo.iHueDivisions = tag->toInt(0); - LookInfo.iSatDivisions = tag->toInt(4); - LookInfo.iValDivisions = tag->toInt(8); - - tag = tagDir->getTag(TagProfileLookTableEncoding); - LookInfo.sRGBGamma = tag != NULL && tag->toInt(0); - - tag = tagDir->getTag(TagProfileLookTableData); - LookInfo.iArrayCount = tag->getCount() / 3; - - aLookTable = new HSBModify[LookInfo.iArrayCount]; - - for (int i = 0; i < LookInfo.iArrayCount; i++) { - aLookTable[i].fHueShift = tag->toDouble((i * 3) * TIFFFloatSize); - aLookTable[i].fSatScale = tag->toDouble((i * 3 + 1) * TIFFFloatSize); - aLookTable[i].fValScale = tag->toDouble((i * 3 + 2) * TIFFFloatSize); + if (h_index0 >= table_info.pc.max_hue_index0) { + h_index0 = table_info.pc.max_hue_index0; + h_index1 = 0; } - // precalculated constants for table application - LookInfo.pc.hScale = (LookInfo.iHueDivisions < 2) ? 0.0f : (LookInfo.iHueDivisions * (1.0f / 6.0f)); - LookInfo.pc.sScale = (float) (LookInfo.iSatDivisions - 1); - LookInfo.pc.vScale = (float) (LookInfo.iValDivisions - 1); - LookInfo.pc.maxHueIndex0 = LookInfo.iHueDivisions - 1; - LookInfo.pc.maxSatIndex0 = LookInfo.iSatDivisions - 2; - LookInfo.pc.maxValIndex0 = LookInfo.iValDivisions - 2; - LookInfo.pc.hueStep = LookInfo.iSatDivisions; - LookInfo.pc.valStep = LookInfo.iHueDivisions * LookInfo.pc.hueStep; - } + const float h_fract1 = h_scaled - static_cast(h_index0); + const float s_fract1 = s_scaled - static_cast(s_index0); - tag = tagDir->getTag(TagProfileHueSatMapDims); + const float h_fract0 = 1.0f - h_fract1; + const float s_fract0 = 1.0f - s_fract1; - if (tag != NULL) { - DeltaInfo.iHueDivisions = tag->toInt(0); - DeltaInfo.iSatDivisions = tag->toInt(4); - DeltaInfo.iValDivisions = tag->toInt(8); + std::vector::size_type e00_index = h_index0 * table_info.pc.hue_step + s_index0; + std::vector::size_type e01_index = e00_index + (h_index1 - h_index0) * table_info.pc.hue_step; - tag = tagDir->getTag(TagProfileHueSatMapEncoding); - DeltaInfo.sRGBGamma = tag != NULL && tag->toInt(0); + const float hue_shift0 = h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift; + const float sat_scale0 = h_fract0 * table_base[e00_index].sat_scale + h_fract1 * table_base[e01_index].sat_scale; + const float val_scale0 = h_fract0 * table_base[e00_index].val_scale + h_fract1 * table_base[e01_index].val_scale; - tag = tagDir->getTag(TagProfileHueSatMapData1); - DeltaInfo.iArrayCount = tag->getCount() / 3; + ++e00_index; + ++e01_index; - aDeltas1 = new HSBModify[DeltaInfo.iArrayCount]; - - for (int i = 0; i < DeltaInfo.iArrayCount; i++) { - aDeltas1[i].fHueShift = tag->toDouble((i * 3) * TIFFFloatSize); - aDeltas1[i].fSatScale = tag->toDouble((i * 3 + 1) * TIFFFloatSize); - aDeltas1[i].fValScale = tag->toDouble((i * 3 + 2) * TIFFFloatSize); - } - - DeltaInfo.pc.hScale = (DeltaInfo.iHueDivisions < 2) ? 0.0f : (DeltaInfo.iHueDivisions * (1.0f / 6.0f)); - DeltaInfo.pc.sScale = (float) (DeltaInfo.iSatDivisions - 1); - DeltaInfo.pc.vScale = (float) (DeltaInfo.iValDivisions - 1); - DeltaInfo.pc.maxHueIndex0 = DeltaInfo.iHueDivisions - 1; - DeltaInfo.pc.maxSatIndex0 = DeltaInfo.iSatDivisions - 2; - DeltaInfo.pc.maxValIndex0 = DeltaInfo.iValDivisions - 2; - DeltaInfo.pc.hueStep = DeltaInfo.iSatDivisions; - DeltaInfo.pc.valStep = DeltaInfo.iHueDivisions * DeltaInfo.pc.hueStep; - } - - if (iLightSource2 != -1) { - // Second matrix - tag = tagDir->getTag(TagColorMatrix2); - hasColorMatrix2 = true; - - for (int row = 0; row < 3; row++) { - for (int col = 0; col < 3; col++) { - mColorMatrix2[row][col] = (tag != NULL ? (float)tag->toDouble((col + row * 3) * 8) : mColorMatrix1[row][col]); - } - } - - // Second huesatmap - if (hasSecondHueSat) { - aDeltas2 = new HSBModify[DeltaInfo.iArrayCount]; - - // Saturation maps. Need to be unwinded. - tag = tagDir->getTag(TagProfileHueSatMapData2); - - for (int i = 0; i < DeltaInfo.iArrayCount; i++) { - aDeltas2[i].fHueShift = tag->toDouble((i * 3) * TIFFFloatSize); - aDeltas2[i].fSatScale = tag->toDouble((i * 3 + 1) * TIFFFloatSize); - aDeltas2[i].fValScale = tag->toDouble((i * 3 + 2) * TIFFFloatSize); - } - } - } - - tag = tagDir->getTag(TagBaselineExposureOffset); - - if (tag) { - hasBaselineExposureOffset = true; - baselineExposureOffset = tag->toDouble(); - } - - // Read tone curve points, if any, but disable to RTs own profiles - tag = tagDir->getTag(TagProfileToneCurve); - - if (tag != NULL) { - std::vector cPoints; - cPoints.push_back(double(DCT_Spline)); // The first value is the curve type - - // push back each X/Y coordinates in a loop - bool curve_is_linear = true; - - for (int i = 0; i < tag->getCount(); i += 2) { - double x = tag->toDouble((i + 0) * TIFFFloatSize); - double y = tag->toDouble((i + 1) * TIFFFloatSize); - - if (x != y) { - curve_is_linear = false; - } - - cPoints.push_back( x ); - cPoints.push_back( y ); - } - - if (!curve_is_linear) { - // Create the curve - DiagonalCurve rawCurve(cPoints, CURVES_MIN_POLY_POINTS); - - toneCurve.Set((Curve*)&rawCurve); - hasToneCurve = true; - } - } else if (tag == NULL) { - tag = tagDir->getTag(TagProfileCopyright); - - if (tag != NULL && tag->valueToString().find("Adobe Systems") != std::string::npos) { - // an Adobe profile without tone curve is expected to have the Adobe Default Curve, we add that - std::vector cPoints; - cPoints.push_back(double(DCT_Spline)); - const size_t tc_len = sizeof(adobe_camera_raw_default_curve) / sizeof(adobe_camera_raw_default_curve[0]); - - for (size_t i = 0; i < tc_len; i++) { - double x = (double)i / (tc_len - 1); - double y = (double)adobe_camera_raw_default_curve[i]; - cPoints.push_back( x ); - cPoints.push_back( y ); - } - - DiagonalCurve rawCurve(cPoints, CURVES_MIN_POLY_POINTS); - toneCurve.Set((Curve*)&rawCurve); - hasToneCurve = true; - } - } - - willInterpolate = false; - - if (hasForwardMatrix1) { - if (hasForwardMatrix2) { - if (memcmp(mForwardMatrix1, mForwardMatrix2, sizeof(mForwardMatrix1)) != 0) { - // common that forward matrices are the same! - willInterpolate = true; - } - - if (aDeltas1 && aDeltas2) { - // we assume tables are different - willInterpolate = true; - } - } - } - - if (hasColorMatrix1 && hasColorMatrix2) { - if (memcmp(mColorMatrix1, mColorMatrix2, sizeof(mColorMatrix1)) != 0) { - willInterpolate = true; - } - - if (aDeltas1 && aDeltas2) { - willInterpolate = true; - } - } - - if (pFile != NULL) { - fclose(pFile); - } - - delete tagDir; -} - -DCPProfile::~DCPProfile() -{ - delete[] aDeltas1; - delete[] aDeltas2; - delete[] aLookTable; -} - -void DCPProfile::HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, float &h, float &s, float &v) const -{ - - // Apply the HueSatMap. Ported from Adobes reference implementation - float hueShift, satScale, valScale; - float vEncoded = v; - - if (ti.iValDivisions < 2) { // Optimize most common case of "2.5D" table. - float hScaled = h * ti.pc.hScale; - float sScaled = s * ti.pc.sScale; - - int hIndex0 = max((int)hScaled, 0); - int sIndex0 = max(min((int)sScaled, ti.pc.maxSatIndex0), 0); - - int hIndex1 = hIndex0 + 1; - - if (hIndex0 >= ti.pc.maxHueIndex0) { - hIndex0 = ti.pc.maxHueIndex0; - hIndex1 = 0; - } - - float hFract1 = hScaled - (float) hIndex0; - float sFract1 = sScaled - (float) sIndex0; - - float hFract0 = 1.0f - hFract1; - float sFract0 = 1.0f - sFract1; - - const HSBModify *entry00 = tableBase + hIndex0 * ti.pc.hueStep + sIndex0; - const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * ti.pc.hueStep; - - float hueShift0 = hFract0 * entry00->fHueShift + hFract1 * entry01->fHueShift; - float satScale0 = hFract0 * entry00->fSatScale + hFract1 * entry01->fSatScale; - float valScale0 = hFract0 * entry00->fValScale + hFract1 * entry01->fValScale; - - entry00++; - entry01++; - - float hueShift1 = hFract0 * entry00->fHueShift + - hFract1 * entry01->fHueShift; - - float satScale1 = hFract0 * entry00->fSatScale + - hFract1 * entry01->fSatScale; - - float valScale1 = hFract0 * entry00->fValScale + - hFract1 * entry01->fValScale; - - hueShift = sFract0 * hueShift0 + sFract1 * hueShift1; - satScale = sFract0 * satScale0 + sFract1 * satScale1; - valScale = sFract0 * valScale0 + sFract1 * valScale1; + const float hueShift1 = h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift; + const float satScale1 = h_fract0 * table_base[e00_index].sat_scale + h_fract1 * table_base[e01_index].sat_scale; + const float valScale1 = h_fract0 * table_base[e00_index].val_scale + h_fract1 * table_base[e01_index].val_scale; + hue_shift = s_fract0 * hue_shift0 + s_fract1 * hueShift1; + sat_scale = s_fract0 * sat_scale0 + s_fract1 * satScale1; + val_scale = s_fract0 * val_scale0 + s_fract1 * valScale1; } else { + const float h_scaled = h * table_info.pc.h_scale; + const float s_scaled = s * table_info.pc.s_scale; - float hScaled = h * ti.pc.hScale; - float sScaled = s * ti.pc.sScale; - - if (ti.sRGBGamma) { - vEncoded = sRGBGammaForward(v); + if (table_info.srgb_gamma) { + v_encoded = srgbGammaForward(v); } - float vScaled = vEncoded * ti.pc.vScale; + const float v_scaled = v_encoded * table_info.pc.v_scale; - int hIndex0 = (int) hScaled; - int sIndex0 = max(min((int)sScaled, ti.pc.maxSatIndex0), 0); - int vIndex0 = max(min((int)vScaled, ti.pc.maxValIndex0), 0); + int h_index0 = (int) h_scaled; + const int s_index0 = std::max(std::min(s_scaled, table_info.pc.max_sat_index0), 0); + const int v_index0 = std::max(std::min(v_scaled, table_info.pc.max_val_index0), 0); - int hIndex1 = hIndex0 + 1; + int h_index1 = h_index0 + 1; - if (hIndex0 >= ti.pc.maxHueIndex0) { - hIndex0 = ti.pc.maxHueIndex0; - hIndex1 = 0; + if (h_index0 >= table_info.pc.max_hue_index0) { + h_index0 = table_info.pc.max_hue_index0; + h_index1 = 0; } - float hFract1 = hScaled - (float) hIndex0; - float sFract1 = sScaled - (float) sIndex0; - float vFract1 = vScaled - (float) vIndex0; + const float h_fract1 = h_scaled - static_cast(h_index0); + const float s_fract1 = s_scaled - static_cast(s_index0); + const float v_fract1 = v_scaled - static_cast(v_index0); - float hFract0 = 1.0f - hFract1; - float sFract0 = 1.0f - sFract1; - float vFract0 = 1.0f - vFract1; + const float h_fract0 = 1.0f - h_fract1; + const float s_fract0 = 1.0f - s_fract1; + const float v_fract0 = 1.0f - v_fract1; - const HSBModify *entry00 = tableBase + vIndex0 * ti.pc.valStep + hIndex0 * ti.pc.hueStep + sIndex0; + std::vector::size_type e00_index = v_index0 * table_info.pc.val_step + h_index0 * table_info.pc.hue_step + s_index0; + std::vector::size_type e01_index = e00_index + (h_index1 - h_index0) * table_info.pc.hue_step; + std::vector::size_type e10_index = e00_index + table_info.pc.val_step; + std::vector::size_type e11_index = e01_index + table_info.pc.val_step; - const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * ti.pc.hueStep; + const float hueShift0 = + v_fract0 * (h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift) + + v_fract1 * (h_fract0 * table_base[e10_index].hue_shift + h_fract1 * table_base[e11_index].hue_shift); + const float satScale0 = + v_fract0 * (h_fract0 * table_base[e00_index].sat_scale + h_fract1 * table_base[e01_index].sat_scale) + + v_fract1 * (h_fract0 * table_base[e10_index].sat_scale + h_fract1 * table_base[e11_index].sat_scale); + const float valScale0 = + v_fract0 * (h_fract0 * table_base[e00_index].val_scale + h_fract1 * table_base[e01_index].val_scale) + + v_fract1 * (h_fract0 * table_base[e10_index].val_scale + h_fract1 * table_base[e11_index].val_scale); - const HSBModify *entry10 = entry00 + ti.pc.valStep; - const HSBModify *entry11 = entry01 + ti.pc.valStep; + ++e00_index; + ++e01_index; + ++e10_index; + ++e11_index; - float hueShift0 = vFract0 * (hFract0 * entry00->fHueShift + - hFract1 * entry01->fHueShift) + - vFract1 * (hFract0 * entry10->fHueShift + - hFract1 * entry11->fHueShift); + const float hueShift1 = + v_fract0 * (h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift) + + v_fract1 * (h_fract0 * table_base[e10_index].hue_shift + h_fract1 * table_base[e11_index].hue_shift); + const float satScale1 = + v_fract0 * (h_fract0 * table_base[e00_index].sat_scale + h_fract1 * table_base[e01_index].sat_scale) + + v_fract1 * (h_fract0 * table_base[e10_index].sat_scale + h_fract1 * table_base[e11_index].sat_scale); + const float valScale1 = + v_fract0 * (h_fract0 * table_base[e00_index].val_scale + h_fract1 * table_base[e01_index].val_scale) + + v_fract1 * (h_fract0 * table_base[e10_index].val_scale + h_fract1 * table_base[e11_index].val_scale); - float satScale0 = vFract0 * (hFract0 * entry00->fSatScale + - hFract1 * entry01->fSatScale) + - vFract1 * (hFract0 * entry10->fSatScale + - hFract1 * entry11->fSatScale); - - float valScale0 = vFract0 * (hFract0 * entry00->fValScale + - hFract1 * entry01->fValScale) + - vFract1 * (hFract0 * entry10->fValScale + - hFract1 * entry11->fValScale); - - entry00++; - entry01++; - entry10++; - entry11++; - - float hueShift1 = vFract0 * (hFract0 * entry00->fHueShift + - hFract1 * entry01->fHueShift) + - vFract1 * (hFract0 * entry10->fHueShift + - hFract1 * entry11->fHueShift); - - float satScale1 = vFract0 * (hFract0 * entry00->fSatScale + - hFract1 * entry01->fSatScale) + - vFract1 * (hFract0 * entry10->fSatScale + - hFract1 * entry11->fSatScale); - - float valScale1 = vFract0 * (hFract0 * entry00->fValScale + - hFract1 * entry01->fValScale) + - vFract1 * (hFract0 * entry10->fValScale + - hFract1 * entry11->fValScale); - - hueShift = sFract0 * hueShift0 + sFract1 * hueShift1; - satScale = sFract0 * satScale0 + sFract1 * satScale1; - valScale = sFract0 * valScale0 + sFract1 * valScale1; + hue_shift = s_fract0 * hueShift0 + s_fract1 * hueShift1; + sat_scale = s_fract0 * satScale0 + s_fract1 * satScale1; + val_scale = s_fract0 * valScale0 + s_fract1 * valScale1; } - hueShift *= (6.0f / 360.0f); // Convert to internal hue range. + hue_shift *= 6.0f / 360.0f; // Convert to internal hue range. - h += hueShift; - s *= satScale; // no clipping here, we are RT float :-) + h += hue_shift; + s *= sat_scale; // No clipping here, we are RT float :-) - if (ti.sRGBGamma) { - v = sRGBGammaInverse(vEncoded * valScale); + if (table_info.srgb_gamma) { + v = srgbGammaInverse(v_encoded * val_scale); } else { - v *= valScale; + v *= val_scale; } } -struct ruvt { - double r; - double u; - double v; - double t; -}; - -static const double kTintScale = -3000.0; -static const ruvt kTempTable [] = { - { 0, 0.18006, 0.26352, -0.24341 }, - { 10, 0.18066, 0.26589, -0.25479 }, - { 20, 0.18133, 0.26846, -0.26876 }, - { 30, 0.18208, 0.27119, -0.28539 }, - { 40, 0.18293, 0.27407, -0.30470 }, - { 50, 0.18388, 0.27709, -0.32675 }, - { 60, 0.18494, 0.28021, -0.35156 }, - { 70, 0.18611, 0.28342, -0.37915 }, - { 80, 0.18740, 0.28668, -0.40955 }, - { 90, 0.18880, 0.28997, -0.44278 }, - { 100, 0.19032, 0.29326, -0.47888 }, - { 125, 0.19462, 0.30141, -0.58204 }, - { 150, 0.19962, 0.30921, -0.70471 }, - { 175, 0.20525, 0.31647, -0.84901 }, - { 200, 0.21142, 0.32312, -1.0182 }, - { 225, 0.21807, 0.32909, -1.2168 }, - { 250, 0.22511, 0.33439, -1.4512 }, - { 275, 0.23247, 0.33904, -1.7298 }, - { 300, 0.24010, 0.34308, -2.0637 }, - { 325, 0.24702, 0.34655, -2.4681 }, - { 350, 0.25591, 0.34951, -2.9641 }, - { 375, 0.26400, 0.35200, -3.5814 }, - { 400, 0.27218, 0.35407, -4.3633 }, - { 425, 0.28039, 0.35577, -5.3762 }, - { 450, 0.28863, 0.35714, -6.7262 }, - { 475, 0.29685, 0.35823, -8.5955 }, - { 500, 0.30505, 0.35907, -11.324 }, - { 525, 0.31320, 0.35968, -15.628 }, - { 550, 0.32129, 0.36011, -23.325 }, - { 575, 0.32931, 0.36038, -40.770 }, - { 600, 0.33724, 0.36051, -116.45 } -}; - -void DCPProfile::dngref_XYCoord2Temperature(const double whiteXY[2], double *temp, double *tint) const -{ - double fTemperature = 0; - double fTint = 0; - - // Convert to uv space. - double u = 2.0 * whiteXY[0] / (1.5 - whiteXY[0] + 6.0 * whiteXY[1]); - double v = 3.0 * whiteXY[1] / (1.5 - whiteXY[0] + 6.0 * whiteXY[1]); - - // Search for line pair coordinate is between. - double last_dt = 0.0; - double last_dv = 0.0; - double last_du = 0.0; - - for (uint32_t index = 1; index <= 30; index++) { - // Convert slope to delta-u and delta-v, with length 1. - double du = 1.0; - double dv = kTempTable [index] . t; - double len = sqrt (1.0 + dv * dv); - du /= len; - dv /= len; - - // Find delta from black body point to test coordinate. - double uu = u - kTempTable [index] . u; - double vv = v - kTempTable [index] . v; - - // Find distance above or below line. - double dt = - uu * dv + vv * du; - - // If below line, we have found line pair. - if (dt <= 0.0 || index == 30) { - // Find fractional weight of two lines. - if (dt > 0.0) { - dt = 0.0; - } - - dt = -dt; - double f; - - if (index == 1) { - f = 0.0; - } else { - f = dt / (last_dt + dt); - } - - // Interpolate the temperature. - fTemperature = 1.0E6 / (kTempTable [index - 1] . r * f + - kTempTable [index ] . r * (1.0 - f)); - - // Find delta from black body point to test coordinate. - uu = u - (kTempTable [index - 1] . u * f + - kTempTable [index ] . u * (1.0 - f)); - vv = v - (kTempTable [index - 1] . v * f + - kTempTable [index ] . v * (1.0 - f)); - // Interpolate vectors along slope. - du = du * (1.0 - f) + last_du * f; - dv = dv * (1.0 - f) + last_dv * f; - len = sqrt (du * du + dv * dv); - du /= len; - dv /= len; - - // Find distance along slope. - fTint = (uu * du + vv * dv) * kTintScale; - break; - } - - // Try next line pair. - last_dt = dt; - last_du = du; - last_dv = dv; - } - - if (temp != NULL) { - *temp = fTemperature; - } - - if (tint != NULL) { - *tint = fTint; - } -} - -void DCPProfile::dngref_FindXYZtoCamera(const double whiteXY[2], int preferredIlluminant, double (*xyzToCamera)[3]) const -{ - - bool hasCol1 = hasColorMatrix1; - bool hasCol2 = hasColorMatrix2; - - if (preferredIlluminant == 1) { - if (hasCol1) { - hasCol2 = false; - } - } else if (preferredIlluminant == 2) { - if (hasCol2) { - hasCol1 = false; - } - } - - // mix if we have two matrices - double mix; - - if (hasCol1 && hasCol2) { - double wbtemp; - /* - Note: we're using DNG SDK reference code for XY to temperature translation to get the exact same mix as - the reference code does. - */ - dngref_XYCoord2Temperature(whiteXY, &wbtemp, NULL); - - if (wbtemp <= temperature1) { - mix = 1.0; - } else if (wbtemp >= temperature2) { - mix = 0.0; - } else { - double invT = 1.0 / wbtemp; - mix = (invT - (1.0 / temperature2)) / ((1.0 / temperature1) - (1.0 / temperature2)); - } - } - - // Interpolate the color matrix. - double mCol[3][3]; - - if (hasCol1 && hasCol2) { - // interpolate - if (mix >= 1.0) { - memcpy(mCol, mColorMatrix1, sizeof(mCol)); - } else if (mix <= 0.0) { - memcpy(mCol, mColorMatrix2, sizeof(mCol)); - } else { - Mix3x3(mColorMatrix1, mix, mColorMatrix2, 1.0 - mix, mCol); - } - } else if (hasCol1) { - memcpy(mCol, mColorMatrix1, sizeof(mCol)); - } else { - memcpy(mCol, mColorMatrix2, sizeof(mCol)); - } - - memcpy(xyzToCamera, mCol, sizeof(mCol)); -} - -void DCPProfile::dngref_NeutralToXY(double neutral[3], int preferredIlluminant, double XY[2]) const -{ - const int kMaxPasses = 30; - double lastXY[2] = { 0.3457, 0.3585 }; // D50 - - for (int pass = 0; pass < kMaxPasses; pass++) { - double xyzToCamera[3][3]; - dngref_FindXYZtoCamera(lastXY, preferredIlluminant, xyzToCamera); - - double invM[3][3], nextXYZ[3], nextXY[2]; - Invert3x3(xyzToCamera, invM); - Multiply3x3_v3(invM, neutral, nextXYZ); - XYZtoXY(nextXYZ, nextXY); - - if (fabs(nextXY[0] - lastXY[0]) + - fabs(nextXY[1] - lastXY[1]) < 0.0000001) { - XY[0] = nextXY[0]; - XY[1] = nextXY[1]; - return; - } - - // If we reach the limit without converging, we are most likely - // in a two value oscillation. So take the average of the last - // two estimates and give up. - if (pass == kMaxPasses - 1) { - nextXY[0] = (lastXY[0] + nextXY[0]) * 0.5; - nextXY[1] = (lastXY[1] + nextXY[1]) * 0.5; - } - - lastXY[0] = nextXY[0]; - lastXY[1] = nextXY[1]; - } - - XY[0] = lastXY[0]; - XY[1] = lastXY[1]; -} - -void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], bool useToneCurve, bool applyHueSatMap, bool applyLookTable) const -{ - - TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace); - - double mXYZCAM[3][3]; // Camera RGB to XYZ D50 matrix - MakeXYZCAM(wb, pre_mul, camWbMatrix, preferredIlluminant, mXYZCAM); - HSBModify *deleteTableHandle; - const HSBModify *deltaBase = MakeHueSatMap(wb, preferredIlluminant, &deleteTableHandle); - - if (!deltaBase) { - applyHueSatMap = false; - } - - if (!aLookTable) { - applyLookTable = false; - } - - useToneCurve &= toneCurve; - - if (!applyHueSatMap && !applyLookTable && !useToneCurve) { - //===== The fast path: no LUT and not tone curve- Calculate matrix for direct conversion raw>working space - double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - for (int k = 0; k < 3; k++) { - mat[i][j] += mWork[i][k] * mXYZCAM[k][j]; - } - - // Apply the matrix part - #pragma omp parallel for - - for (int y = 0; y < pImg->height; y++) { - float newr, newg, newb; - - for (int x = 0; x < pImg->width; x++) { - newr = mat[0][0] * pImg->r(y, x) + mat[0][1] * pImg->g(y, x) + mat[0][2] * pImg->b(y, x); - newg = mat[1][0] * pImg->r(y, x) + mat[1][1] * pImg->g(y, x) + mat[1][2] * pImg->b(y, x); - newb = mat[2][0] * pImg->r(y, x) + mat[2][1] * pImg->g(y, x) + mat[2][2] * pImg->b(y, x); - - pImg->r(y, x) = newr; - pImg->g(y, x) = newg; - pImg->b(y, x) = newb; - } - } - } else { - //===== LUT available- Calculate matrix for conversion raw>ProPhoto - double m2ProPhoto[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - for (int k = 0; k < 3; k++) { - m2ProPhoto[i][j] += prophoto_xyz[i][k] * mXYZCAM[k][j]; - } - - double m2Work[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - for (int k = 0; k < 3; k++) { - m2Work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; - } - - // Convert to prophoto and apply LUT - #pragma omp parallel for - - for (int y = 0; y < pImg->height; y++) { - float newr, newg, newb, h, s, v, hs, ss, vs; - - for (int x = 0; x < pImg->width; x++) { - newr = m2ProPhoto[0][0] * pImg->r(y, x) + m2ProPhoto[0][1] * pImg->g(y, x) + m2ProPhoto[0][2] * pImg->b(y, x); - newg = m2ProPhoto[1][0] * pImg->r(y, x) + m2ProPhoto[1][1] * pImg->g(y, x) + m2ProPhoto[1][2] * pImg->b(y, x); - newb = m2ProPhoto[2][0] * pImg->r(y, x) + m2ProPhoto[2][1] * pImg->g(y, x) + m2ProPhoto[2][2] * pImg->b(y, x); - - // if point is in negative area, just the matrix, but not the LUT - if ((applyHueSatMap || applyLookTable) && newr >= 0 && newg >= 0 && newb >= 0) { - Color::rgb2hsv(newr, newg, newb, h , s, v); - h *= 6.f; // RT calculates in [0,1] - - if (applyHueSatMap) { - HSDApply(DeltaInfo, deltaBase, h, s, v); - } - - if (applyLookTable) { - HSDApply(LookInfo, aLookTable, h, s, v); - } - - // RT range correction - if (h < 0.0f) { - h += 6.0f; - } - - if (h >= 6.0f) { - h -= 6.0f; - } - - h /= 6.f; - Color::hsv2rgb( h, s, v, newr, newg, newb); - } - - // tone curve - if (useToneCurve) { - toneCurve.Apply(newr, newg, newb); - } - - pImg->r(y, x) = m2Work[0][0] * newr + m2Work[0][1] * newg + m2Work[0][2] * newb; - pImg->g(y, x) = m2Work[1][0] * newr + m2Work[1][1] * newg + m2Work[1][2] * newb; - pImg->b(y, x) = m2Work[2][0] * newr + m2Work[2][1] * newg + m2Work[2][2] * newb; - } - } - } - - if (deleteTableHandle) { - delete[] deleteTableHandle; - } -} - -void DCPProfile::setStep2ApplyState(Glib::ustring workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure) -{ - - applyState.useToneCurve = useToneCurve; - applyState.applyLookTable = applyLookTable; - applyState.blScale = 1.0; - - if (!aLookTable) { - applyState.applyLookTable = false; - } - - if (!hasToneCurve) { - applyState.useToneCurve = false; - } - - if (hasBaselineExposureOffset && applyBaselineExposure) { - applyState.blScale = powf(2, baselineExposureOffset); - } - - if (workingSpace == "ProPhoto") { - applyState.alreadyProPhoto = true; - } else { - applyState.alreadyProPhoto = false; - TMatrix mWork; - - mWork = iccStore->workingSpaceMatrix (workingSpace); - memset(applyState.m2ProPhoto, 0, sizeof(applyState.m2ProPhoto)); - - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - for (int k = 0; k < 3; k++) { - applyState.m2ProPhoto[i][j] += prophoto_xyz[i][k] * mWork[k][j]; - } - - mWork = iccStore->workingSpaceInverseMatrix (workingSpace); - memset(applyState.m2Work, 0, sizeof(applyState.m2Work)); - - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - for (int k = 0; k < 3; k++) { - applyState.m2Work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; - } - } -} - -void DCPProfile::step2ApplyTile(float *rc, float *gc, float *bc, int width, int height, int tileWidth) const -{ - -#define FCLIP(a) ((a)>0.0?((a)<65535.5?(a):65535.5):0.0) -#define CLIP01(a) ((a)>0?((a)<1?(a):1):0) - - float exp_scale = 1.0; - exp_scale *= applyState.blScale; - - if (!applyState.useToneCurve && !applyState.applyLookTable) { - if (exp_scale == 1.0) { - return; - } - - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - rc[y * tileWidth + x] *= exp_scale; - gc[y * tileWidth + x] *= exp_scale; - bc[y * tileWidth + x] *= exp_scale; - } - } - } else { - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - float r = rc[y * tileWidth + x]; - float g = gc[y * tileWidth + x]; - float b = bc[y * tileWidth + x]; - - if (exp_scale != 1.0) { - r *= exp_scale; - g *= exp_scale; - b *= exp_scale; - } - - float newr, newg, newb; - - if (applyState.alreadyProPhoto) { - newr = r; - newg = g; - newb = b; - } else { - newr = applyState.m2ProPhoto[0][0] * r + applyState.m2ProPhoto[0][1] * g + applyState.m2ProPhoto[0][2] * b; - newg = applyState.m2ProPhoto[1][0] * r + applyState.m2ProPhoto[1][1] * g + applyState.m2ProPhoto[1][2] * b; - newb = applyState.m2ProPhoto[2][0] * r + applyState.m2ProPhoto[2][1] * g + applyState.m2ProPhoto[2][2] * b; - } - - // with looktable and tonecurve we need to clip - newr = FCLIP(newr); - newg = FCLIP(newg); - newb = FCLIP(newb); - - if (applyState.applyLookTable) { - float h, s, v; - Color::rgb2hsv(newr, newg, newb, h, s, v); - h *= 6.f; // RT calculates in [0,1] - - HSDApply(LookInfo, aLookTable, h, s, v); - s = CLIP01(s); - v = CLIP01(v); - - // RT range correction - if (h < 0.0f) { - h += 6.0f; - } - - if (h >= 6.0f) { - h -= 6.0f; - } - - h /= 6.f; - Color::hsv2rgb( h, s, v, newr, newg, newb); - } - - if (applyState.useToneCurve) { - toneCurve.Apply(newr, newg, newb); - } - - if (applyState.alreadyProPhoto) { - rc[y * tileWidth + x] = newr; - gc[y * tileWidth + x] = newg; - bc[y * tileWidth + x] = newb; - } else { - rc[y * tileWidth + x] = applyState.m2Work[0][0] * newr + applyState.m2Work[0][1] * newg + applyState.m2Work[0][2] * newb; - gc[y * tileWidth + x] = applyState.m2Work[1][0] * newr + applyState.m2Work[1][1] * newg + applyState.m2Work[1][2] * newb; - bc[y * tileWidth + x] = applyState.m2Work[2][0] * newr + applyState.m2Work[2][1] * newg + applyState.m2Work[2][2] * newb; - } - } - } - } -} - -// Generates as singleton DCPStore* DCPStore::getInstance() { - static DCPStore instance_; - return &instance_; + static DCPStore instance; + return &instance; } -// Reads all profiles from the given profiles dir -void DCPStore::init (Glib::ustring rtProfileDir) +void DCPStore::init(const Glib::ustring& rt_profile_dir) { - MyMutex::MyLock lock(mtx); + MyMutex::MyLock lock(mutex); - fileStdProfiles.clear(); + file_std_profiles.clear(); - Glib::ustring rootDirName = rtProfileDir; + if (!rt_profile_dir.empty()) { + std::deque dirs = { + rt_profile_dir + }; - if (rootDirName != "") { - std::deque qDirs; + while (!dirs.empty()) { + // Process directory + Glib::ustring dirname = dirs.back(); + dirs.pop_back(); - qDirs.push_front(rootDirName); - - while (!qDirs.empty()) { - // process directory - Glib::ustring dirname = qDirs.back(); - qDirs.pop_back(); - - Glib::Dir* dir = NULL; + std::unique_ptr dir; try { - if (!Glib::file_test (dirname, Glib::FILE_TEST_IS_DIR)) { + if (!Glib::file_test(dirname, Glib::FILE_TEST_IS_DIR)) { return; } - dir = new Glib::Dir (dirname); - } catch (Glib::Exception& fe) { + dir.reset(new Glib::Dir(dirname)); + } catch (Glib::Exception& exception) { return; } - dirname = dirname + "/"; + dirname += '/'; - for (Glib::DirIterator i = dir->begin(); i != dir->end(); ++i) { - Glib::ustring fname = dirname + *i; - Glib::ustring sname = *i; + for (const Glib::ustring& sname : *dir) { + const Glib::ustring fname = dirname + sname; - // ignore directories - if (!Glib::file_test (fname, Glib::FILE_TEST_IS_DIR)) { - size_t lastdot = sname.find_last_of ('.'); + if (!Glib::file_test(fname, Glib::FILE_TEST_IS_DIR)) { + // File + const auto lastdot = sname.rfind('.'); - if (lastdot != Glib::ustring::npos && lastdot <= sname.size() - 4 && (!sname.casefold().compare (lastdot, 4, ".dcp"))) { - Glib::ustring camShortName = sname.substr(0, lastdot).uppercase(); - fileStdProfiles[camShortName] = fname; // they will be loaded and cached on demand + if ( + lastdot != Glib::ustring::npos + && lastdot <= sname.size() - 4 + && !sname.casefold().compare(lastdot, 4, ".dcp") + ) { + const Glib::ustring cam_short_name = sname.substr(0, lastdot).uppercase(); + file_std_profiles[cam_short_name] = fname; // They will be loaded and cached on demand } } else { - qDirs.push_front(fname); // for later scanning + // Directory + dirs.push_front(fname); } } - - delete dir; } } } -DCPProfile* DCPStore::getProfile (Glib::ustring filename) +bool DCPStore::isValidDCPFileName(const Glib::ustring& filename) const { - MyMutex::MyLock lock(mtx); - - std::map::iterator r = profileCache.find (filename); - - if (r != profileCache.end()) { - return r->second; - } - - // Add profile - profileCache[filename] = new DCPProfile(filename); - - return profileCache[filename]; -} - -DCPProfile* DCPStore::getStdProfile(Glib::ustring camShortName) -{ - Glib::ustring name2 = camShortName.uppercase(); - - // Warning: do NOT use map.find(), since it does not seem to work reliably here - for (std::map::iterator i = fileStdProfiles.begin(); i != fileStdProfiles.end(); i++) - if (name2 == (*i).first) { - return getProfile((*i).second); - } - - return NULL; -} - -bool DCPStore::isValidDCPFileName(Glib::ustring filename) const -{ - if (!Glib::file_test (filename, Glib::FILE_TEST_EXISTS) || Glib::file_test (filename, Glib::FILE_TEST_IS_DIR)) { + if (!Glib::file_test(filename, Glib::FILE_TEST_EXISTS) || Glib::file_test(filename, Glib::FILE_TEST_IS_DIR)) { return false; } - size_t pos = filename.find_last_of ('.'); - return pos > 0 && (!filename.casefold().compare (pos, 4, ".dcp") || !filename.casefold().compare (pos, 4, ".dng")); + const auto pos = filename.rfind('.'); + return + pos > 0 + && ( + !filename.casefold().compare(pos, 4, ".dcp") + || !filename.casefold().compare(pos, 4, ".dng") + ); +} + +DCPProfile* DCPStore::getProfile(const Glib::ustring& filename) const +{ + MyMutex::MyLock lock(mutex); + + const std::map::iterator r = profile_cache.find(filename); + + if (r != profile_cache.end()) { + return r->second; + } + + DCPProfile* const res = new DCPProfile(filename); + + // Add profile + profile_cache[filename] = res; + + return res; +} + +DCPProfile* DCPStore::getStdProfile(const Glib::ustring& cam_short_name) const +{ + const Glib::ustring name = cam_short_name.uppercase(); + + // Warning: do NOT use map.find(), since it does not seem to work reliably here + for (const auto& file_std_profile : file_std_profiles) + if (file_std_profile.first == name) { + return getProfile(file_std_profile.second); + } + + return nullptr; } diff --git a/rtengine/dcp.h b/rtengine/dcp.h index 7a960edc9..ace32869a 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -17,117 +17,159 @@ * along with RawTherapee. If not, see . */ -#ifndef _DCP_ -#define _DCP_ +#pragma once + +#include +#include +#include +#include + +#include #include "imagefloat.h" #include "curves.h" #include "colortemp.h" + #include "../rtgui/threadutils.h" -#include -#include -#include namespace rtengine { -class DCPProfile +class DCPProfile final { - struct HSBModify { - float fHueShift; - float fSatScale; - float fValScale; +public: + class ApplyState final + { + public: + ApplyState(); + ~ApplyState(); + + private: + struct Data; + + std::unique_ptr data; + + friend class DCPProfile; }; - struct HSDTableInfo { - int iHueDivisions, iSatDivisions, iValDivisions; - int iHueStep, iValStep, iArrayCount; - bool sRGBGamma; + + struct Illuminants { + short light_source_1; + short light_source_2; + double temperature_1; + double temperature_2; + bool will_interpolate; + }; + + using Triple = std::array; + using Matrix = std::array; + + DCPProfile(const Glib::ustring& filename); + ~DCPProfile(); + + bool getHasToneCurve() const; + bool getHasLookTable() const; + bool getHasHueSatMap() const; + bool getHasBaselineExposureOffset() const; + + Illuminants getIlluminants() const; + + void apply( + Imagefloat* img, + int preferred_illuminant, + const Glib::ustring& working_space, + const ColorTemp& white_balance, + const Triple& pre_mul, + const Matrix& cam_wb_matrix, + bool use_tone_curve = false, + bool apply_hue_sat_map = true, + bool apply_look_table = false + ) const; + void setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, ApplyState& as_out); + void step2ApplyTile(float* r, float* g, float* b, int width, int height, int tile_width, const ApplyState& as_in) const; + +private: + struct HsbModify { + float hue_shift; + float sat_scale; + float val_scale; + }; + + struct HsdTableInfo { + int hue_divisions; + int sat_divisions; + int val_divisions; + int hue_step; + int val_step; + unsigned int array_count; + bool srgb_gamma; struct { - float hScale, sScale, vScale; - int maxHueIndex0, maxSatIndex0, maxValIndex0; - int hueStep, valStep; + float h_scale; + float s_scale; + float v_scale; + int max_hue_index0; + int max_sat_index0; + int max_val_index0; + int hue_step; + int val_step; } pc; }; - double mColorMatrix1[3][3], mColorMatrix2[3][3]; - bool hasColorMatrix1, hasColorMatrix2, hasForwardMatrix1, hasForwardMatrix2, hasToneCurve, hasBaselineExposureOffset, willInterpolate; - double mForwardMatrix1[3][3], mForwardMatrix2[3][3]; - double temperature1, temperature2; - double baselineExposureOffset; - HSBModify *aDeltas1, *aDeltas2, *aLookTable; - HSDTableInfo DeltaInfo, LookInfo; - short iLightSource1, iLightSource2; + void findXyztoCamera(const double white_xy[2], int preferred_illuminant, Matrix& xyz_to_camera) const; + void neutralToXy(const Triple& neutral, int preferred_illuminant, double xy[2]) const; + void makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, int preferred_illuminant, Matrix& xyz_cam) const; + std::vector makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const; + void hsdApply(const HsdTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const; - AdobeToneCurve toneCurve; - struct { - double m2ProPhoto[3][3]; - double m2Work[3][3]; - bool alreadyProPhoto; - bool useToneCurve; - bool applyLookTable; - float blScale; - } applyState; + Matrix color_matrix_1; + Matrix color_matrix_2; + bool has_color_matrix_1; + bool has_color_matrix_2; + bool has_forward_matrix_1; + bool has_forward_matrix_2; + bool has_tone_curve; + bool has_baseline_exposure_offset; + bool will_interpolate; + Matrix forward_matrix_1; + Matrix forward_matrix_2; + double temperature_1; + double temperature_2; + double baseline_exposure_offset; + std::vector deltas_1; + std::vector deltas_2; + std::vector look_table; + HsdTableInfo delta_info; + HsdTableInfo look_info; + short light_source_1; + short light_source_2; - void dngref_XYCoord2Temperature(const double whiteXY[2], double *temp, double *tint) const; - void dngref_FindXYZtoCamera(const double whiteXY[2], int preferredIlluminant, double (*xyzToCamera)[3]) const; - void dngref_NeutralToXY(double neutral[3], int preferredIlluminant, double XY[2]) const; - void MakeXYZCAM(ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const; - const HSBModify* MakeHueSatMap(ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const; - void HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, float &h, float &s, float &v) const; - -public: - DCPProfile(Glib::ustring fname); - ~DCPProfile(); - - bool getHasToneCurve() - { - return hasToneCurve; - } - bool getHasLookTable() - { - return !!aLookTable; - } - bool getHasHueSatMap() - { - return !!aDeltas1; - } - bool getHasBaselineExposureOffset() - { - return hasBaselineExposureOffset; - } - void getIlluminants(int &i1, double &temp1, int &i2, double &temp2, bool &willInterpolate_) - { - i1 = iLightSource1; - i2 = iLightSource2; - temp1 = temperature1, temp2 = temperature2; - willInterpolate_ = willInterpolate; - }; - void Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camMatrix[3][3], bool useToneCurve = false, bool applyHueSatMap = true, bool applyLookTable = false) const; - void setStep2ApplyState(Glib::ustring workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure); - void step2ApplyTile(float *r, float *g, float *b, int width, int height, int tileWidth) const; + AdobeToneCurve tone_curve; }; -class DCPStore +class DCPStore final { - MyMutex mtx; +public: + static DCPStore* getInstance(); + + DCPStore(const DCPStore& other) = delete; + DCPStore& operator =(const DCPStore& other) = delete; + + void init(const Glib::ustring& rt_profile_dir); + + bool isValidDCPFileName(const Glib::ustring& filename) const; + + DCPProfile* getProfile(const Glib::ustring& filename) const; + DCPProfile* getStdProfile(const Glib::ustring& camShortName) const; + +private: + DCPStore() = default; + + mutable MyMutex mutex; // these contain standard profiles from RT. keys are all in uppercase, file path is value - std::map fileStdProfiles; + std::map file_std_profiles; // Maps file name to profile as cache - std::map profileCache; - -public: - void init(Glib::ustring rtProfileDir); - - bool isValidDCPFileName(Glib::ustring filename) const; - - DCPProfile* getProfile(Glib::ustring filename); - DCPProfile* getStdProfile(Glib::ustring camShortName); - - static DCPStore* getInstance(); + mutable std::map profile_cache; }; -#define dcpStore DCPStore::getInstance() } -#endif diff --git a/rtengine/dcraw.c b/rtengine/dcraw.c index cf1afe4ac..441f967da 100644 --- a/rtengine/dcraw.c +++ b/rtengine/dcraw.c @@ -1,6 +1,6 @@ /* dcraw.c -- Dave Coffin's raw photo decoder - Copyright 1997-2015 by Dave Coffin, dcoffin a cybercom o net + Copyright 1997-2016 by Dave Coffin, dcoffin a cybercom o net This is a command-line ANSI C program to convert raw photos from any digital camera on any computer running any operating system. @@ -19,11 +19,11 @@ *If you have not modified dcraw.c in any way, a link to my homepage qualifies as "full source code". - $Revision: 1.475 $ - $Date: 2015/04/11 00:08:36 $ + $Revision: 1.477 $ + $Date: 2016/05/10 21:30:43 $ */ -#define DCRAW_VERSION "9.25" +#define DCRAW_VERSION "9.27" #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -89,15 +89,6 @@ typedef unsigned long long UINT64; #define _(String) (String) #endif -#ifdef LJPEG_DECODE -#error Please compile dcraw.c by itself. -#error Do not link it with ljpeg_decode. -#endif - -#ifndef LONG_BIT -#define LONG_BIT (8 * sizeof (long)) -#endif - #if !defined(uchar) #define uchar unsigned char #endif @@ -158,6 +149,7 @@ struct decode { struct tiff_ifd { int width, height, bps, comp, phint, offset, flip, samples, bytes; int tile_width, tile_length; + float shutter; } tiff_ifd[10]; struct ph1 { @@ -179,7 +171,7 @@ struct ph1 { #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LIM(x,min,max) MAX(min,MIN(x,max)) #define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) -#define CLIP(x) LIM(x,0,65535) +#define CLIP(x) LIM((int)(x),0,65535) #define SWAP(a,b) { a=a+b; b=a-b; a=a-b; } /* @@ -813,27 +805,22 @@ void CLASS canon_load_raw() FORC(2) free (huff[c]); } -/* - Not a full implementation of Lossless JPEG, just - enough to decode Canon, Kodak and Adobe DNG images. - */ struct jhead { - int bits, high, wide, clrs, sraw, psv, restart, vpred[6]; - ushort *huff[6], *free[4], *row; + int algo, bits, high, wide, clrs, sraw, psv, restart, vpred[6]; + ushort quant[64], idct[64], *huff[20], *free[20], *row; }; int CLASS ljpeg_start (struct jhead *jh, int info_only) { - int c, tag, len; + ushort c, tag, len; uchar data[0x10000]; const uchar *dp; memset (jh, 0, sizeof *jh); jh->restart = INT_MAX; - fread (data, 2, 1, ifp); - if (data[1] != 0xd8) return 0; + if ((fgetc(ifp),fgetc(ifp)) != 0xd8) return 0; do { - fread (data, 2, 2, ifp); + if (!fread (data, 2, 2, ifp)) return 0; tag = data[0] << 8 | data[1]; len = (data[2] << 8 | data[3]) - 2; if (tag <= 0xff00) return 0; @@ -841,7 +828,9 @@ int CLASS ljpeg_start (struct jhead *jh, int info_only) switch (tag) { case 0xffc3: jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3; + case 0xffc1: case 0xffc0: + jh->algo = tag & 0xff; jh->bits = data[0]; jh->high = data[1] << 8 | data[2]; jh->wide = data[3] << 8 | data[4]; @@ -850,20 +839,25 @@ int CLASS ljpeg_start (struct jhead *jh, int info_only) break; case 0xffc4: if (info_only) break; - for (dp = data; dp < data+len && (c = *dp++) < 4; ) + for (dp = data; dp < data+len && !((c = *dp++) & -20); ) jh->free[c] = jh->huff[c] = make_decoder_ref (&dp); break; case 0xffda: jh->psv = data[1+data[0]*2]; jh->bits -= data[3+data[0]*2] & 15; break; + case 0xffdb: + FORC(64) jh->quant[c] = data[c*2+1] << 8 | data[c*2+2]; + break; case 0xffdd: jh->restart = data[0] << 8 | data[1]; } } while (tag != 0xffda); + if (jh->bits > 16 || jh->clrs > 6 || + !jh->bits || !jh->high || !jh->wide || !jh->clrs) return 0; if (info_only) return 1; - if (jh->clrs > 6 || !jh->huff[0]) return 0; - FORC(5) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c]; + if (!jh->huff[0]) return 0; + FORC(19) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c]; if (jh->sraw) { FORC(4) jh->huff[2+c] = jh->huff[1]; FORC(jh->sraw) jh->huff[1+c] = jh->huff[0]; @@ -1042,23 +1036,59 @@ void CLASS adobe_copy_pixel (unsigned row, unsigned col, ushort **rp) { int c; - if (is_raw == 2 && shot_select) (*rp)++; + if (tiff_samples == 2 && shot_select) (*rp)++; if (raw_image) { if (row < raw_height && col < raw_width) RAW(row,col) = curve[**rp]; - *rp += is_raw; + *rp += tiff_samples; } else { if (row < height && col < width) FORC(tiff_samples) image[row*width+col][c] = curve[(*rp)[c]]; *rp += tiff_samples; } - if (is_raw == 2 && shot_select) (*rp)--; + if (tiff_samples == 2 && shot_select) (*rp)--; +} + +void CLASS ljpeg_idct (struct jhead *jh) +{ + int c, i, j, len, skip, coef; + float work[3][8][8]; + static float cs[106] = { 0 }; + static const uchar zigzag[80] = + { 0, 1, 8,16, 9, 2, 3,10,17,24,32,25,18,11, 4, 5,12,19,26,33, + 40,48,41,34,27,20,13, 6, 7,14,21,28,35,42,49,56,57,50,43,36, + 29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54, + 47,55,62,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63 }; + + if (!cs[0]) + FORC(106) cs[c] = cos((c & 31)*M_PI/16)/2; + memset (work, 0, sizeof work); + work[0][0][0] = jh->vpred[0] += ljpeg_diff (jh->huff[0]) * jh->quant[0]; + for (i=1; i < 64; i++ ) { + len = gethuff (jh->huff[16]); + i += skip = len >> 4; + if (!(len &= 15) && skip < 15) break; + coef = getbits(len); + if ((coef & (1 << (len-1))) == 0) + coef -= (1 << len) - 1; + ((float *)work)[zigzag[i]] = coef * jh->quant[i]; + } + FORC(8) work[0][0][c] *= M_SQRT1_2; + FORC(8) work[0][c][0] *= M_SQRT1_2; + for (i=0; i < 8; i++) + for (j=0; j < 8; j++) + FORC(8) work[1][i][j] += work[0][i][c] * cs[(j*2+1)*c]; + for (i=0; i < 8; i++) + for (j=0; j < 8; j++) + FORC(8) work[2][i][j] += work[1][c][j] * cs[(i*2+1)*c]; + + FORC(64) jh->idct[c] = CLIP(((float *)work[2])[c]+0.5); } void CLASS lossless_dng_load_raw() { - unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col; + unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col, i, j; struct jhead jh; ushort *rp; @@ -1069,14 +1099,32 @@ void CLASS lossless_dng_load_raw() if (!ljpeg_start (&jh, 0)) break; jwide = jh.wide; if (filters) jwide *= jh.clrs; - jwide /= is_raw; - for (row=col=jrow=0; jrow < jh.high; jrow++) { - rp = ljpeg_row (jrow, &jh); - for (jcol=0; jcol < jwide; jcol++) { - adobe_copy_pixel (trow+row, tcol+col, &rp); - if (++col >= tile_width || col >= raw_width) - row += 1 + (col = 0); - } + jwide /= MIN (is_raw, tiff_samples); + switch (jh.algo) { + case 0xc1: + jh.vpred[0] = 16384; + getbits(-1); + for (jrow=0; jrow+7 < jh.high; jrow += 8) { + for (jcol=0; jcol+7 < jh.wide; jcol += 8) { + ljpeg_idct (&jh); + rp = jh.idct; + row = trow + jcol/tile_width + jrow*2; + col = tcol + jcol%tile_width; + for (i=0; i < 16; i+=2) + for (j=0; j < 8; j++) + adobe_copy_pixel (row+i, col+j, &rp); + } + } + break; + case 0xc3: + for (row=col=jrow=0; jrow < jh.high; jrow++) { + rp = ljpeg_row (jrow, &jh); + for (jcol=0; jcol < jwide; jcol++) { + adobe_copy_pixel (trow+row, tcol+col, &rp); + if (++col >= tile_width || col >= raw_width) + row += 1 + (col = 0); + } + } } fseek (ifp, save+4, SEEK_SET); if ((tcol += tile_width) >= raw_width) @@ -1721,7 +1769,7 @@ void CLASS phase_one_load_raw_c() pixel[col] = curve[pixel[col]]; } for (col=0; col < raw_width; col++) { - i = (pixel[col] << 2) - ph1.black + i = (pixel[col] << 2*(ph1.format != 8)) - ph1.black + cblack[row][col >= ph1.split_col] + rblack[col][row >= ph1.split_row]; if (i > 0) RAW(row,col) = i; @@ -2813,6 +2861,8 @@ void CLASS smal_decode_segment (unsigned seg[2][2], int holes) fseek (ifp, seg[0][1]+1, SEEK_SET); getbits(-1); + if (seg[1][0] > raw_width*raw_height) + seg[1][0] = raw_width*raw_height; for (pix=seg[0][0]; pix < seg[1][0]; pix++) { for (s=0; s < 3; s++) { data = data << nbits | getbits(nbits); @@ -5261,7 +5311,7 @@ nf: order = 0x4949; FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4(); } if (tag == 0x3d && type == 3 && len == 4) - FORC4 cblack[c ^ c >> 1] = get2() >> (14-tiff_ifd[2].bps); + FORC4 cblack[c ^ c >> 1] = get2() >> (14-tiff_bps); if (tag == 0x81 && type == 4) { data_offset = get4(); fseek (ifp, data_offset + 41, SEEK_SET); @@ -5291,7 +5341,8 @@ nf: order = 0x4949; break; case 102: fseek (ifp, 6, SEEK_CUR); - goto get2_rggb; + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + break; case 103: fseek (ifp, 16, SEEK_CUR); FORC4 cam_mul[c] = get2(); @@ -5325,7 +5376,7 @@ nf: order = 0x4949; if (tag == 0x200 && len == 4) FORC4 cblack[c ^ c >> 1] = get2(); if (tag == 0x201 && len == 4) - goto get2_rggb; + FORC4 cam_mul[c ^ (c >> 1)] = get2(); if (tag == 0x220 && type == 7) meta_offset = ftell(ifp); if (tag == 0x401 && type == 4 && len == 4) @@ -5371,7 +5422,7 @@ get2_256: } if ((tag | 0x70) == 0x2070 && (type == 4 || type == 13)) fseek (ifp, get4()+base, SEEK_SET); - if (tag == 0x2020) + if (tag == 0x2020 && !strncmp(buf,"OLYMP",5)) parse_thumb_note (base, 257, 258); if (tag == 0x2040) parse_makernote (base, 0x2040); @@ -5382,11 +5433,12 @@ get2_256: if (tag == 0x4001 && len > 500) { i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126; fseek (ifp, i, SEEK_CUR); -get2_rggb: FORC4 cam_mul[c ^ (c >> 1)] = get2(); - i = len >> 3 == 164 || len == 1506 ? 112:22; - fseek (ifp, i, SEEK_CUR); - FORC4 sraw_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; + } } if (tag == 0x4021 && get4() && get4()) FORC4 cam_mul[c] = 1024; @@ -5439,12 +5491,14 @@ void CLASS parse_exif (int base) while (entries--) { tiff_get (base, &tag, &type, &len, &save); switch (tag) { - case 33434: shutter = getreal(type); break; + case 33434: tiff_ifd[tiff_nifds-1].shutter = + shutter = getreal(type); break; case 33437: aperture = getreal(type); break; case 34855: iso_speed = get2(); break; case 36867: case 36868: get_timestamp(0); break; case 37377: if ((expo = -getreal(type)) < 128) + tiff_ifd[tiff_nifds-1].shutter = shutter = pow (2, expo); break; case 37378: aperture = pow (2, getreal(type)/2); break; case 37386: focal_len = getreal(type); break; @@ -5682,6 +5736,8 @@ int CLASS parse_tiff_ifd (int base) case 61443: tiff_ifd[ifd].samples = len & 7; tiff_ifd[ifd].bps = getint(type); + if (tiff_bps < tiff_ifd[ifd].bps) + tiff_bps = tiff_ifd[ifd].bps; break; case 61446: raw_height = 0; @@ -5843,7 +5899,7 @@ int CLASS parse_tiff_ifd (int base) parse_kodak_ifd (base); break; case 33434: /* ExposureTime */ - shutter = getreal(type); + tiff_ifd[ifd].shutter = shutter = getreal(type); break; case 33437: /* FNumber */ aperture = getreal(type); @@ -5971,6 +6027,14 @@ int CLASS parse_tiff_ifd (int base) if (!make[0]) strcpy (make, "DNG"); is_raw = 1; break; + case 50708: /* UniqueCameraModel */ + if (model[0]) break; + fgets (make, 64, ifp); + if ((cp = strchr(make,' '))) { + strcpy(model,cp+1); + *cp = 0; + } + break; case 50710: /* CFAPlaneColor */ if (filters == 9) break; if (len > 4) len = 4; @@ -5984,10 +6048,7 @@ guess_cfa_pc: filters -= !filters; break; case 50711: /* CFALayout */ - if (get2() == 2) { - fuji_width = 1; - filters = 0x49494949; - } + if (get2() == 2) fuji_width = 1; break; case 291: case 50712: /* LinearizationTable */ @@ -6010,7 +6071,7 @@ guess_cfa_pc: break; case 50715: /* BlackLevelDeltaH */ case 50716: /* BlackLevelDeltaV */ - for (num=i=0; i < len; i++) + for (num=i=0; i < (len & 0xffff); i++) num += getreal(type); black += num/len + 0.5; break; @@ -6128,7 +6189,7 @@ int CLASS parse_tiff (int base) void CLASS apply_tiff() { - int max_samp=0, raw=-1, thm=-1, i; + int max_samp=0, ties=0, os, ns, raw=-1, thm=-1, i; struct jhead jh; thumb_misc = 16; @@ -6140,13 +6201,25 @@ void CLASS apply_tiff() thumb_height = jh.high; } } + for (i=tiff_nifds; i--; ) { + if (tiff_ifd[i].shutter) + shutter = tiff_ifd[i].shutter; + tiff_ifd[i].shutter = shutter; + } for (i=0; i < tiff_nifds; i++) { if (max_samp < tiff_ifd[i].samples) max_samp = tiff_ifd[i].samples; if (max_samp > 3) max_samp = 3; + os = raw_width*raw_height; + ns = tiff_ifd[i].width*tiff_ifd[i].height; + if (tiff_bps) { + os *= tiff_bps; + ns *= tiff_ifd[i].bps; + } if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) && (tiff_ifd[i].width | tiff_ifd[i].height) < 0x10000 && - tiff_ifd[i].width*tiff_ifd[i].height > raw_width*raw_height) { + ns && ((ns > os && (ties = 1)) || + (ns == os && shot_select == ties++))) { raw_width = tiff_ifd[i].width; raw_height = tiff_ifd[i].height; tiff_bps = tiff_ifd[i].bps; @@ -6156,9 +6229,11 @@ void CLASS apply_tiff() tiff_samples = tiff_ifd[i].samples; tile_width = tiff_ifd[i].tile_width; tile_length = tiff_ifd[i].tile_length; + shutter = tiff_ifd[i].shutter; raw = i; } } + if (is_raw == 1 && ties) is_raw = ties; if (!tile_width ) tile_width = INT_MAX; if (!tile_length) tile_length = INT_MAX; for (i=tiff_nifds; i--; ) @@ -6235,8 +6310,8 @@ void CLASS apply_tiff() if (!dng_version) if ( (tiff_samples == 3 && tiff_ifd[raw].bytes && tiff_bps != 14 && (tiff_compress & -16) != 32768) - || (tiff_bps == 8 && !strcasestr(make,"Kodak") && - !strstr(model2,"DEBUG RAW"))) + || (tiff_bps == 8 && strncmp(make,"Phase",5) && + !strcasestr(make,"Kodak") && !strstr(model2,"DEBUG RAW"))) is_raw = 0; for (i=0; i < tiff_nifds; i++) if (i != raw && tiff_ifd[i].samples == max_samp && @@ -6377,9 +6452,7 @@ void CLASS ciff_block_1030() bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); vbits += 16; } - white[row][col] = - bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp); - vbits -= bpp; + white[row][col] = bitbuf >> (vbits -= bpp) & ~(-1 << bpp); } } @@ -6658,7 +6731,7 @@ void CLASS parse_fuji (int offset) } else if (tag == 0xc000) { c = order; order = 0x4949; - if ((tag = get4()) > 10000) tag = get4(); + while ((tag = get4()) > raw_width); width = tag; height = get4(); order = c; @@ -6680,7 +6753,7 @@ int CLASS parse_jpeg (int offset) order = 0x4d4d; len = get2() - 2; save = ftell(ifp); - if (mark == 0xc0 || mark == 0xc3) { + if (mark == 0xc0 || mark == 0xc3 || mark == 0xc9) { fgetc(ifp); raw_height = get2(); raw_width = get2(); @@ -6974,8 +7047,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } }, { "Canon EOS D60", 0, 0xfa0, { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } }, - { "Canon EOS 5DS", 0, 0x3c96, /* DJC */ - { 6885,-753,-856,-4416,11752,2665,-1266,2393,5468 } }, + { "Canon EOS 5DS", 0, 0x3c96, + { 6250,-711,-808,-5153,12794,2636,-1249,2198,5610 } }, { "Canon EOS 5D Mark III", 0, 0x3c80, { 6722,-635,-963,-4287,12460,2028,-908,2162,5668 } }, { "Canon EOS 5D Mark II", 0, 0x3cf0, @@ -7004,6 +7077,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 6719,-994,-925,-4408,12426,2211,-887,2129,6051 } }, { "Canon EOS 70D", 0, 0x3bc7, { 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 } }, + { "Canon EOS 80D", 0, 0, + { 7457,-671,-937,-4849,12495,2643,-1213,2354,5492 } }, { "Canon EOS 100D", 0, 0x350f, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS 300D", 0, 0xfa0, @@ -7024,12 +7099,22 @@ void CLASS adobe_coeff (const char *make, const char *model) { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS 700D", 0, 0x3c00, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + { "Canon EOS 750D", 0, 0x368e, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, + { "Canon EOS 760D", 0, 0x350f, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, { "Canon EOS 1000D", 0, 0xe43, { 6771,-1139,-977,-7818,15123,2928,-1244,1437,7533 } }, { "Canon EOS 1100D", 0, 0x3510, { 6444,-904,-893,-4563,12308,2535,-903,2016,6728 } }, { "Canon EOS 1200D", 0, 0x37c2, { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } }, + { "Canon EOS 1300D", 0, 0x3510, + { 6939,-1016,-866,-4428,12473,2177,-1175,2178,6162 } }, + { "Canon EOS M3", 0, 0, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, + { "Canon EOS M10", 0, 0, + { 6400,-480,-888,-5294,13416,2047,-1296,2203,6137 } }, { "Canon EOS M", 0, 0, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS-1Ds Mark III", 0, 0x3bb0, @@ -7048,6 +7133,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } }, { "Canon EOS-1D C", 0, 0x3c4e, { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, + { "Canon EOS-1D X Mark II", 0, 0, + { 7596,-978,-967,-4808,12571,2503,-1398,2567,5752 } }, { "Canon EOS-1D X", 0, 0x3c4e, { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, { "Canon EOS-1D", 0, 0xe20, @@ -7076,14 +7163,20 @@ void CLASS adobe_coeff (const char *make, const char *model) { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } }, { "Canon PowerShot G2", 0, 0, { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } }, + { "Canon PowerShot G3 X", 0, 0, + { 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 } }, { "Canon PowerShot G3", 0, 0, { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } }, + { "Canon PowerShot G5 X", 0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, { "Canon PowerShot G5", 0, 0, { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } }, { "Canon PowerShot G6", 0, 0, { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }, { "Canon PowerShot G7 X", 0, 0, { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, + { "Canon PowerShot G9 X", 0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, { "Canon PowerShot G9", 0, 0, { 7368,-2141,-598,-5621,13254,2625,-1418,1696,5743 } }, { "Canon PowerShot Pro1", 0, 0, @@ -7142,6 +7235,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 14134,-5576,-1527,-1991,10719,1273,-1158,1929,3581 } }, { "Canon PowerShot SX220", 0, 0, /* DJC */ { 13898,-5076,-1447,-1405,10109,1297,-244,1860,3687 } }, + { "Canon IXUS 160", 0, 0, /* DJC */ + { 11657,-3781,-1136,-3544,11262,2283,-160,1219,4700 } }, { "Casio EX-S20", 0, 0, /* DJC */ { 11634,-3924,-1128,-4968,12954,2015,-1588,2648,7206 } }, { "Casio EX-Z750", 0, 0, /* DJC */ @@ -7156,6 +7251,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 20183,-4295,-423,-3940,15330,3985,-280,4870,9800 } }, { "Contax N Digital", 0, 0xf1e, { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, + { "DXO ONE", 0, 0, + { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, { "Epson R-D1", 0, 0, { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, { "Fujifilm E550", 0, 0, @@ -7236,25 +7333,31 @@ void CLASS adobe_coeff (const char *make, const char *model) { 11768,-4971,-1133,-4904,12927,2183,-480,1723,4605 } }, { "Fujifilm X30", 0, 0, { 12328,-5256,-1144,-4469,12927,1675,-87,1291,4351 } }, + { "Fujifilm X70", 0, 0, + { 10450,-4329,-878,-3217,11105,2421,-752,1758,6519 } }, { "Fujifilm X-Pro1", 0, 0, { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, + { "Fujifilm X-Pro2", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, { "Fujifilm X-A1", 0, 0, { 11086,-4555,-839,-3512,11310,2517,-815,1341,5940 } }, { "Fujifilm X-A2", 0, 0, { 10763,-4560,-917,-3346,11311,2322,-475,1135,5843 } }, { "Fujifilm X-E1", 0, 0, { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, + { "Fujifilm X-E2S", 0, 0, + { 11562,-5118,-961,-3022,11007,2311,-525,1569,6097 } }, { "Fujifilm X-E2", 0, 0, { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, { "Fujifilm X-M1", 0, 0, { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, { "Fujifilm X-S1", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, - { "Fujifilm X-T1", 0, 0, + { "Fujifilm X-T1", 0, 0, /* also X-T10 */ { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, { "Fujifilm XF1", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, - { "Fujifilm XQ", 0, 0, // XQ1 and XQ2 + { "Fujifilm XQ", 0, 0, /* XQ1 and XQ2 */ { 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 } }, { "Imacon Ixpress", 0, 0, /* DJC */ { 7025,-1415,-704,-5188,13765,1424,-1248,2742,6038 } }, @@ -7396,8 +7499,12 @@ void CLASS adobe_coeff (const char *make, const char *model) { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, { "Nikon D5500", 0, 0, { 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 } }, + { "Nikon D500", 0, 0, + { 8813,-3210,-1036,-4703,12868,2021,-1054,1940,6129 } }, { "Nikon D50", 0, 0, { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, + { "Nikon D5", 0, 0, + { 9200,-3522,-992,-5755,13803,2117,-753,1486,6338 } }, { "Nikon D600", 0, 0x3e07, { 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 } }, { "Nikon D610", 0, 0, @@ -7408,8 +7515,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, { "Nikon D7100", 0, 0, { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, - { "Nikon D7200", 0, 0, /* DJC */ - { 6111,-2759,-358,-5108,10766,4343,-769,1691,8030 } }, + { "Nikon D7200", 0, 0, + { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, { "Nikon D750", 0, 0, { 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 } }, { "Nikon D700", 0, 0, @@ -7474,8 +7581,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, { "Nikon 1 J4", 0, 0, { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, - { "Nikon 1 J5", 0, 0, /* DJC */ - { 2621,-856,500,-4471,8761,5711,-1321,2644,11945 } }, + { "Nikon 1 J5", 0, 0, + { 7520,-2518,-645,-3844,12102,1945,-913,2249,6835 } }, { "Nikon 1 S2", 200, 0, { 6612,-1342,-618,-3338,11055,2623,-174,1792,5075 } }, { "Nikon 1 V2", 0, 0, @@ -7486,6 +7593,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, { "Nikon 1 ", 0, 0, /* J1, J2, S1, V1 */ { 8994,-2667,-865,-4594,12324,2552,-699,1786,6260 } }, + { "Olympus AIR A01", 0, 0, + { 8992,-3093,-639,-2563,10721,2122,-437,1270,5473 } }, { "Olympus C5050", 0, 0, { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } }, { "Olympus C5060", 0, 0, @@ -7556,7 +7665,7 @@ void CLASS adobe_coeff (const char *make, const char *model) { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, { "Olympus E-PM2", 0, 0, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, - { "Olympus E-M10", 0, 0, + { "Olympus E-M10", 0, 0, /* also E-M10 Mark II */ { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-M1", 0, 0, { 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 } }, @@ -7564,6 +7673,10 @@ void CLASS adobe_coeff (const char *make, const char *model) { 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 } }, { "Olympus E-M5", 0, 0xfe1, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus PEN-F", 0, 0, + { 9476,-3182,-765,-2613,10958,1893,-449,1315,5268 } }, + { "Olympus SH-2", 0, 0, + { 10156,-3425,-1077,-2611,11177,1624,-385,1592,5080 } }, { "Olympus SP350", 0, 0, { 12078,-4836,-1069,-6671,14306,2578,-786,939,7418 } }, { "Olympus SP3", 0, 0, @@ -7580,6 +7693,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 11522,-4044,-1146,-4736,12172,2904,-988,1829,6039 } }, { "Olympus STYLUS1", 0, 0, { 8360,-2420,-880,-3928,12353,1739,-1381,2416,5173 } }, + { "Olympus TG-4", 0, 0, + { 11426,-4159,-1126,-2066,10678,1593,-120,1327,4998 } }, { "Olympus XZ-10", 0, 0, { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, { "Olympus XZ-1", 0, 0, @@ -7614,6 +7729,12 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8843,-2837,-625,-5025,12644,2668,-411,1234,7410 } }, { "Pentax K-r", 0, 0, { 9895,-3077,-850,-5304,13035,2521,-883,1768,6936 } }, + { "Pentax K-1", 0, 0, + { 8566,-2746,-1201,-3612,12204,1550,-893,1680,6264 } }, + { "Pentax K-30", 0, 0, + { 8710,-2632,-1167,-3995,12301,1881,-981,1719,6535 } }, + { "Pentax K-3 II", 0, 0, + { 8626,-2607,-1155,-3995,12301,1881,-1039,1822,6925 } }, { "Pentax K-3", 0, 0, { 7415,-2052,-721,-5186,12788,2682,-1446,2157,6773 } }, { "Pentax K-5 II", 0, 0, @@ -7624,6 +7745,10 @@ void CLASS adobe_coeff (const char *make, const char *model) { 9142,-2947,-678,-8648,16967,1663,-2224,2898,8615 } }, { "Pentax K-S1", 0, 0, { 8512,-3211,-787,-4167,11966,2487,-638,1288,6054 } }, + { "Pentax K-S2", 0, 0, + { 8662,-3280,-798,-3928,11771,2444,-586,1232,6054 } }, + { "Pentax Q-S1", 0, 0, + { 12995,-5593,-1107,-1879,10139,2027,-64,1233,4919 } }, { "Pentax 645D", 0, 0x3e00, { 10646,-3593,-1158,-3329,11699,1831,-667,2874,6287 } }, { "Panasonic DMC-CM1", 15, 0, @@ -7634,6 +7759,10 @@ void CLASS adobe_coeff (const char *make, const char *model) { 9932,-3060,-935,-5809,13331,2753,-1267,2155,5575 } }, { "Panasonic DMC-FZ28", 15, 0xf96, { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } }, + { "Panasonic DMC-FZ330", 15, 0, + { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } }, + { "Panasonic DMC-FZ300", 15, 0, + { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } }, { "Panasonic DMC-FZ30", 0, 0xf94, { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, { "Panasonic DMC-FZ3", 15, 0, @@ -7714,6 +7843,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 7798,-2562,-740,-3879,11584,2613,-1055,2248,5434 } }, { "Panasonic DMC-G6", 15, 0xfff, { 8294,-2891,-651,-3869,11590,2595,-1183,2267,5352 } }, + { "Panasonic DMC-G7", 15, 0xfff, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-GF1", 15, 0xf92, { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, { "Panasonic DMC-GF2", 15, 0xfff, @@ -7726,6 +7857,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8130,-2801,-946,-3520,11289,2552,-1314,2511,5791 } }, { "Panasonic DMC-GF7", 15, 0, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DMC-GF8", 15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-GH1", 15, 0xf92, { 6299,-1466,-532,-6535,13852,2969,-2331,3112,5984 } }, { "Panasonic DMC-GH2", 15, 0xf95, @@ -7742,6 +7875,12 @@ void CLASS adobe_coeff (const char *make, const char *model) { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, { "Panasonic DMC-GX7", 15, 0, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DMC-GX8", 15, 0, + { 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 } }, + { "Panasonic DMC-TZ1", 15, 0, + { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, + { "Panasonic DMC-ZS1", 15, 0, + { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Panasonic DMC-TZ6", 15, 0, { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } }, { "Panasonic DMC-ZS4", 15, 0, @@ -7750,6 +7889,20 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 } }, { "Panasonic DMC-ZS5", 15, 0, { 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 } }, + { "Panasonic DMC-TZ8", 15, 0, + { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, + { "Panasonic DMC-ZS6", 15, 0, + { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, + { "Leica S (Typ 007)", 0, 0, + { 6063,-2234,-231,-5210,13787,1500,-1043,2866,6997 } }, + { "Leica X", 0, 0, /* X and X-U, both (Typ 113) */ + { 7712,-2059,-653,-3882,11494,2726,-710,1332,5958 } }, + { "Leica Q (Typ 116)", 0, 0, + { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830 } }, + { "Leica M (Typ 262)", 0, 0, + { 6653,-1486,-611,-4221,13303,929,-881,2416,7226 } }, + { "Leica SL (Typ 601)", 0, 0, + { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830} }, { "Phase One H 20", 0, 0, /* DJC */ { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } }, { "Phase One H 25", 0, 0, @@ -7764,8 +7917,14 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, { "Phase One P65", 0, 0, { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, + { "Photron BC2-HD", 0, 0, /* DJC */ + { 14603,-4122,-528,-1810,9794,2017,-297,2763,5936 } }, { "Red One", 704, 0xffff, /* DJC */ { 21014,-7891,-2613,-3056,12201,856,-2203,5125,8042 } }, + { "Ricoh GR II", 0, 0, + { 4630,-834,-423,-4977,12805,2417,-638,1467,6115 } }, + { "Ricoh GR", 0, 0, + { 3708,-543,-160,-5381,12254,3556,-1471,1929,8234 } }, { "Samsung EX1", 0, 0x3e00, { 8898,-2498,-994,-3144,11328,2066,-760,1381,4576 } }, { "Samsung EX2F", 0, 0x7ff, @@ -7774,6 +7933,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, { "Samsung NX mini", 0, 0, { 5222,-1196,-550,-6540,14649,2009,-1666,2819,5657 } }, + { "Samsung NX3300", 0, 0, + { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, { "Samsung NX3000", 0, 0, { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, { "Samsung NX30", 0, 0, /* NX30, NX300, NX300M */ @@ -7790,8 +7951,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, { "Samsung NX10", 0, 0, /* also NX100 */ { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, - { "Samsung NX500", 0, 0, /* DJC */ - { 10196,-4532,-272,-3888,11489,2400,-1203,2424,9173 } }, + { "Samsung NX500", 0, 0, + { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, { "Samsung NX5", 0, 0, { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, { "Samsung NX1", 0, 0, @@ -7808,17 +7969,19 @@ void CLASS adobe_coeff (const char *make, const char *model) { 16442,-2956,-2422,-2877,12128,750,-1136,6066,4559 } }, { "Sony DSC-F828", 0, 0, { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } }, - { "Sony DSC-R1", 512, 0, + { "Sony DSC-R1", 0, 0, { 8512,-2641,-694,-8042,15670,2526,-1821,2117,7414 } }, { "Sony DSC-V3", 0, 0, { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } }, - { "Sony DSC-RX100M", 200, 0, /* M2 and M3 */ + { "Sony DSC-RX100M", 0, 0, /* M2, M3, and M4 */ { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, - { "Sony DSC-RX100", 200, 0, + { "Sony DSC-RX100", 0, 0, { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } }, - { "Sony DSC-RX10", 200, 0, + { "Sony DSC-RX10", 0, 0, /* also RX10M2 */ { 6679,-1825,-745,-5047,13256,1953,-1580,2422,5183 } }, - { "Sony DSC-RX1", 128, 0, + { "Sony DSC-RX1RM2", 0, 0, + { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, + { "Sony DSC-RX1", 0, 0, { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, { "Sony DSLR-A100", 0, 0xfeb, { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } }, @@ -7836,71 +7999,77 @@ void CLASS adobe_coeff (const char *make, const char *model) { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, { "Sony DSLR-A390", 0, 0, { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, - { "Sony DSLR-A450", 128, 0xfeb, + { "Sony DSLR-A450", 0, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, - { "Sony DSLR-A580", 128, 0xfeb, + { "Sony DSLR-A580", 0, 0xfeb, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, - { "Sony DSLR-A500", 128, 0xfeb, + { "Sony DSLR-A500", 0, 0xfeb, { 6046,-1127,-278,-5574,13076,2786,-691,1419,7625 } }, - { "Sony DSLR-A5", 128, 0xfeb, + { "Sony DSLR-A5", 0, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, - { "Sony DSLR-A700", 128, 0, + { "Sony DSLR-A700", 0, 0, { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } }, - { "Sony DSLR-A850", 128, 0, + { "Sony DSLR-A850", 0, 0, { 5413,-1162,-365,-5665,13098,2866,-608,1179,8440 } }, - { "Sony DSLR-A900", 128, 0, + { "Sony DSLR-A900", 0, 0, { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } }, - { "Sony ILCA-77M2", 128, 0, + { "Sony ILCA-68", 0, 0, + { 6435,-1903,-536,-4722,12449,2550,-663,1363,6517 } }, + { "Sony ILCA-77M2", 0, 0, { 5991,-1732,-443,-4100,11989,2381,-704,1467,5992 } }, - { "Sony ILCE-7M2", 128, 0, + { "Sony ILCE-6300", 0, 0, + { 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 } }, + { "Sony ILCE-7M2", 0, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, - { "Sony ILCE-7S", 128, 0, + { "Sony ILCE-7S", 0, 0, /* also ILCE-7SM2 */ { 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 } }, - { "Sony ILCE-7R", 128, 0, + { "Sony ILCE-7RM2", 0, 0, + { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, + { "Sony ILCE-7R", 0, 0, { 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 } }, - { "Sony ILCE-7", 128, 0, + { "Sony ILCE-7", 0, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, - { "Sony ILCE", 128, 0, /* 3000, 5000, 5100, 6000, and QX1 */ + { "Sony ILCE", 0, 0, /* 3000, 5000, 5100, 6000, and QX1 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony NEX-5N", 128, 0, + { "Sony NEX-5N", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony NEX-5R", 128, 0, + { "Sony NEX-5R", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, - { "Sony NEX-5T", 128, 0, + { "Sony NEX-5T", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, - { "Sony NEX-3N", 128, 0, + { "Sony NEX-3N", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, { "Sony NEX-3", 138, 0, /* DJC */ { 6907,-1256,-645,-4940,12621,2320,-1710,2581,6230 } }, { "Sony NEX-5", 116, 0, /* DJC */ { 6807,-1350,-342,-4216,11649,2567,-1089,2001,6420 } }, - { "Sony NEX-3", 128, 0, /* Adobe */ + { "Sony NEX-3", 0, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, - { "Sony NEX-5", 128, 0, /* Adobe */ + { "Sony NEX-5", 0, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, - { "Sony NEX-6", 128, 0, + { "Sony NEX-6", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, - { "Sony NEX-7", 128, 0, + { "Sony NEX-7", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, - { "Sony NEX", 128, 0, /* NEX-C3, NEX-F3 */ + { "Sony NEX", 0, 0, /* NEX-C3, NEX-F3 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A33", 128, 0, + { "Sony SLT-A33", 0, 0, { 6069,-1221,-366,-5221,12779,2734,-1024,2066,6834 } }, - { "Sony SLT-A35", 128, 0, + { "Sony SLT-A35", 0, 0, { 5986,-1618,-415,-4557,11820,3120,-681,1404,6971 } }, - { "Sony SLT-A37", 128, 0, + { "Sony SLT-A37", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A55", 128, 0, + { "Sony SLT-A55", 0, 0, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, - { "Sony SLT-A57", 128, 0, + { "Sony SLT-A57", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A58", 128, 0, + { "Sony SLT-A58", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A65", 128, 0, + { "Sony SLT-A65", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, - { "Sony SLT-A77", 128, 0, + { "Sony SLT-A77", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, - { "Sony SLT-A99", 128, 0, + { "Sony SLT-A99", 0, 0, { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, }; double cam_xyz[4][3]; @@ -8057,6 +8226,8 @@ void CLASS identify() { 5712, 3774, 62, 20, 10, 2 }, { 5792, 3804, 158, 51, 0, 0 }, { 5920, 3950, 122, 80, 2, 0 }, + { 6096, 4056, 72, 34, 0, 0 }, + { 6288, 4056, 264, 34, 0, 0 }, { 8896, 5920, 160, 64, 0, 0 }, }; static const struct { @@ -8070,6 +8241,7 @@ void CLASS identify() { 0x261, "EOS 50D" }, { 0x281, "EOS-1D Mark IV" }, { 0x287, "EOS 60D" }, { 0x167, "EOS-1DS" }, { 0x325, "EOS 70D" }, + { 0x350, "EOS 80D" }, { 0x328, "EOS-1D X Mark II" }, { 0x170, "EOS 300D" }, { 0x188, "EOS-1Ds Mark II" }, { 0x176, "EOS 450D" }, { 0x215, "EOS-1Ds Mark III" }, { 0x189, "EOS 350D" }, { 0x324, "EOS-1D C" }, @@ -8079,9 +8251,12 @@ void CLASS identify() { 0x286, "EOS 600D" }, { 0x285, "EOS 5D Mark III" }, { 0x301, "EOS 650D" }, { 0x302, "EOS 6D" }, { 0x326, "EOS 700D" }, { 0x250, "EOS 7D" }, + { 0x393, "EOS 750D" }, { 0x289, "EOS 7D Mark II" }, + { 0x347, "EOS 760D" }, { 0x254, "EOS 1000D" }, { 0x288, "EOS 1100D" }, - { 0x327, "EOS 1200D" }, + { 0x327, "EOS 1200D" }, { 0x382, "Canon EOS 5DS" }, + { 0x404, "EOS 1300D" }, { 0x401, "Canon EOS 5DS R" }, { 0x346, "EOS 100D" }, }, sonique[] = { { 0x002, "DSC-R1" }, { 0x100, "DSLR-A100" }, @@ -8109,7 +8284,10 @@ void CLASS identify() { 0x139, "ILCE-5000" }, { 0x13d, "DSC-RX100M3" }, { 0x13e, "ILCE-7S" }, { 0x13f, "ILCA-77M2" }, { 0x153, "ILCE-5100" }, { 0x154, "ILCE-7M2" }, - { 0x15a, "ILCE-QX1" }, + { 0x155, "DSC-RX100M4" },{ 0x156, "DSC-RX10M2" }, + { 0x158, "DSC-RX1RM2" }, { 0x15a, "ILCE-QX1" }, + { 0x15b, "ILCE-7RM2" }, { 0x15e, "ILCE-7SM2" }, + { 0x161, "ILCA-68" }, { 0x165, "ILCE-6300" }, }; static const struct { unsigned fsize; @@ -8146,6 +8324,7 @@ void CLASS identify() { 19131120,4168,3060,92,16, 4, 1,40,0x94,0,2,"Canon","PowerShot SX220 HS" }, { 21936096,4464,3276,25,10,73,12,40,0x16,0,2,"Canon","PowerShot SX30 IS" }, { 24724224,4704,3504, 8,16,56, 8,40,0x94,0,2,"Canon","PowerShot A3300 IS" }, + { 30858240,5248,3920, 8,16,56,16,40,0x94,0,2,"Canon","IXUS 160" }, { 1976352,1632,1211, 0, 2, 0, 1, 0,0x94,0,1,"Casio","QV-2000UX" }, { 3217760,2080,1547, 0, 0,10, 1, 0,0x94,0,1,"Casio","QV-3*00EX" }, { 6218368,2585,1924, 0, 0, 9, 0, 0,0x94,0,1,"Casio","QV-5700" }, @@ -8204,6 +8383,8 @@ void CLASS identify() { 4841984,2090,1544, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S" }, { 6114240,2346,1737, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S4" }, { 10702848,3072,2322, 0, 0, 0,21,30,0x94,0,1,"Pentax","Optio 750Z" }, + { 4147200,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD" }, + { 4151666,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD",8 }, { 13248000,2208,3000, 0, 0, 0, 0,13,0x61,0,0,"Pixelink","A782" }, { 6291456,2048,1536, 0, 0, 0, 0,96,0x61,0,0,"RoverShot","3320AF" }, { 311696, 644, 484, 0, 0, 0, 0, 0,0x16,0,8,"ST Micro","STV680 VGA" }, @@ -8220,7 +8401,7 @@ void CLASS identify() static const char *corp[] = { "AgfaPhoto", "Canon", "Casio", "Epson", "Fujifilm", "Mamiya", "Minolta", "Motorola", "Kodak", "Konica", "Leica", - "Nikon", "Nokia", "Olympus", "Pentax", "Phase One", "Ricoh", + "Nikon", "Nokia", "Olympus", "Ricoh", "Pentax", "Phase One", "Samsung", "Sigma", "Sinar", "Sony" }; char head[32], *cp; int hlen, flen, fsize, zero_fsize=1, i, c; @@ -8387,7 +8568,7 @@ void CLASS identify() parse_foveon(); else if (!memcmp (head,"CI",2)) parse_cine(); - else + if (make[0] == 0) for (zero_fsize=i=0; i < sizeof table / sizeof *table; i++) if (fsize == table[i].fsize) { strcpy (make, table[i].make ); @@ -8482,9 +8663,10 @@ void CLASS identify() width = 4014; if (dng_version) { if (filters == UINT_MAX) filters = 0; - if (filters) is_raw = tiff_samples; - else colors = tiff_samples; + if (filters) is_raw *= tiff_samples; + else colors = tiff_samples; switch (tiff_compress) { + case 0: case 1: load_raw = &CLASS packed_dng_load_raw; break; case 7: load_raw = &CLASS lossless_dng_load_raw; break; case 34892: load_raw = &CLASS lossy_dng_load_raw; break; @@ -8536,6 +8718,8 @@ void CLASS identify() top_margin = filters = 0; strcpy (model,"C603"); } + if (!strcmp(make,"Sony") && raw_width > 3888) + black = 128 << (tiff_bps - 12); if (is_foveon) { if (height*2 < width) pixel_aspect = 0.5; if (height > width) pixel_aspect = 2; @@ -8550,6 +8734,10 @@ void CLASS identify() SWAP(height,width); SWAP(raw_height,raw_width); } + if (width == 7200 && height == 3888) { + raw_width = width = 6480; + raw_height = height = 4320; + } filters = 0; tiff_samples = colors = 3; load_raw = &CLASS canon_sraw_load_raw; @@ -8725,7 +8913,7 @@ canon_a5: top_margin = (raw_height - height) >> 2 << 1; left_margin = (raw_width - width ) >> 2 << 1; if (width == 2848 || width == 3664) filters = 0x16161616; - if (width == 4032 || width == 4952) left_margin = 0; + if (width == 4032 || width == 4952 || width == 6032) left_margin = 0; if (width == 3328 && (width -= 66)) left_margin = 34; if (width == 4936) left_margin = 4; if (!strcmp(model,"HS50EXR") || @@ -8968,6 +9156,8 @@ konica_400z: thumb_length = flen - (thumb_offset = 0xa39800); thumb_height = 480; thumb_width = 640; + } else if (!strcmp(model,"TG-4")) { + width -= 16; } } else if (!strcmp(model,"N Digital")) { height = 2047; @@ -8995,16 +9185,29 @@ konica_400z: order = 0x4d4d; } else if (!strcmp(make,"Sony") && raw_width == 4288) { width -= 32; + } else if (!strcmp(make,"Sony") && raw_width == 4600) { + if (!strcmp(model,"DSLR-A350")) + height -= 4; + black = 0; } else if (!strcmp(make,"Sony") && raw_width == 4928) { if (height < 3280) width -= 8; } else if (!strcmp(make,"Sony") && raw_width == 5504) { width -= height > 3664 ? 8 : 32; + if (!strncmp(model,"DSC",3)) + black = 200 << (tiff_bps - 12); } else if (!strcmp(make,"Sony") && raw_width == 6048) { width -= 24; if (strstr(model,"RX1") || strstr(model,"A99")) width -= 6; } else if (!strcmp(make,"Sony") && raw_width == 7392) { width -= 30; + } else if (!strcmp(make,"Sony") && raw_width == 8000) { + width -= 32; + if (!strncmp(model,"DSC",3)) { + tiff_bps = 14; + load_raw = &CLASS unpacked_load_raw; + black = 512; + } } else if (!strcmp(model,"DSLR-A100")) { if (width == 3880) { height--; @@ -9016,8 +9219,6 @@ konica_400z: load_flags = 2; } filters = 0x61616161; - } else if (!strcmp(model,"DSLR-A350")) { - height -= 4; } else if (!strcmp(model,"PIXL")) { height -= top_margin = 4; width -= left_margin = 32; @@ -9082,6 +9283,7 @@ bw: colors = 1; width = 768; data_offset = 1152; load_raw = &CLASS kodak_radc_load_raw; + tiff_bps = 12; } else if (strstr(model,"DC50")) { strcpy (model, "DC50"); height = 512; @@ -9160,7 +9362,7 @@ dng_skip: if (raw_color) adobe_coeff ("Apple","Quicktake"); if (fuji_width) { fuji_width = width >> !fuji_layout; - if (~fuji_width & 1) filters = 0x49494949; + filters = fuji_width & 1 ? 0x94949494 : 0x49494949; width = (height >> fuji_layout) + fuji_width; height = width - 1; pixel_aspect = 1; @@ -9274,10 +9476,14 @@ void CLASS convert_to_rgb() { { 0.529317, 0.330092, 0.140588 }, { 0.098368, 0.873465, 0.028169 }, { 0.016879, 0.117663, 0.865457 } }; + static const double aces_rgb[3][3] = + { { 0.432996, 0.375380, 0.189317 }, + { 0.089427, 0.816523, 0.102989 }, + { 0.019165, 0.118150, 0.941914 } }; static const double (*out_rgb[])[3] = - { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb }; + { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb, aces_rgb }; static const char *name[] = - { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ" }; + { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ", "ACES" }; static const unsigned phead[] = { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, 0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d }; @@ -9298,7 +9504,7 @@ void CLASS convert_to_rgb() gamma_curve (gamm[0], gamm[1], 0, 0); memcpy (out_cam, rgb_cam, sizeof out_cam); raw_color |= colors == 1 || document_mode || - output_color < 1 || output_color > 5; + output_color < 1 || output_color > 6; if (!raw_color) { oprof = (unsigned *) calloc (phead[0], 1); merror (oprof, "convert_to_rgb()"); @@ -9461,21 +9667,25 @@ struct tiff_hdr { char desc[512], make[64], model[64], soft[32], date[20], artist[64]; }; -void CLASS tiff_set (ushort *ntag, +void CLASS tiff_set (struct tiff_hdr *th, ushort *ntag, ushort tag, ushort type, int count, int val) { struct tiff_tag *tt; int c; tt = (struct tiff_tag *)(ntag+1) + (*ntag)++; - tt->tag = tag; - tt->type = type; - tt->count = count; - if (type < 3 && count <= 4) + tt->val.i = val; + if (type == 1 && count <= 4) FORC(4) tt->val.c[c] = val >> (c << 3); - else if (type == 3 && count <= 2) + else if (type == 2) { + count = strnlen((char *)th + val, count-1) + 1; + if (count <= 4) + FORC(4) tt->val.c[c] = ((char *)th)[val+c]; + } else if (type == 3 && count <= 2) FORC(2) tt->val.s[c] = val >> (c << 4); - else tt->val.i = val; + tt->count = count; + tt->type = type; + tt->tag = tag; } #define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) @@ -9489,55 +9699,6 @@ void CLASS tiff_head (struct tiff_hdr *th, int full) th->order = htonl(0x4d4d4949) >> 16; th->magic = 42; th->ifd = 10; - if (full) { - tiff_set (&th->ntag, 254, 4, 1, 0); - tiff_set (&th->ntag, 256, 4, 1, width); - tiff_set (&th->ntag, 257, 4, 1, height); - tiff_set (&th->ntag, 258, 3, colors, output_bps); - if (colors > 2) - th->tag[th->ntag-1].val.i = TOFF(th->bps); - FORC4 th->bps[c] = output_bps; - tiff_set (&th->ntag, 259, 3, 1, 1); - tiff_set (&th->ntag, 262, 3, 1, 1 + (colors > 1)); - } - tiff_set (&th->ntag, 270, 2, 512, TOFF(th->desc)); - tiff_set (&th->ntag, 271, 2, 64, TOFF(th->make)); - tiff_set (&th->ntag, 272, 2, 64, TOFF(th->model)); - if (full) { - if (oprof) psize = ntohl(oprof[0]); - tiff_set (&th->ntag, 273, 4, 1, sizeof *th + psize); - tiff_set (&th->ntag, 277, 3, 1, colors); - tiff_set (&th->ntag, 278, 4, 1, height); - tiff_set (&th->ntag, 279, 4, 1, height*width*colors*output_bps/8); - } else - tiff_set (&th->ntag, 274, 3, 1, "12435867"[flip]-'0'); - tiff_set (&th->ntag, 282, 5, 1, TOFF(th->rat[0])); - tiff_set (&th->ntag, 283, 5, 1, TOFF(th->rat[2])); - tiff_set (&th->ntag, 284, 3, 1, 1); - tiff_set (&th->ntag, 296, 3, 1, 2); - tiff_set (&th->ntag, 305, 2, 32, TOFF(th->soft)); - tiff_set (&th->ntag, 306, 2, 20, TOFF(th->date)); - tiff_set (&th->ntag, 315, 2, 64, TOFF(th->artist)); - tiff_set (&th->ntag, 34665, 4, 1, TOFF(th->nexif)); - if (psize) tiff_set (&th->ntag, 34675, 7, psize, sizeof *th); - tiff_set (&th->nexif, 33434, 5, 1, TOFF(th->rat[4])); - tiff_set (&th->nexif, 33437, 5, 1, TOFF(th->rat[6])); - tiff_set (&th->nexif, 34855, 3, 1, iso_speed); - tiff_set (&th->nexif, 37386, 5, 1, TOFF(th->rat[8])); - if (gpsdata[1]) { - tiff_set (&th->ntag, 34853, 4, 1, TOFF(th->ngps)); - tiff_set (&th->ngps, 0, 1, 4, 0x202); - tiff_set (&th->ngps, 1, 2, 2, gpsdata[29]); - tiff_set (&th->ngps, 2, 5, 3, TOFF(th->gps[0])); - tiff_set (&th->ngps, 3, 2, 2, gpsdata[30]); - tiff_set (&th->ngps, 4, 5, 3, TOFF(th->gps[6])); - tiff_set (&th->ngps, 5, 1, 1, gpsdata[31]); - tiff_set (&th->ngps, 6, 5, 1, TOFF(th->gps[18])); - tiff_set (&th->ngps, 7, 5, 3, TOFF(th->gps[12])); - tiff_set (&th->ngps, 18, 2, 12, TOFF(th->gps[20])); - tiff_set (&th->ngps, 29, 2, 12, TOFF(th->gps[23])); - memcpy (th->gps, gpsdata, sizeof th->gps); - } th->rat[0] = th->rat[2] = 300; th->rat[1] = th->rat[3] = 1; FORC(6) th->rat[4+c] = 1000000; @@ -9552,6 +9713,55 @@ void CLASS tiff_head (struct tiff_hdr *th, int full) sprintf (th->date, "%04d:%02d:%02d %02d:%02d:%02d", t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); strncpy (th->artist, artist, 64); + if (full) { + tiff_set (th, &th->ntag, 254, 4, 1, 0); + tiff_set (th, &th->ntag, 256, 4, 1, width); + tiff_set (th, &th->ntag, 257, 4, 1, height); + tiff_set (th, &th->ntag, 258, 3, colors, output_bps); + if (colors > 2) + th->tag[th->ntag-1].val.i = TOFF(th->bps); + FORC4 th->bps[c] = output_bps; + tiff_set (th, &th->ntag, 259, 3, 1, 1); + tiff_set (th, &th->ntag, 262, 3, 1, 1 + (colors > 1)); + } + tiff_set (th, &th->ntag, 270, 2, 512, TOFF(th->desc)); + tiff_set (th, &th->ntag, 271, 2, 64, TOFF(th->make)); + tiff_set (th, &th->ntag, 272, 2, 64, TOFF(th->model)); + if (full) { + if (oprof) psize = ntohl(oprof[0]); + tiff_set (th, &th->ntag, 273, 4, 1, sizeof *th + psize); + tiff_set (th, &th->ntag, 277, 3, 1, colors); + tiff_set (th, &th->ntag, 278, 4, 1, height); + tiff_set (th, &th->ntag, 279, 4, 1, height*width*colors*output_bps/8); + } else + tiff_set (th, &th->ntag, 274, 3, 1, "12435867"[flip]-'0'); + tiff_set (th, &th->ntag, 282, 5, 1, TOFF(th->rat[0])); + tiff_set (th, &th->ntag, 283, 5, 1, TOFF(th->rat[2])); + tiff_set (th, &th->ntag, 284, 3, 1, 1); + tiff_set (th, &th->ntag, 296, 3, 1, 2); + tiff_set (th, &th->ntag, 305, 2, 32, TOFF(th->soft)); + tiff_set (th, &th->ntag, 306, 2, 20, TOFF(th->date)); + tiff_set (th, &th->ntag, 315, 2, 64, TOFF(th->artist)); + tiff_set (th, &th->ntag, 34665, 4, 1, TOFF(th->nexif)); + if (psize) tiff_set (th, &th->ntag, 34675, 7, psize, sizeof *th); + tiff_set (th, &th->nexif, 33434, 5, 1, TOFF(th->rat[4])); + tiff_set (th, &th->nexif, 33437, 5, 1, TOFF(th->rat[6])); + tiff_set (th, &th->nexif, 34855, 3, 1, iso_speed); + tiff_set (th, &th->nexif, 37386, 5, 1, TOFF(th->rat[8])); + if (gpsdata[1]) { + tiff_set (th, &th->ntag, 34853, 4, 1, TOFF(th->ngps)); + tiff_set (th, &th->ngps, 0, 1, 4, 0x202); + tiff_set (th, &th->ngps, 1, 2, 2, gpsdata[29]); + tiff_set (th, &th->ngps, 2, 5, 3, TOFF(th->gps[0])); + tiff_set (th, &th->ngps, 3, 2, 2, gpsdata[30]); + tiff_set (th, &th->ngps, 4, 5, 3, TOFF(th->gps[6])); + tiff_set (th, &th->ngps, 5, 1, 1, gpsdata[31]); + tiff_set (th, &th->ngps, 6, 5, 1, TOFF(th->gps[18])); + tiff_set (th, &th->ngps, 7, 5, 3, TOFF(th->gps[12])); + tiff_set (th, &th->ngps, 18, 2, 12, TOFF(th->gps[20])); + tiff_set (th, &th->ngps, 29, 2, 12, TOFF(th->gps[23])); + memcpy (th->gps, gpsdata, sizeof th->gps); + } } void CLASS jpeg_thumb() @@ -9672,7 +9882,7 @@ int CLASS main (int argc, const char **argv) puts(_("-n Set threshold for wavelet denoising")); puts(_("-H [0-9] Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)")); puts(_("-t [0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW)")); - puts(_("-o [0-5] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ)")); + puts(_("-o [0-6] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ,ACES)")); #ifndef NO_LCMS puts(_("-o Apply output ICC profile from file")); puts(_("-p Apply camera ICC profile from file or \"embed\"")); diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index c0dbd816d..8ebc073d1 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -12,7 +12,7 @@ /* dcraw.c -- Dave Coffin's raw photo decoder - Copyright 1997-2015 by Dave Coffin, dcoffin a cybercom o net + Copyright 1997-2016 by Dave Coffin, dcoffin a cybercom o net This is a command-line ANSI C program to convert raw photos from any digital camera on any computer running any operating system. @@ -31,11 +31,11 @@ *If you have not modified dcraw.c in any way, a link to my homepage qualifies as "full source code". - $Revision: 1.475 $ - $Date: 2015/04/11 00:08:36 $ + $Revision: 1.477 $ + $Date: 2016/05/10 21:30:43 $ */ -#define DCRAW_VERSION "9.25" +#define DCRAW_VERSION "9.27" #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -100,15 +100,6 @@ typedef unsigned long long UINT64; #define _(String) (String) #endif -#ifdef LJPEG_DECODE -#error Please compile dcraw.c by itself. -#error Do not link it with ljpeg_decode. -#endif - -#ifndef LONG_BIT -#define LONG_BIT (8 * sizeof (long)) -#endif - #define ushort UshORt typedef unsigned char uchar; typedef unsigned short ushort; @@ -787,17 +778,15 @@ struct jhead { int CLASS ljpeg_start (struct jhead *jh, int info_only) { - int c, tag; - ushort len; + ushort c, tag, len; uchar data[0x10000]; const uchar *dp; memset (jh, 0, sizeof *jh); jh->restart = INT_MAX; - fread (data, 2, 1, ifp); - if (data[1] != 0xd8) return 0; + if ((fgetc(ifp),fgetc(ifp)) != 0xd8) return 0; do { - fread (data, 2, 2, ifp); + if (!fread (data, 2, 2, ifp)) return 0; tag = data[0] << 8 | data[1]; len = (data[2] << 8 | data[3]) - 2; if (tag <= 0xff00) return 0; @@ -805,7 +794,9 @@ int CLASS ljpeg_start (struct jhead *jh, int info_only) switch (tag) { case 0xffc3: jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3; + case 0xffc1: case 0xffc0: + jh->algo = tag & 0xff; jh->bits = data[0]; jh->high = data[1] << 8 | data[2]; jh->wide = data[3] << 8 | data[4]; @@ -814,20 +805,25 @@ int CLASS ljpeg_start (struct jhead *jh, int info_only) break; case 0xffc4: if (info_only) break; - for (dp = data; dp < data+len && (c = *dp++) < 4; ) + for (dp = data; dp < data+len && !((c = *dp++) & -20); ) jh->free[c] = jh->huff[c] = make_decoder_ref (&dp); break; case 0xffda: jh->psv = data[1+data[0]*2]; jh->bits -= data[3+data[0]*2] & 15; break; + case 0xffdb: + FORC(64) jh->quant[c] = data[c*2+1] << 8 | data[c*2+2]; + break; case 0xffdd: jh->restart = data[0] << 8 | data[1]; } } while (tag != 0xffda); + if (jh->bits > 16 || jh->clrs > 6 || + !jh->bits || !jh->high || !jh->wide || !jh->clrs) return 0; if (info_only) return 1; - if (jh->clrs > 6 || !jh->huff[0]) return 0; - FORC(5) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c]; + if (!jh->huff[0]) return 0; + FORC(19) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c]; if (jh->sraw) { FORC(4) jh->huff[2+c] = jh->huff[1]; FORC(jh->sraw) jh->huff[1+c] = jh->huff[0]; @@ -1006,23 +1002,59 @@ void CLASS adobe_copy_pixel (unsigned row, unsigned col, ushort **rp) { int c; - if (is_raw == 2 && shot_select) (*rp)++; + if (tiff_samples == 2 && shot_select) (*rp)++; if (raw_image) { if (row < raw_height && col < raw_width) RAW(row,col) = curve[**rp]; - *rp += is_raw; + *rp += tiff_samples; } else { if (row < height && col < width) FORC(tiff_samples) image[row*width+col][c] = curve[(*rp)[c]]; *rp += tiff_samples; } - if (is_raw == 2 && shot_select) (*rp)--; + if (tiff_samples == 2 && shot_select) (*rp)--; +} + +void CLASS ljpeg_idct (struct jhead *jh) +{ + int c, i, j, len, skip, coef; + float work[3][8][8]; + static float cs[106] = { 0 }; + static const uchar zigzag[80] = + { 0, 1, 8,16, 9, 2, 3,10,17,24,32,25,18,11, 4, 5,12,19,26,33, + 40,48,41,34,27,20,13, 6, 7,14,21,28,35,42,49,56,57,50,43,36, + 29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54, + 47,55,62,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63 }; + + if (!cs[0]) + FORC(106) cs[c] = cos((c & 31)*M_PI/16)/2; + memset (work, 0, sizeof work); + work[0][0][0] = jh->vpred[0] += ljpeg_diff (jh->huff[0]) * jh->quant[0]; + for (i=1; i < 64; i++ ) { + len = gethuff (jh->huff[16]); + i += skip = len >> 4; + if (!(len &= 15) && skip < 15) break; + coef = getbits(len); + if ((coef & (1 << (len-1))) == 0) + coef -= (1 << len) - 1; + ((float *)work)[zigzag[i]] = coef * jh->quant[i]; + } + FORC(8) work[0][0][c] *= M_SQRT1_2; + FORC(8) work[0][c][0] *= M_SQRT1_2; + for (i=0; i < 8; i++) + for (j=0; j < 8; j++) + FORC(8) work[1][i][j] += work[0][i][c] * cs[(j*2+1)*c]; + for (i=0; i < 8; i++) + for (j=0; j < 8; j++) + FORC(8) work[2][i][j] += work[1][c][j] * cs[(i*2+1)*c]; + + FORC(64) jh->idct[c] = CLIP(((float *)work[2])[c]+0.5); } void CLASS lossless_dng_load_raw() { - unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col; + unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col, i, j; struct jhead jh; ushort *rp; @@ -1033,15 +1065,32 @@ void CLASS lossless_dng_load_raw() if (!ljpeg_start (&jh, 0)) break; jwide = jh.wide; if (filters) jwide *= jh.clrs; - jwide /= is_raw; - for (row=col=jrow=0; jrow < jh.high; jrow++) { - rp = ljpeg_row (jrow, &jh); - for (jcol=0; jcol < jwide; jcol++) { - adobe_copy_pixel (trow+row, tcol+col, &rp); - if (++col >= tile_width || col >= raw_width) - row += 1 + (col = 0); - } - } + jwide /= MIN (is_raw, tiff_samples); + switch (jh.algo) { + case 0xc1: + jh.vpred[0] = 16384; + getbits(-1); + for (jrow=0; jrow+7 < jh.high; jrow += 8) { + for (jcol=0; jcol+7 < jh.wide; jcol += 8) { + ljpeg_idct (&jh); + rp = jh.idct; + row = trow + jcol/tile_width + jrow*2; + col = tcol + jcol%tile_width; + for (i=0; i < 16; i+=2) + for (j=0; j < 8; j++) + adobe_copy_pixel (row+i, col+j, &rp); + } + } + break; + case 0xc3: + for (row=col=jrow=0; jrow < jh.high; jrow++) { + rp = ljpeg_row (jrow, &jh); + for (jcol=0; jcol < jwide; jcol++) { + adobe_copy_pixel (trow+row, tcol+col, &rp); + if (++col >= tile_width || col >= raw_width) + row += 1 + (col = 0); + } + } } fseek (ifp, save+4, SEEK_SET); if ((tcol += tile_width) >= raw_width) trow += tile_length + (tcol = 0); @@ -1685,8 +1734,7 @@ void CLASS phase_one_load_raw_c() pixel[col] = curve[pixel[col]]; } for (col=0; col < raw_width; col++) { - if (ph1.format != 8) pixel[col] <<= 2; - i = pixel[col] - ph1.black + i = (pixel[col] << 2*(ph1.format != 8)) - ph1.black + cblack[row][col >= ph1.split_col] + rblack[col][row >= ph1.split_row]; if (i > 0) RAW(row,col) = i; @@ -3111,6 +3159,8 @@ void CLASS smal_decode_segment (unsigned seg[2][2], int holes) fseek (ifp, seg[0][1]+1, SEEK_SET); getbits(-1); + if (seg[1][0] > raw_width*raw_height) + seg[1][0] = raw_width*raw_height; for (pix=seg[0][0]; pix < seg[1][0]; pix++) { for (s=0; s < 3; s++) { data = data << nbits | getbits(nbits); @@ -5237,7 +5287,7 @@ nf: order = 0x4949; FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4(); } if (tag == 0x3d && type == 3 && len == 4) - FORC4 cblack[c ^ c >> 1] = get2() >> (14-tiff_ifd[2].bps); + FORC4 cblack[c ^ c >> 1] = get2() >> (14-tiff_bps); if (tag == 0x81 && type == 4) { data_offset = get4(); fseek (ifp, data_offset + 41, SEEK_SET); @@ -5267,7 +5317,8 @@ nf: order = 0x4949; break; case 102: fseek (ifp, 6, SEEK_CUR); - goto get2_rggb; + FORC4 cam_mul[c ^ (c >> 1)] = get2(); + break; case 103: fseek (ifp, 16, SEEK_CUR); FORC4 cam_mul[c] = get2(); @@ -5301,7 +5352,7 @@ nf: order = 0x4949; if (tag == 0x200 && len == 4) FORC4 cblack[c ^ c >> 1] = get2(); if (tag == 0x201 && len == 4) - goto get2_rggb; + FORC4 cam_mul[c ^ (c >> 1)] = get2(); if (tag == 0x220 && type == 7) meta_offset = ftell(ifp); if (tag == 0x401 && type == 4 && len == 4) @@ -5347,7 +5398,7 @@ get2_256: } if ((tag | 0x70) == 0x2070 && (type == 4 || type == 13)) fseek (ifp, get4()+base, SEEK_SET); - if (tag == 0x2020) + if (tag == 0x2020 && !strncmp(buf,"OLYMP",5)) parse_thumb_note (base, 257, 258); if (tag == 0x2040) parse_makernote (base, 0x2040); @@ -5358,11 +5409,12 @@ get2_256: if (tag == 0x4001 && len > 500) { i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126; fseek (ifp, i, SEEK_CUR); -get2_rggb: FORC4 cam_mul[c ^ (c >> 1)] = get2(); - i = len >> 3 == 164 || len == 1506 ? 112:22; - fseek (ifp, i, SEEK_CUR); - FORC4 sraw_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; + } } if (tag == 0x4021 && get4() && get4()) FORC4 cam_mul[c] = 1024; @@ -5415,13 +5467,14 @@ void CLASS parse_exif (int base) while (entries--) { tiff_get (base, &tag, &type, &len, &save); switch (tag) { - case 33434: shutter = getreal(type); break; + case 33434: tiff_ifd[tiff_nifds-1].shutter = shutter = getreal(type); break; case 33437: aperture = getreal(type); break; case 34855: iso_speed = get2(); break; case 34866: if((!iso_speed) || iso_speed == 65535) iso_speed = get4();break; case 36867: case 36868: get_timestamp(0); break; case 37377: if ((expo = -getreal(type)) < 128) + tiff_ifd[tiff_nifds-1].shutter = shutter = pow (2, expo); break; case 37378: aperture = pow (2, getreal(type)/2); break; case 37386: focal_len = getreal(type); break; @@ -5664,6 +5717,8 @@ int CLASS parse_tiff_ifd (int base) case 61443: tiff_ifd[ifd].samples = len & 7; tiff_ifd[ifd].bps = getint(type); + if (tiff_bps < tiff_ifd[ifd].bps) + tiff_bps = tiff_ifd[ifd].bps; break; case 61446: raw_height = 0; @@ -5835,7 +5890,7 @@ int CLASS parse_tiff_ifd (int base) parse_kodak_ifd (base); break; case 33434: /* ExposureTime */ - shutter = getreal(type); + tiff_ifd[ifd].shutter = shutter = getreal(type); break; case 33437: /* FNumber */ aperture = getreal(type); @@ -5964,7 +6019,12 @@ int CLASS parse_tiff_ifd (int base) is_raw = 1; break; case 50708: /* UniqueCameraModel */ - fgets (model3, 64, ifp); + if (model[0]) break; + fgets (make, 64, ifp); + if ((cp = strchr(make,' '))) { + strcpy(model,cp+1); + *cp = 0; + } break; case 50710: /* CFAPlaneColor */ if (filters == 9) break; @@ -5979,10 +6039,7 @@ guess_cfa_pc: filters -= !filters; break; case 50711: /* CFALayout */ - if (get2() == 2) { - fuji_width = 1; - filters = 0x49494949; - } + if (get2() == 2) fuji_width = 1; break; case 291: case 50712: /* LinearizationTable */ @@ -6014,7 +6071,7 @@ guess_cfa_pc: break; case 50715: /* BlackLevelDeltaH */ case 50716: /* BlackLevelDeltaV */ - for (num=i=0; i < len; i++) + for (num=i=0; i < (len & 0xffff); i++) num += getreal(type); black += num/len + 0.5; break; @@ -6144,7 +6201,7 @@ int CLASS parse_tiff (int base) void CLASS apply_tiff() { - int max_samp=0, raw=-1, thm=-1, i; + int max_samp=0, ties=0, os, ns, raw=-1, thm=-1, i; struct jhead jh; thumb_misc = 16; @@ -6156,13 +6213,26 @@ void CLASS apply_tiff() thumb_height = jh.high; } } + for (i=tiff_nifds; i--; ) { + if (tiff_ifd[i].shutter) + shutter = tiff_ifd[i].shutter; + tiff_ifd[i].shutter = shutter; + } + for (i=0; i < tiff_nifds; i++) { if (max_samp < tiff_ifd[i].samples) max_samp = tiff_ifd[i].samples; if (max_samp > 3) max_samp = 3; + os = raw_width*raw_height; + ns = tiff_ifd[i].width*tiff_ifd[i].height; + if (tiff_bps) { + os *= tiff_bps; + ns *= tiff_ifd[i].bps; + } if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) && (tiff_ifd[i].width | tiff_ifd[i].height) < 0x10000 && - tiff_ifd[i].width*tiff_ifd[i].height > raw_width*raw_height) { + ns && ((ns > os && (ties = 1)) || + (ns == os && shot_select == ties++))) { raw_width = tiff_ifd[i].width; raw_height = tiff_ifd[i].height; tiff_bps = tiff_ifd[i].bps; @@ -6172,9 +6242,11 @@ void CLASS apply_tiff() tiff_samples = tiff_ifd[i].samples; tile_width = tiff_ifd[i].tile_width; tile_length = tiff_ifd[i].tile_length; + shutter = tiff_ifd[i].shutter; raw = i; } } + if (is_raw == 1 && ties) is_raw = ties; if (!tile_width ) tile_width = INT_MAX; if (!tile_length) tile_length = INT_MAX; for (i=tiff_nifds; i--; ) @@ -6257,8 +6329,8 @@ void CLASS apply_tiff() if (!dng_version) if ( (tiff_samples == 3 && tiff_ifd[raw].bytes && tiff_bps != 14 && (tiff_compress & -16) != 32768) - || (tiff_bps == 8 && !strcasestr(make,"Kodak") && - !strstr(model2,"DEBUG RAW"))) + || (tiff_bps == 8 && strncmp(make,"Phase",5) && + !strcasestr(make,"Kodak") && !strstr(model2,"DEBUG RAW"))) is_raw = 0; for (i=0; i < tiff_nifds; i++) if (i != raw && tiff_ifd[i].samples == max_samp && @@ -6400,9 +6472,7 @@ void CLASS ciff_block_1030() bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); vbits += 16; } - white[row][col] = - bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp); - vbits -= bpp; + white[row][col] = bitbuf >> (vbits -= bpp) & ~(-1 << bpp); } } @@ -6682,7 +6752,7 @@ void CLASS parse_fuji (int offset) } else if (tag == 0xc000) { c = order; order = 0x4949; - while ((tag = get4()) > 10000); + while ((tag = get4()) > raw_width); width = tag; height = get4(); order = c; @@ -6704,7 +6774,7 @@ int CLASS parse_jpeg (int offset) order = 0x4d4d; len = get2() - 2; save = ftell(ifp); - if (mark == 0xc0 || mark == 0xc3) { + if (mark == 0xc0 || mark == 0xc3 || mark == 0xc9) { fgetc(ifp); raw_height = get2(); raw_width = get2(); @@ -7003,8 +7073,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } }, { "Canon EOS D60", 0, 0xfa0, { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } }, - { "Canon EOS 5DS", 0, 0x3c96, /* DJC */ - { 6885,-753,-856,-4416,11752,2665,-1266,2393,5468 } }, + { "Canon EOS 5DS", 0, 0x3c96, + { 6250,-711,-808,-5153,12794,2636,-1249,2198,5610 } }, { "Canon EOS 5D Mark III", 0, 0x3c80, { 6722,-635,-963,-4287,12460,2028,-908,2162,5668 } }, { "Canon EOS 5D Mark II", 0, 0x3cf0, @@ -7033,6 +7103,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 6719,-994,-925,-4408,12426,2211,-887,2129,6051 } }, { "Canon EOS 70D", 0, 0x3bc7, { 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 } }, + { "Canon EOS 80D", 0, 0, + { 7457,-671,-937,-4849,12495,2643,-1213,2354,5492 } }, { "Canon EOS 100D", 0, 0x350f, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS 300D", 0, 0xfa0, @@ -7053,12 +7125,22 @@ void CLASS adobe_coeff (const char *make, const char *model) { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS 700D", 0, 0x3c00, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, + { "Canon EOS 750D", 0, 0x368e, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, + { "Canon EOS 760D", 0, 0x350f, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, { "Canon EOS 1000D", 0, 0xe43, { 6771,-1139,-977,-7818,15123,2928,-1244,1437,7533 } }, { "Canon EOS 1100D", 0, 0x3510, { 6444,-904,-893,-4563,12308,2535,-903,2016,6728 } }, { "Canon EOS 1200D", 0, 0x37c2, { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } }, + { "Canon EOS 1300D", 0, 0x3510, + { 6939,-1016,-866,-4428,12473,2177,-1175,2178,6162 } }, + { "Canon EOS M3", 0, 0, + { 6362,-823,-847,-4426,12109,2616,-743,1857,5635 } }, + { "Canon EOS M10", 0, 0, + { 6400,-480,-888,-5294,13416,2047,-1296,2203,6137 } }, { "Canon EOS M", 0, 0, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS-1Ds Mark III", 0, 0x3bb0, @@ -7077,6 +7159,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } }, { "Canon EOS-1D C", 0, 0x3c4e, { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, + { "Canon EOS-1D X Mark II", 0, 0, + { 7596,-978,-967,-4808,12571,2503,-1398,2567,5752 } }, { "Canon EOS-1D X", 0, 0x3c4e, { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, { "Canon EOS-1D", 0, 0xe20, @@ -7105,14 +7189,20 @@ void CLASS adobe_coeff (const char *make, const char *model) { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } }, { "Canon PowerShot G2", 0, 0, { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } }, + { "Canon PowerShot G3 X", 0, 0, + { 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 } }, { "Canon PowerShot G3", 0, 0, { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } }, + { "Canon PowerShot G5 X", 0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, { "Canon PowerShot G5", 0, 0, { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } }, { "Canon PowerShot G6", 0, 0, { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }, { "Canon PowerShot G7 X", 0, 0, { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, + { "Canon PowerShot G9 X", 0, 0, + { 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 } }, { "Canon PowerShot G9", 0, 0, { 7368,-2141,-598,-5621,13254,2625,-1418,1696,5743 } }, { "Canon PowerShot Pro1", 0, 0, @@ -7171,6 +7261,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 14134,-5576,-1527,-1991,10719,1273,-1158,1929,3581 } }, { "Canon PowerShot SX220", 0, 0, /* DJC */ { 13898,-5076,-1447,-1405,10109,1297,-244,1860,3687 } }, + { "Canon IXUS 160", 0, 0, /* DJC */ + { 11657,-3781,-1136,-3544,11262,2283,-160,1219,4700 } }, { "Casio EX-S20", 0, 0, /* DJC */ { 11634,-3924,-1128,-4968,12954,2015,-1588,2648,7206 } }, { "Casio EX-Z750", 0, 0, /* DJC */ @@ -7185,6 +7277,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 20183,-4295,-423,-3940,15330,3985,-280,4870,9800 } }, { "Contax N Digital", 0, 0xf1e, { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, + { "DXO ONE", 0, 0, + { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, { "Epson R-D1", 0, 0, { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, { "Fujifilm E550", 0, 0, @@ -7265,25 +7359,31 @@ void CLASS adobe_coeff (const char *make, const char *model) { 11768,-4971,-1133,-4904,12927,2183,-480,1723,4605 } }, { "Fujifilm X30", 0, 0, { 12328,-5256,-1144,-4469,12927,1675,-87,1291,4351 } }, + { "Fujifilm X70", 0, 0, + { 10450,-4329,-878,-3217,11105,2421,-752,1758,6519 } }, { "Fujifilm X-Pro1", 0, 0, { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, + { "Fujifilm X-Pro2", 0, 0, + { 11434,-4948,-1210,-3746,12042,1903,-666,1479,5235 } }, { "Fujifilm X-A1", 0, 0, { 11086,-4555,-839,-3512,11310,2517,-815,1341,5940 } }, { "Fujifilm X-A2", 0, 0, { 10763,-4560,-917,-3346,11311,2322,-475,1135,5843 } }, { "Fujifilm X-E1", 0, 0, { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, + { "Fujifilm X-E2S", 0, 0, + { 11562,-5118,-961,-3022,11007,2311,-525,1569,6097 } }, { "Fujifilm X-E2", 0, 0, { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, { "Fujifilm X-M1", 0, 0, { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, { "Fujifilm X-S1", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, - { "Fujifilm X-T1", 0, 0, + { "Fujifilm X-T1", 0, 0, /* also X-T10 */ { 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 } }, { "Fujifilm XF1", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, - { "Fujifilm XQ", 0, 0, // XQ1 and XQ2 + { "Fujifilm XQ", 0, 0, /* XQ1 and XQ2 */ { 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 } }, { "Imacon Ixpress", 0, 0, /* DJC */ { 7025,-1415,-704,-5188,13765,1424,-1248,2742,6038 } }, @@ -7425,8 +7525,12 @@ void CLASS adobe_coeff (const char *make, const char *model) { 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 } }, { "Nikon D5500", 0, 0, { 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 } }, + { "Nikon D500", 0, 0, + { 8813,-3210,-1036,-4703,12868,2021,-1054,1940,6129 } }, { "Nikon D50", 0, 0, { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, + { "Nikon D5", 0, 0, + { 9200,-3522,-992,-5755,13803,2117,-753,1486,6338 } }, { "Nikon D600", 0, 0x3e07, { 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 } }, { "Nikon D610", 0, 0, @@ -7437,8 +7541,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, { "Nikon D7100", 0, 0, { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, - { "Nikon D7200", 0, 0, /* DJC */ - { 6111,-2759,-358,-5108,10766,4343,-769,1691,8030 } }, + { "Nikon D7200", 0, 0, + { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, { "Nikon D750", 0, 0, { 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 } }, { "Nikon D700", 0, 0, @@ -7503,8 +7607,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, { "Nikon 1 J4", 0, 0, { 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 } }, - { "Nikon 1 J5", 0, 0, /* DJC */ - { 2621,-856,500,-4471,8761,5711,-1321,2644,11945 } }, + { "Nikon 1 J5", 0, 0, + { 7520,-2518,-645,-3844,12102,1945,-913,2249,6835 } }, { "Nikon 1 S2", 200, 0, { 6612,-1342,-618,-3338,11055,2623,-174,1792,5075 } }, { "Nikon 1 V2", 0, 0, @@ -7515,6 +7619,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, { "Nikon 1 ", 0, 0, /* J1, J2, S1, V1 */ { 8994,-2667,-865,-4594,12324,2552,-699,1786,6260 } }, + { "Olympus AIR A01", 0, 0, + { 8992,-3093,-639,-2563,10721,2122,-437,1270,5473 } }, { "Olympus C5050", 0, 0, { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } }, { "Olympus C5060", 0, 0, @@ -7585,7 +7691,7 @@ void CLASS adobe_coeff (const char *make, const char *model) { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, { "Olympus E-PM2", 0, 0, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, - { "Olympus E-M10", 0, 0, + { "Olympus E-M10", 0, 0, /* also E-M10 Mark II */ { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-M1", 0, 0, { 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 } }, @@ -7593,6 +7699,10 @@ void CLASS adobe_coeff (const char *make, const char *model) { 9422,-3258,-711,-2655,10898,2015,-512,1354,5512 } }, { "Olympus E-M5", 0, 0xfe1, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, + { "Olympus PEN-F", 0, 0, + { 9476,-3182,-765,-2613,10958,1893,-449,1315,5268 } }, + { "Olympus SH-2", 0, 0, + { 10156,-3425,-1077,-2611,11177,1624,-385,1592,5080 } }, { "Olympus SP350", 0, 0, { 12078,-4836,-1069,-6671,14306,2578,-786,939,7418 } }, { "Olympus SP3", 0, 0, @@ -7609,6 +7719,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 11522,-4044,-1146,-4736,12172,2904,-988,1829,6039 } }, { "Olympus STYLUS1", 0, 0, { 8360,-2420,-880,-3928,12353,1739,-1381,2416,5173 } }, + { "Olympus TG-4", 0, 0, + { 11426,-4159,-1126,-2066,10678,1593,-120,1327,4998 } }, { "Olympus XZ-10", 0, 0, { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, { "Olympus XZ-1", 0, 0, @@ -7643,6 +7755,12 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8843,-2837,-625,-5025,12644,2668,-411,1234,7410 } }, { "Pentax K-r", 0, 0, { 9895,-3077,-850,-5304,13035,2521,-883,1768,6936 } }, + { "Pentax K-1", 0, 0, + { 8566,-2746,-1201,-3612,12204,1550,-893,1680,6264 } }, + { "Pentax K-30", 0, 0, + { 8710,-2632,-1167,-3995,12301,1881,-981,1719,6535 } }, + { "Pentax K-3 II", 0, 0, + { 8626,-2607,-1155,-3995,12301,1881,-1039,1822,6925 } }, { "Pentax K-3", 0, 0, { 7415,-2052,-721,-5186,12788,2682,-1446,2157,6773 } }, { "Pentax K-5 II", 0, 0, @@ -7653,6 +7771,10 @@ void CLASS adobe_coeff (const char *make, const char *model) { 9142,-2947,-678,-8648,16967,1663,-2224,2898,8615 } }, { "Pentax K-S1", 0, 0, { 8512,-3211,-787,-4167,11966,2487,-638,1288,6054 } }, + { "Pentax K-S2", 0, 0, + { 8662,-3280,-798,-3928,11771,2444,-586,1232,6054 } }, + { "Pentax Q-S1", 0, 0, + { 12995,-5593,-1107,-1879,10139,2027,-64,1233,4919 } }, { "Pentax 645D", 0, 0x3e00, { 10646,-3593,-1158,-3329,11699,1831,-667,2874,6287 } }, { "Panasonic DMC-CM1", 15, 0, @@ -7663,6 +7785,10 @@ void CLASS adobe_coeff (const char *make, const char *model) { 9932,-3060,-935,-5809,13331,2753,-1267,2155,5575 } }, { "Panasonic DMC-FZ28", 15, 0xf96, { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } }, + { "Panasonic DMC-FZ330", 15, 0, + { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } }, + { "Panasonic DMC-FZ300", 15, 0, + { 8378,-2798,-769,-3068,11410,1877,-538,1792,4623 } }, { "Panasonic DMC-FZ30", 0, 0xf94, { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, { "Panasonic DMC-FZ3", 15, 0, @@ -7743,6 +7869,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 7798,-2562,-740,-3879,11584,2613,-1055,2248,5434 } }, { "Panasonic DMC-G6", 15, 0xfff, { 8294,-2891,-651,-3869,11590,2595,-1183,2267,5352 } }, + { "Panasonic DMC-G7", 15, 0xfff, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-GF1", 15, 0xf92, { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, { "Panasonic DMC-GF2", 15, 0xfff, @@ -7755,6 +7883,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8130,-2801,-946,-3520,11289,2552,-1314,2511,5791 } }, { "Panasonic DMC-GF7", 15, 0, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DMC-GF8", 15, 0, + { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, { "Panasonic DMC-GH1", 15, 0xf92, { 6299,-1466,-532,-6535,13852,2969,-2331,3112,5984 } }, { "Panasonic DMC-GH2", 15, 0xf95, @@ -7771,6 +7901,12 @@ void CLASS adobe_coeff (const char *make, const char *model) { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, { "Panasonic DMC-GX7", 15, 0, { 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 } }, + { "Panasonic DMC-GX8", 15, 0, + { 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 } }, + { "Panasonic DMC-TZ1", 15, 0, + { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, + { "Panasonic DMC-ZS1", 15, 0, + { 7790,-2736,-755,-3452,11870,1769,-628,1647,4898 } }, { "Panasonic DMC-TZ6", 15, 0, { 8607,-2822,-808,-3755,11930,2049,-820,2060,5224 } }, { "Panasonic DMC-ZS4", 15, 0, @@ -7779,6 +7915,20 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 } }, { "Panasonic DMC-ZS5", 15, 0, { 8802,-3135,-789,-3151,11468,1904,-550,1745,4810 } }, + { "Panasonic DMC-TZ8", 15, 0, + { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, + { "Panasonic DMC-ZS6", 15, 0, + { 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 } }, + { "Leica S (Typ 007)", 0, 0, + { 6063,-2234,-231,-5210,13787,1500,-1043,2866,6997 } }, + { "Leica X", 0, 0, /* X and X-U, both (Typ 113) */ + { 7712,-2059,-653,-3882,11494,2726,-710,1332,5958 } }, + { "Leica Q (Typ 116)", 0, 0, + { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830 } }, + { "Leica M (Typ 262)", 0, 0, + { 6653,-1486,-611,-4221,13303,929,-881,2416,7226 } }, + { "Leica SL (Typ 601)", 0, 0, + { 11865,-4523,-1441,-5423,14458,935,-1587,2687,4830} }, { "Phase One H 20", 0, 0, /* DJC */ { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } }, { "Phase One H 25", 0, 0, @@ -7793,8 +7943,14 @@ void CLASS adobe_coeff (const char *make, const char *model) { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, { "Phase One P65", 0, 0, { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, + { "Photron BC2-HD", 0, 0, /* DJC */ + { 14603,-4122,-528,-1810,9794,2017,-297,2763,5936 } }, { "Red One", 704, 0xffff, /* DJC */ { 21014,-7891,-2613,-3056,12201,856,-2203,5125,8042 } }, + { "Ricoh GR II", 0, 0, + { 4630,-834,-423,-4977,12805,2417,-638,1467,6115 } }, + { "Ricoh GR", 0, 0, + { 3708,-543,-160,-5381,12254,3556,-1471,1929,8234 } }, { "Samsung EX1", 0, 0x3e00, { 8898,-2498,-994,-3144,11328,2066,-760,1381,4576 } }, { "Samsung EX2F", 0, 0x7ff, @@ -7803,6 +7959,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, { "Samsung NX mini", 0, 0, { 5222,-1196,-550,-6540,14649,2009,-1666,2819,5657 } }, + { "Samsung NX3300", 0, 0, + { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, { "Samsung NX3000", 0, 0, { 8060,-2933,-761,-4504,12890,1762,-630,1489,5227 } }, { "Samsung NX30", 0, 0, /* NX30, NX300, NX300M */ @@ -7819,8 +7977,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, { "Samsung NX10", 0, 0, /* also NX100 */ { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, - { "Samsung NX500", 0, 0, /* DJC */ - { 10196,-4532,-272,-3888,11489,2400,-1203,2424,9173 } }, + { "Samsung NX500", 0, 0, + { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, { "Samsung NX5", 0, 0, { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, { "Samsung NX1", 0, 0, @@ -7837,18 +7995,20 @@ void CLASS adobe_coeff (const char *make, const char *model) { 16442,-2956,-2422,-2877,12128,750,-1136,6066,4559 } }, { "Sony DSC-F828", 0, 0, { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } }, - { "Sony DSC-R1", 512, 0, + { "Sony DSC-R1", 0, 0, { 8512,-2641,-694,-8042,15670,2526,-1821,2117,7414 } }, { "Sony DSC-V3", 0, 0, { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } }, - { "Sony DSC-RX100M", 200, 0, /* M2 and M3 */ + { "Sony DSC-RX100M", 0, 0, /* M2, M3, and M4 */ { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, - { "Sony DSC-RX100", 200, 0, + { "Sony DSC-RX100", 0, 0, { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } }, - { "Sony DSC-RX10", 200, 0, + { "Sony DSC-RX10", 0, 0, { 6679,-1825,-745,-5047,13256,1953,-1580,2422,5183 } }, - { "Sony DSC-RX1", 128, 0, - { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, + { "Sony DSC-RX1RM2", 0, 0, + { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, + { "Sony DSC-RX1", 0, 0, + { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, { "Sony DSLR-A100", 0, 0xfeb, { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } }, { "Sony DSLR-A290", 0, 0, @@ -7865,71 +8025,77 @@ void CLASS adobe_coeff (const char *make, const char *model) { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, { "Sony DSLR-A390", 0, 0, { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, - { "Sony DSLR-A450", 128, 0xfeb, + { "Sony DSLR-A450", 0, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, - { "Sony DSLR-A580", 128, 0xfeb, + { "Sony DSLR-A580", 0, 0xfeb, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, - { "Sony DSLR-A500", 128, 0xfeb, + { "Sony DSLR-A500", 0, 0xfeb, { 6046,-1127,-278,-5574,13076,2786,-691,1419,7625 } }, - { "Sony DSLR-A5", 128, 0xfeb, + { "Sony DSLR-A5", 0, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, - { "Sony DSLR-A700", 128, 0, + { "Sony DSLR-A700", 0, 0, { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } }, - { "Sony DSLR-A850", 128, 0, + { "Sony DSLR-A850", 0, 0, { 5413,-1162,-365,-5665,13098,2866,-608,1179,8440 } }, - { "Sony DSLR-A900", 128, 0, + { "Sony DSLR-A900", 0, 0, { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } }, - { "Sony ILCA-77M2", 128, 0, + { "Sony ILCA-68", 0, 0, + { 6435,-1903,-536,-4722,12449,2550,-663,1363,6517 } }, + { "Sony ILCA-77M2", 0, 0, { 5991,-1732,-443,-4100,11989,2381,-704,1467,5992 } }, - { "Sony ILCE-7M2", 128, 0, + { "Sony ILCE-6300", 0, 0, + { 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 } }, + { "Sony ILCE-7M2", 0, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, - { "Sony ILCE-7S", 128, 0, + { "Sony ILCE-7S", 0, 0, /* also ILCE-7SM2 */ { 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 } }, - { "Sony ILCE-7R", 128, 0, + { "Sony ILCE-7RM2", 0, 0, + { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, + { "Sony ILCE-7R", 0, 0, { 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 } }, - { "Sony ILCE-7", 128, 0, + { "Sony ILCE-7", 0, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, - { "Sony ILCE", 128, 0, /* 3000, 5000, 5100, 6000, and QX1 */ + { "Sony ILCE", 0, 0, /* 3000, 5000, 5100, 6000, and QX1 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony NEX-5N", 128, 0, + { "Sony NEX-5N", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony NEX-5R", 128, 0, + { "Sony NEX-5R", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, - { "Sony NEX-5T", 128, 0, + { "Sony NEX-5T", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, - { "Sony NEX-3N", 128, 0, + { "Sony NEX-3N", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, { "Sony NEX-3", 138, 0, /* DJC */ { 6907,-1256,-645,-4940,12621,2320,-1710,2581,6230 } }, { "Sony NEX-5", 116, 0, /* DJC */ { 6807,-1350,-342,-4216,11649,2567,-1089,2001,6420 } }, - { "Sony NEX-3", 128, 0, /* Adobe */ + { "Sony NEX-3", 0, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, - { "Sony NEX-5", 128, 0, /* Adobe */ + { "Sony NEX-5", 0, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, - { "Sony NEX-6", 128, 0, + { "Sony NEX-6", 0, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, - { "Sony NEX-7", 128, 0, + { "Sony NEX-7", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, - { "Sony NEX", 128, 0, /* NEX-C3, NEX-F3 */ + { "Sony NEX", 0, 0, /* NEX-C3, NEX-F3 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A33", 128, 0, + { "Sony SLT-A33", 0, 0, { 6069,-1221,-366,-5221,12779,2734,-1024,2066,6834 } }, - { "Sony SLT-A35", 128, 0, + { "Sony SLT-A35", 0, 0, { 5986,-1618,-415,-4557,11820,3120,-681,1404,6971 } }, - { "Sony SLT-A37", 128, 0, + { "Sony SLT-A37", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A55", 128, 0, + { "Sony SLT-A55", 0, 0, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, - { "Sony SLT-A57", 128, 0, + { "Sony SLT-A57", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A58", 128, 0, + { "Sony SLT-A58", 0, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A65", 128, 0, + { "Sony SLT-A65", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, - { "Sony SLT-A77", 128, 0, + { "Sony SLT-A77", 0, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, - { "Sony SLT-A99", 128, 0, + { "Sony SLT-A99", 0, 0, { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, }; double cam_xyz[4][3]; @@ -8113,6 +8279,8 @@ void CLASS identify() { 5712, 3774, 62, 20, 10, 2 }, { 5792, 3804, 158, 51, 0, 0 }, { 5920, 3950, 122, 80, 2, 0 }, + { 6096, 4056, 72, 34, 0, 0 }, + { 6288, 4056, 264, 34, 0, 0 }, { 8896, 5920, 160, 64, 0, 0 }, }; static const struct { @@ -8126,6 +8294,7 @@ void CLASS identify() { 0x261, "EOS 50D" }, { 0x281, "EOS-1D Mark IV" }, { 0x287, "EOS 60D" }, { 0x167, "EOS-1DS" }, { 0x325, "EOS 70D" }, + { 0x350, "EOS 80D" }, { 0x328, "EOS-1D X Mark II" }, { 0x170, "EOS 300D" }, { 0x188, "EOS-1Ds Mark II" }, { 0x176, "EOS 450D" }, { 0x215, "EOS-1Ds Mark III" }, { 0x189, "EOS 350D" }, { 0x324, "EOS-1D C" }, @@ -8135,9 +8304,12 @@ void CLASS identify() { 0x286, "EOS 600D" }, { 0x285, "EOS 5D Mark III" }, { 0x301, "EOS 650D" }, { 0x302, "EOS 6D" }, { 0x326, "EOS 700D" }, { 0x250, "EOS 7D" }, + { 0x393, "EOS 750D" }, { 0x289, "EOS 7D Mark II" }, + { 0x347, "EOS 760D" }, { 0x254, "EOS 1000D" }, { 0x288, "EOS 1100D" }, - { 0x327, "EOS 1200D" }, + { 0x327, "EOS 1200D" }, { 0x382, "Canon EOS 5DS" }, + { 0x404, "EOS 1300D" }, { 0x401, "Canon EOS 5DS R" }, { 0x346, "EOS 100D" }, }, sonique[] = { { 0x002, "DSC-R1" }, { 0x100, "DSLR-A100" }, @@ -8165,7 +8337,10 @@ void CLASS identify() { 0x139, "ILCE-5000" }, { 0x13d, "DSC-RX100M3" }, { 0x13e, "ILCE-7S" }, { 0x13f, "ILCA-77M2" }, { 0x153, "ILCE-5100" }, { 0x154, "ILCE-7M2" }, - { 0x15a, "ILCE-QX1" }, + { 0x155, "DSC-RX100M4" },{ 0x156, "DSC-RX10M2" }, + { 0x158, "DSC-RX1RM2" }, { 0x15a, "ILCE-QX1" }, + { 0x15b, "ILCE-7RM2" }, { 0x15e, "ILCE-7SM2" }, + { 0x161, "ILCA-68" }, { 0x165, "ILCE-6300" }, }; static const struct { unsigned fsize; @@ -8202,6 +8377,7 @@ void CLASS identify() { 19131120,4168,3060,92,16, 4, 1,40,0x94,0,2,"Canon","PowerShot SX220 HS" }, { 21936096,4464,3276,25,10,73,12,40,0x16,0,2,"Canon","PowerShot SX30 IS" }, { 24724224,4704,3504, 8,16,56, 8,40,0x94,0,2,"Canon","PowerShot A3300 IS" }, + { 30858240,5248,3920, 8,16,56,16,40,0x94,0,2,"Canon","IXUS 160" }, { 1976352,1632,1211, 0, 2, 0, 1, 0,0x94,0,1,"Casio","QV-2000UX" }, { 3217760,2080,1547, 0, 0,10, 1, 0,0x94,0,1,"Casio","QV-3*00EX" }, { 6218368,2585,1924, 0, 0, 9, 0, 0,0x94,0,1,"Casio","QV-5700" }, @@ -8260,6 +8436,8 @@ void CLASS identify() { 4841984,2090,1544, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S" }, { 6114240,2346,1737, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S4" }, { 10702848,3072,2322, 0, 0, 0,21,30,0x94,0,1,"Pentax","Optio 750Z" }, + { 4147200,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD" }, + { 4151666,1920,1080, 0, 0, 0, 0, 0,0x49,0,0,"Photron","BC2-HD",8 }, { 13248000,2208,3000, 0, 0, 0, 0,13,0x61,0,0,"Pixelink","A782" }, { 6291456,2048,1536, 0, 0, 0, 0,96,0x61,0,0,"RoverShot","3320AF" }, { 311696, 644, 484, 0, 0, 0, 0, 0,0x16,0,8,"ST Micro","STV680 VGA" }, @@ -8276,7 +8454,7 @@ void CLASS identify() static const char *corp[] = { "AgfaPhoto", "Canon", "Casio", "Epson", "Fujifilm", "Mamiya", "Minolta", "Motorola", "Kodak", "Konica", "Leica", - "Nikon", "Nokia", "Olympus", "Pentax", "Phase One", "Ricoh", + "Nikon", "Nokia", "Olympus", "Ricoh", "Pentax", "Phase One", "Samsung", "Sigma", "Sinar", "Sony" }; char head[32], *cp; int hlen, flen, fsize, zero_fsize=1, i, c; @@ -8451,7 +8629,7 @@ void CLASS identify() parse_foveon(); else if (!memcmp (head,"CI",2)) parse_cine(); - else + if (make[0] == 0) for (zero_fsize=i=0; i < sizeof table / sizeof *table; i++) if (fsize == table[i].fsize) { strcpy (make, table[i].make ); @@ -8548,9 +8726,10 @@ void CLASS identify() width = 4014; if (dng_version) { if (filters == UINT_MAX) filters = 0; - if (filters) is_raw = tiff_samples; - else colors = tiff_samples; + if (filters) is_raw *= tiff_samples; + else colors = tiff_samples; switch (tiff_compress) { + case 0: case 1: load_raw = &CLASS packed_dng_load_raw; break; case 7: load_raw = &CLASS lossless_dng_load_raw; break; case 8: load_raw = &CLASS deflate_dng_load_raw; break; @@ -8603,6 +8782,8 @@ void CLASS identify() top_margin = filters = 0; strcpy (model,"C603"); } + if (!strcmp(make,"Sony") && raw_width > 3888) + black = 128 << (tiff_bps - 12); if (is_foveon) { if (height*2 < width) pixel_aspect = 0.5; if (height > width) pixel_aspect = 2; @@ -8618,6 +8799,10 @@ void CLASS identify() SWAP(height,width); SWAP(raw_height,raw_width); } + if (width == 7200 && height == 3888) { + raw_width = width = 6480; + raw_height = height = 4320; + } filters = 0; tiff_samples = colors = 3; load_raw = &CLASS canon_sraw_load_raw; @@ -8793,7 +8978,7 @@ canon_a5: top_margin = (raw_height - height) >> 2 << 1; left_margin = (raw_width - width ) >> 2 << 1; if (width == 2848 || width == 3664) filters = 0x16161616; - if (width == 4032 || width == 4952) left_margin = 0; + if (width == 4032 || width == 4952 || width == 6032) left_margin = 0; if (width == 3328 && (width -= 66)) left_margin = 34; if (width == 4936) left_margin = 4; if (!strcmp(model,"HS50EXR") || @@ -9067,6 +9252,8 @@ konica_400z: thumb_length = flen - (thumb_offset = 0xa39800); thumb_height = 480; thumb_width = 640; + } else if (!strcmp(model,"TG-4")) { + width -= 16; } } else if (!strcmp(model,"N Digital")) { height = 2047; @@ -9094,16 +9281,29 @@ konica_400z: order = 0x4d4d; } else if (!strcmp(make,"Sony") && raw_width == 4288) { width -= 32; + } else if (!strcmp(make,"Sony") && raw_width == 4600) { + if (!strcmp(model,"DSLR-A350")) + height -= 4; + black = 0; } else if (!strcmp(make,"Sony") && raw_width == 4928) { if (height < 3280) width -= 8; } else if (!strcmp(make,"Sony") && raw_width == 5504) { width -= height > 3664 ? 8 : 32; + if (!strncmp(model,"DSC",3)) + black = 200 << (tiff_bps - 12); } else if (!strcmp(make,"Sony") && raw_width == 6048) { width -= 24; if (strstr(model,"RX1") || strstr(model,"A99")) width -= 6; } else if (!strcmp(make,"Sony") && raw_width == 7392) { width -= 30; + } else if (!strcmp(make,"Sony") && raw_width == 8000) { + width -= 32; + if (!strncmp(model,"DSC",3)) { + tiff_bps = 14; + load_raw = &CLASS unpacked_load_raw; + black = 512; + } } else if (!strcmp(model,"DSLR-A100")) { if (width == 3880) { height--; @@ -9115,8 +9315,6 @@ konica_400z: load_flags = 2; } filters = 0x61616161; - } else if (!strcmp(model,"DSLR-A350")) { - height -= 4; } else if (!strcmp(model,"PIXL")) { height -= top_margin = 4; width -= left_margin = 32; @@ -9181,6 +9379,7 @@ bw: colors = 1; width = 768; data_offset = 1152; load_raw = &CLASS kodak_radc_load_raw; + tiff_bps = 12; } else if (strstr(model,"DC50")) { strcpy (model, "DC50"); height = 512; @@ -9271,7 +9470,7 @@ dng_skip: if (raw_color) adobe_coeff ("Apple","Quicktake"); if (fuji_width) { fuji_width = width >> !fuji_layout; - if (~fuji_width & 1) filters = 0x49494949; + filters = fuji_width & 1 ? 0x94949494 : 0x49494949; width = (height >> fuji_layout) + fuji_width; height = width - 1; pixel_aspect = 1; diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index 856da84d1..405f202bd 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -127,6 +127,7 @@ protected: struct tiff_ifd { int width, height, bps, comp, phint, offset, flip, samples, bytes; int tile_width, tile_length, sample_format, predictor; + float shutter; } tiff_ifd[10]; struct ph1 { @@ -139,8 +140,8 @@ protected: } hbd; struct jhead { - int bits, high, wide, clrs, sraw, psv, restart, vpred[6]; - ushort *huff[6], *free[4], *row; + int algo, bits, high, wide, clrs, sraw, psv, restart, vpred[6]; + ushort quant[64], idct[64], *huff[20], *free[20], *row; }; struct tiff_tag { @@ -217,6 +218,8 @@ void ljpeg_end (struct jhead *jh); int ljpeg_diff (ushort *huff); ushort * ljpeg_row (int jrow, struct jhead *jh); void lossless_jpeg_load_raw(); +void ljpeg_idct (struct jhead *jh); + void canon_sraw_load_raw(); void adobe_copy_pixel (unsigned row, unsigned col, ushort **rp); diff --git a/rtengine/dcraw.patch b/rtengine/dcraw.patch index 88a56068c..2b4ee4102 100644 --- a/rtengine/dcraw.patch +++ b/rtengine/dcraw.patch @@ -1,5 +1,5 @@ ---- dcraw.c 2016-02-11 22:56:58.043957200 +0100 -+++ dcraw.cc 2016-02-11 23:13:28.708268000 +0100 +--- dcraw.c 2016-05-29 22:32:01.173135400 +0200 ++++ dcraw.cc 2016-05-29 21:57:44.144527700 +0200 @@ -1,3 +1,15 @@ +/*RT*/#include +/*RT*/#include @@ -15,7 +15,7 @@ + /* dcraw.c -- Dave Coffin's raw photo decoder - Copyright 1997-2015 by Dave Coffin, dcoffin a cybercom o net + Copyright 1997-2016 by Dave Coffin, dcoffin a cybercom o net @@ -29,17 +41,17 @@ #define _GNU_SOURCE #endif @@ -52,8 +52,8 @@ #define snprintf _snprintf #define strcasecmp stricmp #define strncasecmp strnicmp -@@ -98,88 +109,38 @@ - #define LONG_BIT (8 * sizeof (long)) +@@ -89,89 +100,38 @@ + #define _(String) (String) #endif -#if !defined(uchar) @@ -123,6 +123,7 @@ -struct tiff_ifd { - int width, height, bps, comp, phint, offset, flip, samples, bytes; - int tile_width, tile_length; +- float shutter; -} tiff_ifd[10]; - -struct ph1 { @@ -147,7 +148,7 @@ -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#define LIM(x,min,max) MAX(min,MIN(x,max)) -#define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) --#define CLIP(x) LIM(x,0,65535) +-#define CLIP(x) LIM((int)(x),0,65535) +#define MIN(a,b) rtengine::min(a,static_cast<__typeof__(a)>(b)) +#define MAX(a,b) rtengine::max(a,static_cast<__typeof__(a)>(b)) +#define LIM(x,min,max) rtengine::LIM(x,static_cast<__typeof__(x)>(min),static_cast<__typeof__(x)>(max)) @@ -156,7 +157,7 @@ #define SWAP(a,b) { a=a+b; b=a-b; a=a-b; } /* -@@ -255,6 +216,7 @@ +@@ -247,6 +207,7 @@ if (filters == 1) return filter[(row+top_margin)&15][(col+left_margin)&15]; if (filters == 9) return xtrans[(row+6) % 6][(col+6) % 6]; @@ -164,7 +165,7 @@ return FC(row,col); } -@@ -297,6 +259,7 @@ +@@ -289,6 +250,7 @@ fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp)); } data_error++; @@ -172,7 +173,7 @@ } ushort CLASS sget2 (uchar *s) -@@ -370,7 +333,7 @@ +@@ -362,7 +324,7 @@ { if (fread (pixel, 2, count, ifp) < count) derror(); if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) @@ -181,7 +182,7 @@ } void CLASS cubic_spline (const int *x_, const int *y_, const int len) -@@ -597,10 +560,10 @@ +@@ -589,10 +551,10 @@ return 0; } @@ -195,17 +196,45 @@ unsigned c; if (nbits > 25) return 0; -@@ -824,7 +787,8 @@ +@@ -805,9 +767,13 @@ + FORC(2) free (huff[c]); + } + ++/* ++ Not a full implementation of Lossless JPEG, just ++ enough to decode Canon, Kodak and Adobe DNG images. ++ */ + struct jhead { +- int algo, bits, high, wide, clrs, sraw, psv, restart, vpred[6]; +- ushort quant[64], idct[64], *huff[20], *free[20], *row; ++ int bits, high, wide, clrs, sraw, psv, restart, vpred[6]; ++ ushort *huff[6], *free[4], *row; + }; int CLASS ljpeg_start (struct jhead *jh, int info_only) - { -- int c, tag, len; -+ int c, tag; -+ ushort len; - uchar data[0x10000]; - const uchar *dp; - -@@ -1284,14 +1248,14 @@ +@@ -828,9 +794,9 @@ + switch (tag) { + case 0xffc3: + jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3; +- case 0xffc1: ++ case 0xffc1: + case 0xffc0: +- jh->algo = tag & 0xff; ++ jh->algo = tag & 0xff; + jh->bits = data[0]; + jh->high = data[1] << 8 | data[2]; + jh->wide = data[3] << 8 | data[4]; +@@ -1124,8 +1090,7 @@ + if (++col >= tile_width || col >= raw_width) + row += 1 + (col = 0); + } +- } +- } ++ } } + fseek (ifp, save+4, SEEK_SET); + if ((tcol += tile_width) >= raw_width) + trow += tile_length + (tcol = 0); +@@ -1332,14 +1297,14 @@ int i, nz; char tail[424]; @@ -222,7 +251,7 @@ void CLASS ppm_thumb() { -@@ -1653,10 +1617,10 @@ +@@ -1701,10 +1666,10 @@ } } @@ -236,17 +265,7 @@ unsigned c; if (nbits == -1) -@@ -1721,7 +1685,8 @@ - pixel[col] = curve[pixel[col]]; - } - for (col=0; col < raw_width; col++) { -- i = (pixel[col] << 2) - ph1.black -+ if (ph1.format != 8) pixel[col] <<= 2; -+ i = pixel[col] - ph1.black - + cblack[row][col >= ph1.split_col] - + rblack[col][row >= ph1.split_row]; - if (i > 0) RAW(row,col) = i; -@@ -1731,6 +1696,338 @@ +@@ -1779,6 +1744,338 @@ maximum = 0xfffc - ph1.black; } @@ -585,7 +604,7 @@ void CLASS hasselblad_load_raw() { struct jhead jh; -@@ -1954,10 +2251,10 @@ +@@ -2002,10 +2299,10 @@ maximum = curve[0x3ff]; } @@ -599,7 +618,7 @@ int byte; if (!nbits) return vbits=0; -@@ -2140,7 +2437,7 @@ +@@ -2188,7 +2485,7 @@ void CLASS kodak_radc_load_raw() { @@ -608,7 +627,7 @@ 1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8, 1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8, 2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8, -@@ -2246,11 +2543,11 @@ +@@ -2294,11 +2591,11 @@ METHODDEF(boolean) fill_input_buffer (j_decompress_ptr cinfo) { @@ -622,7 +641,7 @@ cinfo->src->next_input_byte = jpeg_buffer; cinfo->src->bytes_in_buffer = nbytes; return TRUE; -@@ -2600,10 +2897,9 @@ +@@ -2648,10 +2945,9 @@ maximum = (1 << (thumb_misc & 31)) - 1; } @@ -635,7 +654,7 @@ if (start) { for (p=0; p < 4; p++) pad[p] = key = key * 48828125 + 1; -@@ -2688,11 +2984,13 @@ +@@ -2736,11 +3032,13 @@ bit += 7; } for (i=0; i < 16; i++, col+=2) @@ -650,7 +669,7 @@ } void CLASS samsung_load_raw() -@@ -2988,7 +3286,7 @@ +@@ -3038,7 +3336,7 @@ void CLASS foveon_decoder (unsigned size, unsigned code) { @@ -659,7 +678,7 @@ struct decode *cur; int i, len; -@@ -3085,7 +3383,7 @@ +@@ -3135,7 +3433,7 @@ pred[c] += diff[dindex->leaf]; if (pred[c] >> 16 && ~pred[c] >> 16) derror(); } @@ -668,7 +687,7 @@ } } } -@@ -3696,6 +3994,8 @@ +@@ -3746,6 +4044,8 @@ if (load_raw == &CLASS phase_one_load_raw || load_raw == &CLASS phase_one_load_raw_c) phase_one_correct(); @@ -677,7 +696,7 @@ if (fuji_width) { for (row=0; row < raw_height-top_margin*2; row++) { for (col=0; col < fuji_width << !fuji_layout; col++) { -@@ -3711,10 +4011,13 @@ +@@ -3761,10 +4061,13 @@ } } } else { @@ -693,7 +712,7 @@ if (mask[0][3] > 0) goto mask_set; if (load_raw == &CLASS canon_load_raw || load_raw == &CLASS lossless_jpeg_load_raw) { -@@ -4316,239 +4619,8 @@ +@@ -4366,239 +4669,8 @@ } } @@ -702,8 +721,7 @@ - int code[16][16][32], size=16, *ip, sum[4]; - int f, c, i, x, y, row, col, shift, color; - ushort *pix; -+/* RT: delete interpolation functions */ - +- - if (verbose) fprintf (stderr,_("Bilinear interpolation...\n")); - if (filters == 9) size = 6; - border_interpolate(1); @@ -886,7 +904,8 @@ - int dir[5] = { 1, width, -1, -width, 1 }; - int row, col, diff[2], guess[2], c, d, i; - ushort (*pix)[4]; -- ++/* RT: delete interpolation functions */ + - border_interpolate(3); - if (verbose) fprintf (stderr,_("PPG interpolation...\n")); - @@ -934,7 +953,7 @@ void CLASS cielab (ushort rgb[3], short lab[3]) { -@@ -4814,112 +4886,7 @@ +@@ -4864,112 +4936,7 @@ } #undef fcol @@ -952,7 +971,7 @@ - char (*homo)[TS][TS], *buffer; - - if (verbose) fprintf (stderr,_("AHD interpolation...\n")); - +- - cielab (0,0); - border_interpolate(5); - buffer = (char *) malloc (26*TS*TS); @@ -960,7 +979,7 @@ - rgb = (ushort(*)[TS][TS][3]) buffer; - lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS); - homo = (char (*)[TS][TS]) (buffer + 24*TS*TS); -- + - for (top=2; top < height-5; top += TS-6) - for (left=2; left < width-5; left += TS-6) { - @@ -1047,7 +1066,7 @@ #undef TS void CLASS median_filter() -@@ -5089,7 +5056,7 @@ +@@ -5139,7 +5106,7 @@ } } @@ -1056,7 +1075,7 @@ void CLASS parse_makernote (int base, int uptag) { -@@ -5194,6 +5161,11 @@ +@@ -5244,6 +5211,11 @@ tag |= uptag << 16; if (tag == 2 && strstr(make,"NIKON") && !iso_speed) iso_speed = (get2(),get2()); @@ -1068,7 +1087,7 @@ if (tag == 4 && len > 26 && len < 35) { if ((i=(get4(),get2())) != 0x7fff && !iso_speed) iso_speed = 50 * pow (2, i/32.0 - 4); -@@ -5246,12 +5218,16 @@ +@@ -5296,12 +5268,16 @@ cam_mul[2] = get4() << 2; } } @@ -1086,15 +1105,25 @@ if (tag == 0x1d) while ((c = fgetc(ifp)) && c != EOF) serial = serial*10 + (isdigit(c) ? c - '0' : c % 10); -@@ -5442,6 +5418,7 @@ - case 33434: shutter = getreal(type); break; +@@ -5491,14 +5467,14 @@ + while (entries--) { + tiff_get (base, &tag, &type, &len, &save); + switch (tag) { +- case 33434: tiff_ifd[tiff_nifds-1].shutter = +- shutter = getreal(type); break; ++ case 33434: tiff_ifd[tiff_nifds-1].shutter = shutter = getreal(type); break; case 33437: aperture = getreal(type); break; case 34855: iso_speed = get2(); break; + case 34866: if((!iso_speed) || iso_speed == 65535) iso_speed = get4();break; case 36867: case 36868: get_timestamp(0); break; case 37377: if ((expo = -getreal(type)) < 128) -@@ -5613,28 +5590,33 @@ +- tiff_ifd[tiff_nifds-1].shutter = ++ tiff_ifd[tiff_nifds-1].shutter = + shutter = pow (2, expo); break; + case 37378: aperture = pow (2, getreal(type)/2); break; + case 37386: focal_len = getreal(type); break; +@@ -5667,28 +5643,33 @@ } } @@ -1134,7 +1163,7 @@ entries = get2(); if (entries > 512) return 1; while (entries--) { -@@ -5702,7 +5684,8 @@ +@@ -5758,7 +5739,8 @@ fgets (make, 64, ifp); break; case 272: /* Model */ @@ -1144,7 +1173,7 @@ break; case 280: /* Panasonic RW2 offset */ if (type != 4) break; -@@ -5762,6 +5745,9 @@ +@@ -5818,6 +5800,9 @@ case 315: /* Artist */ fread (artist, 64, 1, ifp); break; @@ -1154,7 +1183,7 @@ case 322: /* TileWidth */ tiff_ifd[ifd].tile_width = getint(type); break; -@@ -5777,6 +5763,9 @@ +@@ -5833,6 +5818,9 @@ is_raw = 5; } break; @@ -1164,7 +1193,7 @@ case 330: /* SubIFDs */ if (!strcmp(model,"DSLR-A100") && tiff_ifd[ifd].width == 3872) { load_raw = &CLASS sony_arw_load_raw; -@@ -5790,6 +5779,9 @@ +@@ -5846,6 +5834,9 @@ fseek (ifp, i+4, SEEK_SET); } break; @@ -1174,17 +1203,7 @@ case 400: strcpy (make, "Sarnoff"); maximum = 0xfff; -@@ -5971,6 +5963,9 @@ - if (!make[0]) strcpy (make, "DNG"); - is_raw = 1; - break; -+ case 50708: /* UniqueCameraModel */ -+ fgets (model3, 64, ifp); -+ break; - case 50710: /* CFAPlaneColor */ - if (filters == 9) break; - if (len > 4) len = 4; -@@ -6002,12 +5997,21 @@ +@@ -6063,12 +6054,21 @@ case 61450: cblack[4] = cblack[5] = MIN(sqrt(len),64); case 50714: /* BlackLevel */ @@ -1211,8 +1230,8 @@ + break; case 50715: /* BlackLevelDeltaH */ case 50716: /* BlackLevelDeltaV */ - for (num=i=0; i < len; i++) -@@ -6024,13 +6028,13 @@ + for (num=i=0; i < (len & 0xffff); i++) +@@ -6085,13 +6085,13 @@ case 50721: /* ColorMatrix1 */ case 50722: /* ColorMatrix2 */ FORCC for (j=0; j < 3; j++) @@ -1228,7 +1247,7 @@ break; case 50727: /* AnalogBalance */ FORCC ab[c] = getreal(type); -@@ -6053,6 +6057,11 @@ +@@ -6114,6 +6114,11 @@ case 50752: read_shorts (cr2_slice, 3); break; @@ -1240,7 +1259,7 @@ case 50829: /* ActiveArea */ top_margin = getint(type); left_margin = getint(type); -@@ -6085,21 +6094,27 @@ +@@ -6146,21 +6151,27 @@ fread (buf, sony_length, 1, ifp); sony_decrypt (buf, sony_length/4, 1, sony_key); sfp = ifp; @@ -1276,7 +1295,7 @@ cam_xyz_coeff (cmatrix, cam_xyz); } if (asn[0]) { -@@ -6107,13 +6122,14 @@ +@@ -6168,13 +6179,14 @@ FORCC cam_mul[c] = 1 / asn[c]; } if (!use_cm) @@ -1292,7 +1311,15 @@ fseek (ifp, base, SEEK_SET); order = get2(); -@@ -6191,7 +6207,12 @@ +@@ -6206,6 +6218,7 @@ + shutter = tiff_ifd[i].shutter; + tiff_ifd[i].shutter = shutter; + } ++ + for (i=0; i < tiff_nifds; i++) { + if (max_samp < tiff_ifd[i].samples) + max_samp = tiff_ifd[i].samples; +@@ -6266,7 +6279,12 @@ case 8: load_raw = &CLASS eight_bit_load_raw; break; case 12: if (tiff_ifd[raw].phint == 2) load_flags = 6; @@ -1306,7 +1333,7 @@ case 14: load_flags = 0; case 16: load_raw = &CLASS unpacked_load_raw; if (!strncmp(make,"OLYMPUS",7) && -@@ -6230,6 +6251,7 @@ +@@ -6305,6 +6323,7 @@ case 32803: load_raw = &CLASS kodak_65000_load_raw; } case 32867: case 34892: break; @@ -1314,7 +1341,7 @@ default: is_raw = 0; } if (!dng_version) -@@ -6315,7 +6337,7 @@ +@@ -6390,7 +6409,7 @@ { const char *file, *ext; char *jname, *jfile, *jext; @@ -1323,7 +1350,7 @@ ext = strrchr (ifname, '.'); file = strrchr (ifname, '/'); -@@ -6337,13 +6359,14 @@ +@@ -6412,13 +6431,14 @@ } else while (isdigit(*--jext)) { if (*jext != '9') { @@ -1340,7 +1367,7 @@ if (verbose) fprintf (stderr,_("Reading metadata from %s ...\n"), jname); parse_tiff (12); -@@ -6620,6 +6643,7 @@ +@@ -6693,6 +6713,7 @@ load_raw = ph1.format < 3 ? &CLASS phase_one_load_raw : &CLASS phase_one_load_raw_c; maximum = 0xffff; @@ -1348,16 +1375,7 @@ strcpy (make, "Phase One"); if (model[0]) return; switch (raw_height) { -@@ -6658,7 +6682,7 @@ - } else if (tag == 0xc000) { - c = order; - order = 0x4949; -- if ((tag = get4()) > 10000) tag = get4(); -+ while ((tag = get4()) > 10000); - width = tag; - height = get4(); - order = c; -@@ -6688,7 +6712,11 @@ +@@ -6761,7 +6782,11 @@ order = get2(); hlen = get4(); if (get4() == 0x48454150) /* "HEAP" */ @@ -1369,7 +1387,7 @@ if (parse_tiff (save+6)) apply_tiff(); fseek (ifp, save+len, SEEK_SET); } -@@ -6960,7 +6988,8 @@ +@@ -7033,7 +7058,8 @@ { static const struct { const char *prefix; @@ -1379,7 +1397,22 @@ } table[] = { { "AgfaPhoto DC-833m", 0, 0, /* DJC */ { 11438,-3762,-1115,-2409,9914,2497,-1227,2295,5300 } }, -@@ -7919,6 +7948,33 @@ +@@ -7977,12 +8003,12 @@ + { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, + { "Sony DSC-RX100", 0, 0, + { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } }, +- { "Sony DSC-RX10", 0, 0, /* also RX10M2 */ ++ { "Sony DSC-RX10", 0, 0, + { 6679,-1825,-745,-5047,13256,1953,-1580,2422,5183 } }, + { "Sony DSC-RX1RM2", 0, 0, + { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, + { "Sony DSC-RX1", 0, 0, +- { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, ++ { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, + { "Sony DSLR-A100", 0, 0xfeb, + { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } }, + { "Sony DSLR-A290", 0, 0, +@@ -8088,6 +8114,33 @@ } break; } @@ -1413,7 +1446,7 @@ } void CLASS simple_coeff (int index) -@@ -8229,7 +8285,7 @@ +@@ -8410,7 +8463,7 @@ tiff_flip = flip = filters = UINT_MAX; /* unknown */ raw_height = raw_width = fuji_width = fuji_layout = cr2_slice[0] = 0; maximum = height = width = top_margin = left_margin = 0; @@ -1422,7 +1455,7 @@ iso_speed = shutter = aperture = focal_len = unique_id = 0; tiff_nifds = 0; memset (tiff_ifd, 0, sizeof tiff_ifd); -@@ -8261,13 +8317,20 @@ +@@ -8442,13 +8495,20 @@ fread (head, 1, 32, ifp); fseek (ifp, 0, SEEK_END); flen = fsize = ftell(ifp); @@ -1445,7 +1478,7 @@ parse_ciff (hlen, flen-hlen, 0); load_raw = &CLASS canon_load_raw; } else if (parse_tiff(0)) apply_tiff(); -@@ -8313,6 +8376,7 @@ +@@ -8494,6 +8554,7 @@ fseek (ifp, 100+28*(shot_select > 0), SEEK_SET); parse_tiff (data_offset = get4()); parse_tiff (thumb_offset+12); @@ -1453,7 +1486,7 @@ apply_tiff(); } else if (!memcmp (head,"RIFF",4)) { fseek (ifp, 0, SEEK_SET); -@@ -8426,9 +8490,10 @@ +@@ -8607,9 +8668,10 @@ if (make[0] == 0) parse_smal (0, flen); if (make[0] == 0) { parse_jpeg(0); @@ -1467,7 +1500,7 @@ strcpy (make, "OmniVision"); data_offset = ftell(ifp) + 0x8000-32; width = raw_width; -@@ -8437,6 +8502,7 @@ +@@ -8618,6 +8680,7 @@ filters = 0x16161616; } else is_raw = 0; } @@ -1475,7 +1508,7 @@ for (i=0; i < sizeof corp / sizeof *corp; i++) if (strcasestr (make, corp[i])) /* Simplify company names */ -@@ -8468,7 +8534,7 @@ +@@ -8649,7 +8712,7 @@ if (height == 3136 && width == 4864) /* Pentax K20D and Samsung GX20 */ { height = 3124; width = 4688; filters = 0x16161616; } if (width == 4352 && (!strcmp(model,"K-r") || !strcmp(model,"K-x"))) @@ -1484,15 +1517,15 @@ if (width >= 4960 && !strncmp(model,"K-5",3)) { left_margin = 10; width = 4950; filters = 0x16161616; } if (width == 4736 && !strcmp(model,"K-7")) -@@ -8487,6 +8553,7 @@ - switch (tiff_compress) { +@@ -8669,6 +8732,7 @@ + case 0: case 1: load_raw = &CLASS packed_dng_load_raw; break; case 7: load_raw = &CLASS lossless_dng_load_raw; break; + case 8: load_raw = &CLASS deflate_dng_load_raw; break; case 34892: load_raw = &CLASS lossy_dng_load_raw; break; default: load_raw = 0; } -@@ -8541,6 +8608,7 @@ +@@ -8725,6 +8789,7 @@ if (height > width) pixel_aspect = 2; filters = 0; simple_coeff(0); @@ -1500,7 +1533,7 @@ } else if (!strcmp(make,"Canon") && tiff_bps == 15) { switch (width) { case 3344: width -= 66; -@@ -8846,24 +8914,53 @@ +@@ -9034,24 +9099,53 @@ if (load_raw == &CLASS lossless_jpeg_load_raw) load_raw = &CLASS hasselblad_load_raw; if (raw_width == 7262) { @@ -1559,7 +1592,7 @@ } else if (raw_width == 4090) { strcpy (model, "V96C"); height -= (top_margin = 6); -@@ -8921,6 +9018,7 @@ +@@ -9109,6 +9203,7 @@ filters = 0x16161616; } } else if (!strcmp(make,"Leica") || !strcmp(make,"Panasonic")) { @@ -1567,7 +1600,7 @@ if ((flen - data_offset) / (raw_width*8/7) == raw_height) load_raw = &CLASS panasonic_load_raw; if (!load_raw) { -@@ -8938,6 +9036,7 @@ +@@ -9126,6 +9221,7 @@ } filters = 0x01010101 * (uchar) "\x94\x61\x49\x16" [((filters-1) ^ (left_margin & 1) ^ (top_margin << 1)) & 3]; @@ -1575,7 +1608,7 @@ } else if (!strcmp(model,"C770UZ")) { height = 1718; width = 2304; -@@ -9155,6 +9254,18 @@ +@@ -9357,6 +9453,18 @@ memcpy (rgb_cam, cmatrix, sizeof cmatrix); raw_color = 0; } @@ -1594,7 +1627,7 @@ if (raw_color) adobe_coeff (make, model); if (load_raw == &CLASS kodak_radc_load_raw) if (raw_color) adobe_coeff ("Apple","Quicktake"); -@@ -9169,9 +9280,9 @@ +@@ -9371,9 +9479,9 @@ if (raw_width < width ) raw_width = width; } if (!tiff_bps) tiff_bps = 12; @@ -1606,7 +1639,7 @@ is_raw = 0; #ifdef NO_JASPER if (load_raw == &CLASS redcine_load_raw) { -@@ -9250,194 +9361,249 @@ +@@ -9452,199 +9560,250 @@ } #endif @@ -1634,10 +1667,14 @@ - { { 0.529317, 0.330092, 0.140588 }, - { 0.098368, 0.873465, 0.028169 }, - { 0.016879, 0.117663, 0.865457 } }; +- static const double aces_rgb[3][3] = +- { { 0.432996, 0.375380, 0.189317 }, +- { 0.089427, 0.816523, 0.102989 }, +- { 0.019165, 0.118150, 0.941914 } }; - static const double (*out_rgb[])[3] = -- { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb }; +- { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb, aces_rgb }; - static const char *name[] = -- { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ" }; +- { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ", "ACES" }; - static const unsigned phead[] = - { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, - 0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d }; @@ -1658,7 +1695,7 @@ - gamma_curve (gamm[0], gamm[1], 0, 0); - memcpy (out_cam, rgb_cam, sizeof out_cam); - raw_color |= colors == 1 || document_mode || -- output_color < 1 || output_color > 5; +- output_color < 1 || output_color > 6; - if (!raw_color) { - oprof = (unsigned *) calloc (phead[0], 1); - merror (oprof, "convert_to_rgb()"); @@ -2023,37 +2060,42 @@ + + delete [] cBuffer; + delete [] uBuffer; - } ++} + } + + if (ifd->sample_format == 3) { // Floating point data + copyFloatDataToInt(float_raw_image, raw_image, raw_width*raw_height, maximum); + } -+} -+ -+/* RT: removed unused functions */ + } ++/* RT: removed unused functions */ ++ struct tiff_tag { ushort tag, type; -@@ -9461,590 +9627,11 @@ + int count; +@@ -9667,594 +9826,11 @@ char desc[512], make[64], model[64], soft[32], date[20], artist[64]; }; --void CLASS tiff_set (ushort *ntag, +-void CLASS tiff_set (struct tiff_hdr *th, ushort *ntag, - ushort tag, ushort type, int count, int val) -{ - struct tiff_tag *tt; - int c; - - tt = (struct tiff_tag *)(ntag+1) + (*ntag)++; -- tt->tag = tag; -- tt->type = type; -- tt->count = count; -- if (type < 3 && count <= 4) +- tt->val.i = val; +- if (type == 1 && count <= 4) - FORC(4) tt->val.c[c] = val >> (c << 3); -- else if (type == 3 && count <= 2) +- else if (type == 2) { +- count = strnlen((char *)th + val, count-1) + 1; +- if (count <= 4) +- FORC(4) tt->val.c[c] = ((char *)th)[val+c]; +- } else if (type == 3 && count <= 2) - FORC(2) tt->val.s[c] = val >> (c << 4); -- else tt->val.i = val; +- tt->count = count; +- tt->type = type; +- tt->tag = tag; -} - -#define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) @@ -2067,55 +2109,6 @@ - th->order = htonl(0x4d4d4949) >> 16; - th->magic = 42; - th->ifd = 10; -- if (full) { -- tiff_set (&th->ntag, 254, 4, 1, 0); -- tiff_set (&th->ntag, 256, 4, 1, width); -- tiff_set (&th->ntag, 257, 4, 1, height); -- tiff_set (&th->ntag, 258, 3, colors, output_bps); -- if (colors > 2) -- th->tag[th->ntag-1].val.i = TOFF(th->bps); -- FORC4 th->bps[c] = output_bps; -- tiff_set (&th->ntag, 259, 3, 1, 1); -- tiff_set (&th->ntag, 262, 3, 1, 1 + (colors > 1)); -- } -- tiff_set (&th->ntag, 270, 2, 512, TOFF(th->desc)); -- tiff_set (&th->ntag, 271, 2, 64, TOFF(th->make)); -- tiff_set (&th->ntag, 272, 2, 64, TOFF(th->model)); -- if (full) { -- if (oprof) psize = ntohl(oprof[0]); -- tiff_set (&th->ntag, 273, 4, 1, sizeof *th + psize); -- tiff_set (&th->ntag, 277, 3, 1, colors); -- tiff_set (&th->ntag, 278, 4, 1, height); -- tiff_set (&th->ntag, 279, 4, 1, height*width*colors*output_bps/8); -- } else -- tiff_set (&th->ntag, 274, 3, 1, "12435867"[flip]-'0'); -- tiff_set (&th->ntag, 282, 5, 1, TOFF(th->rat[0])); -- tiff_set (&th->ntag, 283, 5, 1, TOFF(th->rat[2])); -- tiff_set (&th->ntag, 284, 3, 1, 1); -- tiff_set (&th->ntag, 296, 3, 1, 2); -- tiff_set (&th->ntag, 305, 2, 32, TOFF(th->soft)); -- tiff_set (&th->ntag, 306, 2, 20, TOFF(th->date)); -- tiff_set (&th->ntag, 315, 2, 64, TOFF(th->artist)); -- tiff_set (&th->ntag, 34665, 4, 1, TOFF(th->nexif)); -- if (psize) tiff_set (&th->ntag, 34675, 7, psize, sizeof *th); -- tiff_set (&th->nexif, 33434, 5, 1, TOFF(th->rat[4])); -- tiff_set (&th->nexif, 33437, 5, 1, TOFF(th->rat[6])); -- tiff_set (&th->nexif, 34855, 3, 1, iso_speed); -- tiff_set (&th->nexif, 37386, 5, 1, TOFF(th->rat[8])); -- if (gpsdata[1]) { -- tiff_set (&th->ntag, 34853, 4, 1, TOFF(th->ngps)); -- tiff_set (&th->ngps, 0, 1, 4, 0x202); -- tiff_set (&th->ngps, 1, 2, 2, gpsdata[29]); -- tiff_set (&th->ngps, 2, 5, 3, TOFF(th->gps[0])); -- tiff_set (&th->ngps, 3, 2, 2, gpsdata[30]); -- tiff_set (&th->ngps, 4, 5, 3, TOFF(th->gps[6])); -- tiff_set (&th->ngps, 5, 1, 1, gpsdata[31]); -- tiff_set (&th->ngps, 6, 5, 1, TOFF(th->gps[18])); -- tiff_set (&th->ngps, 7, 5, 3, TOFF(th->gps[12])); -- tiff_set (&th->ngps, 18, 2, 12, TOFF(th->gps[20])); -- tiff_set (&th->ngps, 29, 2, 12, TOFF(th->gps[23])); -- memcpy (th->gps, gpsdata, sizeof th->gps); -- } - th->rat[0] = th->rat[2] = 300; - th->rat[1] = th->rat[3] = 1; - FORC(6) th->rat[4+c] = 1000000; @@ -2130,6 +2123,55 @@ - sprintf (th->date, "%04d:%02d:%02d %02d:%02d:%02d", - t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); - strncpy (th->artist, artist, 64); +- if (full) { +- tiff_set (th, &th->ntag, 254, 4, 1, 0); +- tiff_set (th, &th->ntag, 256, 4, 1, width); +- tiff_set (th, &th->ntag, 257, 4, 1, height); +- tiff_set (th, &th->ntag, 258, 3, colors, output_bps); +- if (colors > 2) +- th->tag[th->ntag-1].val.i = TOFF(th->bps); +- FORC4 th->bps[c] = output_bps; +- tiff_set (th, &th->ntag, 259, 3, 1, 1); +- tiff_set (th, &th->ntag, 262, 3, 1, 1 + (colors > 1)); +- } +- tiff_set (th, &th->ntag, 270, 2, 512, TOFF(th->desc)); +- tiff_set (th, &th->ntag, 271, 2, 64, TOFF(th->make)); +- tiff_set (th, &th->ntag, 272, 2, 64, TOFF(th->model)); +- if (full) { +- if (oprof) psize = ntohl(oprof[0]); +- tiff_set (th, &th->ntag, 273, 4, 1, sizeof *th + psize); +- tiff_set (th, &th->ntag, 277, 3, 1, colors); +- tiff_set (th, &th->ntag, 278, 4, 1, height); +- tiff_set (th, &th->ntag, 279, 4, 1, height*width*colors*output_bps/8); +- } else +- tiff_set (th, &th->ntag, 274, 3, 1, "12435867"[flip]-'0'); +- tiff_set (th, &th->ntag, 282, 5, 1, TOFF(th->rat[0])); +- tiff_set (th, &th->ntag, 283, 5, 1, TOFF(th->rat[2])); +- tiff_set (th, &th->ntag, 284, 3, 1, 1); +- tiff_set (th, &th->ntag, 296, 3, 1, 2); +- tiff_set (th, &th->ntag, 305, 2, 32, TOFF(th->soft)); +- tiff_set (th, &th->ntag, 306, 2, 20, TOFF(th->date)); +- tiff_set (th, &th->ntag, 315, 2, 64, TOFF(th->artist)); +- tiff_set (th, &th->ntag, 34665, 4, 1, TOFF(th->nexif)); +- if (psize) tiff_set (th, &th->ntag, 34675, 7, psize, sizeof *th); +- tiff_set (th, &th->nexif, 33434, 5, 1, TOFF(th->rat[4])); +- tiff_set (th, &th->nexif, 33437, 5, 1, TOFF(th->rat[6])); +- tiff_set (th, &th->nexif, 34855, 3, 1, iso_speed); +- tiff_set (th, &th->nexif, 37386, 5, 1, TOFF(th->rat[8])); +- if (gpsdata[1]) { +- tiff_set (th, &th->ntag, 34853, 4, 1, TOFF(th->ngps)); +- tiff_set (th, &th->ngps, 0, 1, 4, 0x202); +- tiff_set (th, &th->ngps, 1, 2, 2, gpsdata[29]); +- tiff_set (th, &th->ngps, 2, 5, 3, TOFF(th->gps[0])); +- tiff_set (th, &th->ngps, 3, 2, 2, gpsdata[30]); +- tiff_set (th, &th->ngps, 4, 5, 3, TOFF(th->gps[6])); +- tiff_set (th, &th->ngps, 5, 1, 1, gpsdata[31]); +- tiff_set (th, &th->ngps, 6, 5, 1, TOFF(th->gps[18])); +- tiff_set (th, &th->ngps, 7, 5, 3, TOFF(th->gps[12])); +- tiff_set (th, &th->ngps, 18, 2, 12, TOFF(th->gps[20])); +- tiff_set (th, &th->ngps, 29, 2, 12, TOFF(th->gps[23])); +- memcpy (th->gps, gpsdata, sizeof th->gps); +- } -} - -void CLASS jpeg_thumb() @@ -2250,7 +2292,7 @@ - puts(_("-n Set threshold for wavelet denoising")); - puts(_("-H [0-9] Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)")); - puts(_("-t [0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW)")); -- puts(_("-o [0-5] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ)")); +- puts(_("-o [0-6] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ,ACES)")); -#ifndef NO_LCMS - puts(_("-o Apply output ICC profile from file")); - puts(_("-p Apply camera ICC profile from file or \"embed\"")); diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 77f0598b4..bfe9c1c9a 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -773,11 +773,13 @@ void Crop::update (int todo) if (todo & M_RGBCURVE) { double rrm, ggm, bbm; - DCPProfile *dcpProf = parent->imgsrc->getDCP(params.icm, parent->currWB); + DCPProfile::ApplyState as; + DCPProfile *dcpProf = parent->imgsrc->getDCP(params.icm, parent->currWB, as); + parent->ipf.rgbProc (baseCrop, laboCrop, this, parent->hltonecurve, parent->shtonecurve, parent->tonecurve, cshmap, params.toneCurve.saturation, parent->rCurve, parent->gCurve, parent->bCurve, satLimit , satLimitOpacity, parent->ctColorCurve, parent->ctOpacityCurve, parent->opautili, parent->clToningcurve, parent->cl2Toningcurve, parent->customToneCurve1, parent->customToneCurve2, parent->beforeToneCurveBW, parent->afterToneCurveBW, rrm, ggm, bbm, - parent->bwAutoR, parent->bwAutoG, parent->bwAutoB, dcpProf); + parent->bwAutoR, parent->bwAutoG, parent->bwAutoB, dcpProf, as); } /*xref=000;yref=000; @@ -814,7 +816,7 @@ void Crop::update (int todo) LUTu dummy; int moderetinex; // parent->ipf.MSR(labnCrop, labnCrop->W, labnCrop->H, 1); - parent->ipf.chromiLuminanceCurve (this, 1, labnCrop, labnCrop, parent->chroma_acurve, parent->chroma_bcurve, parent->satcurve, parent->lhskcurve, parent->clcurve, parent->lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy, dummy, dummy); + parent->ipf.chromiLuminanceCurve (this, 1, labnCrop, labnCrop, parent->chroma_acurve, parent->chroma_bcurve, parent->satcurve, parent->lhskcurve, parent->clcurve, parent->lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); parent->ipf.vibrance (labnCrop); if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { diff --git a/rtengine/demosaic_algos.cc b/rtengine/demosaic_algos.cc index c6d66e4bf..72f801bab 100644 --- a/rtengine/demosaic_algos.cc +++ b/rtengine/demosaic_algos.cc @@ -1414,10 +1414,7 @@ SSEFUNCTION void RawImageSource::lmmse_interpolate_omp(int winw, int winh, int i gamtab = &(Color::gammatab_24_17a); } else { gamtab = new LUTf(65536, LUT_CLIP_ABOVE | LUT_CLIP_BELOW); - - for(int i = 0; i < 65536; i++) { - (*gamtab)[i] = (float)i / 65535.f; - } + gamtab->makeIdentity(65535.f); } diff --git a/rtengine/diagonalcurves.cc b/rtengine/diagonalcurves.cc index f09eb3459..a5505391e 100644 --- a/rtengine/diagonalcurves.cc +++ b/rtengine/diagonalcurves.cc @@ -72,11 +72,15 @@ DiagonalCurve::DiagonalCurve (const std::vector& p, int poly_pn) if(x[0] == 0.f && x[1] == 0.f) // Avoid crash when first two points are at x = 0 (git Issue 2888) + { x[1] = 0.01f; + } if(x[0] == 1.f && x[1] == 1.f) // Avoid crash when first two points are at x = 1 (100 in gui) (git Issue 2923) + { x[0] = 0.99f; + } if (!identity) { if (kind == DCT_Spline && N > 2) { @@ -260,6 +264,8 @@ void DiagonalCurve::NURBS_set () // adding the final horizontal segment, always (see under) poly_x.push_back(3.0); // 3.0 is a hack for optimization purpose of the getVal method (the last value has to be beyond the normal range) poly_y.push_back(y[N - 1]); + + fillDyByDx(); } double DiagonalCurve::getVal (double t) const @@ -301,10 +307,10 @@ double DiagonalCurve::getVal (double t) const } // do a binary search for the right interval: - int k_lo = 0, k_hi = N - 1; + unsigned int k_lo = 0, k_hi = N - 1; - while (k_hi - k_lo > 1) { - int k = (k_hi + k_lo) / 2; + while (k_hi > 1 + k_lo) { + unsigned int k = (k_hi + k_lo) / 2; if (x[k] > t) { k_hi = k; @@ -323,7 +329,7 @@ double DiagonalCurve::getVal (double t) const else { // if (kind==Spline) { double a = (x[k_hi] - t) / h; double b = (t - x[k_lo]) / h; - double r = a * y[k_lo] + b * y[k_hi] + ((a * a * a - a) * ypp[k_lo] + (b * b * b - b) * ypp[k_hi]) * (h * h) / 6.0; + double r = a * y[k_lo] + b * y[k_hi] + ((a * a * a - a) * ypp[k_lo] + (b * b * b - b) * ypp[k_hi]) * (h * h) * 0.1666666666666666666666666666666; return CLIPD(r); } @@ -334,7 +340,7 @@ double DiagonalCurve::getVal (double t) const // get the hash table entry by rounding the value (previously multiplied by "hashSize") unsigned short int i = (unsigned short int)(t * hashSize); - if (i > (hashSize + 1)) { + if (UNLIKELY(i > (hashSize + 1))) { //printf("\nOVERFLOW: hash #%d is used while seeking for value %.8f, corresponding polygon's point #%d (out of %d point) x value: %.8f\n\n", i, t, hash.at(i), poly_x.size(), poly_x[hash.at(i)]); printf("\nOVERFLOW: hash #%d is used while seeking for value %.8f\n\n", i, t); return t; @@ -347,7 +353,7 @@ double DiagonalCurve::getVal (double t) const k_hi = hash.at(i).higherValue; // do a binary search for the right interval : - while (k_hi - k_lo > 1) { + while (k_hi > 1 + k_lo) { unsigned int k = (k_hi + k_lo) / 2; if (poly_x[k] > t) { @@ -357,13 +363,7 @@ double DiagonalCurve::getVal (double t) const } } - if (k_lo == k_hi) { - k_hi = k_lo + 1; - } - - double dx = poly_x[k_hi] - poly_x[k_lo]; - double dy = poly_y[k_hi] - poly_y[k_lo]; - return poly_y[k_lo] + (t - poly_x[k_lo]) * ( dy ) / dx; + return poly_y[k_lo] + (t - poly_x[k_lo]) * dyByDx[k_lo]; break; } diff --git a/rtengine/flatcurves.cc b/rtengine/flatcurves.cc index ee4d6d29c..5a4dfeacf 100644 --- a/rtengine/flatcurves.cc +++ b/rtengine/flatcurves.cc @@ -16,21 +16,14 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include -#include #include "curves.h" #include #include -#include "mytime.h" -#include - -#include -#include namespace rtengine { -FlatCurve::FlatCurve (const std::vector& p, bool isPeriodic, int poly_pn) : kind(FCT_Empty), leftTangent(NULL), rightTangent(NULL), identityValue(0.5), periodic(isPeriodic) +FlatCurve::FlatCurve (const std::vector& p, bool isPeriodic, int poly_pn) : kind(FCT_Empty), leftTangent(nullptr), rightTangent(nullptr), identityValue(0.5), periodic(isPeriodic) { ppn = poly_pn > 65500 ? 65500 : poly_pn; @@ -341,17 +334,7 @@ void FlatCurve::CtrlPoints_set () poly_x.push_back(3.0); // 3.0 is a hack for optimization purpose of the getVal method (the last value has to be beyond the normal range) poly_y.push_back(sc_y[j - 1]); - /* - // Checking the values - Glib::ustring fname = "Curve.xyz"; // TopSolid'Design "plot" file format - std::ofstream f (fname.c_str()); - f << "$" << std::endl;; - for (unsigned int iter = 0; iter < poly_x.size(); iter++) { - f << poly_x[iter] << ", " << poly_y[iter] << ", 0." << std::endl;; - } - f << "$" << std::endl;; - f.close (); - */ + fillDyByDx(); } double FlatCurve::getVal (double t) const @@ -367,10 +350,10 @@ double FlatCurve::getVal (double t) const } // do a binary search for the right interval: - int k_lo = 0, k_hi = poly_x.size() - 1; + unsigned int k_lo = 0, k_hi = poly_x.size() - 1; - while (k_hi - k_lo > 1) { - int k = (k_hi + k_lo) / 2; + while (k_hi > 1 + k_lo) { + unsigned int k = (k_hi + k_lo) / 2; if (poly_x[k] > t) { k_hi = k; @@ -379,9 +362,7 @@ double FlatCurve::getVal (double t) const } } - double dx = poly_x[k_hi] - poly_x[k_lo]; - double dy = poly_y[k_hi] - poly_y[k_lo]; - return poly_y[k_lo] + (t - poly_x[k_lo]) * dy / dx; + return poly_y[k_lo] + (t - poly_x[k_lo]) * dyByDx[k_lo]; break; } diff --git a/rtengine/helpersse2.h b/rtengine/helpersse2.h index da1691748..0f1fc5759 100644 --- a/rtengine/helpersse2.h +++ b/rtengine/helpersse2.h @@ -26,17 +26,20 @@ typedef __m128i vint2; #define LVFU(x) _mm_loadu_ps(&x) #define STVF(x,y) _mm_store_ps(&x,y) #define STVFU(x,y) _mm_storeu_ps(&x,y) +#define LVI(x) _mm_load_si128((__m128i*)&x) #else // there is a bug in gcc 4.7.x when using openmp and aligned memory and -O3, also need to map the aligned functions to unaligned functions for WIN32 builds #define LVF(x) _mm_loadu_ps((float*)&x) #define LVFU(x) _mm_loadu_ps(&x) #define STVF(x,y) _mm_storeu_ps(&x,y) #define STVFU(x,y) _mm_storeu_ps(&x,y) +#define LVI(x) _mm_loadu_si128((__m128i*)&x) #endif #else #define LVF(x) _mm_load_ps((float*)&x) #define LVFU(x) _mm_loadu_ps(&x) #define STVF(x,y) _mm_store_ps(&x,y) #define STVFU(x,y) _mm_storeu_ps(&x,y) +#define LVI(x) _mm_load_si128((__m128i*)&x) #endif #if defined(__x86_64__) && defined(__AVX__) diff --git a/rtengine/iimage.h b/rtengine/iimage.h index 4b0450e54..1f82ea3e6 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -818,33 +818,21 @@ public: } } } else if (interp == TI_Bilinear) { - for (int i = 0; i < nh; i++) { - int sy = i * height / nh; + float heightByNh = float(height) / float(nh); + float widthByNw = float(width) / float(nw); + float syf = 0.f; - if (sy >= height) { - sy = height - 1; - } + for (int i = 0; i < nh; i++, syf += heightByNh) { + int sy = syf; + float dy = syf - float(sy); + int ny = sy < height - 1 ? sy + 1 : sy; - float dy = float(i) * float(height) / float(nh) - float(sy); - int ny = sy + 1; + float sxf = 0.f; - if (ny >= height) { - ny = sy; - } - - for (int j = 0; j < nw; j++) { - int sx = j * width / nw; - - if (sx >= width) { - sx = width; - } - - float dx = float(j) * float(width) / float(nw) - float(sx); - int nx = sx + 1; - - if (nx >= width) { - nx = sx; - } + for (int j = 0; j < nw; j++, sxf += widthByNw) { + int sx = sxf; + float dx = sxf - float(sx); + int nx = sx < width - 1 ? sx + 1 : sx; convertTo(r(sy, sx) * (1.f - dx) * (1.f - dy) + r(sy, nx)*dx * (1.f - dy) + r(ny, sx) * (1.f - dx)*dy + r(ny, nx)*dx * dy, imgPtr->r(i, j)); convertTo(g(sy, sx) * (1.f - dx) * (1.f - dy) + g(sy, nx)*dx * (1.f - dy) + g(ny, sx) * (1.f - dx)*dy + g(ny, nx)*dx * dy, imgPtr->g(i, j)); @@ -1010,9 +998,6 @@ public: avg_r += double(r_); avg_g += double(g_); avg_b += double(b_); - /*avg_r += intpow( (double)r(i, j), p); - avg_g += intpow( (double)g(i, j), p); - avg_b += intpow( (double)b(i, j), p);*/ n++; } @@ -1616,9 +1601,6 @@ public: avg_r += double(r_); avg_g += double(g_); avg_b += double(b_); - /*avg_r += intpow( (double)r(i, j), p); - avg_g += intpow( (double)g(i, j), p); - avg_b += intpow( (double)b(i, j), p);*/ n++; } diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 905c8c50e..f252dc1bb 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -66,7 +66,7 @@ public: embProfile(NULL), idata(NULL), dirpyrdenoiseExpComp(INFINITY) {} virtual ~ImageSource () {} - virtual int load (Glib::ustring fname, bool batch = false) = 0; + virtual int load (const Glib::ustring &fname, bool batch = false) = 0; virtual void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse) {}; virtual void demosaic (const RAWParams &raw) {}; virtual void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) {}; @@ -78,10 +78,10 @@ public: virtual void HLRecovery_inpaint (float** red, float** green, float** blue) {}; virtual void MSR(LabImage* lab, LUTf & mapcurve, bool &mapcontlutili, int width, int height, int skip, RetinexParams deh, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax) {}; - virtual bool IsrgbSourceModified() = 0; // tracks whether cached rgb output of demosaic has been modified + virtual bool IsrgbSourceModified() const = 0; // tracks whether cached rgb output of demosaic has been modified // use right after demosaicing image, add coarse transformation and put the result in the provided Imagefloat* - virtual void getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hlp, ColorManagementParams cmp, RAWParams raw) {} + virtual void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hlp, const ColorManagementParams &cmp, const RAWParams &raw) = 0; virtual eSensorType getSensorType () { return ST_NONE; @@ -89,12 +89,12 @@ public: // true is ready to provide the AutoWB, i.e. when the image has been demosaiced for RawImageSource virtual bool isWBProviderReady () = 0; - virtual void convertColorSpace (Imagefloat* image, ColorManagementParams cmp, ColorTemp &wb) = 0; // DIRTY HACK: this method is derived in rawimagesource and strimagesource, but (...,RAWParams raw) will be used ONLY for raw images + virtual void convertColorSpace (Imagefloat* image, const ColorManagementParams &cmp, const ColorTemp &wb) = 0; // DIRTY HACK: this method is derived in rawimagesource and strimagesource, but (...,RAWParams raw) will be used ONLY for raw images virtual void getAutoWBMultipliers (double &rm, double &gm, double &bm) = 0; - virtual ColorTemp getWB () = 0; + virtual ColorTemp getWB () const = 0; virtual ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal) = 0; - virtual double getDefGain () + virtual double getDefGain () const { return 1.0; } @@ -109,7 +109,7 @@ public: virtual ImageData* getImageData () = 0; virtual ImageMatrices* getImageMatrices () = 0; virtual bool isRAW() const = 0; - virtual DCPProfile* getDCP(ColorManagementParams cmp, ColorTemp &wb) + virtual DCPProfile* getDCP(const ColorManagementParams &cmp, ColorTemp &wb, DCPProfile::ApplyState &as) { return NULL; }; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 7434776d5..f585acacf 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -23,7 +23,9 @@ #include "../rtgui/ppversion.h" #include "colortemp.h" #include "improcfun.h" - +#ifdef _OPENMP +#include +#endif namespace rtengine { @@ -40,7 +42,7 @@ ImProcCoordinator::ImProcCoordinator () tonecurve(65536, 0), //,1); chaut(0.f), redaut(0.f), blueaut(0.f), maxredaut(0.f), maxblueaut(0.f), minredaut(0.f), minblueaut(0.f), nresi(0.f), chromina(0.f), sigma(0.f), lumema(0.f), - lumacurve(65536, 0), + lumacurve(32770, 0), // lumacurve[32768] and lumacurve[32769] will be set to 32768 and 32769 later to allow linear interpolation chroma_acurve(65536, 0), chroma_bcurve(65536, 0), satcurve(65536, 0), @@ -52,13 +54,10 @@ ImProcCoordinator::ImProcCoordinator () Noisecurve(65536, 0), NoiseCCcurve(65536, 0), vhist16(65536), vhist16bw(65536), - lhist16(65536), lhist16Cropped(65536), - lhist16CAM(65536), lhist16CroppedCAM(65536), + lhist16CAM(65536), lhist16CCAM(65536), lhist16RETI(), - histCropped(65536), - lhist16Clad(65536), lhist16CLlad(65536), - lhist16LClad(65536), lhist16LLClad(65536), + lhist16LClad(65536), histRed(256), histRedRaw(256), histGreen(256), histGreenRaw(256), histBlue(256), histBlueRaw(256), @@ -67,7 +66,6 @@ ImProcCoordinator::ImProcCoordinator () histToneCurveBW(256), histLCurve(256), histCCurve(256), - histCLurve(256), histLLCurve(256), histLCAM(256), @@ -367,7 +365,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) */ imgsrc->convertColorSpace(orig_prev, params.icm, currWB); - ipf.firstAnalysis (orig_prev, ¶ms, vhist16); + ipf.firstAnalysis (orig_prev, params, vhist16); } readyphase++; @@ -444,36 +442,36 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, - vhist16, histCropped, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, scale == 1 ? 1 : 1); + vhist16, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, scale == 1 ? 1 : 1); CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, scale == 1 ? 1 : 1); CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, scale == 1 ? 1 : 1); CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, scale == 1 ? 1 : 1); - TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); - double wp[3][3] = { - {wprof[0][0], wprof[0][1], wprof[0][2]}, - {wprof[1][0], wprof[1][1], wprof[1][2]}, - {wprof[2][0], wprof[2][1], wprof[2][2]} - }; - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params.icm.working); - double wip[3][3] = { - {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, - {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, - {wiprof[2][0], wiprof[2][1], wiprof[2][2]} - }; opautili = false; - params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, wip, opautili); - bool clctoningutili = false; - bool llctoningutili = false; - CurveFactory::curveToningCL(clctoningutili, params.colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16); - // clToningcurve.dump("CLToning3"); - CurveFactory::curveToningLL(llctoningutili, params.colorToning.cl2curve, cl2Toningcurve, scale == 1 ? 1 : 16); - - CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, vhist16bw, histToneCurveBW, beforeToneCurveBW, afterToneCurveBW, scale == 1 ? 1 : 1); + if(params.colorToning.enabled) { + TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); + double wp[3][3] = { + {wprof[0][0], wprof[0][1], wprof[0][2]}, + {wprof[1][0], wprof[1][1], wprof[1][2]}, + {wprof[2][0], wprof[2][1], wprof[2][2]} + }; + TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params.icm.working); + double wip[3][3] = { + {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, + {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, + {wiprof[2][0], wiprof[2][1], wiprof[2][2]} + }; + params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, wip, opautili); + CurveFactory::curveToning(params.colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16); + CurveFactory::curveToning(params.colorToning.cl2curve, cl2Toningcurve, scale == 1 ? 1 : 16); + } + if(params.blackwhite.enabled) { + CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, vhist16bw, histToneCurveBW, beforeToneCurveBW, afterToneCurveBW, scale == 1 ? 1 : 1); + } float satLimit = float(params.colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f; float satLimitOpacity = 1.f - (float(params.colorToning.saturatedOpacity) / 100.f); @@ -537,9 +535,11 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) double ggm = 33.; double bbm = 33.; - DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB); + DCPProfile::ApplyState as; + DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB, as); + ipf.rgbProc (oprevi, oprevl, NULL, hltonecurve, shtonecurve, tonecurve, shmap, params.toneCurve.saturation, - rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, beforeToneCurveBW, afterToneCurveBW, rrm, ggm, bbm, bwAutoR, bwAutoG, bwAutoB, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, dcpProf); + rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, beforeToneCurveBW, afterToneCurveBW, rrm, ggm, bbm, bwAutoR, bwAutoG, bwAutoB, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, dcpProf, as); if(params.blackwhite.enabled && params.blackwhite.autoc && abwListener) { if (settings->verbose) { @@ -561,55 +561,46 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } // compute L channel histogram - int x1, y1, x2, y2, pos; + int x1, y1, x2, y2; params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); - lhist16.clear(); - lhist16Cropped.clear(); - lhist16Clad.clear(); - lhist16CLlad.clear(); - lhist16LLClad.clear(); - - for (int x = 0; x < pH; x++) - for (int y = 0; y < pW; y++) { - pos = CLIP((int)(oprevl->L[x][y])); - lhist16[pos]++; - - if (y >= y1 && y < y2 && x >= x1 && x < x2) { - lhist16Cropped[pos]++; - } - } } readyphase++; - if ((todo & M_LUMACURVE) || (todo & M_CROP)) { - utili = false; - CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, lhist16, lhist16Cropped, - lumacurve, histLCurve, scale == 1 ? 1 : 16, utili); + if (todo & (M_LUMACURVE | M_CROP)) { + LUTu lhist16(32768); + lhist16.clear(); +#ifdef _OPENMP + const int numThreads = min(max(pW * pH / (int)lhist16.getSize(), 1), omp_get_max_threads()); + #pragma omp parallel num_threads(numThreads) if(numThreads>1) +#endif + { + LUTu lhist16thr(lhist16.getSize()); + lhist16thr.clear(); +#ifdef _OPENMP + #pragma omp for nowait +#endif + + for (int x = 0; x < pH; x++) + for (int y = 0; y < pW; y++) { + int pos = (int)(oprevl->L[x][y]); + lhist16thr[pos]++; + } + +#ifdef _OPENMP + #pragma omp critical +#endif + lhist16 += lhist16thr; + } + CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, lhist16, lumacurve, histLCurve, scale == 1 ? 1 : 16, utili); } if (todo & M_LUMACURVE) { - autili = false; - butili = false; - ccutili = false; - cclutili = false; - clcutili = false; - CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, lhist16CLlad, histCLurve, scale == 1 ? 1 : 16); - float adjustr = 1.0f; + CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, scale == 1 ? 1 : 16); - - /* if (params.icm.working=="ProPhoto") {adjustr = adjustbg = 1.2f;}// 1.2 instead 1.0 because it's very rare to have C>170.. - else if (params.icm.working=="Adobe RGB") {adjustr = 1.8f; adjustbg = 1.4f;} - else if (params.icm.working=="sRGB") {adjustr = 2.0f; adjustbg = 1.7f;} - else if (params.icm.working=="WideGamut") {adjustr = adjustbg = 1.2f;} - else if (params.icm.working=="Beta RGB") {adjustr = adjustbg = 1.4f;} - else if (params.icm.working=="BestRGB") {adjustr = adjustbg = 1.4f;} - else if (params.icm.working=="BruceRGB") {adjustr = 1.8f; adjustbg = 1.5f;} - */ - CurveFactory::complexsgnCurve (adjustr, autili, butili, ccutili, cclutili, params.labCurve.chromaticity, params.labCurve.rstprotection, - params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, params.labCurve.lccurve, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, - lhist16Clad, lhist16LLClad, histCCurve, histLLCurve, scale == 1 ? 1 : 16); + CurveFactory::complexsgnCurve (autili, butili, ccutili, cclutili, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, + params.labCurve.lccurve, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, scale == 1 ? 1 : 16); } if (todo & (M_LUMINANCE + M_COLOR) ) { @@ -617,8 +608,9 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) progress ("Applying Color Boost...", 100 * readyphase / numofphases); // ipf.MSR(nprevl, nprevl->W, nprevl->H, 1); - - ipf.chromiLuminanceCurve (NULL, pW, nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, histCCurve, histCLurve, histLLCurve, histLCurve); + histCCurve.clear(); + histLCurve.clear(); + ipf.chromiLuminanceCurve (NULL, pW, nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, histCCurve, histLCurve); ipf.vibrance(nprevl); if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { @@ -680,7 +672,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) wavcontlutili = false; //CurveFactory::curveWavContL ( wavcontlutili,params.wavelet.lcurve, wavclCurve, LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,int skip); - CurveFactory::curveWavContL(wavcontlutili, params.wavelet.wavclCurve, wavclCurve , /*lhist16CLlad, histCLurve,*/ scale == 1 ? 1 : 16); + CurveFactory::curveWavContL(wavcontlutili, params.wavelet.wavclCurve, wavclCurve, scale == 1 ? 1 : 16); if((params.wavelet.enabled)) { @@ -699,39 +691,24 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) if(params.colorappearance.enabled) { //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, pos, posc; + int x1, y1, x2, y2; params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); lhist16CAM.clear(); - lhist16CroppedCAM.clear(); lhist16CCAM.clear(); - for (int x = 0; x < pH; x++) - for (int y = 0; y < pW; y++) { - pos = CLIP((int)(nprevl->L[x][y])); - - if(!params.colorappearance.datacie) { - posc = CLIP((int)sqrt(nprevl->a[x][y] * nprevl->a[x][y] + nprevl->b[x][y] * nprevl->b[x][y])); + if(!params.colorappearance.datacie) { + for (int x = 0; x < pH; x++) + for (int y = 0; y < pW; y++) { + int pos = CLIP((int)(nprevl->L[x][y])); + int posc = CLIP((int)sqrt(nprevl->a[x][y] * nprevl->a[x][y] + nprevl->b[x][y] * nprevl->b[x][y])); lhist16CAM[pos]++; lhist16CCAM[posc]++; } + } - if (y >= y1 && y < y2 && x >= x1 && x < x2) { - lhist16CroppedCAM[pos]++; - } - } - - LUTu dummy; - CurveFactory::curveLightBrightColor ( - params.colorappearance.curveMode, params.colorappearance.curve, - params.colorappearance.curveMode2, params.colorappearance.curve2, - params.colorappearance.curveMode3, params.colorappearance.curve3, - lhist16CAM, lhist16CroppedCAM, histLCAM, - lhist16CCAM, histCCAM, - customColCurve1, - customColCurve2, - customColCurve3, - scale == 1 ? 1 : 1 - ); + CurveFactory::curveLightBrightColor (params.colorappearance.curve, params.colorappearance.curve2, params.colorappearance.curve3, + lhist16CAM, histLCAM, lhist16CCAM, histCCAM, + customColCurve1, customColCurve2, customColCurve3, 1); float fnum = imgsrc->getMetaData()->getFNumber (); // F number float fiso = imgsrc->getMetaData()->getISOSpeed () ; // ISO float fspeed = imgsrc->getMetaData()->getShutterSpeed () ; // Speed @@ -1308,7 +1285,6 @@ void ImProcCoordinator::startProcessing(int changeCode) void ImProcCoordinator::process () { - if (plistener) { plistener->setProgressState (true); } diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 6a6c203d2..4f1a6a691 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -107,16 +107,14 @@ protected: LUTf NoiseCCcurve; LUTu vhist16, vhist16bw; - LUTu lhist16, lhist16Cropped; - LUTu lhist16CAM, lhist16CroppedCAM; + LUTu lhist16CAM; LUTu lhist16CCAM; LUTu lhist16RETI; - LUTu histCropped; - LUTu lhist16Clad, lhist16CLlad, lhist16LClad, lhist16LLClad; + LUTu lhist16CLlad, lhist16LClad; LUTu histRed, histRedRaw; LUTu histGreen, histGreenRaw; LUTu histBlue, histBlueRaw; - LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve, histCLurve; + LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve; LUTu histLLCurve, histLCAM, histCCAM, histClad, bcabhist, histChroma, histLRETI; LUTf CAMBrightCurveJ, CAMBrightCurveQ; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index bc70bf5e5..264ff1e2a 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -40,6 +40,10 @@ #include "improccoordinator.h" #include "clutstore.h" #include "ciecam02.h" +#define BENCHMARK +#include "StopWatch.h" +#include "../rtgui/ppversion.h" +#include "../rtgui/guiutils.h" #undef CLIPD #define CLIPD(a) ((a)>0.0f?((a)<1.0f?(a):1.0f):0.0f) @@ -54,15 +58,15 @@ extern const Settings* settings; ImProcFunctions::~ImProcFunctions () { - if (monitorTransform != NULL) { + if (monitorTransform) { cmsDeleteTransform (monitorTransform); } - if (output2monitorTransform != NULL) { + if (output2monitorTransform) { cmsDeleteTransform (output2monitorTransform); } - if (lab2outputTransform != NULL) { + if (lab2outputTransform) { cmsDeleteTransform (lab2outputTransform); } } @@ -72,52 +76,24 @@ void ImProcFunctions::setScale (double iscale) scale = iscale; } -// Called from several threads -void ImProcFunctions::firstAnalysisThread (Imagefloat* original, Glib::ustring wprofile, unsigned int* histogram, int row_from, int row_to) -{ - - TMatrix wprof = iccStore->workingSpaceMatrix (wprofile); - - lumimul[0] = wprof[1][0]; - lumimul[1] = wprof[1][1]; - lumimul[2] = wprof[1][2]; - - int W = original->width; - - for (int i = row_from; i < row_to; i++) { - for (int j = 0; j < W; j++) { - - int r = original->r(i, j); - int g = original->g(i, j); - int b = original->b(i, j); - - int y = CLIP((int)(lumimul[0] * r + lumimul[1] * g + lumimul[2] * b)) ; - - if (histogram) { - histogram[y]++; - } - } - } -} - void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent) { // set up monitor transform - if (monitorTransform != NULL) { + if (monitorTransform) { cmsDeleteTransform (monitorTransform); } - if (output2monitorTransform != NULL) { + if (output2monitorTransform) { cmsDeleteTransform (output2monitorTransform); } - if (lab2outputTransform != NULL) { + if (lab2outputTransform) { cmsDeleteTransform (lab2outputTransform); } - monitorTransform = NULL; - output2monitorTransform = NULL; - lab2outputTransform = NULL; + monitorTransform = nullptr; + output2monitorTransform = nullptr; + lab2outputTransform = nullptr; #if !defined(__APPLE__) // No support for monitor profiles on OS X, all data is sRGB @@ -125,7 +101,7 @@ void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, con if (monitor) { MyMutex::MyLock lcmsLock (*lcmsMutex); - cmsHPROFILE iprof = cmsCreateLab4Profile(NULL); + cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr); monitorTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_8, monitorIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); // NOCACHE is for thread safety, NOOPTIMIZE for precision @@ -147,59 +123,66 @@ void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, con #endif } -void ImProcFunctions::firstAnalysis (Imagefloat* original, const ProcParams* params, LUTu & histogram) +void ImProcFunctions::firstAnalysis (const Imagefloat* const original, const ProcParams ¶ms, LUTu & histogram) { - Glib::ustring wprofile = params->icm.working; + TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); + + lumimul[0] = wprof[1][0]; + lumimul[1] = wprof[1][1]; + lumimul[2] = wprof[1][2]; + int W = original->width; + int H = original->height; + + float lumimulf[3] = {static_cast(lumimul[0]), static_cast(lumimul[1]), static_cast(lumimul[2])}; // calculate histogram of the y channel needed for contrast curve calculation in exposure adjustments - - int T = 1; -#ifdef _OPENMP - - if(multiThread) { - T = omp_get_max_threads(); - } - -#endif - - unsigned int** hist = new unsigned int* [T]; - - for (int i = 0; i < T; i++) { - hist[i] = new unsigned int[65536]; - memset (hist[i], 0, 65536 * sizeof(int)); - } - -#ifdef _OPENMP - #pragma omp parallel if (multiThread) - { - int H = original->height; - int tid = omp_get_thread_num(); - int nthreads = omp_get_num_threads(); - int blk = H / nthreads; - - if (tid < nthreads - 1) { - firstAnalysisThread (original, wprofile, hist[tid], tid * blk, (tid + 1)*blk); - } else { - firstAnalysisThread (original, wprofile, hist[tid], tid * blk, H); - } - } -#else - firstAnalysisThread (original, wprofile, hist[0], 0, original->height); -#endif - histogram.clear(); - for (int j = 0; j < T; j++) - for (int i = 0; i < 65536; i++) { - histogram[i] += hist[j][i]; + if(multiThread) { + +#ifdef _OPENMP + const int numThreads = min(max(W * H / (int)histogram.getSize(), 1), omp_get_max_threads()); + #pragma omp parallel num_threads(numThreads) if(numThreads>1) +#endif + { + LUTu hist(histogram.getSize()); + hist.clear(); +#ifdef _OPENMP + #pragma omp for nowait +#endif + + for (int i = 0; i < H; i++) { + for (int j = 0; j < W; j++) { + + float r = original->r(i, j); + float g = original->g(i, j); + float b = original->b(i, j); + + int y = (lumimulf[0] * r + lumimulf[1] * g + lumimulf[2] * b); + hist[y]++; + } + } + +#ifdef _OPENMP + #pragma omp critical +#endif + histogram += hist; + } + } else { + for (int i = 0; i < H; i++) { + for (int j = 0; j < W; j++) { - for (int i = 0; i < T; i++) { - delete [] hist[i]; + float r = original->r(i, j); + float g = original->g(i, j); + float b = original->b(i, j); + + int y = (lumimulf[0] * r + lumimulf[1] * g + lumimulf[2] * b); + histogram[y]++; + } + } } - - delete [] hist; } // Copyright (c) 2012 Jacques Desmis @@ -1460,41 +1443,20 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int LUTu & histLCAM, LUTu & histCCAM, LUTf & CAMBrightCurveJ, LUTf & CAMBrightCurveQ, float &mean, int Iterates, int scale, bool execsharp, float &d, int scalecd, int rtt) { if(params->colorappearance.enabled) { -//int lastskip; -//if(rtt==1) {lastskip=scalecd;} //not for Rtthumbnail #ifdef _DEBUG MyTime t1e, t2e; t1e.set(); #endif - LUTf dLcurve; - LUTu hist16JCAM; - float val; //preparate for histograms CIECAM - if(pW != 1) { //only with improccoordinator - dLcurve(65536, 0); - dLcurve.clear(); - hist16JCAM(65536); + LUTu hist16JCAM; + LUTu hist16_CCAM; + + if(pW != 1 && params->colorappearance.datacie) { //only with improccoordinator + hist16JCAM(32768); hist16JCAM.clear(); - - for (int i = 0; i < 32768; i++) { //# 32768*1.414 approximation maxi for chroma - val = (double)i / 32767.0; - dLcurve[i] = CLIPD(val); - } - } - - LUTf dCcurve(65536, 0); - LUTu hist16_CCAM(65536); - bool chropC = false; - float valc; - - if(pW != 1) { //only with improccoordinator - for (int i = 0; i < 48000; i++) { //# 32768*1.414 approximation maxi for chroma - valc = (double)i / 47999.0; - dCcurve[i] = CLIPD(valc); - } - + hist16_CCAM(48000); hist16_CCAM.clear(); } @@ -1505,15 +1467,16 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int float Yw; Yw = 1.0; double Xw, Zw; - float f, nc, yb, la, c, xw, yw, zw, f2, c2, nc2, yb2, la2; + float f, nc, yb, la, c, xw, yw, zw, f2, c2, nc2, yb2; float fl, n, nbb, ncb, aw; //d float xwd, ywd, zwd; int alg = 0; bool algepd = false; - float sum = 0.f; - const bool ciedata = (params->colorappearance.datacie && pW != 1); - bool jp = ciedata; + const bool epdEnabled = params->epd.enabled; + bool ciedata = (params->colorappearance.datacie && pW != 1) && !((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) + || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) + || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)); ColorTemp::temp2mulxyz (params->wb.temperature, params->wb.green, params->wb.method, Xw, Zw); //compute white Xw Yw Zw : white current WB @@ -1555,7 +1518,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } else if(params->colorappearance.algo == "QM") { alg = 2; algepd = true; - } else if(params->colorappearance.algo == "ALL") { + } else { /*if(params->colorappearance.algo == "ALL")*/ alg = 3; algepd = true; } @@ -1589,7 +1552,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int xwd = 95.04f; //fluo F7 ywd = 100.0f; zwd = 108.75f; - } else if(settings->viewingdevice == 7) { + } else { /*if(settings->viewingdevice == 7) */ xwd = 100.96f; //fluo F11 ywd = 100.0f; zwd = 64.35f; @@ -1609,7 +1572,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int yb2 = 23.0f; } else if(settings->viewingdevicegrey == 5) { yb2 = 30.0f; - } else if(settings->viewingdevicegrey == 6) { + } else { /* if(settings->viewingdevicegrey == 6)*/ yb2 = 40.0f; } @@ -1622,7 +1585,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } } - la2 = float(params->colorappearance.adaplum); + const float la2 = float(params->colorappearance.adaplum); // level of adaptation const float deg = (params->colorappearance.degree) / 100.0f; @@ -1704,132 +1667,6 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int const ColorAppearanceParams::eCTCModeId curveMode3 = params->colorappearance.curveMode3; const bool hasColCurve3 = bool(customColCurve3); - bool c1s = false; - bool c1co = false; - - if( hasColCurve3 && curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { - c1s = true; - } - - if(hasColCurve3 && curveMode3 == ColorAppearanceParams::TC_MODE_COLORF) { - c1co = true; - } - - if(CAMBrightCurveJ.dirty || CAMBrightCurveQ.dirty) { - bool needJ = (alg == 0 || alg == 1 || alg == 3); - bool needQ = (alg == 2 || alg == 3); - LUTu hist16J; - LUTu hist16Q; - - if (needJ) { - hist16J (65536); - hist16J.clear(); - } - - if (needQ) { - hist16Q (65536); - hist16Q.clear(); - } - - #pragma omp parallel - { - LUTu hist16Jthr; - LUTu hist16Qthr; - - if (needJ) { - hist16Jthr (65536); - hist16Jthr.clear(); - } - - if (needQ) { - hist16Qthr(65536); - hist16Qthr.clear(); - } - - #pragma omp for reduction(+:sum) - - for (int i = 0; i < height; i++) - for (int j = 0; j < width; j++) { //rough correspondence between L and J - float currL = lab->L[i][j] / 327.68f; - float koef = 1.0f; //rough correspondence between L and J - -// if (currL>95.f) koef=1.f; - if(currL > 85.f) { - koef = 0.97f; - } else if(currL > 80.f) { - koef = 0.93f; - } else if(currL > 70.f) { - koef = 0.87f; - } else if(currL > 60.f) { - koef = 0.85f; - } else if(currL > 50.f) { - koef = 0.8f; - } else if(currL > 40.f) { - koef = 0.75f; - } -// else if(currL>30.f) koef=0.7f; - else if(currL > 20.f) { - koef = 0.7f; - } else if(currL > 10.f) { - koef = 0.9f; - } - -// else if(currL>0.f) koef=1.0f; - - if (needJ) { - hist16Jthr[CLIP((int)((koef * lab->L[i][j])))]++; //evaluate histogram luminance L # J - } - - if (needQ) { - hist16Qthr[CLIP((int) (sqrtf((koef * (lab->L[i][j])) * 32768.f)))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L - } - - sum += koef * lab->L[i][j]; //evaluate mean J to calculate Yb - } - - #pragma omp critical - { - if(needJ) - for(int i = 0; i < 65536; i++) { - hist16J[i] += hist16Jthr[i]; - } - - if(needQ) - for(int i = 0; i < 65536; i++) { - hist16Q[i] += hist16Qthr[i]; - } - - } - } - - - //mean=(sum/((endh-begh)*width))/327.68f;//for Yb for all image...if one day "pipette" we can adapt Yb for each zone - mean = (sum / ((height) * width)) / 327.68f; //for Yb for all image...if one day "pipette" we can adapt Yb for each zone - - //evaluate lightness, contrast - if (needJ) { - if (!CAMBrightCurveJ) { - CAMBrightCurveJ(32768, LUT_CLIP_ABOVE); - CAMBrightCurveJ.dirty = false; - } - - float jli = params->colorappearance.jlight; - float contra = params->colorappearance.contrast; - Ciecam02::curveJfloat (jli, contra, 1, CAMBrightCurveJ, hist16J);//lightness and contrast J - } - - if (needQ) { - if (!CAMBrightCurveQ) { - CAMBrightCurveQ(32768, LUT_CLIP_ABOVE); - CAMBrightCurveQ.clear(); - CAMBrightCurveQ.dirty = false; - } - - float qbri = params->colorappearance.qbright; - float qcontra = params->colorappearance.qcontrast; - Ciecam02::curveJfloat (qbri, qcontra, 1, CAMBrightCurveQ, hist16Q);//brightness and contrast Q - } - } if(settings->viewinggreySc == 0) { //auto if (mean < 15.f) { @@ -1855,9 +1692,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } else { yb = 90.0f; } - } - - if(settings->viewinggreySc == 1) { + } else if(settings->viewinggreySc == 1) { yb = 18.0f; //fixed } @@ -1897,16 +1732,145 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int const float epsil = 0.0001f; const float w_h = wh + epsil; + const float coefQ = 32767.f / wh; const float a_w = aw; const float c_ = c; const float f_l = fl; const float coe = pow_F(fl, 0.25f); const float QproFactor = ( 0.4f / c ) * ( aw + 4.0f ) ; - const bool epdEnabled = params->epd.enabled; const bool LabPassOne = !((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp) || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)); + + if(CAMBrightCurveJ.dirty || CAMBrightCurveQ.dirty) { + bool needJ = (alg == 0 || alg == 1 || alg == 3); + bool needQ = (alg == 2 || alg == 3); + LUTu hist16J; + LUTu hist16Q; + + if (needJ) { + hist16J (32768); + hist16J.clear(); + } + + if (needQ) { + hist16Q (32768); + hist16Q.clear(); + } + + float sum = 0.f; + +#ifdef _OPENMP + const int numThreads = min(max(width * height / 65536, 1), omp_get_max_threads()); + #pragma omp parallel num_threads(numThreads) if(numThreads>1) +#endif + { + LUTu hist16Jthr; + LUTu hist16Qthr; + + if (needJ) { + hist16Jthr(hist16J.getSize()); + hist16Jthr.clear(); + } + + if (needQ) { + hist16Qthr(hist16Q.getSize()); + hist16Qthr.clear(); + } + + #pragma omp for reduction(+:sum) + + for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) { //rough correspondence between L and J + float currL = lab->L[i][j] / 327.68f; + float koef; //rough correspondence between L and J + + if(currL > 50.f) { + if(currL > 70.f) { + if(currL > 80.f) { + if(currL > 85.f) { + koef = 0.97f; + } else { + koef = 0.93f; + } + } else { + koef = 0.87f; + } + } else { + if (currL > 60.f) { + koef = 0.85f; + } else { + koef = 0.8f; + } + } + } else { + if(currL > 10.f) { + if(currL > 20.f) { + if(currL > 40.f) { + koef = 0.75f; + } else { + koef = 0.7f; + } + } else { + koef = 0.9f; + } + } else { + koef = 1.0; + } + } + + if (needJ) { + hist16Jthr[(int)((koef * lab->L[i][j]))]++; //evaluate histogram luminance L # J + } + + if (needQ) { + hist16Qthr[(int) (sqrtf((koef * (lab->L[i][j])) * 32768.f))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L + } + + sum += koef * lab->L[i][j]; //evaluate mean J to calculate Yb + } + + #pragma omp critical + { + if(needJ) { + hist16J += hist16Jthr; + } + + if(needQ) { + hist16Q += hist16Qthr; + } + + } + } + + + //mean=(sum/((endh-begh)*width))/327.68f;//for Yb for all image...if one day "pipette" we can adapt Yb for each zone + mean = (sum / ((height) * width)) / 327.68f; //for Yb for all image...if one day "pipette" we can adapt Yb for each zone + + //evaluate lightness, contrast + if (needJ) { + if (!CAMBrightCurveJ) { + CAMBrightCurveJ(32768, LUT_CLIP_ABOVE); + CAMBrightCurveJ.dirty = false; + } + + Ciecam02::curveJfloat (params->colorappearance.jlight, params->colorappearance.contrast, hist16J, CAMBrightCurveJ);//lightness and contrast J + CAMBrightCurveJ /= 327.68f; + } + + if (needQ) { + if (!CAMBrightCurveQ) { + CAMBrightCurveQ(32768, LUT_CLIP_ABOVE); + CAMBrightCurveQ.dirty = false; + } + + Ciecam02::curveJfloat (params->colorappearance.qbright, params->colorappearance.qcontrast, hist16Q, CAMBrightCurveQ);//brightness and contrast Q + CAMBrightCurveQ /= coefQ; + } + } + + //matrix for current working space TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params->icm.working); const float wip[3][3] = { @@ -2029,18 +1993,16 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int // we cannot have all algorithms with all chroma curves if(alg == 0) { - Jpro = CAMBrightCurveJ[Jpro * 327.68f] / 327.68f; //lightness CIECAM02 + contrast + Jpro = CAMBrightCurveJ[Jpro * 327.68f]; //lightness CIECAM02 + contrast Qpro = QproFactor * sqrtf(Jpro); float Cp = (spro * spro * Qpro) / (1000000.f); Cpro = Cp * 100.f; float sres; Ciecam02::curvecolorfloat(chr, Cp , sres, 1.8f); Color::skinredfloat(Jpro, hpro, sres, Cp, 55.f, 30.f, 1, rstprotection, 100.f, Cpro); - } - - if(alg == 1) { + } else if(alg == 1) { // Lightness saturation - Jpro = CAMBrightCurveJ[Jpro * 327.68f] / 327.68f; //lightness CIECAM02 + contrast + Jpro = CAMBrightCurveJ[Jpro * 327.68f]; //lightness CIECAM02 + contrast float sres; float Sp = spro / 100.0f; float parsat = 1.5f; //parsat=1.5 =>saturation ; 1.8 => chroma ; 2.5 => colorfullness (personal evaluation) @@ -2053,8 +2015,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int Qpro = QproFactor * sqrtf(Jpro); Cpro = (spro * spro * Qpro) / (10000.0f); } else if(alg == 2) { - float coef = 32767.f / wh; - Qpro = (CAMBrightCurveQ[(float)(Qpro * coef)]) / coef; //brightness and contrast + Qpro = CAMBrightCurveQ[(float)(Qpro * coefQ)]; //brightness and contrast float Mp, sres; Mp = Mpro / 100.0f; Ciecam02::curvecolorfloat(mchr, Mp , sres, 2.5f); @@ -2067,14 +2028,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int Cpro = Mpro / coe; Qpro = (Qpro == 0.f ? epsil : Qpro); // avoid division by zero spro = 100.0f * sqrtf( Mpro / Qpro ); - } else if(alg == 3) { - float coef = 32760.f / wh; - - if(Qpro * coef >= 32767.0f) { - Qpro = (CAMBrightCurveQ[32767]) / coef; //brightness and contrast - } else { - Qpro = (CAMBrightCurveQ[(float)(Qpro * coef)]) / coef; //brightness and contrast - } + } else { /*if(alg == 3) */ + Qpro = CAMBrightCurveQ[(float)(Qpro * coefQ)]; //brightness and contrast float Mp, sres; Mp = Mpro / 100.0f; @@ -2093,7 +2048,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int Jpro = 99.9f; } - Jpro = (CAMBrightCurveJ[(float)(Jpro * 327.68f)]) / 327.68f; //lightness CIECAM02 + contrast + Jpro = CAMBrightCurveJ[(float)(Jpro * 327.68f)]; //lightness CIECAM02 + contrast float Sp = spro / 100.0f; Ciecam02::curvecolorfloat(schr, Sp , sres, 1.5f); dred = 100.f; // in C mode @@ -2312,7 +2267,6 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int Color::skinredfloat(Jpro, hpro, Ss, Sold, dred, protect_red, sk, rstprotection, ko, spro); Qpro = ( 4.0f / c ) * sqrtf( Jpro / 100.0f ) * ( aw + 4.0f ) ; Cpro = (spro * spro * Qpro) / (10000.0f); - } else if (curveMode3 == ColorAppearanceParams::TC_MODE_COLORF) { // float parsat = 0.8f; //0.68; float coef = 327.68f / parsat; @@ -2327,7 +2281,6 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int int sk = 0; float ko = 1.f / coef; Color::skinredfloat(Jpro, hpro, Mm, Mold, dred, protect_red, sk, rstprotection, ko, Mpro); - Cpro = Mpro / coe; if(Jpro < 1.f && Mpro > 12.f * coe) { Mpro = 12.f * coe; //reduce artifacts by "pseudo gamut control CIECAM" @@ -2338,20 +2291,13 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } else if(Jpro < 7.f && Mpro > 50.f * coe) { Mpro = 50.f * coe; } + + Cpro = Mpro / coe; } } //to retrieve the correct values of variables - if(c1s) { - Qpro = ( 4.0f / c ) * sqrtf( Jpro / 100.0f ) * ( aw + 4.0f ) ; //for saturation curve - Cpro = (spro * spro * Qpro) / (10000.0f); - } - - if(c1co) { - float coe = pow_F(fl, 0.25f); - Cpro = Mpro / coe; - } // for colorfullness curve //retrieve values C,J...s C = Cpro; @@ -2382,57 +2328,40 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int if(!params->colorappearance.tonecie || !settings->autocielab || !epdEnabled) { - if(ciedata) { + 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; - int libr = 0; - int colch = 0; + float libr; + float colch; + //update histogram if(curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) { brli = 70.0f; - libr = 1; - } else if(curveMode == ColorAppearanceParams::TC_MODE_LIGHT) { + libr = Q; //40.0 to 100.0 approximative factor for Q - 327 for J + } else { /*if(curveMode == ColorAppearanceParams::TC_MODE_LIGHT)*/ brli = 327.f; - libr = 0; + libr = J; //327 for J } + posl = (int)(libr * brli); + hist16JCAM[posl]++; + if (curveMode3 == ColorAppearanceParams::TC_MODE_CHROMA) { chsacol = 327.f; - colch = 0; + colch = C; //450.0 approximative factor for s 320 for M } else if(curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { chsacol = 450.0f; - colch = 1; - } else if(curveMode3 == ColorAppearanceParams::TC_MODE_COLORF) { + colch = s; + } else { /*if(curveMode3 == ColorAppearanceParams::TC_MODE_COLORF)*/ chsacol = 327.0f; - colch = 2; + colch = M; } - //update histogram - if(pW != 1) { //only with improccoordinator - if(libr == 1) { - posl = CLIP((int)(Q * brli)); //40.0 to 100.0 approximative factor for Q - 327 for J - } else if(libr == 0) { - posl = CLIP((int)(J * brli)); //327 for J - } + posc = (int)(colch * chsacol); + hist16_CCAM[posc]++; - hist16JCAM[posl]++; - } - - chropC = true; - - if(pW != 1) { //only with improccoordinator - if(colch == 0) { - posc = CLIP((int)(C * chsacol)); //450.0 approximative factor for s 320 for M - } else if(colch == 1) { - posc = CLIP((int)(s * chsacol)); - } else if(colch == 2) { - posc = CLIP((int)(M * chsacol)); - } - - hist16_CCAM[posc]++; - } } if(LabPassOne) { @@ -2450,9 +2379,9 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int xw2, yw2, zw2, f2, c2, nc2, gamu, pow1n, nbbj, ncbj, flj, czj, dj, awj); float x, y, z; - x = (float)xx * 655.35f; - y = (float)yy * 655.35f; - z = (float)zz * 655.35f; + x = xx * 655.35f; + y = yy * 655.35f; + z = zz * 655.35f; float Ll, aa, bb; //convert xyz=>lab Color::XYZ2Lab(x, y, z, Ll, aa, bb); @@ -2573,25 +2502,13 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } // End of parallelization - if(!params->colorappearance.tonecie || !settings->autocielab) { //normal + if(!params->colorappearance.tonecie || !settings->autocielab) { //normal if(ciedata) { //update histogram J - for (int i = 0; i < 32768; i++) { // - if (jp) { - float hval = dLcurve[i]; - int hi = (int)(255.0f * CLIPD(hval)); // - histLCAM[hi] += hist16JCAM[i] ; - } - } - - for (int i = 0; i < 48000; i++) { // - if (chropC) { - float hvalc = dCcurve[i]; - int hic = (int)(255.0f * CLIPD(hvalc)); // - histCCAM[hic] += hist16_CCAM[i] ; - } - } + hist16JCAM.compressTo(histLCAM); + //update histogram C + hist16_CCAM.compressTo(histCCAM); } } @@ -2723,6 +2640,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)) { + ciedata = (params->colorappearance.datacie && pW != 1); + if(epdEnabled && params->colorappearance.tonecie && algepd) { lab->deleteLab(); ImProcFunctions::EPDToneMapCIE(ncie, a_w, c_, w_h, width, height, begh, endh, minQ, maxQ, Iterates, scale ); @@ -2732,14 +2651,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int //EPDToneMapCIE adated to CIECAM - const float eps = 0.0001f; + constexpr float eps = 0.0001f; const float co_e = (pow_F(f_l, 0.25f)) + eps; - TMatrix wiprofa = iccStore->workingSpaceInverseMatrix (params->icm.working); - const float wipa[3][3] = { - {float(wiprofa[0][0]), float(wiprofa[0][1]), float(wiprofa[0][2])}, - {float(wiprofa[1][0]), float(wiprofa[1][1]), float(wiprofa[1][2])}, - {float(wiprofa[2][0]), float(wiprofa[2][1]), float(wiprofa[2][2])} - }; #ifndef _DEBUG #pragma omp parallel @@ -2777,54 +2690,33 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int int posl, posc; float brli = 327.f; float chsacol = 327.f; - int libr = 0; - int colch = 0; - float sa_t; + float libr; + float colch; if(curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) { brli = 70.0f; - libr = 1; - } else if(curveMode == ColorAppearanceParams::TC_MODE_LIGHT) { + libr = ncie->Q_p[i][j]; //40.0 to 100.0 approximative factor for Q - 327 for J + } else { /*if(curveMode == ColorAppearanceParams::TC_MODE_LIGHT)*/ brli = 327.f; - libr = 0; + libr = ncie->J_p[i][j]; //327 for J } + posl = (int)(libr * brli); + hist16JCAM[posl]++; + if (curveMode3 == ColorAppearanceParams::TC_MODE_CHROMA) { chsacol = 327.f; - colch = 0; + colch = ncie_C_p; } else if(curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { chsacol = 450.0f; - colch = 1; - } else if(curveMode3 == ColorAppearanceParams::TC_MODE_COLORF) { + colch = 100.f * sqrtf(ncie_C_p / ncie->Q_p[i][j]); + } else { /*if(curveMode3 == ColorAppearanceParams::TC_MODE_COLORF)*/ chsacol = 327.0f; - colch = 2; + colch = ncie->M_p[i][j]; } - //update histogram - if(pW != 1) { //only with improccoordinator - if(libr == 1) { - posl = CLIP((int)(ncie->Q_p[i][j] * brli)); //40.0 to 100.0 approximative factor for Q - 327 for J - } else if(libr == 0) { - posl = CLIP((int)(ncie->J_p[i][j] * brli)); //327 for J - } - - hist16JCAM[posl]++; - } - - chropC = true; - - if(pW != 1) { //only with improccoordinator - if(colch == 0) { - posc = CLIP((int)(ncie_C_p * chsacol)); //450.0 approximative factor for s 320 for M - } else if(colch == 1) { - sa_t = 100.f * sqrtf(ncie_C_p / ncie->Q_p[i][j]); //Q_p always > 0 - posc = CLIP((int)(sa_t * chsacol)); - } else if(colch == 2) { - posc = CLIP((int)(ncie->M_p[i][j] * chsacol)); - } - - hist16_CCAM[posc]++; - } + posc = (int)(colch * chsacol); + hist16_CCAM[posc]++; } //end histograms @@ -2864,10 +2756,10 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int bool neg = false; bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wipa, highlight, 0.15f, 0.96f, neg, more_rgb); + Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); #else //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wipa, highlight, 0.15f, 0.96f); + Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); #endif lab->L[i][j] = Lprov1 * 327.68f; @@ -2926,10 +2818,10 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int bool neg = false; bool more_rgb = false; //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wipa, highlight, 0.15f, 0.96f, neg, more_rgb); + Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f, neg, more_rgb); #else //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wipa, highlight, 0.15f, 0.96f); + Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); #endif lab->L[i][j] = Lprov1 * 327.68f; lab->a[i][j] = 327.68f * Chprov1 * sincosval.y; @@ -2950,24 +2842,12 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int //show CIECAM histograms if(ciedata) { //update histogram J and Q - for (int i = 0; i < 32768; i++) { // - if (jp) { - float hval = dLcurve[i]; - int hi = (int)(255.0f * CLIPD(hval)); // - histLCAM[hi] += hist16JCAM[i] ; - } - } + //update histogram J + hist16JCAM.compressTo(histLCAM); //update color histogram M,s,C - for (int i = 0; i < 48000; i++) { // - if (chropC) { - float hvalc = dCcurve[i]; - int hic = (int)(255.0f * CLIPD(hvalc)); // - histCCAM[hic] += hist16_CCAM[i] ; - } - } + hist16_CCAM.compressTo(histCCAM); } - } } } @@ -3067,23 +2947,22 @@ filmlike_clip(float *r, float *g, float *b) void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, 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 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 DCPProfile::ApplyState &asIn ) { - rgbProc (working, lab, pipetteBuffer, hltonecurve, shtonecurve, tonecurve, shmap, 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); + rgbProc (working, lab, pipetteBuffer, hltonecurve, shtonecurve, tonecurve, shmap, 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); } // Process RGB image and convert to LAB space void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, 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 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 DCPProfile::ApplyState &asIn ) { - LUTf fGammaLUTf; - Imagefloat *tmpImage = NULL; + Imagefloat *tmpImage = nullptr; // NOTE: We're getting all 3 pointers here, but this function may not need them all, so one could optimize this - Imagefloat* editImgFloat = NULL; - LabImage* editLab = NULL; - PlanarWhateverData* editWhatever = NULL; + Imagefloat* editImgFloat = nullptr; + LabImage* editLab = nullptr; + PlanarWhateverData* editWhatever = nullptr; EditUniqueID editID = pipetteBuffer ? pipetteBuffer->getEditID() : EUID_None; if (editID != EUID_None) { @@ -3109,8 +2988,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer s_th = params->sh.stonalwidth * (shmap->avg - shmap->min_f) / 100; } - bool processSH = params->sh.enabled && shmap != NULL && (params->sh.highlights > 0 || params->sh.shadows > 0); - bool processLCE = params->sh.enabled && shmap != NULL && params->sh.localcontrast > 0; + bool processSH = params->sh.enabled && shmap && (params->sh.highlights > 0 || params->sh.shadows > 0); + bool processLCE = params->sh.enabled && shmap && params->sh.localcontrast > 0; double lceamount = params->sh.localcontrast / 200.0; TMatrix wprof = iccStore->workingSpaceMatrix (params->icm.working); @@ -3170,7 +3049,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (hCurve->isIdentity()) { delete hCurve; - hCurve = NULL; + hCurve = nullptr; hCurveEnabled = false; } } @@ -3180,7 +3059,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (sCurve->isIdentity()) { delete sCurve; - sCurve = NULL; + sCurve = nullptr; sCurveEnabled = false; } } @@ -3190,7 +3069,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (vCurve->isIdentity()) { delete vCurve; - vCurve = NULL; + vCurve = nullptr; vCurveEnabled = false; } } @@ -3200,14 +3079,14 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (bwlCurve->isIdentity()) { delete bwlCurve; - bwlCurve = NULL; + bwlCurve = nullptr; bwlCurveEnabled = false; } } std::shared_ptr hald_clut; bool clutAndWorkingProfilesAreSame = false; - TMatrix work2xyz, xyz2clut, clut2xyz, xyz2work; + TMatrix xyz2clut, clut2xyz; #ifdef __SSE2__ vfloat v_work2xyz[3][3] ALIGNED16; vfloat v_xyz2clut[3][3] ALIGNED16; @@ -3222,20 +3101,20 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer clutAndWorkingProfilesAreSame = hald_clut->getProfile() == params->icm.working; if ( !clutAndWorkingProfilesAreSame ) { - work2xyz = iccStore->workingSpaceMatrix( params->icm.working ); xyz2clut = iccStore->workingSpaceInverseMatrix( hald_clut->getProfile() ); - xyz2work = iccStore->workingSpaceInverseMatrix( params->icm.working ); clut2xyz = iccStore->workingSpaceMatrix( hald_clut->getProfile() ); #ifdef __SSE2__ + for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { - v_work2xyz[i][j] = F2V(work2xyz[i][j]); + v_work2xyz[i][j] = F2V(wprof[i][j]); v_xyz2clut[i][j] = F2V(xyz2clut[i][j]); - v_xyz2work[i][j] = F2V(xyz2work[i][j]); + v_xyz2work[i][j] = F2V(wiprof[i][j]); v_clut2xyz[i][j] = F2V(clut2xyz[i][j]); } } + #endif } @@ -3390,13 +3269,6 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } bool hasgammabw = gammabwr != 1.f || gammabwg != 1.f || gammabwb != 1.f; - fGammaLUTf(65536); - #pragma omp parallel for - - for (int i = 0; i < 65536; i++) { - fGammaLUTf[i] = CurveFactory::gamma2 (float(i) / 65535.f) * 65535.f; - } - if (hasColorToning || blackwhite || (params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled)) { tmpImage = new Imagefloat(working->width, working->height); } @@ -3404,15 +3276,6 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer int W = working->width; int H = working->height; - - - - - - - - - #define TS 112 #ifdef _OPENMP @@ -3420,8 +3283,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer #endif { char *buffer; - char *editIFloatBuffer = NULL; - char *editWhateverBuffer = NULL; + char *editIFloatBuffer = nullptr; + char *editWhateverBuffer = nullptr; buffer = (char *) malloc(3 * sizeof(float) * TS * TS + 20 * 64 + 63); char *data; @@ -3564,8 +3427,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } } - if (dcpProf != NULL) { - dcpProf->step2ApplyTile(rtemp, gtemp, btemp, tW - jstart, tH - istart, TS); + if (dcpProf) { + dcpProf->step2ApplyTile(rtemp, gtemp, btemp, tW - jstart, tH - istart, TS, asIn); } for (int i = istart, ti = 0; i < tH; i++, ti++) { @@ -3610,9 +3473,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (editID == EUID_ToneCurve1) { // filling the pipette buffer for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - editIFloatTmpR[ti * TS + tj] = CLIP(fGammaLUTf[rtemp[ti * TS + tj]] / 65535.f); - editIFloatTmpG[ti * TS + tj] = CLIP(fGammaLUTf[gtemp[ti * TS + tj]] / 65535.f); - editIFloatTmpB[ti * TS + tj] = CLIP(fGammaLUTf[btemp[ti * TS + tj]] / 65535.f); + editIFloatTmpR[ti * TS + tj] = Color::gamma2curve[rtemp[ti * TS + tj]] / 65535.f; + editIFloatTmpG[ti * TS + tj] = Color::gamma2curve[gtemp[ti * TS + tj]] / 65535.f; + editIFloatTmpB[ti * TS + tj] = Color::gamma2curve[btemp[ti * TS + tj]] / 65535.f; } } } @@ -3681,9 +3544,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (editID == EUID_ToneCurve2) { // filling the pipette buffer for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - editIFloatTmpR[ti * TS + tj] = CLIP(fGammaLUTf[rtemp[ti * TS + tj]] / 65535.f); - editIFloatTmpG[ti * TS + tj] = CLIP(fGammaLUTf[gtemp[ti * TS + tj]] / 65535.f); - editIFloatTmpB[ti * TS + tj] = CLIP(fGammaLUTf[btemp[ti * TS + tj]] / 65535.f); + editIFloatTmpR[ti * TS + tj] = Color::gamma2curve[rtemp[ti * TS + tj]] / 65535.f; + editIFloatTmpG[ti * TS + tj] = Color::gamma2curve[gtemp[ti * TS + tj]] / 65535.f; + editIFloatTmpB[ti * TS + tj] = Color::gamma2curve[btemp[ti * TS + tj]] / 65535.f; } } } @@ -3740,19 +3603,19 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (editID == EUID_RGB_R) { for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - editWhateverTmp[ti * TS + tj] = fGammaLUTf[rtemp[ti * TS + tj]] / 65536.f; + editWhateverTmp[ti * TS + tj] = Color::gamma2curve[rtemp[ti * TS + tj]] / 65536.f; } } } else if (editID == EUID_RGB_G) { for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - editWhateverTmp[ti * TS + tj] = fGammaLUTf[gtemp[ti * TS + tj]] / 65536.f; + editWhateverTmp[ti * TS + tj] = Color::gamma2curve[gtemp[ti * TS + tj]] / 65536.f; } } } else if (editID == EUID_RGB_B) { for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - editWhateverTmp[ti * TS + tj] = fGammaLUTf[btemp[ti * TS + tj]] / 65536.f; + editWhateverTmp[ti * TS + tj] = Color::gamma2curve[btemp[ti * TS + tj]] / 65536.f; } } } @@ -4185,9 +4048,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (editID == EUID_BlackWhiteBeforeCurve) { for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - editIFloatTmpR[ti * TS + tj] = CLIP(fGammaLUTf[rtemp[ti * TS + tj]] / 65535.f); - editIFloatTmpG[ti * TS + tj] = CLIP(fGammaLUTf[gtemp[ti * TS + tj]] / 65535.f); - editIFloatTmpB[ti * TS + tj] = CLIP(fGammaLUTf[btemp[ti * TS + tj]] / 65535.f); + editIFloatTmpR[ti * TS + tj] = Color::gamma2curve[rtemp[ti * TS + tj]] / 65535.f; + editIFloatTmpG[ti * TS + tj] = Color::gamma2curve[gtemp[ti * TS + tj]] / 65535.f; + editIFloatTmpB[ti * TS + tj] = Color::gamma2curve[btemp[ti * TS + tj]] / 65535.f; } } } else if (editID == EUID_BlackWhiteLuminance) { @@ -4363,6 +4226,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer int tj = 0; #ifdef __SSE2__ + for (; j < tW - 3; j += 4, tj += 4) { vfloat sourceR = LVF(rtemp[ti * TS + tj]); vfloat sourceG = LVF(gtemp[ti * TS + tj]); @@ -4378,6 +4242,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer STVF(gtemp[ti * TS + tj], sourceG); STVF(btemp[ti * TS + tj], sourceB); } + #endif for (; j < tW; j++, tj++) { @@ -4386,7 +4251,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float &sourceB = btemp[ti * TS + tj]; float x, y, z; - Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, work2xyz); + Color::rgbxyz( sourceR, sourceG, sourceB, x, y, z, wprof ); Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, xyz2clut); } } @@ -4429,6 +4294,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer int tj = 0; #ifdef __SSE2__ + for (; j < tW - 3; j += 4, tj += 4) { vfloat sourceR = LVF(rtemp[ti * TS + tj]); vfloat sourceG = LVF(gtemp[ti * TS + tj]); @@ -4444,6 +4310,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer STVF(gtemp[ti * TS + tj], sourceG); STVF(btemp[ti * TS + tj], sourceB); } + #endif for (; j < tW; j++, tj++) { @@ -4453,7 +4320,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float x, y, z; Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, clut2xyz); - Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, xyz2work); + Color::xyz2rgb( x, y, z, sourceR, sourceG, sourceB, wiprof ); } } } @@ -4484,9 +4351,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float fx, fy, fz; - fx = (x < 65535.0f ? Color::cachef[std::max(x, 0.f)] : 327.68f * std::cbrt(x / MAXVALF)); - fy = (y < 65535.0f ? Color::cachef[std::max(y, 0.f)] : 327.68f * std::cbrt(y / MAXVALF)); - fz = (z < 65535.0f ? Color::cachef[std::max(z, 0.f)] : 327.68f * std::cbrt(z / MAXVALF)); + fx = (x < 65535.0f ? Color::cachef[x] : 327.68f * std::cbrt(x / MAXVALF)); + fy = (y < 65535.0f ? Color::cachef[y] : 327.68f * std::cbrt(y / MAXVALF)); + fz = (z < 65535.0f ? Color::cachef[z] : 327.68f * std::cbrt(z / MAXVALF)); lab->L[i][j] = (116.0f * fy - 5242.88f); //5242.88=16.0*327.68; lab->a[i][j] = (500.0f * (fx - fy) ); @@ -4642,7 +4509,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - editWhatever->v(i, j) = CLIP(fGammaLUTf[tmpImage->r(i, j)] / 65535.f); // assuming that r=g=b + editWhatever->v(i, j) = Color::gamma2curve[tmpImage->r(i, j)] / 65535.f; // assuming that r=g=b } } } @@ -5607,7 +5474,7 @@ void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, LUTf & cur -SSEFUNCTION 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 &histCLurve, LUTu &histLLCurve, LUTu &histLCurve) +SSEFUNCTION 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) { int W = lold->W; int H = lold->H; @@ -5615,9 +5482,9 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu //init Flatcurve for C=f(H) // NOTE: We're getting all 3 pointers here, but this function may not need them all, so one could optimize this - Imagefloat* editImgFloat = NULL; - LabImage* editLab = NULL; - PlanarWhateverData* editWhatever = NULL; + Imagefloat* editImgFloat = nullptr; + LabImage* editLab = nullptr; + PlanarWhateverData* editWhatever = nullptr; EditUniqueID editID = EUID_None; bool editPipette = false; @@ -5643,7 +5510,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu } } - FlatCurve* chCurve = NULL;// curve C=f(H) + FlatCurve* chCurve = nullptr;// curve C=f(H) bool chutili = false; if (params->labCurve.chromaticity > -100) { @@ -5652,7 +5519,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu if (!chCurve || chCurve->isIdentity()) { if (chCurve) { delete chCurve; - chCurve = NULL; + chCurve = nullptr; } }//do not use "Munsell" if Chcurve not used else { @@ -5660,7 +5527,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu } } - FlatCurve* lhCurve = NULL;//curve L=f(H) + FlatCurve* lhCurve = nullptr;//curve L=f(H) bool lhutili = false; if (params->labCurve.chromaticity > -100) { @@ -5669,7 +5536,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu if (!lhCurve || lhCurve->isIdentity()) { if (lhCurve) { delete lhCurve; - lhCurve = NULL; + lhCurve = nullptr; } }//do not use "Munsell" if Chcurve not used else { @@ -5677,7 +5544,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu } } - FlatCurve* hhCurve = NULL;//curve H=f(H) + FlatCurve* hhCurve = nullptr;//curve H=f(H) bool hhutili = false; if (params->labCurve.chromaticity > -100) { @@ -5686,7 +5553,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu if (!hhCurve || hhCurve->isIdentity()) { if (hhCurve) { delete hhCurve; - hhCurve = NULL; + hhCurve = nullptr; } }//do not use "Munsell" if Chcurve not used else { @@ -5694,31 +5561,15 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu } } - LUTf dCcurve; - LUTf dLcurve; LUTu hist16Clad; LUTu hist16Llad; //preparate for histograms CIECAM if(pW != 1) { //only with improccoordinator - dCcurve(48000, 0); - dLcurve(65536, 0); hist16Clad(65536); - hist16Llad(65536); - float val; - - for (int i = 0; i < 48000; i++) { //# 32768*1.414 approximation maxi for chroma - val = (double)i / 47999.0; - dCcurve[i] = CLIPD(val); - } - - for (int i = 0; i < 65535; i++) { // a - val = (double)i / 65534.0; - dLcurve[i] = CLIPD(val); - } - hist16Clad.clear(); + hist16Llad(65536); hist16Llad.clear(); } @@ -5756,7 +5607,10 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu const int chromaticity = params->labCurve.chromaticity; const float chromapro = (chromaticity + 100.0f) / 100.0f; const bool bwonly = params->blackwhite.enabled && !params->colorToning.enabled; - const bool bwToning = params->labCurve.chromaticity == - 100 /*|| params->blackwhite.method=="Ch" || params->blackwhite.enabled */ || bwonly; + bool bwq = false; +// if(params->ppVersion > 300 && params->labCurve.chromaticity == - 100) bwq = true; + // const bool bwToning = params->labCurve.chromaticity == - 100 /*|| params->blackwhite.method=="Ch" || params->blackwhite.enabled */ || bwonly; + const bool bwToning = bwq /*|| params->blackwhite.method=="Ch" || params->blackwhite.enabled */ || bwonly; //if(chromaticity==-100) chromaticity==-99; const bool LCredsk = params->labCurve.lcredsk; const bool ccut = ccutili; @@ -6214,7 +6068,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu //update histogram C if(pW != 1) { //only with improccoordinator - int posp = CLIP((int)sqrt((atmp * atmp + btmp * btmp))); + int posp = (int)sqrt(atmp * atmp + btmp * btmp); hist16Clad[posp]++; } @@ -6270,7 +6124,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu //update histo LC if(pW != 1) { //only with improccoordinator - int posl = CLIP((int(Lprov1 * 327.68f))); + int posl = Lprov1 * 327.68f; hist16Llad[posl]++; } @@ -6358,20 +6212,11 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu } } // end of parallelization - //update histogram C with data chromaticity and not with CC curve if(pW != 1) { //only with improccoordinator - for (int i = 0; i < 48000; i++) { //32768*1.414 + ... - float hval = dCcurve[i]; - int hi = (int)(255.0 * CLIPD(hval)); // - histCCurve[hi] += hist16Clad[i] ; - } - - //update histogram L with data luminance - for (int i = 0; i < 65535; i++) { - float hlval = dLcurve[i]; - int hli = (int)(255.0 * CLIPD(hlval)); - histLCurve[hli] += hist16Llad[i] ; - } + //update histogram C with data chromaticity and not with CC curve + hist16Clad.compressTo(histCCurve); + //update histogram L with data luminance + hist16Llad.compressTo(histLCurve); } #ifdef _DEBUG @@ -6772,15 +6617,15 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) #pragma omp parallel for // removed schedule(dynamic,10) #endif - for(int ii = 0; ii < N; ii++) - a[ii] *= s, - b[ii] *= s, - //L[ii] = L[ii]*32767.0f*(1.f/gamm) + minL; - L[ii] = L[ii] * maxL * (1.f / gamm) + minL; + for(int ii = 0; ii < N; ii++) { + a[ii] *= s; + b[ii] *= s; + L[ii] = L[ii] * maxL * (1.f / gamm) + minL; + } } -void ImProcFunctions::getAutoExp (LUTu & histogram, int histcompr, double defgain, double clip, +void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double defgain, double clip, double& expcomp, int& bright, int& contr, int& black, int& hlcompr, int& hlcomprthresh) { @@ -6793,12 +6638,7 @@ void ImProcFunctions::getAutoExp (LUTu & histogram, int histcompr, double defga float ave = 0.f, hidev = 0.f, lodev = 0.f; //find average luminance - for (int i = 0; i < imax; i++) { - sum += histogram[i]; - ave += histogram[i] * (float)i; - } - - ave /= (sum); + histogram.getSumAndAverage(sum, ave); //find median of luminance int median = 0, count = histogram[0]; @@ -6823,25 +6663,37 @@ void ImProcFunctions::getAutoExp (LUTu & histogram, int histcompr, double defga float octile[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}, ospread = 0.f; count = 0; - for (int i = 0; i < imax; i++) { + int i = 0; + + for (; i < min((int)ave, imax); i++) { if (count < 8) { octile[count] += histogram[i]; if (octile[count] > sum / 8.f || (count == 7 && octile[count] > sum / 16.f)) { - octile[count] = log(1. + (float)i) / log(2.f); + octile[count] = xlog(1. + (float)i) / log(2.f); count++;// = min(count+1,7); } } - if (i < ave) { - //lodev += SQR(ave-i)*histogram[i]; - lodev += (log(ave + 1.f) - log((float)i + 1.)) * histogram[i]; - losum += histogram[i]; - } else { - //hidev += SQR(i-ave)*histogram[i]; - hidev += (log((float)i + 1.) - log(ave + 1.f)) * histogram[i]; - hisum += histogram[i]; + //lodev += SQR(ave-i)*histogram[i]; + lodev += (xlog(ave + 1.f) - xlog((float)i + 1.)) * histogram[i]; + losum += histogram[i]; + } + + for (; i < imax; i++) { + if (count < 8) { + octile[count] += histogram[i]; + + if (octile[count] > sum / 8.f || (count == 7 && octile[count] > sum / 16.f)) { + octile[count] = xlog(1. + (float)i) / 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]; + } if (losum == 0 || hisum == 0) { //probably the image is a blackframe @@ -6904,7 +6756,7 @@ void ImProcFunctions::getAutoExp (LUTu & histogram, int histcompr, double defga int clipped = 0; int rawmax = (imax) - 1; - while (rawmax > 1 && histogram[rawmax] + clipped <= 0) { + while (histogram[rawmax] + clipped <= 0 && rawmax > 1) { clipped += histogram[rawmax]; rawmax--; } @@ -6996,12 +6848,18 @@ void ImProcFunctions::getAutoExp (LUTu & histogram, int histcompr, double defga //take gamma into account double whiteclipg = (int)(CurveFactory::gamma2 (whiteclip * corr / 65536.0) * 65536.0); - double gavg = 0.; + float gavg = 0.; - for (int i = 0; i<65536 >> histcompr; i++) { - gavg += histogram[i] * CurveFactory::gamma2((float)(corr * (i << histcompr) < 65535 ? corr * (i << histcompr) : 65535)) / sum; + float val = 0.f; + float increment = corr * (1 << histcompr); + + for (int i = 0; i < 65536 >> histcompr; i++) { + gavg += histogram[i] * Color::gamma2curve[val]; + val += increment; } + gavg /= sum; + if (black < gavg) { int maxwhiteclip = (gavg - black) * 4 / 3 + black; // dont let whiteclip be such large that the histogram average goes above 3/4 @@ -7070,6 +6928,7 @@ void ImProcFunctions::getAutoExp (LUTu & histogram, int histcompr, double defga } bright = max(-100, min(bright, 100)); + } @@ -7084,13 +6943,13 @@ double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_si Thumbnail* thumb = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, w_thumb, h_thumb, 1, FALSE); - if (thumb == NULL) { + if (!thumb) { return 0.0; } Thumbnail* raw = rtengine::Thumbnail::loadFromRaw (fname, ri, w_raw, h_raw, 1, 1.0, FALSE); - if (raw == NULL) { + if (!raw) { delete thumb; return 0.0; } @@ -7114,7 +6973,7 @@ double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_si thumbGray = thumb->getGrayscaleHistEQ (width); rawGray = raw->getGrayscaleHistEQ (width); - if (thumbGray == NULL || rawGray == NULL) { + if (!thumbGray || !rawGray) { if (thumbGray) { delete thumbGray; } diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 90a046149..ccc77ab9f 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -75,7 +75,6 @@ class ImProcFunctions void sharpenHaloCtrl (float** luminance, float** blurmap, float** base, int W, int H, const SharpeningParams &sharpenParam); void sharpenHaloCtrl (LabImage* lab, float** blurmap, float** base, int W, int H, SharpeningParams &sharpenParam); void sharpenHaloCtrlcam (CieImage* ncie, float** blurmap, float** base, int W, int H); - void firstAnalysisThread(Imagefloat* original, Glib::ustring wprofile, unsigned int* histogram, int row_from, int row_to); void dcdamping (float** aI, float** aO, float damping, int W, int H); bool needsCA (); @@ -229,15 +228,15 @@ public: bool needsTransform (); bool needsPCVignetting (); - void firstAnalysis (Imagefloat* working, const ProcParams* params, LUTu & vhist16); + void firstAnalysis (const Imagefloat* const working, const ProcParams ¶ms, LUTu & vhist16); void updateColorProfiles (const ColorManagementParams& icm, const Glib::ustring& monitorProfile, RenderingIntent monitorIntent); void rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, 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 ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn ); void rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, SHMap* shmap, 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); + double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn ); 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 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, int preser, float strProtect); @@ -255,7 +254,7 @@ public: void ciecam_02 (CieImage* ncie, double adap, int begh, int endh, int pW, int pwb, LabImage* lab, const 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, double &d, int scalecd, int rtt); - 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 &histCLurve, LUTu &histLCurve, LUTu &histLurve); + 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 vibrance (LabImage* lab);//Jacques' vibrance void colorCurve (LabImage* lold, LabImage* lnew); void sharpening (LabImage* lab, float** buffer, SharpeningParams &sharpenParam); @@ -377,7 +376,7 @@ public: bool transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1, const LCPMapper *pLCPMap = NULL); bool transCoord (int W, int H, const std::vector &src, std::vector &red, std::vector &green, std::vector &blue, double ascaleDef = -1, const LCPMapper *pLCPMap = NULL); - static void getAutoExp (LUTu & histogram, int histcompr, double defgain, double clip, double& expcomp, int& bright, int& contr, int& black, int& hlcompr, int& hlcomprthresh); + static void getAutoExp (const LUTu & histogram, int histcompr, double defgain, double clip, double& expcomp, int& bright, int& contr, int& black, int& hlcompr, int& hlcomprthresh); static double getAutoDistor (const Glib::ustring& fname, int thumb_size); double getTransformAutoFill (int oW, int oH, const LCPMapper *pLCPMap = NULL); void rgb2lab(const Imagefloat &src, LabImage &dst, const Glib::ustring &workingSpace); diff --git a/rtengine/init.cc b/rtengine/init.cc index d2509b620..3b2c5fbdc 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -42,7 +42,7 @@ int init (const Settings* s, Glib::ustring baseDir, Glib::ustring userSettingsDi settings = s; iccStore->init (s->iccDirectory, baseDir + "/iccprofiles"); iccStore->findDefaultMonitorProfile(); - dcpStore->init (baseDir + "/dcpprofiles"); + DCPStore::getInstance()->init (baseDir + "/dcpprofiles"); CameraConstantsStore::getInstance ()->init (baseDir, userSettingsDir); profileStore.init (); diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 66e630d0f..3e87afe0f 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -117,9 +117,9 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image) /* copy RGB */ //int R1=((int)gamma2curve[(R)]) - data[ix++] = ((int)Color::gamma2curve[CLIP (R)]) >> 8; - data[ix++] = ((int)Color::gamma2curve[CLIP (G)]) >> 8; - data[ix++] = ((int)Color::gamma2curve[CLIP (B)]) >> 8; + data[ix++] = ((int)Color::gamma2curve[R]) >> 8; + data[ix++] = ((int)Color::gamma2curve[G]) >> 8; + data[ix++] = ((int)Color::gamma2curve[B]) >> 8; } } } @@ -229,9 +229,9 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Color::xyz2rgb(x_, y_, z_, R, G, B, xyz_rgb); - image->data[ix++] = (int)Color::gamma2curve[CLIP (R)] >> 8; - image->data[ix++] = (int)Color::gamma2curve[CLIP (G)] >> 8; - image->data[ix++] = (int)Color::gamma2curve[CLIP (B)] >> 8; + image->data[ix++] = (int)Color::gamma2curve[R] >> 8; + image->data[ix++] = (int)Color::gamma2curve[G] >> 8; + image->data[ix++] = (int)Color::gamma2curve[B] >> 8; } } } diff --git a/rtengine/ipvibrance.cc b/rtengine/ipvibrance.cc index 3e6ff97f2..1d152c737 100644 --- a/rtengine/ipvibrance.cc +++ b/rtengine/ipvibrance.cc @@ -59,9 +59,7 @@ void fillCurveArrayVib(DiagonalCurve* diagCurve, LUTf &outCurve) outCurve[i] = 65535.f * diagCurve->getVal( double(i) / 65535.0 ); } } else { - for (int i = 0; i <= 0xffff; i++) { - outCurve[i] = float(i); - } + outCurve.makeIdentity(); } } diff --git a/rtengine/previewimage.cc b/rtengine/previewimage.cc index 9de5c81cb..16355a8c0 100644 --- a/rtengine/previewimage.cc +++ b/rtengine/previewimage.cc @@ -110,15 +110,8 @@ PreviewImage::PreviewImage (const Glib::ustring &fname, const Glib::ustring &ext rtengine::Image8 *output = NULL; const unsigned char *data = NULL; int fw, fh; - LUTf cdcurve; - bool dehacontlutili = false; procparams::ProcParams params; - /*rtengine::RAWParams raw; - rtengine::LensProfParams lensProf; - rtengine::procparams::ToneCurveParams toneCurve; - rtengine::procparams::ColorManagementParams icm; - rtengine::CoarseTransformParams coarse;*/ ColorTemp wb = rawImage.getWB (); rawImage.getFullSize (fw, fh, TR_NONE); PreviewProps pp (0, 0, fw, fh, 1); diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 67b02a650..25d5df212 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -19,7 +19,7 @@ #include #include "procparams.h" #include "rt_math.h" -#include "dcp.h" +#include "curves.h" #include "../rtgui/multilangmgr.h" #include "../rtgui/version.h" #include "../rtgui/ppversion.h" @@ -1271,7 +1271,7 @@ void ProcParams::setDefaults () ppVersion = PPVERSION; } -static Glib::ustring expandRelativePath(Glib::ustring procparams_fname, Glib::ustring prefix, Glib::ustring embedded_fname) +static Glib::ustring expandRelativePath(const Glib::ustring &procparams_fname, const Glib::ustring &prefix, Glib::ustring embedded_fname) { if (embedded_fname == "" || !Glib::path_is_absolute(procparams_fname)) { return embedded_fname; @@ -1293,7 +1293,7 @@ static Glib::ustring expandRelativePath(Glib::ustring procparams_fname, Glib::us return absPath; } -static Glib::ustring relativePathIfInside(Glib::ustring procparams_fname, bool fnameAbsolute, Glib::ustring embedded_fname) +static Glib::ustring relativePathIfInside(const Glib::ustring &procparams_fname, bool fnameAbsolute, Glib::ustring embedded_fname) { if (fnameAbsolute || embedded_fname == "" || !Glib::path_is_absolute(procparams_fname)) { return embedded_fname; @@ -1321,7 +1321,7 @@ static Glib::ustring relativePathIfInside(Glib::ustring procparams_fname, bool f return prefix + embedded_fname.substr(dir1.length()); } -int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsolute, ParamsEdited* pedited) +int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, bool fnameAbsolute, ParamsEdited* pedited) { if (fname.empty () && fname2.empty ()) { @@ -1332,2076 +1332,2076 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol try { - Glib::KeyFile keyFile; + Glib::KeyFile keyFile; - keyFile.set_string ("Version", "AppVersion", APPVERSION); - keyFile.set_integer ("Version", "Version", PPVERSION); + keyFile.set_string ("Version", "AppVersion", APPVERSION); + keyFile.set_integer ("Version", "Version", PPVERSION); - if (!pedited || pedited->general.rank) { - keyFile.set_integer ("General", "Rank", rank); - } - - if (!pedited || pedited->general.colorlabel) { - keyFile.set_integer ("General", "ColorLabel", colorlabel); - } - - if (!pedited || pedited->general.intrash) { - keyFile.set_boolean ("General", "InTrash", inTrash); - } - - // save tone curve - if (!pedited || pedited->toneCurve.autoexp) { - keyFile.set_boolean ("Exposure", "Auto", toneCurve.autoexp); - } - - if (!pedited || pedited->toneCurve.clip) { - keyFile.set_double ("Exposure", "Clip", toneCurve.clip); - } - - if (!pedited || pedited->toneCurve.expcomp) { - keyFile.set_double ("Exposure", "Compensation", toneCurve.expcomp); - } - - if (!pedited || pedited->toneCurve.brightness) { - keyFile.set_integer ("Exposure", "Brightness", toneCurve.brightness); - } - - if (!pedited || pedited->toneCurve.contrast) { - keyFile.set_integer ("Exposure", "Contrast", toneCurve.contrast); - } - - if (!pedited || pedited->toneCurve.saturation) { - keyFile.set_integer ("Exposure", "Saturation", toneCurve.saturation); - } - - if (!pedited || pedited->toneCurve.black) { - keyFile.set_integer ("Exposure", "Black", toneCurve.black); - } - - if (!pedited || pedited->toneCurve.hlcompr) { - keyFile.set_integer ("Exposure", "HighlightCompr", toneCurve.hlcompr); - } - - if (!pedited || pedited->toneCurve.hlcomprthresh) { - keyFile.set_integer ("Exposure", "HighlightComprThreshold", toneCurve.hlcomprthresh); - } - - if (!pedited || pedited->toneCurve.shcompr) { - keyFile.set_integer ("Exposure", "ShadowCompr", toneCurve.shcompr); - } - - // save highlight recovery settings - if (!pedited || pedited->toneCurve.hrenabled) { - keyFile.set_boolean ("HLRecovery", "Enabled", toneCurve.hrenabled); - } - - if (!pedited || pedited->toneCurve.method) { - keyFile.set_string ("HLRecovery", "Method", toneCurve.method); - } - - if (!pedited || pedited->toneCurve.curveMode) { - Glib::ustring method; - - switch (toneCurve.curveMode) { - case (ToneCurveParams::TC_MODE_STD): - method = "Standard"; - break; - - case (ToneCurveParams::TC_MODE_FILMLIKE): - method = "FilmLike"; - break; - - case (ToneCurveParams::TC_MODE_SATANDVALBLENDING): - method = "SatAndValueBlending"; - break; - - case (ToneCurveParams::TC_MODE_WEIGHTEDSTD): - method = "WeightedStd"; - break; - - case (ToneCurveParams::TC_MODE_LUMINANCE): - method = "Luminance"; - break; - - case (ToneCurveParams::TC_MODE_PERCEPTUAL): - method = "Perceptual"; - break; + if (!pedited || pedited->general.rank) { + keyFile.set_integer ("General", "Rank", rank); } - keyFile.set_string ("Exposure", "CurveMode", method); - } - - if (!pedited || pedited->toneCurve.curveMode2) { - Glib::ustring method; - - switch (toneCurve.curveMode2) { - case (ToneCurveParams::TC_MODE_STD): - method = "Standard"; - break; - - case (ToneCurveParams::TC_MODE_FILMLIKE): - method = "FilmLike"; - break; - - case (ToneCurveParams::TC_MODE_SATANDVALBLENDING): - method = "SatAndValueBlending"; - break; - - case (ToneCurveParams::TC_MODE_WEIGHTEDSTD): - method = "WeightedStd"; - break; - - case (ToneCurveParams::TC_MODE_LUMINANCE): - method = "Luminance"; - break; - - case (ToneCurveParams::TC_MODE_PERCEPTUAL): - method = "Perceptual"; - break; + if (!pedited || pedited->general.colorlabel) { + keyFile.set_integer ("General", "ColorLabel", colorlabel); } - keyFile.set_string ("Exposure", "CurveMode2", method); - } - - if (!pedited || pedited->toneCurve.curve) { - Glib::ArrayHandle tcurve = toneCurve.curve; - keyFile.set_double_list("Exposure", "Curve", tcurve); - } - - if (!pedited || pedited->toneCurve.curve2) { - Glib::ArrayHandle tcurve = toneCurve.curve2; - keyFile.set_double_list("Exposure", "Curve2", tcurve); - } - - //save retinex - - if (!pedited || pedited->retinex.str) { - keyFile.set_integer ("Retinex", "Str", retinex.str); - } - - if (!pedited || pedited->retinex.scal) { - keyFile.set_integer ("Retinex", "Scal", retinex.scal); - } - - if (!pedited || pedited->retinex.iter) { - keyFile.set_integer ("Retinex", "Iter", retinex.iter); - } - - if (!pedited || pedited->retinex.grad) { - keyFile.set_integer ("Retinex", "Grad", retinex.grad); - } - - if (!pedited || pedited->retinex.grads) { - keyFile.set_integer ("Retinex", "Grads", retinex.grads); - } - - if (!pedited || pedited->retinex.gam) { - keyFile.set_double ("Retinex", "Gam", retinex.gam); - } - - if (!pedited || pedited->retinex.slope) { - keyFile.set_double ("Retinex", "Slope", retinex.slope); - } - - if (!pedited || pedited->retinex.enabled) { - keyFile.set_boolean ("Retinex", "Enabled", retinex.enabled); - } - - if (!pedited || pedited->retinex.medianmap) { - keyFile.set_boolean ("Retinex", "Median", retinex.medianmap); - } - - - - if (!pedited || pedited->retinex.neigh) { - keyFile.set_integer ("Retinex", "Neigh", retinex.neigh); - } - - if (!pedited || pedited->retinex.gain) { - keyFile.set_integer ("Retinex", "Gain", retinex.gain); - } - - if (!pedited || pedited->retinex.offs) { - keyFile.set_integer ("Retinex", "Offs", retinex.offs); - } - - if (!pedited || pedited->retinex.vart) { - keyFile.set_integer ("Retinex", "Vart", retinex.vart); - } - - if (!pedited || pedited->retinex.limd) { - keyFile.set_integer ("Retinex", "Limd", retinex.limd); - } - - if (!pedited || pedited->retinex.highl) { - keyFile.set_integer ("Retinex", "highl", retinex.highl); - } - - if (!pedited || pedited->retinex.baselog) { - keyFile.set_double ("Retinex", "baselog", retinex.baselog); - } - - if (!pedited || pedited->retinex.skal) { - keyFile.set_integer ("Retinex", "skal", retinex.skal); - } - - if (!pedited || pedited->retinex.retinexMethod) { - keyFile.set_string ("Retinex", "RetinexMethod", retinex.retinexMethod); - } - - if (!pedited || pedited->retinex.mapMethod) { - keyFile.set_string ("Retinex", "mapMethod", retinex.mapMethod); - } - - if (!pedited || pedited->retinex.viewMethod) { - keyFile.set_string ("Retinex", "viewMethod", retinex.viewMethod); - } - - if (!pedited || pedited->retinex.retinexcolorspace) { - keyFile.set_string ("Retinex", "Retinexcolorspace", retinex.retinexcolorspace); - } - - if (!pedited || pedited->retinex.gammaretinex) { - keyFile.set_string ("Retinex", "Gammaretinex", retinex.gammaretinex); - } - - if (!pedited || pedited->retinex.cdcurve) { - Glib::ArrayHandle cdcurve = retinex.cdcurve; - keyFile.set_double_list("Retinex", "CDCurve", cdcurve); - } - - if (!pedited || pedited->retinex.mapcurve) { - Glib::ArrayHandle mapcurve = retinex.mapcurve; - keyFile.set_double_list("Retinex", "MAPCurve", mapcurve); - } - - if (!pedited || pedited->retinex.cdHcurve) { - Glib::ArrayHandle cdHcurve = retinex.cdHcurve; - keyFile.set_double_list("Retinex", "CDHCurve", cdHcurve); - } - - if (!pedited || pedited->retinex.lhcurve) { - Glib::ArrayHandle lhcurve = retinex.lhcurve; - keyFile.set_double_list("Retinex", "LHCurve", lhcurve); - } - - if (!pedited || pedited->retinex.highlights) { - keyFile.set_integer ("Retinex", "Highlights", retinex.highlights); - } - - if (!pedited || pedited->retinex.htonalwidth) { - keyFile.set_integer ("Retinex", "HighlightTonalWidth", retinex.htonalwidth); - } - - if (!pedited || pedited->retinex.shadows) { - keyFile.set_integer ("Retinex", "Shadows", retinex.shadows); - } - - if (!pedited || pedited->retinex.stonalwidth) { - keyFile.set_integer ("Retinex", "ShadowTonalWidth", retinex.stonalwidth); - } - - if (!pedited || pedited->retinex.radius) { - keyFile.set_integer ("Retinex", "Radius", retinex.radius); - } - - if (!pedited || pedited->retinex.transmissionCurve) { - Glib::ArrayHandle transmissionCurve = retinex.transmissionCurve; - keyFile.set_double_list("Retinex", "TransmissionCurve", transmissionCurve); - } - - if (!pedited || pedited->retinex.gaintransmissionCurve) { - Glib::ArrayHandle gaintransmissionCurve = retinex.gaintransmissionCurve; - keyFile.set_double_list("Retinex", "GainTransmissionCurve", gaintransmissionCurve); - } - - // save channel mixer - if (!pedited || pedited->chmixer.red[0] || pedited->chmixer.red[1] || pedited->chmixer.red[2]) { - Glib::ArrayHandle rmix (chmixer.red, 3, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Channel Mixer", "Red", rmix); - } - - if (!pedited || pedited->chmixer.green[0] || pedited->chmixer.green[1] || pedited->chmixer.green[2]) { - Glib::ArrayHandle gmix (chmixer.green, 3, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Channel Mixer", "Green", gmix); - } - - if (!pedited || pedited->chmixer.blue[0] || pedited->chmixer.blue[1] || pedited->chmixer.blue[2]) { - Glib::ArrayHandle bmix (chmixer.blue, 3, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Channel Mixer", "Blue", bmix); - } - - //save Black & White - if (!pedited || pedited->blackwhite.enabled) { - keyFile.set_boolean ("Black & White", "Enabled", blackwhite.enabled); - } - - if (!pedited || pedited->blackwhite.method) { - keyFile.set_string ("Black & White", "Method", blackwhite.method ); - } - - if (!pedited || pedited->blackwhite.autoc) { - keyFile.set_boolean ("Black & White", "Auto", blackwhite.autoc); - } - - if (!pedited || pedited->blackwhite.enabledcc) { - keyFile.set_boolean ("Black & White", "ComplementaryColors", blackwhite.enabledcc); - } - - if (!pedited || pedited->blackwhite.setting) { - keyFile.set_string ("Black & White", "Setting", blackwhite.setting ); - } - - if (!pedited || pedited->blackwhite.filter) { - keyFile.set_string ("Black & White", "Filter", blackwhite.filter ); - } - - if (!pedited || pedited->blackwhite.mixerRed) { - keyFile.set_integer ("Black & White", "MixerRed", blackwhite.mixerRed); - } - - if (!pedited || pedited->blackwhite.mixerOrange) { - keyFile.set_integer ("Black & White", "MixerOrange", blackwhite.mixerOrange); - } - - if (!pedited || pedited->blackwhite.mixerYellow) { - keyFile.set_integer ("Black & White", "MixerYellow", blackwhite.mixerYellow); - } - - if (!pedited || pedited->blackwhite.mixerGreen) { - keyFile.set_integer ("Black & White", "MixerGreen", blackwhite.mixerGreen); - } - - if (!pedited || pedited->blackwhite.mixerCyan) { - keyFile.set_integer ("Black & White", "MixerCyan", blackwhite.mixerCyan); - } - - if (!pedited || pedited->blackwhite.mixerBlue) { - keyFile.set_integer ("Black & White", "MixerBlue", blackwhite.mixerBlue); - } - - if (!pedited || pedited->blackwhite.mixerMagenta) { - keyFile.set_integer ("Black & White", "MixerMagenta", blackwhite.mixerMagenta); - } - - if (!pedited || pedited->blackwhite.mixerPurple) { - keyFile.set_integer ("Black & White", "MixerPurple", blackwhite.mixerPurple); - } - - if (!pedited || pedited->blackwhite.gammaRed) { - keyFile.set_integer ("Black & White", "GammaRed", blackwhite.gammaRed); - } - - if (!pedited || pedited->blackwhite.gammaGreen) { - keyFile.set_integer ("Black & White", "GammaGreen", blackwhite.gammaGreen); - } - - if (!pedited || pedited->blackwhite.gammaBlue) { - keyFile.set_integer ("Black & White", "GammaBlue", blackwhite.gammaBlue); - } - - if (!pedited || pedited->blackwhite.algo) { - keyFile.set_string ("Black & White", "Algorithm", blackwhite.algo); - } - - if (!pedited || pedited->blackwhite.luminanceCurve) { - Glib::ArrayHandle luminanceCurve = blackwhite.luminanceCurve; - keyFile.set_double_list("Black & White", "LuminanceCurve", luminanceCurve); - } - - if (!pedited || pedited->blackwhite.beforeCurveMode) { - Glib::ustring mode; - - switch (blackwhite.beforeCurveMode) { - case (BlackWhiteParams::TC_MODE_STD_BW): - mode = "Standard"; - break; - - case (BlackWhiteParams::TC_MODE_FILMLIKE_BW): - mode = "FilmLike"; - break; - - case (BlackWhiteParams::TC_MODE_SATANDVALBLENDING_BW): - mode = "SatAndValueBlending"; - break; - - case (BlackWhiteParams::TC_MODE_WEIGHTEDSTD_BW): - mode = "WeightedStd"; - break; + if (!pedited || pedited->general.intrash) { + keyFile.set_boolean ("General", "InTrash", inTrash); } - keyFile.set_string ("Black & White", "BeforeCurveMode", mode); - } - - if (!pedited || pedited->blackwhite.afterCurveMode) { - Glib::ustring mode; - - switch (blackwhite.afterCurveMode) { - case (BlackWhiteParams::TC_MODE_STD_BW): - mode = "Standard"; - break; - - case (BlackWhiteParams::TC_MODE_WEIGHTEDSTD_BW): - mode = "WeightedStd"; - break; - - default: - break; + // save tone curve + if (!pedited || pedited->toneCurve.autoexp) { + keyFile.set_boolean ("Exposure", "Auto", toneCurve.autoexp); } - keyFile.set_string ("Black & White", "AfterCurveMode", mode); - } + if (!pedited || pedited->toneCurve.clip) { + keyFile.set_double ("Exposure", "Clip", toneCurve.clip); + } - if (!pedited || pedited->blackwhite.beforeCurve) { - Glib::ArrayHandle tcurvebw = blackwhite.beforeCurve; - keyFile.set_double_list("Black & White", "BeforeCurve", tcurvebw); - } + if (!pedited || pedited->toneCurve.expcomp) { + keyFile.set_double ("Exposure", "Compensation", toneCurve.expcomp); + } - if (!pedited || pedited->blackwhite.afterCurve) { - Glib::ArrayHandle tcurvebw = blackwhite.afterCurve; - keyFile.set_double_list("Black & White", "AfterCurve", tcurvebw); - } + if (!pedited || pedited->toneCurve.brightness) { + keyFile.set_integer ("Exposure", "Brightness", toneCurve.brightness); + } - // save luma curve - if (!pedited || pedited->labCurve.brightness) { - keyFile.set_integer ("Luminance Curve", "Brightness", labCurve.brightness); - } + if (!pedited || pedited->toneCurve.contrast) { + keyFile.set_integer ("Exposure", "Contrast", toneCurve.contrast); + } - if (!pedited || pedited->labCurve.contrast) { - keyFile.set_integer ("Luminance Curve", "Contrast", labCurve.contrast); - } + if (!pedited || pedited->toneCurve.saturation) { + keyFile.set_integer ("Exposure", "Saturation", toneCurve.saturation); + } - if (!pedited || pedited->labCurve.chromaticity) { - keyFile.set_integer ("Luminance Curve", "Chromaticity", labCurve.chromaticity); - } + if (!pedited || pedited->toneCurve.black) { + keyFile.set_integer ("Exposure", "Black", toneCurve.black); + } - if (!pedited || pedited->labCurve.avoidcolorshift) { - keyFile.set_boolean ("Luminance Curve", "AvoidColorShift", labCurve.avoidcolorshift); - } + if (!pedited || pedited->toneCurve.hlcompr) { + keyFile.set_integer ("Exposure", "HighlightCompr", toneCurve.hlcompr); + } - if (!pedited || pedited->labCurve.rstprotection) { - keyFile.set_double ("Luminance Curve", "RedAndSkinTonesProtection", labCurve.rstprotection); - } + if (!pedited || pedited->toneCurve.hlcomprthresh) { + keyFile.set_integer ("Exposure", "HighlightComprThreshold", toneCurve.hlcomprthresh); + } - if (!pedited || pedited->labCurve.lcredsk) { - keyFile.set_boolean ("Luminance Curve", "LCredsk", labCurve.lcredsk); - } + if (!pedited || pedited->toneCurve.shcompr) { + keyFile.set_integer ("Exposure", "ShadowCompr", toneCurve.shcompr); + } - if (!pedited || pedited->labCurve.lcurve) { - Glib::ArrayHandle lcurve = labCurve.lcurve; - keyFile.set_double_list("Luminance Curve", "LCurve", lcurve); - } + // save highlight recovery settings + if (!pedited || pedited->toneCurve.hrenabled) { + keyFile.set_boolean ("HLRecovery", "Enabled", toneCurve.hrenabled); + } - if (!pedited || pedited->labCurve.acurve) { - Glib::ArrayHandle acurve = labCurve.acurve; - keyFile.set_double_list("Luminance Curve", "aCurve", acurve); - } + if (!pedited || pedited->toneCurve.method) { + keyFile.set_string ("HLRecovery", "Method", toneCurve.method); + } - if (!pedited || pedited->labCurve.bcurve) { - Glib::ArrayHandle bcurve = labCurve.bcurve; - keyFile.set_double_list("Luminance Curve", "bCurve", bcurve); - } + if (!pedited || pedited->toneCurve.curveMode) { + Glib::ustring method; - if (!pedited || pedited->labCurve.cccurve) { - Glib::ArrayHandle cccurve = labCurve.cccurve; - keyFile.set_double_list("Luminance Curve", "ccCurve", cccurve); - } + switch (toneCurve.curveMode) { + case (ToneCurveParams::TC_MODE_STD): + method = "Standard"; + break; - if (!pedited || pedited->labCurve.chcurve) { - Glib::ArrayHandle chcurve = labCurve.chcurve; - keyFile.set_double_list("Luminance Curve", "chCurve", chcurve); - } + case (ToneCurveParams::TC_MODE_FILMLIKE): + method = "FilmLike"; + break; - if (!pedited || pedited->labCurve.lhcurve) { - Glib::ArrayHandle lhcurve = labCurve.lhcurve; - keyFile.set_double_list("Luminance Curve", "lhCurve", lhcurve); - } + case (ToneCurveParams::TC_MODE_SATANDVALBLENDING): + method = "SatAndValueBlending"; + break; - if (!pedited || pedited->labCurve.hhcurve) { - Glib::ArrayHandle hhcurve = labCurve.hhcurve; - keyFile.set_double_list("Luminance Curve", "hhCurve", hhcurve); - } + case (ToneCurveParams::TC_MODE_WEIGHTEDSTD): + method = "WeightedStd"; + break; - if (!pedited || pedited->labCurve.lccurve) { - Glib::ArrayHandle lccurve = labCurve.lccurve; - keyFile.set_double_list("Luminance Curve", "LcCurve", lccurve); - } + case (ToneCurveParams::TC_MODE_LUMINANCE): + method = "Luminance"; + break; - if (!pedited || pedited->labCurve.clcurve) { - Glib::ArrayHandle clcurve = labCurve.clcurve; - keyFile.set_double_list("Luminance Curve", "ClCurve", clcurve); - } + case (ToneCurveParams::TC_MODE_PERCEPTUAL): + method = "Perceptual"; + break; + } - // save sharpening - if (!pedited || pedited->sharpening.enabled) { - keyFile.set_boolean ("Sharpening", "Enabled", sharpening.enabled); - } + keyFile.set_string ("Exposure", "CurveMode", method); + } - if (!pedited || pedited->sharpening.method) { - keyFile.set_string ("Sharpening", "Method", sharpening.method); - } + if (!pedited || pedited->toneCurve.curveMode2) { + Glib::ustring method; - if (!pedited || pedited->sharpening.radius) { - keyFile.set_double ("Sharpening", "Radius", sharpening.radius); - } + switch (toneCurve.curveMode2) { + case (ToneCurveParams::TC_MODE_STD): + method = "Standard"; + break; - if (!pedited || pedited->sharpening.amount) { - keyFile.set_integer ("Sharpening", "Amount", sharpening.amount); - } + case (ToneCurveParams::TC_MODE_FILMLIKE): + method = "FilmLike"; + break; - if (!pedited || pedited->sharpening.threshold) { - Glib::ArrayHandle thresh (sharpening.threshold.value, 4, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Sharpening", "Threshold", thresh); - } + case (ToneCurveParams::TC_MODE_SATANDVALBLENDING): + method = "SatAndValueBlending"; + break; - if (!pedited || pedited->sharpening.edgesonly) { - keyFile.set_boolean ("Sharpening", "OnlyEdges", sharpening.edgesonly); - } + case (ToneCurveParams::TC_MODE_WEIGHTEDSTD): + method = "WeightedStd"; + break; - if (!pedited || pedited->sharpening.edges_radius) { - keyFile.set_double ("Sharpening", "EdgedetectionRadius", sharpening.edges_radius); - } + case (ToneCurveParams::TC_MODE_LUMINANCE): + method = "Luminance"; + break; - if (!pedited || pedited->sharpening.edges_tolerance) { - keyFile.set_integer ("Sharpening", "EdgeTolerance", sharpening.edges_tolerance); - } + case (ToneCurveParams::TC_MODE_PERCEPTUAL): + method = "Perceptual"; + break; + } - if (!pedited || pedited->sharpening.halocontrol) { - keyFile.set_boolean ("Sharpening", "HalocontrolEnabled", sharpening.halocontrol); - } + keyFile.set_string ("Exposure", "CurveMode2", method); + } - if (!pedited || pedited->sharpening.halocontrol_amount) { - keyFile.set_integer ("Sharpening", "HalocontrolAmount", sharpening.halocontrol_amount); - } + if (!pedited || pedited->toneCurve.curve) { + Glib::ArrayHandle tcurve = toneCurve.curve; + keyFile.set_double_list("Exposure", "Curve", tcurve); + } - if (!pedited || pedited->sharpening.deconvradius) { - keyFile.set_double ("Sharpening", "DeconvRadius", sharpening.deconvradius); - } + if (!pedited || pedited->toneCurve.curve2) { + Glib::ArrayHandle tcurve = toneCurve.curve2; + keyFile.set_double_list("Exposure", "Curve2", tcurve); + } - if (!pedited || pedited->sharpening.deconvamount) { - keyFile.set_integer ("Sharpening", "DeconvAmount", sharpening.deconvamount); - } + //save retinex - if (!pedited || pedited->sharpening.deconvdamping) { - keyFile.set_integer ("Sharpening", "DeconvDamping", sharpening.deconvdamping); - } + if (!pedited || pedited->retinex.str) { + keyFile.set_integer ("Retinex", "Str", retinex.str); + } - if (!pedited || pedited->sharpening.deconviter) { - keyFile.set_integer ("Sharpening", "DeconvIterations", sharpening.deconviter); - } + if (!pedited || pedited->retinex.scal) { + keyFile.set_integer ("Retinex", "Scal", retinex.scal); + } - // save vibrance - if (!pedited || pedited->vibrance.enabled) { - keyFile.set_boolean ("Vibrance", "Enabled", vibrance.enabled); - } + if (!pedited || pedited->retinex.iter) { + keyFile.set_integer ("Retinex", "Iter", retinex.iter); + } - if (!pedited || pedited->vibrance.pastels) { - keyFile.set_integer ("Vibrance", "Pastels", vibrance.pastels); - } + if (!pedited || pedited->retinex.grad) { + keyFile.set_integer ("Retinex", "Grad", retinex.grad); + } - if (!pedited || pedited->vibrance.saturated) { - keyFile.set_integer ("Vibrance", "Saturated", vibrance.saturated); - } + if (!pedited || pedited->retinex.grads) { + keyFile.set_integer ("Retinex", "Grads", retinex.grads); + } - if (!pedited || pedited->vibrance.psthreshold) { - Glib::ArrayHandle thresh (vibrance.psthreshold.value, 2, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Vibrance", "PSThreshold", thresh); - } + if (!pedited || pedited->retinex.gam) { + keyFile.set_double ("Retinex", "Gam", retinex.gam); + } - if (!pedited || pedited->vibrance.protectskins) { - keyFile.set_boolean ("Vibrance", "ProtectSkins", vibrance.protectskins); - } + if (!pedited || pedited->retinex.slope) { + keyFile.set_double ("Retinex", "Slope", retinex.slope); + } - if (!pedited || pedited->vibrance.avoidcolorshift) { - keyFile.set_boolean ("Vibrance", "AvoidColorShift", vibrance.avoidcolorshift); - } + if (!pedited || pedited->retinex.enabled) { + keyFile.set_boolean ("Retinex", "Enabled", retinex.enabled); + } - if (!pedited || pedited->vibrance.pastsattog) { - keyFile.set_boolean ("Vibrance", "PastSatTog", vibrance.pastsattog); - } + if (!pedited || pedited->retinex.medianmap) { + keyFile.set_boolean ("Retinex", "Median", retinex.medianmap); + } - if (!pedited || pedited->vibrance.skintonescurve) { - Glib::ArrayHandle skintonescurve = vibrance.skintonescurve; - keyFile.set_double_list("Vibrance", "SkinTonesCurve", skintonescurve); - } - //save edge sharpening - if (!pedited || pedited->sharpenEdge.enabled) { - keyFile.set_boolean ("SharpenEdge", "Enabled", sharpenEdge.enabled); - } - if (!pedited || pedited->sharpenEdge.passes) { - keyFile.set_integer ("SharpenEdge", "Passes", sharpenEdge.passes); - } + if (!pedited || pedited->retinex.neigh) { + keyFile.set_integer ("Retinex", "Neigh", retinex.neigh); + } - if (!pedited || pedited->sharpenEdge.amount) { - keyFile.set_double ("SharpenEdge", "Strength", sharpenEdge.amount); - } + if (!pedited || pedited->retinex.gain) { + keyFile.set_integer ("Retinex", "Gain", retinex.gain); + } - if (!pedited || pedited->sharpenEdge.threechannels) { - keyFile.set_boolean ("SharpenEdge", "ThreeChannels", sharpenEdge.threechannels); - } + if (!pedited || pedited->retinex.offs) { + keyFile.set_integer ("Retinex", "Offs", retinex.offs); + } - //save micro-contrast sharpening - if (!pedited || pedited->sharpenMicro.enabled) { - keyFile.set_boolean ("SharpenMicro", "Enabled", sharpenMicro.enabled); - } + if (!pedited || pedited->retinex.vart) { + keyFile.set_integer ("Retinex", "Vart", retinex.vart); + } - if (!pedited || pedited->sharpenMicro.matrix) { - keyFile.set_boolean ("SharpenMicro", "Matrix", sharpenMicro.matrix); - } + if (!pedited || pedited->retinex.limd) { + keyFile.set_integer ("Retinex", "Limd", retinex.limd); + } - if (!pedited || pedited->sharpenMicro.amount) { - keyFile.set_double ("SharpenMicro", "Strength", sharpenMicro.amount); - } + if (!pedited || pedited->retinex.highl) { + keyFile.set_integer ("Retinex", "highl", retinex.highl); + } - if (!pedited || pedited->sharpenMicro.uniformity) { - keyFile.set_double ("SharpenMicro", "Uniformity", sharpenMicro.uniformity); - } + if (!pedited || pedited->retinex.baselog) { + keyFile.set_double ("Retinex", "baselog", retinex.baselog); + } - /* - // save colorBoost - if (!pedited || pedited->colorBoost.amount) keyFile.set_integer ("Color Boost", "Amount", colorBoost.amount); - if (!pedited || pedited->colorBoost.avoidclip) keyFile.set_boolean ("Color Boost", "AvoidColorClipping", colorBoost.avoidclip); - if (!pedited || pedited->colorBoost.enable_saturationlimiter) keyFile.set_boolean ("Color Boost", "SaturationLimiter", colorBoost.enable_saturationlimiter); - if (!pedited || pedited->colorBoost.saturationlimit) keyFile.set_double ("Color Boost", "SaturationLimit", colorBoost.saturationlimit); - */ + if (!pedited || pedited->retinex.skal) { + keyFile.set_integer ("Retinex", "skal", retinex.skal); + } - // save wb - if (!pedited || pedited->wb.method) { - keyFile.set_string ("White Balance", "Setting", wb.method); - } + if (!pedited || pedited->retinex.retinexMethod) { + keyFile.set_string ("Retinex", "RetinexMethod", retinex.retinexMethod); + } - if (!pedited || pedited->wb.temperature) { - keyFile.set_integer ("White Balance", "Temperature", wb.temperature); - } + if (!pedited || pedited->retinex.mapMethod) { + keyFile.set_string ("Retinex", "mapMethod", retinex.mapMethod); + } - if (!pedited || pedited->wb.green) { - keyFile.set_double ("White Balance", "Green", wb.green); - } + if (!pedited || pedited->retinex.viewMethod) { + keyFile.set_string ("Retinex", "viewMethod", retinex.viewMethod); + } - if (!pedited || pedited->wb.equal) { - keyFile.set_double ("White Balance", "Equal", wb.equal); - } + if (!pedited || pedited->retinex.retinexcolorspace) { + keyFile.set_string ("Retinex", "Retinexcolorspace", retinex.retinexcolorspace); + } - /* - // save colorShift - if (!pedited || pedited->colorShift.a) keyFile.set_double ("Color Shift", "ChannelA", colorShift.a); - if (!pedited || pedited->colorShift.b) keyFile.set_double ("Color Shift", "ChannelB", colorShift.b); - */ - // save colorappearance - if (!pedited || pedited->colorappearance.enabled) { - keyFile.set_boolean ("Color appearance", "Enabled", colorappearance.enabled); - } + if (!pedited || pedited->retinex.gammaretinex) { + keyFile.set_string ("Retinex", "Gammaretinex", retinex.gammaretinex); + } - if (!pedited || pedited->colorappearance.degree) { - keyFile.set_integer ("Color appearance", "Degree", colorappearance.degree); - } + if (!pedited || pedited->retinex.cdcurve) { + Glib::ArrayHandle cdcurve = retinex.cdcurve; + keyFile.set_double_list("Retinex", "CDCurve", cdcurve); + } - if (!pedited || pedited->colorappearance.autodegree) { - keyFile.set_boolean ("Color appearance", "AutoDegree", colorappearance.autodegree); - } + if (!pedited || pedited->retinex.mapcurve) { + Glib::ArrayHandle mapcurve = retinex.mapcurve; + keyFile.set_double_list("Retinex", "MAPCurve", mapcurve); + } - if (!pedited || pedited->colorappearance.surround) { - keyFile.set_string ("Color appearance", "Surround", colorappearance.surround); - } + if (!pedited || pedited->retinex.cdHcurve) { + Glib::ArrayHandle cdHcurve = retinex.cdHcurve; + keyFile.set_double_list("Retinex", "CDHCurve", cdHcurve); + } + + if (!pedited || pedited->retinex.lhcurve) { + Glib::ArrayHandle lhcurve = retinex.lhcurve; + keyFile.set_double_list("Retinex", "LHCurve", lhcurve); + } + + if (!pedited || pedited->retinex.highlights) { + keyFile.set_integer ("Retinex", "Highlights", retinex.highlights); + } + + if (!pedited || pedited->retinex.htonalwidth) { + keyFile.set_integer ("Retinex", "HighlightTonalWidth", retinex.htonalwidth); + } + + if (!pedited || pedited->retinex.shadows) { + keyFile.set_integer ("Retinex", "Shadows", retinex.shadows); + } + + if (!pedited || pedited->retinex.stonalwidth) { + keyFile.set_integer ("Retinex", "ShadowTonalWidth", retinex.stonalwidth); + } + + if (!pedited || pedited->retinex.radius) { + keyFile.set_integer ("Retinex", "Radius", retinex.radius); + } + + if (!pedited || pedited->retinex.transmissionCurve) { + Glib::ArrayHandle transmissionCurve = retinex.transmissionCurve; + keyFile.set_double_list("Retinex", "TransmissionCurve", transmissionCurve); + } + + if (!pedited || pedited->retinex.gaintransmissionCurve) { + Glib::ArrayHandle gaintransmissionCurve = retinex.gaintransmissionCurve; + keyFile.set_double_list("Retinex", "GainTransmissionCurve", gaintransmissionCurve); + } + + // save channel mixer + if (!pedited || pedited->chmixer.red[0] || pedited->chmixer.red[1] || pedited->chmixer.red[2]) { + Glib::ArrayHandle rmix (chmixer.red, 3, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Channel Mixer", "Red", rmix); + } + + if (!pedited || pedited->chmixer.green[0] || pedited->chmixer.green[1] || pedited->chmixer.green[2]) { + Glib::ArrayHandle gmix (chmixer.green, 3, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Channel Mixer", "Green", gmix); + } + + if (!pedited || pedited->chmixer.blue[0] || pedited->chmixer.blue[1] || pedited->chmixer.blue[2]) { + Glib::ArrayHandle bmix (chmixer.blue, 3, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Channel Mixer", "Blue", bmix); + } + + //save Black & White + if (!pedited || pedited->blackwhite.enabled) { + keyFile.set_boolean ("Black & White", "Enabled", blackwhite.enabled); + } + + if (!pedited || pedited->blackwhite.method) { + keyFile.set_string ("Black & White", "Method", blackwhite.method ); + } + + if (!pedited || pedited->blackwhite.autoc) { + keyFile.set_boolean ("Black & White", "Auto", blackwhite.autoc); + } + + if (!pedited || pedited->blackwhite.enabledcc) { + keyFile.set_boolean ("Black & White", "ComplementaryColors", blackwhite.enabledcc); + } + + if (!pedited || pedited->blackwhite.setting) { + keyFile.set_string ("Black & White", "Setting", blackwhite.setting ); + } + + if (!pedited || pedited->blackwhite.filter) { + keyFile.set_string ("Black & White", "Filter", blackwhite.filter ); + } + + if (!pedited || pedited->blackwhite.mixerRed) { + keyFile.set_integer ("Black & White", "MixerRed", blackwhite.mixerRed); + } + + if (!pedited || pedited->blackwhite.mixerOrange) { + keyFile.set_integer ("Black & White", "MixerOrange", blackwhite.mixerOrange); + } + + if (!pedited || pedited->blackwhite.mixerYellow) { + keyFile.set_integer ("Black & White", "MixerYellow", blackwhite.mixerYellow); + } + + if (!pedited || pedited->blackwhite.mixerGreen) { + keyFile.set_integer ("Black & White", "MixerGreen", blackwhite.mixerGreen); + } + + if (!pedited || pedited->blackwhite.mixerCyan) { + keyFile.set_integer ("Black & White", "MixerCyan", blackwhite.mixerCyan); + } + + if (!pedited || pedited->blackwhite.mixerBlue) { + keyFile.set_integer ("Black & White", "MixerBlue", blackwhite.mixerBlue); + } + + if (!pedited || pedited->blackwhite.mixerMagenta) { + keyFile.set_integer ("Black & White", "MixerMagenta", blackwhite.mixerMagenta); + } + + if (!pedited || pedited->blackwhite.mixerPurple) { + keyFile.set_integer ("Black & White", "MixerPurple", blackwhite.mixerPurple); + } + + if (!pedited || pedited->blackwhite.gammaRed) { + keyFile.set_integer ("Black & White", "GammaRed", blackwhite.gammaRed); + } + + if (!pedited || pedited->blackwhite.gammaGreen) { + keyFile.set_integer ("Black & White", "GammaGreen", blackwhite.gammaGreen); + } + + if (!pedited || pedited->blackwhite.gammaBlue) { + keyFile.set_integer ("Black & White", "GammaBlue", blackwhite.gammaBlue); + } + + if (!pedited || pedited->blackwhite.algo) { + keyFile.set_string ("Black & White", "Algorithm", blackwhite.algo); + } + + if (!pedited || pedited->blackwhite.luminanceCurve) { + Glib::ArrayHandle luminanceCurve = blackwhite.luminanceCurve; + keyFile.set_double_list("Black & White", "LuminanceCurve", luminanceCurve); + } + + if (!pedited || pedited->blackwhite.beforeCurveMode) { + Glib::ustring mode; + + switch (blackwhite.beforeCurveMode) { + case (BlackWhiteParams::TC_MODE_STD_BW): + mode = "Standard"; + break; + + case (BlackWhiteParams::TC_MODE_FILMLIKE_BW): + mode = "FilmLike"; + break; + + case (BlackWhiteParams::TC_MODE_SATANDVALBLENDING_BW): + mode = "SatAndValueBlending"; + break; + + case (BlackWhiteParams::TC_MODE_WEIGHTEDSTD_BW): + mode = "WeightedStd"; + break; + } + + keyFile.set_string ("Black & White", "BeforeCurveMode", mode); + } + + if (!pedited || pedited->blackwhite.afterCurveMode) { + Glib::ustring mode; + + switch (blackwhite.afterCurveMode) { + case (BlackWhiteParams::TC_MODE_STD_BW): + mode = "Standard"; + break; + + case (BlackWhiteParams::TC_MODE_WEIGHTEDSTD_BW): + mode = "WeightedStd"; + break; + + default: + break; + } + + keyFile.set_string ("Black & White", "AfterCurveMode", mode); + } + + if (!pedited || pedited->blackwhite.beforeCurve) { + Glib::ArrayHandle tcurvebw = blackwhite.beforeCurve; + keyFile.set_double_list("Black & White", "BeforeCurve", tcurvebw); + } + + if (!pedited || pedited->blackwhite.afterCurve) { + Glib::ArrayHandle tcurvebw = blackwhite.afterCurve; + keyFile.set_double_list("Black & White", "AfterCurve", tcurvebw); + } + + // save luma curve + if (!pedited || pedited->labCurve.brightness) { + keyFile.set_integer ("Luminance Curve", "Brightness", labCurve.brightness); + } + + if (!pedited || pedited->labCurve.contrast) { + keyFile.set_integer ("Luminance Curve", "Contrast", labCurve.contrast); + } + + if (!pedited || pedited->labCurve.chromaticity) { + keyFile.set_integer ("Luminance Curve", "Chromaticity", labCurve.chromaticity); + } + + if (!pedited || pedited->labCurve.avoidcolorshift) { + keyFile.set_boolean ("Luminance Curve", "AvoidColorShift", labCurve.avoidcolorshift); + } + + if (!pedited || pedited->labCurve.rstprotection) { + keyFile.set_double ("Luminance Curve", "RedAndSkinTonesProtection", labCurve.rstprotection); + } + + if (!pedited || pedited->labCurve.lcredsk) { + keyFile.set_boolean ("Luminance Curve", "LCredsk", labCurve.lcredsk); + } + + if (!pedited || pedited->labCurve.lcurve) { + Glib::ArrayHandle lcurve = labCurve.lcurve; + keyFile.set_double_list("Luminance Curve", "LCurve", lcurve); + } + + if (!pedited || pedited->labCurve.acurve) { + Glib::ArrayHandle acurve = labCurve.acurve; + keyFile.set_double_list("Luminance Curve", "aCurve", acurve); + } + + if (!pedited || pedited->labCurve.bcurve) { + Glib::ArrayHandle bcurve = labCurve.bcurve; + keyFile.set_double_list("Luminance Curve", "bCurve", bcurve); + } + + if (!pedited || pedited->labCurve.cccurve) { + Glib::ArrayHandle cccurve = labCurve.cccurve; + keyFile.set_double_list("Luminance Curve", "ccCurve", cccurve); + } + + if (!pedited || pedited->labCurve.chcurve) { + Glib::ArrayHandle chcurve = labCurve.chcurve; + keyFile.set_double_list("Luminance Curve", "chCurve", chcurve); + } + + if (!pedited || pedited->labCurve.lhcurve) { + Glib::ArrayHandle lhcurve = labCurve.lhcurve; + keyFile.set_double_list("Luminance Curve", "lhCurve", lhcurve); + } + + if (!pedited || pedited->labCurve.hhcurve) { + Glib::ArrayHandle hhcurve = labCurve.hhcurve; + keyFile.set_double_list("Luminance Curve", "hhCurve", hhcurve); + } + + if (!pedited || pedited->labCurve.lccurve) { + Glib::ArrayHandle lccurve = labCurve.lccurve; + keyFile.set_double_list("Luminance Curve", "LcCurve", lccurve); + } + + if (!pedited || pedited->labCurve.clcurve) { + Glib::ArrayHandle clcurve = labCurve.clcurve; + keyFile.set_double_list("Luminance Curve", "ClCurve", clcurve); + } + + // save sharpening + if (!pedited || pedited->sharpening.enabled) { + keyFile.set_boolean ("Sharpening", "Enabled", sharpening.enabled); + } + + if (!pedited || pedited->sharpening.method) { + keyFile.set_string ("Sharpening", "Method", sharpening.method); + } + + if (!pedited || pedited->sharpening.radius) { + keyFile.set_double ("Sharpening", "Radius", sharpening.radius); + } + + if (!pedited || pedited->sharpening.amount) { + keyFile.set_integer ("Sharpening", "Amount", sharpening.amount); + } + + if (!pedited || pedited->sharpening.threshold) { + Glib::ArrayHandle thresh (sharpening.threshold.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Sharpening", "Threshold", thresh); + } + + if (!pedited || pedited->sharpening.edgesonly) { + keyFile.set_boolean ("Sharpening", "OnlyEdges", sharpening.edgesonly); + } + + if (!pedited || pedited->sharpening.edges_radius) { + keyFile.set_double ("Sharpening", "EdgedetectionRadius", sharpening.edges_radius); + } + + if (!pedited || pedited->sharpening.edges_tolerance) { + keyFile.set_integer ("Sharpening", "EdgeTolerance", sharpening.edges_tolerance); + } + + if (!pedited || pedited->sharpening.halocontrol) { + keyFile.set_boolean ("Sharpening", "HalocontrolEnabled", sharpening.halocontrol); + } + + if (!pedited || pedited->sharpening.halocontrol_amount) { + keyFile.set_integer ("Sharpening", "HalocontrolAmount", sharpening.halocontrol_amount); + } + + if (!pedited || pedited->sharpening.deconvradius) { + keyFile.set_double ("Sharpening", "DeconvRadius", sharpening.deconvradius); + } + + if (!pedited || pedited->sharpening.deconvamount) { + keyFile.set_integer ("Sharpening", "DeconvAmount", sharpening.deconvamount); + } + + if (!pedited || pedited->sharpening.deconvdamping) { + keyFile.set_integer ("Sharpening", "DeconvDamping", sharpening.deconvdamping); + } + + if (!pedited || pedited->sharpening.deconviter) { + keyFile.set_integer ("Sharpening", "DeconvIterations", sharpening.deconviter); + } + + // save vibrance + if (!pedited || pedited->vibrance.enabled) { + keyFile.set_boolean ("Vibrance", "Enabled", vibrance.enabled); + } + + if (!pedited || pedited->vibrance.pastels) { + keyFile.set_integer ("Vibrance", "Pastels", vibrance.pastels); + } + + if (!pedited || pedited->vibrance.saturated) { + keyFile.set_integer ("Vibrance", "Saturated", vibrance.saturated); + } + + if (!pedited || pedited->vibrance.psthreshold) { + Glib::ArrayHandle thresh (vibrance.psthreshold.value, 2, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Vibrance", "PSThreshold", thresh); + } + + if (!pedited || pedited->vibrance.protectskins) { + keyFile.set_boolean ("Vibrance", "ProtectSkins", vibrance.protectskins); + } + + if (!pedited || pedited->vibrance.avoidcolorshift) { + keyFile.set_boolean ("Vibrance", "AvoidColorShift", vibrance.avoidcolorshift); + } + + if (!pedited || pedited->vibrance.pastsattog) { + keyFile.set_boolean ("Vibrance", "PastSatTog", vibrance.pastsattog); + } + + if (!pedited || pedited->vibrance.skintonescurve) { + Glib::ArrayHandle skintonescurve = vibrance.skintonescurve; + keyFile.set_double_list("Vibrance", "SkinTonesCurve", skintonescurve); + } + + //save edge sharpening + if (!pedited || pedited->sharpenEdge.enabled) { + keyFile.set_boolean ("SharpenEdge", "Enabled", sharpenEdge.enabled); + } + + if (!pedited || pedited->sharpenEdge.passes) { + keyFile.set_integer ("SharpenEdge", "Passes", sharpenEdge.passes); + } + + if (!pedited || pedited->sharpenEdge.amount) { + keyFile.set_double ("SharpenEdge", "Strength", sharpenEdge.amount); + } + + if (!pedited || pedited->sharpenEdge.threechannels) { + keyFile.set_boolean ("SharpenEdge", "ThreeChannels", sharpenEdge.threechannels); + } + + //save micro-contrast sharpening + if (!pedited || pedited->sharpenMicro.enabled) { + keyFile.set_boolean ("SharpenMicro", "Enabled", sharpenMicro.enabled); + } + + if (!pedited || pedited->sharpenMicro.matrix) { + keyFile.set_boolean ("SharpenMicro", "Matrix", sharpenMicro.matrix); + } + + if (!pedited || pedited->sharpenMicro.amount) { + keyFile.set_double ("SharpenMicro", "Strength", sharpenMicro.amount); + } + + if (!pedited || pedited->sharpenMicro.uniformity) { + keyFile.set_double ("SharpenMicro", "Uniformity", sharpenMicro.uniformity); + } + + /* + // save colorBoost + if (!pedited || pedited->colorBoost.amount) keyFile.set_integer ("Color Boost", "Amount", colorBoost.amount); + if (!pedited || pedited->colorBoost.avoidclip) keyFile.set_boolean ("Color Boost", "AvoidColorClipping", colorBoost.avoidclip); + if (!pedited || pedited->colorBoost.enable_saturationlimiter) keyFile.set_boolean ("Color Boost", "SaturationLimiter", colorBoost.enable_saturationlimiter); + if (!pedited || pedited->colorBoost.saturationlimit) keyFile.set_double ("Color Boost", "SaturationLimit", colorBoost.saturationlimit); + */ + + // save wb + if (!pedited || pedited->wb.method) { + keyFile.set_string ("White Balance", "Setting", wb.method); + } + + if (!pedited || pedited->wb.temperature) { + keyFile.set_integer ("White Balance", "Temperature", wb.temperature); + } + + if (!pedited || pedited->wb.green) { + keyFile.set_double ("White Balance", "Green", wb.green); + } + + if (!pedited || pedited->wb.equal) { + keyFile.set_double ("White Balance", "Equal", wb.equal); + } + + /* + // save colorShift + if (!pedited || pedited->colorShift.a) keyFile.set_double ("Color Shift", "ChannelA", colorShift.a); + if (!pedited || pedited->colorShift.b) keyFile.set_double ("Color Shift", "ChannelB", colorShift.b); + */ + // save colorappearance + if (!pedited || pedited->colorappearance.enabled) { + keyFile.set_boolean ("Color appearance", "Enabled", colorappearance.enabled); + } + + if (!pedited || pedited->colorappearance.degree) { + keyFile.set_integer ("Color appearance", "Degree", colorappearance.degree); + } + + if (!pedited || pedited->colorappearance.autodegree) { + keyFile.set_boolean ("Color appearance", "AutoDegree", colorappearance.autodegree); + } + + if (!pedited || pedited->colorappearance.surround) { + keyFile.set_string ("Color appearance", "Surround", colorappearance.surround); + } // if (!pedited || pedited->colorappearance.backgrd) keyFile.set_integer ("Color appearance", "Background", colorappearance.backgrd); - if (!pedited || pedited->colorappearance.adaplum) { - keyFile.set_double ("Color appearance", "AdaptLum", colorappearance.adaplum); - } + if (!pedited || pedited->colorappearance.adaplum) { + keyFile.set_double ("Color appearance", "AdaptLum", colorappearance.adaplum); + } - if (!pedited || pedited->colorappearance.badpixsl) { - keyFile.set_integer ("Color appearance", "Badpixsl", colorappearance.badpixsl); - } + if (!pedited || pedited->colorappearance.badpixsl) { + keyFile.set_integer ("Color appearance", "Badpixsl", colorappearance.badpixsl); + } - if (!pedited || pedited->colorappearance.wbmodel) { - keyFile.set_string ("Color appearance", "Model", colorappearance.wbmodel); - } + if (!pedited || pedited->colorappearance.wbmodel) { + keyFile.set_string ("Color appearance", "Model", colorappearance.wbmodel); + } - if (!pedited || pedited->colorappearance.algo) { - keyFile.set_string ("Color appearance", "Algorithm", colorappearance.algo); - } + if (!pedited || pedited->colorappearance.algo) { + keyFile.set_string ("Color appearance", "Algorithm", colorappearance.algo); + } - if (!pedited || pedited->colorappearance.jlight) { - keyFile.set_double ("Color appearance", "J-Light", colorappearance.jlight); - } + if (!pedited || pedited->colorappearance.jlight) { + keyFile.set_double ("Color appearance", "J-Light", colorappearance.jlight); + } - if (!pedited || pedited->colorappearance.qbright) { - keyFile.set_double ("Color appearance", "Q-Bright", colorappearance.qbright); - } + if (!pedited || pedited->colorappearance.qbright) { + keyFile.set_double ("Color appearance", "Q-Bright", colorappearance.qbright); + } - if (!pedited || pedited->colorappearance.chroma) { - keyFile.set_double ("Color appearance", "C-Chroma", colorappearance.chroma); - } + if (!pedited || pedited->colorappearance.chroma) { + keyFile.set_double ("Color appearance", "C-Chroma", colorappearance.chroma); + } - if (!pedited || pedited->colorappearance.schroma) { - keyFile.set_double ("Color appearance", "S-Chroma", colorappearance.schroma); - } + if (!pedited || pedited->colorappearance.schroma) { + keyFile.set_double ("Color appearance", "S-Chroma", colorappearance.schroma); + } - if (!pedited || pedited->colorappearance.mchroma) { - keyFile.set_double ("Color appearance", "M-Chroma", colorappearance.mchroma); - } + if (!pedited || pedited->colorappearance.mchroma) { + keyFile.set_double ("Color appearance", "M-Chroma", colorappearance.mchroma); + } - if (!pedited || pedited->colorappearance.contrast) { - keyFile.set_double ("Color appearance", "J-Contrast", colorappearance.contrast); - } + if (!pedited || pedited->colorappearance.contrast) { + keyFile.set_double ("Color appearance", "J-Contrast", colorappearance.contrast); + } - if (!pedited || pedited->colorappearance.qcontrast) { - keyFile.set_double ("Color appearance", "Q-Contrast", colorappearance.qcontrast); - } + if (!pedited || pedited->colorappearance.qcontrast) { + keyFile.set_double ("Color appearance", "Q-Contrast", colorappearance.qcontrast); + } - if (!pedited || pedited->colorappearance.colorh) { - keyFile.set_double ("Color appearance", "H-Hue", colorappearance.colorh); - } + if (!pedited || pedited->colorappearance.colorh) { + keyFile.set_double ("Color appearance", "H-Hue", colorappearance.colorh); + } - if (!pedited || pedited->colorappearance.rstprotection) { - keyFile.set_double ("Color appearance", "RSTProtection", colorappearance.rstprotection); - } + if (!pedited || pedited->colorappearance.rstprotection) { + keyFile.set_double ("Color appearance", "RSTProtection", colorappearance.rstprotection); + } - if (!pedited || pedited->colorappearance.adapscen) { - keyFile.set_double ("Color appearance", "AdaptScene", colorappearance.adapscen); - } + if (!pedited || pedited->colorappearance.adapscen) { + keyFile.set_double ("Color appearance", "AdaptScene", colorappearance.adapscen); + } - if (!pedited || pedited->colorappearance.autoadapscen) { - keyFile.set_boolean ("Color appearance", "AutoAdapscen", colorappearance.autoadapscen); - } + if (!pedited || pedited->colorappearance.autoadapscen) { + keyFile.set_boolean ("Color appearance", "AutoAdapscen", colorappearance.autoadapscen); + } - if (!pedited || pedited->colorappearance.surrsource) { - keyFile.set_boolean ("Color appearance", "SurrSource", colorappearance.surrsource); - } + if (!pedited || pedited->colorappearance.surrsource) { + keyFile.set_boolean ("Color appearance", "SurrSource", colorappearance.surrsource); + } - if (!pedited || pedited->colorappearance.gamut) { - keyFile.set_boolean ("Color appearance", "Gamut", colorappearance.gamut); - } + if (!pedited || pedited->colorappearance.gamut) { + keyFile.set_boolean ("Color appearance", "Gamut", colorappearance.gamut); + } // if (!pedited || pedited->colorappearance.badpix) keyFile.set_boolean ("Color appearance", "Badpix", colorappearance.badpix); - if (!pedited || pedited->colorappearance.datacie) { - keyFile.set_boolean ("Color appearance", "Datacie", colorappearance.datacie); - } + if (!pedited || pedited->colorappearance.datacie) { + keyFile.set_boolean ("Color appearance", "Datacie", colorappearance.datacie); + } - if (!pedited || pedited->colorappearance.tonecie) { - keyFile.set_boolean ("Color appearance", "Tonecie", colorappearance.tonecie); - } + if (!pedited || pedited->colorappearance.tonecie) { + keyFile.set_boolean ("Color appearance", "Tonecie", colorappearance.tonecie); + } // if (!pedited || pedited->colorappearance.sharpcie) keyFile.set_boolean ("Color appearance", "Sharpcie", colorappearance.sharpcie); - if (!pedited || pedited->colorappearance.curveMode) { - Glib::ustring method; + if (!pedited || pedited->colorappearance.curveMode) { + Glib::ustring method; - switch (colorappearance.curveMode) { - case (ColorAppearanceParams::TC_MODE_LIGHT): - method = "Lightness"; - break; + switch (colorappearance.curveMode) { + case (ColorAppearanceParams::TC_MODE_LIGHT): + method = "Lightness"; + break; - case (ColorAppearanceParams::TC_MODE_BRIGHT): - method = "Brightness"; - break; + case (ColorAppearanceParams::TC_MODE_BRIGHT): + method = "Brightness"; + break; + } + + keyFile.set_string ("Color appearance", "CurveMode", method); } - keyFile.set_string ("Color appearance", "CurveMode", method); - } + if (!pedited || pedited->colorappearance.curveMode2) { + Glib::ustring method; - if (!pedited || pedited->colorappearance.curveMode2) { - Glib::ustring method; + switch (colorappearance.curveMode2) { + case (ColorAppearanceParams::TC_MODE_LIGHT): + method = "Lightness"; + break; - switch (colorappearance.curveMode2) { - case (ColorAppearanceParams::TC_MODE_LIGHT): - method = "Lightness"; - break; + case (ColorAppearanceParams::TC_MODE_BRIGHT): + method = "Brightness"; + break; + } - case (ColorAppearanceParams::TC_MODE_BRIGHT): - method = "Brightness"; - break; + keyFile.set_string ("Color appearance", "CurveMode2", method); } - keyFile.set_string ("Color appearance", "CurveMode2", method); - } + if (!pedited || pedited->colorappearance.curveMode3) { + Glib::ustring method; - if (!pedited || pedited->colorappearance.curveMode3) { - Glib::ustring method; + switch (colorappearance.curveMode3) { + case (ColorAppearanceParams::TC_MODE_CHROMA): + method = "Chroma"; + break; - switch (colorappearance.curveMode3) { - case (ColorAppearanceParams::TC_MODE_CHROMA): - method = "Chroma"; - break; + case (ColorAppearanceParams::TC_MODE_SATUR): + method = "Saturation"; + break; - case (ColorAppearanceParams::TC_MODE_SATUR): - method = "Saturation"; - break; + case (ColorAppearanceParams::TC_MODE_COLORF): + method = "Colorfullness"; + break; - case (ColorAppearanceParams::TC_MODE_COLORF): - method = "Colorfullness"; - break; + } + keyFile.set_string ("Color appearance", "CurveMode3", method); } - keyFile.set_string ("Color appearance", "CurveMode3", method); - } + if (!pedited || pedited->colorappearance.curve) { + Glib::ArrayHandle tcurve = colorappearance.curve; + keyFile.set_double_list("Color appearance", "Curve", tcurve); + } - if (!pedited || pedited->colorappearance.curve) { - Glib::ArrayHandle tcurve = colorappearance.curve; - keyFile.set_double_list("Color appearance", "Curve", tcurve); - } + if (!pedited || pedited->colorappearance.curve2) { + Glib::ArrayHandle tcurve = colorappearance.curve2; + keyFile.set_double_list("Color appearance", "Curve2", tcurve); + } - if (!pedited || pedited->colorappearance.curve2) { - Glib::ArrayHandle tcurve = colorappearance.curve2; - keyFile.set_double_list("Color appearance", "Curve2", tcurve); - } - - if (!pedited || pedited->colorappearance.curve3) { - Glib::ArrayHandle tcurve = colorappearance.curve3; - keyFile.set_double_list("Color appearance", "Curve3", tcurve); - } + if (!pedited || pedited->colorappearance.curve3) { + Glib::ArrayHandle tcurve = colorappearance.curve3; + keyFile.set_double_list("Color appearance", "Curve3", tcurve); + } - // save impulseDenoise - if (!pedited || pedited->impulseDenoise.enabled) { - keyFile.set_boolean ("Impulse Denoising", "Enabled", impulseDenoise.enabled); - } + // save impulseDenoise + if (!pedited || pedited->impulseDenoise.enabled) { + keyFile.set_boolean ("Impulse Denoising", "Enabled", impulseDenoise.enabled); + } - if (!pedited || pedited->impulseDenoise.thresh) { - keyFile.set_integer ("Impulse Denoising", "Threshold", impulseDenoise.thresh); - } + if (!pedited || pedited->impulseDenoise.thresh) { + keyFile.set_integer ("Impulse Denoising", "Threshold", impulseDenoise.thresh); + } - // save defringe - if (!pedited || pedited->defringe.enabled) { - keyFile.set_boolean ("Defringing", "Enabled", defringe.enabled); - } + // save defringe + if (!pedited || pedited->defringe.enabled) { + keyFile.set_boolean ("Defringing", "Enabled", defringe.enabled); + } - if (!pedited || pedited->defringe.radius) { - keyFile.set_double ("Defringing", "Radius", defringe.radius); - } + if (!pedited || pedited->defringe.radius) { + keyFile.set_double ("Defringing", "Radius", defringe.radius); + } - if (!pedited || pedited->defringe.threshold) { - keyFile.set_integer ("Defringing", "Threshold", defringe.threshold); - } + if (!pedited || pedited->defringe.threshold) { + keyFile.set_integer ("Defringing", "Threshold", defringe.threshold); + } - if (!pedited || pedited->defringe.huecurve) { - Glib::ArrayHandle huecurve = defringe.huecurve; - keyFile.set_double_list("Defringing", "HueCurve", huecurve); - } + if (!pedited || pedited->defringe.huecurve) { + Glib::ArrayHandle huecurve = defringe.huecurve; + keyFile.set_double_list("Defringing", "HueCurve", huecurve); + } - // save dirpyrDenoise - if (!pedited || pedited->dirpyrDenoise.enabled) { - keyFile.set_boolean ("Directional Pyramid Denoising", "Enabled", dirpyrDenoise.enabled); - } + // save dirpyrDenoise + if (!pedited || pedited->dirpyrDenoise.enabled) { + keyFile.set_boolean ("Directional Pyramid Denoising", "Enabled", dirpyrDenoise.enabled); + } - if (!pedited || pedited->dirpyrDenoise.enhance) { - keyFile.set_boolean ("Directional Pyramid Denoising", "Enhance", dirpyrDenoise.enhance); - } + if (!pedited || pedited->dirpyrDenoise.enhance) { + keyFile.set_boolean ("Directional Pyramid Denoising", "Enhance", dirpyrDenoise.enhance); + } - if (!pedited || pedited->dirpyrDenoise.median) { - keyFile.set_boolean ("Directional Pyramid Denoising", "Median", dirpyrDenoise.median); - } + if (!pedited || pedited->dirpyrDenoise.median) { + keyFile.set_boolean ("Directional Pyramid Denoising", "Median", dirpyrDenoise.median); + } - if (!pedited || pedited->dirpyrDenoise.autochroma) { - keyFile.set_boolean ("Directional Pyramid Denoising", "Auto", dirpyrDenoise.autochroma); - } + if (!pedited || pedited->dirpyrDenoise.autochroma) { + keyFile.set_boolean ("Directional Pyramid Denoising", "Auto", dirpyrDenoise.autochroma); + } // if (!pedited || pedited->dirpyrDenoise.perform) keyFile.set_boolean ("Directional Pyramid Denoising", "Perform", dirpyrDenoise.perform); - if (!pedited || pedited->dirpyrDenoise.luma) { - keyFile.set_double ("Directional Pyramid Denoising", "Luma", dirpyrDenoise.luma); - } - - if (!pedited || pedited->dirpyrDenoise.Ldetail) { - keyFile.set_double ("Directional Pyramid Denoising", "Ldetail", dirpyrDenoise.Ldetail); - } - - if (!pedited || pedited->dirpyrDenoise.chroma) { - keyFile.set_double ("Directional Pyramid Denoising", "Chroma", dirpyrDenoise.chroma); - } - - if (!pedited || pedited->dirpyrDenoise.dmethod) { - keyFile.set_string ("Directional Pyramid Denoising", "Method", dirpyrDenoise.dmethod); - } - - if (!pedited || pedited->dirpyrDenoise.Lmethod) { - keyFile.set_string ("Directional Pyramid Denoising", "LMethod", dirpyrDenoise.Lmethod); - } - - // never save 'auto chroma preview mode' to pp3 - if (!pedited || pedited->dirpyrDenoise.Cmethod) { - if(dirpyrDenoise.Cmethod == "PRE") { - dirpyrDenoise.Cmethod = "MAN"; + if (!pedited || pedited->dirpyrDenoise.luma) { + keyFile.set_double ("Directional Pyramid Denoising", "Luma", dirpyrDenoise.luma); } - keyFile.set_string ("Directional Pyramid Denoising", "CMethod", dirpyrDenoise.Cmethod); - } - - if (!pedited || pedited->dirpyrDenoise.C2method) { - if(dirpyrDenoise.C2method == "PREV") { - dirpyrDenoise.C2method = "MANU"; + if (!pedited || pedited->dirpyrDenoise.Ldetail) { + keyFile.set_double ("Directional Pyramid Denoising", "Ldetail", dirpyrDenoise.Ldetail); } - keyFile.set_string ("Directional Pyramid Denoising", "C2Method", dirpyrDenoise.C2method); - } - - if (!pedited || pedited->dirpyrDenoise.smethod) { - keyFile.set_string ("Directional Pyramid Denoising", "SMethod", dirpyrDenoise.smethod); - } - - if (!pedited || pedited->dirpyrDenoise.medmethod) { - keyFile.set_string ("Directional Pyramid Denoising", "MedMethod", dirpyrDenoise.medmethod); - } - - if (!pedited || pedited->dirpyrDenoise.rgbmethod) { - keyFile.set_string ("Directional Pyramid Denoising", "RGBMethod", dirpyrDenoise.rgbmethod); - } - - if (!pedited || pedited->dirpyrDenoise.methodmed) { - keyFile.set_string ("Directional Pyramid Denoising", "MethodMed", dirpyrDenoise.methodmed); - } - - if (!pedited || pedited->dirpyrDenoise.redchro) { - keyFile.set_double ("Directional Pyramid Denoising", "Redchro", dirpyrDenoise.redchro); - } - - if (!pedited || pedited->dirpyrDenoise.bluechro) { - keyFile.set_double ("Directional Pyramid Denoising", "Bluechro", dirpyrDenoise.bluechro); - } - - if (!pedited || pedited->dirpyrDenoise.gamma) { - keyFile.set_double ("Directional Pyramid Denoising", "Gamma", dirpyrDenoise.gamma); - } - - if (!pedited || pedited->dirpyrDenoise.passes) { - keyFile.set_integer ("Directional Pyramid Denoising", "Passes", dirpyrDenoise.passes); - } - - if (!pedited || pedited->dirpyrDenoise.lcurve) { - Glib::ArrayHandle lcurve = dirpyrDenoise.lcurve; - keyFile.set_double_list("Directional Pyramid Denoising", "LCurve", lcurve); - } - - if (!pedited || pedited->dirpyrDenoise.cccurve) { - Glib::ArrayHandle cccurve = dirpyrDenoise.cccurve; - keyFile.set_double_list("Directional Pyramid Denoising", "CCCurve", cccurve); - } - - //Save epd. - if (!pedited || pedited->epd.enabled) { - keyFile.set_boolean ("EPD", "Enabled", epd.enabled); - } - - if (!pedited || pedited->epd.strength) { - keyFile.set_double ("EPD", "Strength", epd.strength); - } - - if (!pedited || pedited->epd.gamma) { - keyFile.set_double ("EPD", "Gamma", epd.gamma); - } - - if (!pedited || pedited->epd.edgeStopping) { - keyFile.set_double ("EPD", "EdgeStopping", epd.edgeStopping); - } - - if (!pedited || pedited->epd.scale) { - keyFile.set_double ("EPD", "Scale", epd.scale); - } - - if (!pedited || pedited->epd.reweightingIterates) { - keyFile.set_integer ("EPD", "ReweightingIterates", epd.reweightingIterates); - } - - /* - // save lumaDenoise - if (!pedited || pedited->lumaDenoise.enabled) keyFile.set_boolean ("Luminance Denoising", "Enabled", lumaDenoise.enabled); - if (!pedited || pedited->lumaDenoise.radius) keyFile.set_double ("Luminance Denoising", "Radius", lumaDenoise.radius); - if (!pedited || pedited->lumaDenoise.edgetolerance) keyFile.set_integer ("Luminance Denoising", "EdgeTolerance", lumaDenoise.edgetolerance); - */ - - /* - // save colorDenoise - //if (!pedited || pedited->colorDenoise.enabled) keyFile.set_boolean ("Chrominance Denoising", "Enabled", colorDenoise.enabled); - if (!pedited || pedited->colorDenoise.amount) keyFile.set_integer ("Chrominance Denoising", "Amount", colorDenoise.amount); - */ - - // save sh - if (!pedited || pedited->sh.enabled) { - keyFile.set_boolean ("Shadows & Highlights", "Enabled", sh.enabled); - } - - if (!pedited || pedited->sh.hq) { - keyFile.set_boolean ("Shadows & Highlights", "HighQuality", sh.hq); - } - - if (!pedited || pedited->sh.highlights) { - keyFile.set_integer ("Shadows & Highlights", "Highlights", sh.highlights); - } - - if (!pedited || pedited->sh.htonalwidth) { - keyFile.set_integer ("Shadows & Highlights", "HighlightTonalWidth", sh.htonalwidth); - } - - if (!pedited || pedited->sh.shadows) { - keyFile.set_integer ("Shadows & Highlights", "Shadows", sh.shadows); - } - - if (!pedited || pedited->sh.stonalwidth) { - keyFile.set_integer ("Shadows & Highlights", "ShadowTonalWidth", sh.stonalwidth); - } - - if (!pedited || pedited->sh.localcontrast) { - keyFile.set_integer ("Shadows & Highlights", "LocalContrast", sh.localcontrast); - } - - if (!pedited || pedited->sh.radius) { - keyFile.set_integer ("Shadows & Highlights", "Radius", sh.radius); - } - - // save crop - if (!pedited || pedited->crop.enabled) { - keyFile.set_boolean ("Crop", "Enabled", crop.enabled); - } - - if (!pedited || pedited->crop.x) { - keyFile.set_integer ("Crop", "X", crop.x); - } - - if (!pedited || pedited->crop.y) { - keyFile.set_integer ("Crop", "Y", crop.y); - } - - if (!pedited || pedited->crop.w) { - keyFile.set_integer ("Crop", "W", crop.w); - } - - if (!pedited || pedited->crop.h) { - keyFile.set_integer ("Crop", "H", crop.h); - } - - if (!pedited || pedited->crop.fixratio) { - keyFile.set_boolean ("Crop", "FixedRatio", crop.fixratio); - } - - if (!pedited || pedited->crop.ratio) { - keyFile.set_string ("Crop", "Ratio", crop.ratio); - } - - if (!pedited || pedited->crop.orientation) { - keyFile.set_string ("Crop", "Orientation", crop.orientation); - } - - if (!pedited || pedited->crop.guide) { - keyFile.set_string ("Crop", "Guide", crop.guide); - } - - // save coarse - if (!pedited || pedited->coarse.rotate) { - keyFile.set_integer ("Coarse Transformation", "Rotate", coarse.rotate); - } - - if (!pedited || pedited->coarse.hflip) { - keyFile.set_boolean ("Coarse Transformation", "HorizontalFlip", coarse.hflip); - } - - if (!pedited || pedited->coarse.vflip) { - keyFile.set_boolean ("Coarse Transformation", "VerticalFlip", coarse.vflip); - } - - // save commonTrans - if (!pedited || pedited->commonTrans.autofill) { - keyFile.set_boolean ("Common Properties for Transformations", "AutoFill", commonTrans.autofill); - } - - // save rotate - if (!pedited || pedited->rotate.degree) { - keyFile.set_double ("Rotation", "Degree", rotate.degree); - } - - // save distortion - if (!pedited || pedited->distortion.amount) { - keyFile.set_double ("Distortion", "Amount", distortion.amount); - } - - // lens profile - if (!pedited || pedited->lensProf.lcpFile) { - keyFile.set_string ("LensProfile", "LCPFile", relativePathIfInside(fname, fnameAbsolute, lensProf.lcpFile)); - } - - if (!pedited || pedited->lensProf.useDist) { - keyFile.set_boolean ("LensProfile", "UseDistortion", lensProf.useDist); - } - - if (!pedited || pedited->lensProf.useVign) { - keyFile.set_boolean ("LensProfile", "UseVignette", lensProf.useVign); - } - - if (!pedited || pedited->lensProf.useCA) { - keyFile.set_boolean ("LensProfile", "UseCA", lensProf.useCA); - } - - // save perspective correction - if (!pedited || pedited->perspective.horizontal) { - keyFile.set_double ("Perspective", "Horizontal", perspective.horizontal); - } - - if (!pedited || pedited->perspective.vertical) { - keyFile.set_double ("Perspective", "Vertical", perspective.vertical); - } - - // save gradient - if (!pedited || pedited->gradient.enabled) { - keyFile.set_boolean ("Gradient", "Enabled", gradient.enabled); - } - - if (!pedited || pedited->gradient.degree) { - keyFile.set_double ("Gradient", "Degree", gradient.degree); - } - - if (!pedited || pedited->gradient.feather) { - keyFile.set_integer ("Gradient", "Feather", gradient.feather); - } - - if (!pedited || pedited->gradient.strength) { - keyFile.set_double ("Gradient", "Strength", gradient.strength); - } - - if (!pedited || pedited->gradient.centerX) { - keyFile.set_integer ("Gradient", "CenterX", gradient.centerX); - } - - if (!pedited || pedited->gradient.centerY) { - keyFile.set_integer ("Gradient", "CenterY", gradient.centerY); - } - - // save post-crop vignette - if (!pedited || pedited->pcvignette.enabled) { - keyFile.set_boolean ("PCVignette", "Enabled", pcvignette.enabled); - } - - if (!pedited || pedited->pcvignette.strength) { - keyFile.set_double ("PCVignette", "Strength", pcvignette.strength); - } - - if (!pedited || pedited->pcvignette.feather) { - keyFile.set_integer ("PCVignette", "Feather", pcvignette.feather); - } - - if (!pedited || pedited->pcvignette.roundness) { - keyFile.set_integer ("PCVignette", "Roundness", pcvignette.roundness); - } - - // save C/A correction - if (!pedited || pedited->cacorrection.red) { - keyFile.set_double ("CACorrection", "Red", cacorrection.red); - } - - if (!pedited || pedited->cacorrection.blue) { - keyFile.set_double ("CACorrection", "Blue", cacorrection.blue); - } - - // save vignetting correction - if (!pedited || pedited->vignetting.amount) { - keyFile.set_integer ("Vignetting Correction", "Amount", vignetting.amount); - } - - if (!pedited || pedited->vignetting.radius) { - keyFile.set_integer ("Vignetting Correction", "Radius", vignetting.radius); - } - - if (!pedited || pedited->vignetting.strength) { - keyFile.set_integer ("Vignetting Correction", "Strength", vignetting.strength); - } - - if (!pedited || pedited->vignetting.centerX) { - keyFile.set_integer ("Vignetting Correction", "CenterX", vignetting.centerX); - } - - if (!pedited || pedited->vignetting.centerY) { - keyFile.set_integer ("Vignetting Correction", "CenterY", vignetting.centerY); - } - - - if (!pedited || pedited->resize.enabled) { - keyFile.set_boolean ("Resize", "Enabled", resize.enabled); - } - - if (!pedited || pedited->resize.scale) { - keyFile.set_double ("Resize", "Scale", resize.scale); - } - - if (!pedited || pedited->resize.appliesTo) { - keyFile.set_string ("Resize", "AppliesTo", resize.appliesTo); - } - - if (!pedited || pedited->resize.method) { - keyFile.set_string ("Resize", "Method", resize.method); - } - - if (!pedited || pedited->resize.dataspec) { - keyFile.set_integer ("Resize", "DataSpecified", resize.dataspec); - } - - if (!pedited || pedited->resize.width) { - keyFile.set_integer ("Resize", "Width", resize.width); - } - - if (!pedited || pedited->resize.height) { - keyFile.set_integer ("Resize", "Height", resize.height); - } - - if (!pedited || pedited->prsharpening.enabled) { - keyFile.set_boolean ("PostResizeSharpening", "Enabled", prsharpening.enabled); - } - - if (!pedited || pedited->prsharpening.method) { - keyFile.set_string ("PostResizeSharpening", "Method", prsharpening.method); - } - - if (!pedited || pedited->prsharpening.radius) { - keyFile.set_double ("PostResizeSharpening", "Radius", prsharpening.radius); - } - - if (!pedited || pedited->prsharpening.amount) { - keyFile.set_integer ("PostResizeSharpening", "Amount", prsharpening.amount); - } - - if (!pedited || pedited->prsharpening.threshold) { - Glib::ArrayHandle thresh (prsharpening.threshold.value, 4, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("PostResizeSharpening", "Threshold", thresh); - } - - if (!pedited || pedited->prsharpening.edgesonly) { - keyFile.set_boolean ("PostResizeSharpening", "OnlyEdges", prsharpening.edgesonly); - } - - if (!pedited || pedited->prsharpening.edges_radius) { - keyFile.set_double ("PostResizeSharpening", "EdgedetectionRadius", prsharpening.edges_radius); - } - - if (!pedited || pedited->prsharpening.edges_tolerance) { - keyFile.set_integer ("PostResizeSharpening", "EdgeTolerance", prsharpening.edges_tolerance); - } - - if (!pedited || pedited->prsharpening.halocontrol) { - keyFile.set_boolean ("PostResizeSharpening", "HalocontrolEnabled", prsharpening.halocontrol); - } - - if (!pedited || pedited->prsharpening.halocontrol_amount) { - keyFile.set_integer ("PostResizeSharpening", "HalocontrolAmount", prsharpening.halocontrol_amount); - } - - if (!pedited || pedited->prsharpening.deconvradius) { - keyFile.set_double ("PostResizeSharpening", "DeconvRadius", prsharpening.deconvradius); - } - - if (!pedited || pedited->prsharpening.deconvamount) { - keyFile.set_integer ("PostResizeSharpening", "DeconvAmount", prsharpening.deconvamount); - } - - if (!pedited || pedited->prsharpening.deconvdamping) { - keyFile.set_integer ("PostResizeSharpening", "DeconvDamping", prsharpening.deconvdamping); - } - - if (!pedited || pedited->prsharpening.deconviter) { - keyFile.set_integer ("PostResizeSharpening", "DeconvIterations", prsharpening.deconviter); - } - - - // save color management settings - if (!pedited || pedited->icm.input) { - keyFile.set_string ("Color Management", "InputProfile", relativePathIfInside(fname, fnameAbsolute, icm.input)); - } - - if (!pedited || pedited->icm.toneCurve) { - keyFile.set_boolean ("Color Management", "ToneCurve", icm.toneCurve); - } - - if (!pedited || pedited->icm.applyLookTable) { - keyFile.set_boolean ("Color Management", "ApplyLookTable", icm.applyLookTable); - } - - if (!pedited || pedited->icm.applyBaselineExposureOffset) { - keyFile.set_boolean ("Color Management", "ApplyBaselineExposureOffset", icm.applyBaselineExposureOffset); - } - - if (!pedited || pedited->icm.applyHueSatMap) { - keyFile.set_boolean ("Color Management", "ApplyHueSatMap", icm.applyHueSatMap); - } - - if (!pedited || pedited->icm.blendCMSMatrix) { - keyFile.set_boolean ("Color Management", "BlendCMSMatrix", icm.blendCMSMatrix); - } - - if (!pedited || pedited->icm.dcpIlluminant) { - keyFile.set_integer ("Color Management", "DCPIlluminant", icm.dcpIlluminant); - } - - if (!pedited || pedited->icm.working) { - keyFile.set_string ("Color Management", "WorkingProfile", icm.working); - } - - if (!pedited || pedited->icm.output) { - keyFile.set_string ("Color Management", "OutputProfile", icm.output); - } - - if (!pedited || pedited->icm.outputIntent) { - Glib::ustring intent; - - switch (icm.outputIntent) { - default: - case RI_PERCEPTUAL: - intent = "Perceptual"; - break; - - case RI_RELATIVE: - intent = "Relative"; - break; - - case RI_SATURATION: - intent = "Saturation"; - break; - - case RI_ABSOLUTE: - intent = "Absolute"; - break; + if (!pedited || pedited->dirpyrDenoise.chroma) { + keyFile.set_double ("Directional Pyramid Denoising", "Chroma", dirpyrDenoise.chroma); } - keyFile.set_string ("Color Management", "OutputProfileIntent", intent); - } - - if (!pedited || pedited->icm.gamma) { - keyFile.set_string ("Color Management", "Gammafree", icm.gamma); - } - - if (!pedited || pedited->icm.freegamma) { - keyFile.set_boolean ("Color Management", "Freegamma", icm.freegamma); - } - - if (!pedited || pedited->icm.gampos) { - keyFile.set_double ("Color Management", "GammaValue", icm.gampos); - } - - if (!pedited || pedited->icm.slpos) { - keyFile.set_double ("Color Management", "GammaSlope", icm.slpos); - } - - - - // save wavelet parameters - if (!pedited || pedited->wavelet.enabled) { - keyFile.set_boolean ("Wavelet", "Enabled", wavelet.enabled); - } - - if (!pedited || pedited->wavelet.strength) { - keyFile.set_integer ("Wavelet", "Strength", wavelet.strength); - } - - if (!pedited || pedited->wavelet.balance) { - keyFile.set_integer ("Wavelet", "Balance", wavelet.balance); - } - - if (!pedited || pedited->wavelet.iter) { - keyFile.set_integer ("Wavelet", "Iter", wavelet.iter); - } - - if (!pedited || pedited->wavelet.thres) { - keyFile.set_integer ("Wavelet", "MaxLev", wavelet.thres); - } - - if (!pedited || pedited->wavelet.Tilesmethod) { - keyFile.set_string ("Wavelet", "TilesMethod", wavelet.Tilesmethod); - } - - if (!pedited || pedited->wavelet.daubcoeffmethod) { - keyFile.set_string ("Wavelet", "DaubMethod", wavelet.daubcoeffmethod); - } - - if (!pedited || pedited->wavelet.CLmethod) { - keyFile.set_string ("Wavelet", "ChoiceLevMethod", wavelet.CLmethod); - } - - if (!pedited || pedited->wavelet.Backmethod) { - keyFile.set_string ("Wavelet", "BackMethod", wavelet.Backmethod); - } - - if (!pedited || pedited->wavelet.Lmethod) { - keyFile.set_string ("Wavelet", "LevMethod", wavelet.Lmethod); - } - - if (!pedited || pedited->wavelet.Dirmethod) { - keyFile.set_string ("Wavelet", "DirMethod", wavelet.Dirmethod); - } - - if (!pedited || pedited->wavelet.greenhigh) { - keyFile.set_integer ("Wavelet", "CBgreenhigh", wavelet.greenhigh); - } - - if (!pedited || pedited->wavelet.greenmed) { - keyFile.set_integer ("Wavelet", "CBgreenmed", wavelet.greenmed); - } - - if (!pedited || pedited->wavelet.greenlow) { - keyFile.set_integer ("Wavelet", "CBgreenlow", wavelet.greenlow); - } - - if (!pedited || pedited->wavelet.bluehigh) { - keyFile.set_integer ("Wavelet", "CBbluehigh", wavelet.bluehigh); - } - - if (!pedited || pedited->wavelet.bluemed) { - keyFile.set_integer ("Wavelet", "CBbluemed", wavelet.bluemed); - } - - if (!pedited || pedited->wavelet.bluelow) { - keyFile.set_integer ("Wavelet", "CBbluelow", wavelet.bluelow); - } - - if (!pedited || pedited->wavelet.expcontrast) { - keyFile.set_boolean ("Wavelet", "Expcontrast", wavelet.expcontrast); - } - - if (!pedited || pedited->wavelet.expchroma) { - keyFile.set_boolean ("Wavelet", "Expchroma", wavelet.expchroma); - } - - if (!pedited || pedited->wavelet.expedge) { - keyFile.set_boolean ("Wavelet", "Expedge", wavelet.expedge); - } - - if (!pedited || pedited->wavelet.expresid) { - keyFile.set_boolean ("Wavelet", "Expresid", wavelet.expresid); - } - - if (!pedited || pedited->wavelet.expfinal) { - keyFile.set_boolean ("Wavelet", "Expfinal", wavelet.expfinal); - } - - if (!pedited || pedited->wavelet.exptoning) { - keyFile.set_boolean ("Wavelet", "Exptoning", wavelet.exptoning); - } - - if (!pedited || pedited->wavelet.expnoise) { - keyFile.set_boolean ("Wavelet", "Expnoise", wavelet.expnoise); - } - - for(int i = 0; i < 9; i++) { - std::stringstream ss; - ss << "Contrast" << (i + 1); - - if (!pedited || pedited->wavelet.c[i]) { - keyFile.set_integer("Wavelet", ss.str(), wavelet.c[i]); + if (!pedited || pedited->dirpyrDenoise.dmethod) { + keyFile.set_string ("Directional Pyramid Denoising", "Method", dirpyrDenoise.dmethod); } - } - for(int i = 0; i < 9; i++) { - std::stringstream ss; - ss << "Chroma" << (i + 1); - - if (!pedited || pedited->wavelet.ch[i]) { - keyFile.set_integer("Wavelet", ss.str(), wavelet.ch[i]); + if (!pedited || pedited->dirpyrDenoise.Lmethod) { + keyFile.set_string ("Directional Pyramid Denoising", "LMethod", dirpyrDenoise.Lmethod); } - } - if (!pedited || pedited->wavelet.sup) { - keyFile.set_integer ("Wavelet", "ContExtra", wavelet.sup); - } + // never save 'auto chroma preview mode' to pp3 + if (!pedited || pedited->dirpyrDenoise.Cmethod) { + if(dirpyrDenoise.Cmethod == "PRE") { + dirpyrDenoise.Cmethod = "MAN"; + } - if (!pedited || pedited->wavelet.HSmethod) { - keyFile.set_string ("Wavelet", "HSMethod", wavelet.HSmethod); - } + keyFile.set_string ("Directional Pyramid Denoising", "CMethod", dirpyrDenoise.Cmethod); + } - if (!pedited || pedited->wavelet.hllev) { - Glib::ArrayHandle thresh (wavelet.hllev.value, 4, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Wavelet", "HLRange", thresh); - } + if (!pedited || pedited->dirpyrDenoise.C2method) { + if(dirpyrDenoise.C2method == "PREV") { + dirpyrDenoise.C2method = "MANU"; + } - if (!pedited || pedited->wavelet.bllev) { - Glib::ArrayHandle thresh (wavelet.bllev.value, 4, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Wavelet", "SHRange", thresh); - } + keyFile.set_string ("Directional Pyramid Denoising", "C2Method", dirpyrDenoise.C2method); + } - if (!pedited || pedited->wavelet.edgcont) { - Glib::ArrayHandle thresh (wavelet.edgcont.value, 4, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Wavelet", "Edgcont", thresh); - } + if (!pedited || pedited->dirpyrDenoise.smethod) { + keyFile.set_string ("Directional Pyramid Denoising", "SMethod", dirpyrDenoise.smethod); + } - if (!pedited || pedited->wavelet.level0noise) { - Glib::ArrayHandle thresh (wavelet.level0noise.value, 2, Glib::OWNERSHIP_NONE); - keyFile.set_double_list("Wavelet", "Level0noise", thresh); - } + if (!pedited || pedited->dirpyrDenoise.medmethod) { + keyFile.set_string ("Directional Pyramid Denoising", "MedMethod", dirpyrDenoise.medmethod); + } - if (!pedited || pedited->wavelet.level1noise) { - Glib::ArrayHandle thresh (wavelet.level1noise.value, 2, Glib::OWNERSHIP_NONE); - keyFile.set_double_list("Wavelet", "Level1noise", thresh); - } + if (!pedited || pedited->dirpyrDenoise.rgbmethod) { + keyFile.set_string ("Directional Pyramid Denoising", "RGBMethod", dirpyrDenoise.rgbmethod); + } - if (!pedited || pedited->wavelet.level2noise) { - Glib::ArrayHandle thresh (wavelet.level2noise.value, 2, Glib::OWNERSHIP_NONE); - keyFile.set_double_list("Wavelet", "Level2noise", thresh); - } + if (!pedited || pedited->dirpyrDenoise.methodmed) { + keyFile.set_string ("Directional Pyramid Denoising", "MethodMed", dirpyrDenoise.methodmed); + } - if (!pedited || pedited->wavelet.level3noise) { - Glib::ArrayHandle thresh (wavelet.level3noise.value, 2, Glib::OWNERSHIP_NONE); - keyFile.set_double_list("Wavelet", "Level3noise", thresh); - } + if (!pedited || pedited->dirpyrDenoise.redchro) { + keyFile.set_double ("Directional Pyramid Denoising", "Redchro", dirpyrDenoise.redchro); + } + + if (!pedited || pedited->dirpyrDenoise.bluechro) { + keyFile.set_double ("Directional Pyramid Denoising", "Bluechro", dirpyrDenoise.bluechro); + } + + if (!pedited || pedited->dirpyrDenoise.gamma) { + keyFile.set_double ("Directional Pyramid Denoising", "Gamma", dirpyrDenoise.gamma); + } + + if (!pedited || pedited->dirpyrDenoise.passes) { + keyFile.set_integer ("Directional Pyramid Denoising", "Passes", dirpyrDenoise.passes); + } + + if (!pedited || pedited->dirpyrDenoise.lcurve) { + Glib::ArrayHandle lcurve = dirpyrDenoise.lcurve; + keyFile.set_double_list("Directional Pyramid Denoising", "LCurve", lcurve); + } + + if (!pedited || pedited->dirpyrDenoise.cccurve) { + Glib::ArrayHandle cccurve = dirpyrDenoise.cccurve; + keyFile.set_double_list("Directional Pyramid Denoising", "CCCurve", cccurve); + } + + //Save epd. + if (!pedited || pedited->epd.enabled) { + keyFile.set_boolean ("EPD", "Enabled", epd.enabled); + } + + if (!pedited || pedited->epd.strength) { + keyFile.set_double ("EPD", "Strength", epd.strength); + } + + if (!pedited || pedited->epd.gamma) { + keyFile.set_double ("EPD", "Gamma", epd.gamma); + } + + if (!pedited || pedited->epd.edgeStopping) { + keyFile.set_double ("EPD", "EdgeStopping", epd.edgeStopping); + } + + if (!pedited || pedited->epd.scale) { + keyFile.set_double ("EPD", "Scale", epd.scale); + } + + if (!pedited || pedited->epd.reweightingIterates) { + keyFile.set_integer ("EPD", "ReweightingIterates", epd.reweightingIterates); + } + + /* + // save lumaDenoise + if (!pedited || pedited->lumaDenoise.enabled) keyFile.set_boolean ("Luminance Denoising", "Enabled", lumaDenoise.enabled); + if (!pedited || pedited->lumaDenoise.radius) keyFile.set_double ("Luminance Denoising", "Radius", lumaDenoise.radius); + if (!pedited || pedited->lumaDenoise.edgetolerance) keyFile.set_integer ("Luminance Denoising", "EdgeTolerance", lumaDenoise.edgetolerance); + */ + + /* + // save colorDenoise + //if (!pedited || pedited->colorDenoise.enabled) keyFile.set_boolean ("Chrominance Denoising", "Enabled", colorDenoise.enabled); + if (!pedited || pedited->colorDenoise.amount) keyFile.set_integer ("Chrominance Denoising", "Amount", colorDenoise.amount); + */ + + // save sh + if (!pedited || pedited->sh.enabled) { + keyFile.set_boolean ("Shadows & Highlights", "Enabled", sh.enabled); + } + + if (!pedited || pedited->sh.hq) { + keyFile.set_boolean ("Shadows & Highlights", "HighQuality", sh.hq); + } + + if (!pedited || pedited->sh.highlights) { + keyFile.set_integer ("Shadows & Highlights", "Highlights", sh.highlights); + } + + if (!pedited || pedited->sh.htonalwidth) { + keyFile.set_integer ("Shadows & Highlights", "HighlightTonalWidth", sh.htonalwidth); + } + + if (!pedited || pedited->sh.shadows) { + keyFile.set_integer ("Shadows & Highlights", "Shadows", sh.shadows); + } + + if (!pedited || pedited->sh.stonalwidth) { + keyFile.set_integer ("Shadows & Highlights", "ShadowTonalWidth", sh.stonalwidth); + } + + if (!pedited || pedited->sh.localcontrast) { + keyFile.set_integer ("Shadows & Highlights", "LocalContrast", sh.localcontrast); + } + + if (!pedited || pedited->sh.radius) { + keyFile.set_integer ("Shadows & Highlights", "Radius", sh.radius); + } + + // save crop + if (!pedited || pedited->crop.enabled) { + keyFile.set_boolean ("Crop", "Enabled", crop.enabled); + } + + if (!pedited || pedited->crop.x) { + keyFile.set_integer ("Crop", "X", crop.x); + } + + if (!pedited || pedited->crop.y) { + keyFile.set_integer ("Crop", "Y", crop.y); + } + + if (!pedited || pedited->crop.w) { + keyFile.set_integer ("Crop", "W", crop.w); + } + + if (!pedited || pedited->crop.h) { + keyFile.set_integer ("Crop", "H", crop.h); + } + + if (!pedited || pedited->crop.fixratio) { + keyFile.set_boolean ("Crop", "FixedRatio", crop.fixratio); + } + + if (!pedited || pedited->crop.ratio) { + keyFile.set_string ("Crop", "Ratio", crop.ratio); + } + + if (!pedited || pedited->crop.orientation) { + keyFile.set_string ("Crop", "Orientation", crop.orientation); + } + + if (!pedited || pedited->crop.guide) { + keyFile.set_string ("Crop", "Guide", crop.guide); + } + + // save coarse + if (!pedited || pedited->coarse.rotate) { + keyFile.set_integer ("Coarse Transformation", "Rotate", coarse.rotate); + } + + if (!pedited || pedited->coarse.hflip) { + keyFile.set_boolean ("Coarse Transformation", "HorizontalFlip", coarse.hflip); + } + + if (!pedited || pedited->coarse.vflip) { + keyFile.set_boolean ("Coarse Transformation", "VerticalFlip", coarse.vflip); + } + + // save commonTrans + if (!pedited || pedited->commonTrans.autofill) { + keyFile.set_boolean ("Common Properties for Transformations", "AutoFill", commonTrans.autofill); + } + + // save rotate + if (!pedited || pedited->rotate.degree) { + keyFile.set_double ("Rotation", "Degree", rotate.degree); + } + + // save distortion + if (!pedited || pedited->distortion.amount) { + keyFile.set_double ("Distortion", "Amount", distortion.amount); + } + + // lens profile + if (!pedited || pedited->lensProf.lcpFile) { + keyFile.set_string ("LensProfile", "LCPFile", relativePathIfInside(fname, fnameAbsolute, lensProf.lcpFile)); + } + + if (!pedited || pedited->lensProf.useDist) { + keyFile.set_boolean ("LensProfile", "UseDistortion", lensProf.useDist); + } + + if (!pedited || pedited->lensProf.useVign) { + keyFile.set_boolean ("LensProfile", "UseVignette", lensProf.useVign); + } + + if (!pedited || pedited->lensProf.useCA) { + keyFile.set_boolean ("LensProfile", "UseCA", lensProf.useCA); + } + + // save perspective correction + if (!pedited || pedited->perspective.horizontal) { + keyFile.set_double ("Perspective", "Horizontal", perspective.horizontal); + } + + if (!pedited || pedited->perspective.vertical) { + keyFile.set_double ("Perspective", "Vertical", perspective.vertical); + } + + // save gradient + if (!pedited || pedited->gradient.enabled) { + keyFile.set_boolean ("Gradient", "Enabled", gradient.enabled); + } + + if (!pedited || pedited->gradient.degree) { + keyFile.set_double ("Gradient", "Degree", gradient.degree); + } + + if (!pedited || pedited->gradient.feather) { + keyFile.set_integer ("Gradient", "Feather", gradient.feather); + } + + if (!pedited || pedited->gradient.strength) { + keyFile.set_double ("Gradient", "Strength", gradient.strength); + } + + if (!pedited || pedited->gradient.centerX) { + keyFile.set_integer ("Gradient", "CenterX", gradient.centerX); + } + + if (!pedited || pedited->gradient.centerY) { + keyFile.set_integer ("Gradient", "CenterY", gradient.centerY); + } + + // save post-crop vignette + if (!pedited || pedited->pcvignette.enabled) { + keyFile.set_boolean ("PCVignette", "Enabled", pcvignette.enabled); + } + + if (!pedited || pedited->pcvignette.strength) { + keyFile.set_double ("PCVignette", "Strength", pcvignette.strength); + } + + if (!pedited || pedited->pcvignette.feather) { + keyFile.set_integer ("PCVignette", "Feather", pcvignette.feather); + } + + if (!pedited || pedited->pcvignette.roundness) { + keyFile.set_integer ("PCVignette", "Roundness", pcvignette.roundness); + } + + // save C/A correction + if (!pedited || pedited->cacorrection.red) { + keyFile.set_double ("CACorrection", "Red", cacorrection.red); + } + + if (!pedited || pedited->cacorrection.blue) { + keyFile.set_double ("CACorrection", "Blue", cacorrection.blue); + } + + // save vignetting correction + if (!pedited || pedited->vignetting.amount) { + keyFile.set_integer ("Vignetting Correction", "Amount", vignetting.amount); + } + + if (!pedited || pedited->vignetting.radius) { + keyFile.set_integer ("Vignetting Correction", "Radius", vignetting.radius); + } + + if (!pedited || pedited->vignetting.strength) { + keyFile.set_integer ("Vignetting Correction", "Strength", vignetting.strength); + } + + if (!pedited || pedited->vignetting.centerX) { + keyFile.set_integer ("Vignetting Correction", "CenterX", vignetting.centerX); + } + + if (!pedited || pedited->vignetting.centerY) { + keyFile.set_integer ("Vignetting Correction", "CenterY", vignetting.centerY); + } - if (!pedited || pedited->wavelet.threshold) { - keyFile.set_integer ("Wavelet", "ThresholdHighlight", wavelet.threshold); - } + if (!pedited || pedited->resize.enabled) { + keyFile.set_boolean ("Resize", "Enabled", resize.enabled); + } - if (!pedited || pedited->wavelet.threshold2) { - keyFile.set_integer ("Wavelet", "ThresholdShadow", wavelet.threshold2); - } + if (!pedited || pedited->resize.scale) { + keyFile.set_double ("Resize", "Scale", resize.scale); + } - if (!pedited || pedited->wavelet.edgedetect) { - keyFile.set_integer ("Wavelet", "Edgedetect", wavelet.edgedetect); - } + if (!pedited || pedited->resize.appliesTo) { + keyFile.set_string ("Resize", "AppliesTo", resize.appliesTo); + } - if (!pedited || pedited->wavelet.edgedetectthr) { - keyFile.set_integer ("Wavelet", "Edgedetectthr", wavelet.edgedetectthr); - } + if (!pedited || pedited->resize.method) { + keyFile.set_string ("Resize", "Method", resize.method); + } - if (!pedited || pedited->wavelet.edgedetectthr2) { - keyFile.set_integer ("Wavelet", "EdgedetectthrHi", wavelet.edgedetectthr2); - } + if (!pedited || pedited->resize.dataspec) { + keyFile.set_integer ("Resize", "DataSpecified", resize.dataspec); + } - if (!pedited || pedited->wavelet.edgesensi) { - keyFile.set_integer ("Wavelet", "Edgesensi", wavelet.edgesensi); - } + if (!pedited || pedited->resize.width) { + keyFile.set_integer ("Resize", "Width", resize.width); + } - if (!pedited || pedited->wavelet.edgeampli) { - keyFile.set_integer ("Wavelet", "Edgeampli", wavelet.edgeampli); - } + if (!pedited || pedited->resize.height) { + keyFile.set_integer ("Resize", "Height", resize.height); + } - if (!pedited || pedited->wavelet.chroma) { - keyFile.set_integer ("Wavelet", "ThresholdChroma", wavelet.chroma); - } + if (!pedited || pedited->prsharpening.enabled) { + keyFile.set_boolean ("PostResizeSharpening", "Enabled", prsharpening.enabled); + } - if (!pedited || pedited->wavelet.CHmethod) { - keyFile.set_string ("Wavelet", "CHromaMethod", wavelet.CHmethod); - } + if (!pedited || pedited->prsharpening.method) { + keyFile.set_string ("PostResizeSharpening", "Method", prsharpening.method); + } - if (!pedited || pedited->wavelet.Medgreinf) { - keyFile.set_string ("Wavelet", "Medgreinf", wavelet.Medgreinf); - } + if (!pedited || pedited->prsharpening.radius) { + keyFile.set_double ("PostResizeSharpening", "Radius", prsharpening.radius); + } - if (!pedited || pedited->wavelet.CHSLmethod) { - keyFile.set_string ("Wavelet", "CHSLromaMethod", wavelet.CHSLmethod); - } + if (!pedited || pedited->prsharpening.amount) { + keyFile.set_integer ("PostResizeSharpening", "Amount", prsharpening.amount); + } - if (!pedited || pedited->wavelet.EDmethod) { - keyFile.set_string ("Wavelet", "EDMethod", wavelet.EDmethod); - } + if (!pedited || pedited->prsharpening.threshold) { + Glib::ArrayHandle thresh (prsharpening.threshold.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("PostResizeSharpening", "Threshold", thresh); + } - if (!pedited || pedited->wavelet.NPmethod) { - keyFile.set_string ("Wavelet", "NPMethod", wavelet.NPmethod); - } + if (!pedited || pedited->prsharpening.edgesonly) { + keyFile.set_boolean ("PostResizeSharpening", "OnlyEdges", prsharpening.edgesonly); + } - if (!pedited || pedited->wavelet.BAmethod) { - keyFile.set_string ("Wavelet", "BAMethod", wavelet.BAmethod); - } + if (!pedited || pedited->prsharpening.edges_radius) { + keyFile.set_double ("PostResizeSharpening", "EdgedetectionRadius", prsharpening.edges_radius); + } - if (!pedited || pedited->wavelet.TMmethod) { - keyFile.set_string ("Wavelet", "TMMethod", wavelet.TMmethod); - } + if (!pedited || pedited->prsharpening.edges_tolerance) { + keyFile.set_integer ("PostResizeSharpening", "EdgeTolerance", prsharpening.edges_tolerance); + } - if (!pedited || pedited->wavelet.chro) { - keyFile.set_integer ("Wavelet", "ChromaLink", wavelet.chro); - } + if (!pedited || pedited->prsharpening.halocontrol) { + keyFile.set_boolean ("PostResizeSharpening", "HalocontrolEnabled", prsharpening.halocontrol); + } - if (!pedited || pedited->wavelet.ccwcurve) { - Glib::ArrayHandle ccwcurve = wavelet.ccwcurve; - keyFile.set_double_list("Wavelet", "ContrastCurve", ccwcurve); - } + if (!pedited || pedited->prsharpening.halocontrol_amount) { + keyFile.set_integer ("PostResizeSharpening", "HalocontrolAmount", prsharpening.halocontrol_amount); + } - if (!pedited || pedited->wavelet.pastlev) { - Glib::ArrayHandle thresh (wavelet.pastlev.value, 4, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Wavelet", "Pastlev", thresh); - } + if (!pedited || pedited->prsharpening.deconvradius) { + keyFile.set_double ("PostResizeSharpening", "DeconvRadius", prsharpening.deconvradius); + } - if (!pedited || pedited->wavelet.satlev) { - Glib::ArrayHandle thresh (wavelet.satlev.value, 4, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Wavelet", "Satlev", thresh); - } + if (!pedited || pedited->prsharpening.deconvamount) { + keyFile.set_integer ("PostResizeSharpening", "DeconvAmount", prsharpening.deconvamount); + } - if (!pedited || pedited->wavelet.opacityCurveRG) { - Glib::ArrayHandle curve = wavelet.opacityCurveRG; - keyFile.set_double_list("Wavelet", "OpacityCurveRG", curve); - } + if (!pedited || pedited->prsharpening.deconvdamping) { + keyFile.set_integer ("PostResizeSharpening", "DeconvDamping", prsharpening.deconvdamping); + } - if (!pedited || pedited->wavelet.opacityCurveBY) { - Glib::ArrayHandle curve = wavelet.opacityCurveBY; - keyFile.set_double_list("Wavelet", "OpacityCurveBY", curve); - } - - if (!pedited || pedited->wavelet.opacityCurveW) { - Glib::ArrayHandle curve = wavelet.opacityCurveW; - keyFile.set_double_list("Wavelet", "OpacityCurveW", curve); - } - - if (!pedited || pedited->wavelet.opacityCurveWL) { - Glib::ArrayHandle curve = wavelet.opacityCurveWL; - keyFile.set_double_list("Wavelet", "OpacityCurveWL", curve); - } - - if (!pedited || pedited->wavelet.hhcurve) { - Glib::ArrayHandle curve = wavelet.hhcurve; - keyFile.set_double_list("Wavelet", "HHcurve", curve); - } - - if (!pedited || pedited->wavelet.Chcurve) { - Glib::ArrayHandle curve = wavelet.Chcurve; - keyFile.set_double_list("Wavelet", "CHcurve", curve); - } - - if (!pedited || pedited->wavelet.wavclCurve) { - Glib::ArrayHandle wavclCurve = wavelet.wavclCurve; - keyFile.set_double_list("Wavelet", "WavclCurve", wavclCurve); - } + if (!pedited || pedited->prsharpening.deconviter) { + keyFile.set_integer ("PostResizeSharpening", "DeconvIterations", prsharpening.deconviter); + } - if (!pedited || pedited->wavelet.median) { - keyFile.set_boolean ("Wavelet", "Median", wavelet.median); - } + // save color management settings + if (!pedited || pedited->icm.input) { + keyFile.set_string ("Color Management", "InputProfile", relativePathIfInside(fname, fnameAbsolute, icm.input)); + } - if (!pedited || pedited->wavelet.medianlev) { - keyFile.set_boolean ("Wavelet", "Medianlev", wavelet.medianlev); - } + if (!pedited || pedited->icm.toneCurve) { + keyFile.set_boolean ("Color Management", "ToneCurve", icm.toneCurve); + } - if (!pedited || pedited->wavelet.linkedg) { - keyFile.set_boolean ("Wavelet", "Linkedg", wavelet.linkedg); - } + if (!pedited || pedited->icm.applyLookTable) { + keyFile.set_boolean ("Color Management", "ApplyLookTable", icm.applyLookTable); + } - if (!pedited || pedited->wavelet.cbenab) { - keyFile.set_boolean ("Wavelet", "CBenab", wavelet.cbenab); - } + if (!pedited || pedited->icm.applyBaselineExposureOffset) { + keyFile.set_boolean ("Color Management", "ApplyBaselineExposureOffset", icm.applyBaselineExposureOffset); + } - if (!pedited || pedited->wavelet.lipst) { - keyFile.set_boolean ("Wavelet", "Lipst", wavelet.lipst); - } + if (!pedited || pedited->icm.applyHueSatMap) { + keyFile.set_boolean ("Color Management", "ApplyHueSatMap", icm.applyHueSatMap); + } + + if (!pedited || pedited->icm.blendCMSMatrix) { + keyFile.set_boolean ("Color Management", "BlendCMSMatrix", icm.blendCMSMatrix); + } + + if (!pedited || pedited->icm.dcpIlluminant) { + keyFile.set_integer ("Color Management", "DCPIlluminant", icm.dcpIlluminant); + } + + if (!pedited || pedited->icm.working) { + keyFile.set_string ("Color Management", "WorkingProfile", icm.working); + } + + if (!pedited || pedited->icm.output) { + keyFile.set_string ("Color Management", "OutputProfile", icm.output); + } + + if (!pedited || pedited->icm.outputIntent) { + Glib::ustring intent; + + switch (icm.outputIntent) { + default: + case RI_PERCEPTUAL: + intent = "Perceptual"; + break; + + case RI_RELATIVE: + intent = "Relative"; + break; + + case RI_SATURATION: + intent = "Saturation"; + break; + + case RI_ABSOLUTE: + intent = "Absolute"; + break; + } + + keyFile.set_string ("Color Management", "OutputProfileIntent", intent); + } + + if (!pedited || pedited->icm.gamma) { + keyFile.set_string ("Color Management", "Gammafree", icm.gamma); + } + + if (!pedited || pedited->icm.freegamma) { + keyFile.set_boolean ("Color Management", "Freegamma", icm.freegamma); + } + + if (!pedited || pedited->icm.gampos) { + keyFile.set_double ("Color Management", "GammaValue", icm.gampos); + } + + if (!pedited || pedited->icm.slpos) { + keyFile.set_double ("Color Management", "GammaSlope", icm.slpos); + } + + + + // save wavelet parameters + if (!pedited || pedited->wavelet.enabled) { + keyFile.set_boolean ("Wavelet", "Enabled", wavelet.enabled); + } + + if (!pedited || pedited->wavelet.strength) { + keyFile.set_integer ("Wavelet", "Strength", wavelet.strength); + } + + if (!pedited || pedited->wavelet.balance) { + keyFile.set_integer ("Wavelet", "Balance", wavelet.balance); + } + + if (!pedited || pedited->wavelet.iter) { + keyFile.set_integer ("Wavelet", "Iter", wavelet.iter); + } + + if (!pedited || pedited->wavelet.thres) { + keyFile.set_integer ("Wavelet", "MaxLev", wavelet.thres); + } + + if (!pedited || pedited->wavelet.Tilesmethod) { + keyFile.set_string ("Wavelet", "TilesMethod", wavelet.Tilesmethod); + } + + if (!pedited || pedited->wavelet.daubcoeffmethod) { + keyFile.set_string ("Wavelet", "DaubMethod", wavelet.daubcoeffmethod); + } + + if (!pedited || pedited->wavelet.CLmethod) { + keyFile.set_string ("Wavelet", "ChoiceLevMethod", wavelet.CLmethod); + } + + if (!pedited || pedited->wavelet.Backmethod) { + keyFile.set_string ("Wavelet", "BackMethod", wavelet.Backmethod); + } + + if (!pedited || pedited->wavelet.Lmethod) { + keyFile.set_string ("Wavelet", "LevMethod", wavelet.Lmethod); + } + + if (!pedited || pedited->wavelet.Dirmethod) { + keyFile.set_string ("Wavelet", "DirMethod", wavelet.Dirmethod); + } + + if (!pedited || pedited->wavelet.greenhigh) { + keyFile.set_integer ("Wavelet", "CBgreenhigh", wavelet.greenhigh); + } + + if (!pedited || pedited->wavelet.greenmed) { + keyFile.set_integer ("Wavelet", "CBgreenmed", wavelet.greenmed); + } + + if (!pedited || pedited->wavelet.greenlow) { + keyFile.set_integer ("Wavelet", "CBgreenlow", wavelet.greenlow); + } + + if (!pedited || pedited->wavelet.bluehigh) { + keyFile.set_integer ("Wavelet", "CBbluehigh", wavelet.bluehigh); + } + + if (!pedited || pedited->wavelet.bluemed) { + keyFile.set_integer ("Wavelet", "CBbluemed", wavelet.bluemed); + } + + if (!pedited || pedited->wavelet.bluelow) { + keyFile.set_integer ("Wavelet", "CBbluelow", wavelet.bluelow); + } + + if (!pedited || pedited->wavelet.expcontrast) { + keyFile.set_boolean ("Wavelet", "Expcontrast", wavelet.expcontrast); + } + + if (!pedited || pedited->wavelet.expchroma) { + keyFile.set_boolean ("Wavelet", "Expchroma", wavelet.expchroma); + } + + if (!pedited || pedited->wavelet.expedge) { + keyFile.set_boolean ("Wavelet", "Expedge", wavelet.expedge); + } + + if (!pedited || pedited->wavelet.expresid) { + keyFile.set_boolean ("Wavelet", "Expresid", wavelet.expresid); + } + + if (!pedited || pedited->wavelet.expfinal) { + keyFile.set_boolean ("Wavelet", "Expfinal", wavelet.expfinal); + } + + if (!pedited || pedited->wavelet.exptoning) { + keyFile.set_boolean ("Wavelet", "Exptoning", wavelet.exptoning); + } + + if (!pedited || pedited->wavelet.expnoise) { + keyFile.set_boolean ("Wavelet", "Expnoise", wavelet.expnoise); + } + + for(int i = 0; i < 9; i++) { + std::stringstream ss; + ss << "Contrast" << (i + 1); + + if (!pedited || pedited->wavelet.c[i]) { + keyFile.set_integer("Wavelet", ss.str(), wavelet.c[i]); + } + } + + for(int i = 0; i < 9; i++) { + std::stringstream ss; + ss << "Chroma" << (i + 1); + + if (!pedited || pedited->wavelet.ch[i]) { + keyFile.set_integer("Wavelet", ss.str(), wavelet.ch[i]); + } + } + + if (!pedited || pedited->wavelet.sup) { + keyFile.set_integer ("Wavelet", "ContExtra", wavelet.sup); + } + + if (!pedited || pedited->wavelet.HSmethod) { + keyFile.set_string ("Wavelet", "HSMethod", wavelet.HSmethod); + } + + if (!pedited || pedited->wavelet.hllev) { + Glib::ArrayHandle thresh (wavelet.hllev.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "HLRange", thresh); + } + + if (!pedited || pedited->wavelet.bllev) { + Glib::ArrayHandle thresh (wavelet.bllev.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "SHRange", thresh); + } + + if (!pedited || pedited->wavelet.edgcont) { + Glib::ArrayHandle thresh (wavelet.edgcont.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "Edgcont", thresh); + } + + if (!pedited || pedited->wavelet.level0noise) { + Glib::ArrayHandle thresh (wavelet.level0noise.value, 2, Glib::OWNERSHIP_NONE); + keyFile.set_double_list("Wavelet", "Level0noise", thresh); + } + + if (!pedited || pedited->wavelet.level1noise) { + Glib::ArrayHandle thresh (wavelet.level1noise.value, 2, Glib::OWNERSHIP_NONE); + keyFile.set_double_list("Wavelet", "Level1noise", thresh); + } + + if (!pedited || pedited->wavelet.level2noise) { + Glib::ArrayHandle thresh (wavelet.level2noise.value, 2, Glib::OWNERSHIP_NONE); + keyFile.set_double_list("Wavelet", "Level2noise", thresh); + } + + if (!pedited || pedited->wavelet.level3noise) { + Glib::ArrayHandle thresh (wavelet.level3noise.value, 2, Glib::OWNERSHIP_NONE); + keyFile.set_double_list("Wavelet", "Level3noise", thresh); + } + + + if (!pedited || pedited->wavelet.threshold) { + keyFile.set_integer ("Wavelet", "ThresholdHighlight", wavelet.threshold); + } + + if (!pedited || pedited->wavelet.threshold2) { + keyFile.set_integer ("Wavelet", "ThresholdShadow", wavelet.threshold2); + } + + if (!pedited || pedited->wavelet.edgedetect) { + keyFile.set_integer ("Wavelet", "Edgedetect", wavelet.edgedetect); + } + + if (!pedited || pedited->wavelet.edgedetectthr) { + keyFile.set_integer ("Wavelet", "Edgedetectthr", wavelet.edgedetectthr); + } + + if (!pedited || pedited->wavelet.edgedetectthr2) { + keyFile.set_integer ("Wavelet", "EdgedetectthrHi", wavelet.edgedetectthr2); + } + + if (!pedited || pedited->wavelet.edgesensi) { + keyFile.set_integer ("Wavelet", "Edgesensi", wavelet.edgesensi); + } + + if (!pedited || pedited->wavelet.edgeampli) { + keyFile.set_integer ("Wavelet", "Edgeampli", wavelet.edgeampli); + } + + if (!pedited || pedited->wavelet.chroma) { + keyFile.set_integer ("Wavelet", "ThresholdChroma", wavelet.chroma); + } + + if (!pedited || pedited->wavelet.CHmethod) { + keyFile.set_string ("Wavelet", "CHromaMethod", wavelet.CHmethod); + } + + if (!pedited || pedited->wavelet.Medgreinf) { + keyFile.set_string ("Wavelet", "Medgreinf", wavelet.Medgreinf); + } + + if (!pedited || pedited->wavelet.CHSLmethod) { + keyFile.set_string ("Wavelet", "CHSLromaMethod", wavelet.CHSLmethod); + } + + if (!pedited || pedited->wavelet.EDmethod) { + keyFile.set_string ("Wavelet", "EDMethod", wavelet.EDmethod); + } + + if (!pedited || pedited->wavelet.NPmethod) { + keyFile.set_string ("Wavelet", "NPMethod", wavelet.NPmethod); + } + + if (!pedited || pedited->wavelet.BAmethod) { + keyFile.set_string ("Wavelet", "BAMethod", wavelet.BAmethod); + } + + if (!pedited || pedited->wavelet.TMmethod) { + keyFile.set_string ("Wavelet", "TMMethod", wavelet.TMmethod); + } + + if (!pedited || pedited->wavelet.chro) { + keyFile.set_integer ("Wavelet", "ChromaLink", wavelet.chro); + } + + if (!pedited || pedited->wavelet.ccwcurve) { + Glib::ArrayHandle ccwcurve = wavelet.ccwcurve; + keyFile.set_double_list("Wavelet", "ContrastCurve", ccwcurve); + } + + if (!pedited || pedited->wavelet.pastlev) { + Glib::ArrayHandle thresh (wavelet.pastlev.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "Pastlev", thresh); + } + + if (!pedited || pedited->wavelet.satlev) { + Glib::ArrayHandle thresh (wavelet.satlev.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "Satlev", thresh); + } + + if (!pedited || pedited->wavelet.opacityCurveRG) { + Glib::ArrayHandle curve = wavelet.opacityCurveRG; + keyFile.set_double_list("Wavelet", "OpacityCurveRG", curve); + } + + if (!pedited || pedited->wavelet.opacityCurveBY) { + Glib::ArrayHandle curve = wavelet.opacityCurveBY; + keyFile.set_double_list("Wavelet", "OpacityCurveBY", curve); + } + + if (!pedited || pedited->wavelet.opacityCurveW) { + Glib::ArrayHandle curve = wavelet.opacityCurveW; + keyFile.set_double_list("Wavelet", "OpacityCurveW", curve); + } + + if (!pedited || pedited->wavelet.opacityCurveWL) { + Glib::ArrayHandle curve = wavelet.opacityCurveWL; + keyFile.set_double_list("Wavelet", "OpacityCurveWL", curve); + } + + if (!pedited || pedited->wavelet.hhcurve) { + Glib::ArrayHandle curve = wavelet.hhcurve; + keyFile.set_double_list("Wavelet", "HHcurve", curve); + } + + if (!pedited || pedited->wavelet.Chcurve) { + Glib::ArrayHandle curve = wavelet.Chcurve; + keyFile.set_double_list("Wavelet", "CHcurve", curve); + } + + if (!pedited || pedited->wavelet.wavclCurve) { + Glib::ArrayHandle wavclCurve = wavelet.wavclCurve; + keyFile.set_double_list("Wavelet", "WavclCurve", wavclCurve); + } + + + if (!pedited || pedited->wavelet.median) { + keyFile.set_boolean ("Wavelet", "Median", wavelet.median); + } + + if (!pedited || pedited->wavelet.medianlev) { + keyFile.set_boolean ("Wavelet", "Medianlev", wavelet.medianlev); + } + + if (!pedited || pedited->wavelet.linkedg) { + keyFile.set_boolean ("Wavelet", "Linkedg", wavelet.linkedg); + } + + if (!pedited || pedited->wavelet.cbenab) { + keyFile.set_boolean ("Wavelet", "CBenab", wavelet.cbenab); + } + + if (!pedited || pedited->wavelet.lipst) { + keyFile.set_boolean ("Wavelet", "Lipst", wavelet.lipst); + } // if (!pedited || pedited->wavelet.edgreinf) keyFile.set_boolean ("Wavelet", "Edgreinf", wavelet.edgreinf); - if (!pedited || pedited->wavelet.skinprotect) { - keyFile.set_double ("Wavelet", "Skinprotect", wavelet.skinprotect); - } + if (!pedited || pedited->wavelet.skinprotect) { + keyFile.set_double ("Wavelet", "Skinprotect", wavelet.skinprotect); + } - if (!pedited || pedited->wavelet.hueskin) { - Glib::ArrayHandle thresh (wavelet.hueskin.value, 4, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Wavelet", "Hueskin", thresh); - } + if (!pedited || pedited->wavelet.hueskin) { + Glib::ArrayHandle thresh (wavelet.hueskin.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "Hueskin", thresh); + } - if (!pedited || pedited->wavelet.edgrad) { - keyFile.set_integer ("Wavelet", "Edgrad", wavelet.edgrad); - } + if (!pedited || pedited->wavelet.edgrad) { + keyFile.set_integer ("Wavelet", "Edgrad", wavelet.edgrad); + } - if (!pedited || pedited->wavelet.edgval) { - keyFile.set_integer ("Wavelet", "Edgval", wavelet.edgval); - } + if (!pedited || pedited->wavelet.edgval) { + keyFile.set_integer ("Wavelet", "Edgval", wavelet.edgval); + } - if (!pedited || pedited->wavelet.edgthresh) { - keyFile.set_integer ("Wavelet", "ThrEdg", wavelet.edgthresh); - } + if (!pedited || pedited->wavelet.edgthresh) { + keyFile.set_integer ("Wavelet", "ThrEdg", wavelet.edgthresh); + } // if (!pedited || pedited->wavelet.strength) keyFile.set_integer ("Wavelet", "Strength", wavelet.strength); - // if (!pedited || pedited->wavelet.balance) keyFile.set_integer ("Wavelet", "Balance", wavelet.balance); + // if (!pedited || pedited->wavelet.balance) keyFile.set_integer ("Wavelet", "Balance", wavelet.balance); - if (!pedited || pedited->wavelet.avoid) { - keyFile.set_boolean ("Wavelet", "AvoidColorShift", wavelet.avoid); - } - - if (!pedited || pedited->wavelet.tmr) { - keyFile.set_boolean ("Wavelet", "TMr", wavelet.tmr); - } - - if (!pedited || pedited->wavelet.rescon) { - keyFile.set_integer ("Wavelet", "ResidualcontShadow", wavelet.rescon); - } - - if (!pedited || pedited->wavelet.resconH) { - keyFile.set_integer ("Wavelet", "ResidualcontHighlight", wavelet.resconH); - } - - if (!pedited || pedited->wavelet.thr) { - keyFile.set_integer ("Wavelet", "ThresholdResidShadow", wavelet.thr); - } - - if (!pedited || pedited->wavelet.thrH) { - keyFile.set_integer ("Wavelet", "ThresholdResidHighLight", wavelet.thrH); - } - - if (!pedited || pedited->wavelet.reschro) { - keyFile.set_integer ("Wavelet", "Residualchroma", wavelet.reschro); - } - - if (!pedited || pedited->wavelet.tmrs) { - keyFile.set_double ("Wavelet", "ResidualTM", wavelet.tmrs); - } - - if (!pedited || pedited->wavelet.gamma) { - keyFile.set_double ("Wavelet", "Residualgamma", wavelet.gamma); - } - - if (!pedited || pedited->wavelet.sky) { - keyFile.set_double ("Wavelet", "HueRangeResidual", wavelet.sky); - } - - if (!pedited || pedited->wavelet.hueskin2) { - Glib::ArrayHandle thresh (wavelet.hueskin2.value, 4, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Wavelet", "HueRange", thresh); - } - - if (!pedited || pedited->wavelet.contrast) { - keyFile.set_integer ("Wavelet", "Contrast", wavelet.contrast); - } - - - // save directional pyramid wavelet parameters - if (!pedited || pedited->dirpyrequalizer.enabled) { - keyFile.set_boolean ("Directional Pyramid Equalizer", "Enabled", dirpyrequalizer.enabled); - } - - if (!pedited || pedited->dirpyrequalizer.gamutlab) { - keyFile.set_boolean ("Directional Pyramid Equalizer", "Gamutlab", dirpyrequalizer.gamutlab); - } - - if (!pedited || pedited->dirpyrequalizer.cbdlMethod) { - keyFile.set_string ("Directional Pyramid Equalizer", "cbdlMethod", dirpyrequalizer.cbdlMethod); - } - - for(int i = 0; i < 6; i++) { - std::stringstream ss; - ss << "Mult" << i; - - if (!pedited || pedited->dirpyrequalizer.mult[i]) { - keyFile.set_double("Directional Pyramid Equalizer", ss.str(), dirpyrequalizer.mult[i]); + if (!pedited || pedited->wavelet.avoid) { + keyFile.set_boolean ("Wavelet", "AvoidColorShift", wavelet.avoid); } - } - if (!pedited || pedited->dirpyrequalizer.threshold) { - keyFile.set_double ("Directional Pyramid Equalizer", "Threshold", dirpyrequalizer.threshold); - } - - if (!pedited || pedited->dirpyrequalizer.skinprotect) { - keyFile.set_double ("Directional Pyramid Equalizer", "Skinprotect", dirpyrequalizer.skinprotect); - } - - // if (!pedited || pedited->dirpyrequalizer.algo) keyFile.set_string ("Directional Pyramid Equalizer", "Algorithm", dirpyrequalizer.algo); - if (!pedited || pedited->dirpyrequalizer.hueskin) { - Glib::ArrayHandle thresh (dirpyrequalizer.hueskin.value, 4, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Directional Pyramid Equalizer", "Hueskin", thresh); - } - - // save hsv wavelet parameters - if (!pedited || pedited->hsvequalizer.hcurve) { - Glib::ArrayHandle hcurve = hsvequalizer.hcurve; - keyFile.set_double_list("HSV Equalizer", "HCurve", hcurve); - } - - if (!pedited || pedited->hsvequalizer.scurve) { - Glib::ArrayHandle scurve = hsvequalizer.scurve; - keyFile.set_double_list("HSV Equalizer", "SCurve", scurve); - } - - if (!pedited || pedited->hsvequalizer.vcurve) { - Glib::ArrayHandle vcurve = hsvequalizer.vcurve; - keyFile.set_double_list("HSV Equalizer", "VCurve", vcurve); - } - - //save film simulation parameters - if ( !pedited || pedited->filmSimulation.enabled ) { - keyFile.set_boolean( "Film Simulation", "Enabled", filmSimulation.enabled ); - } - - if ( !pedited || pedited->filmSimulation.clutFilename ) { - keyFile.set_string ( "Film Simulation", "ClutFilename", filmSimulation.clutFilename ); - } - - if ( !pedited || pedited->filmSimulation.strength ) { - keyFile.set_integer( "Film Simulation", "Strength", filmSimulation.strength ); - } - - - if (!pedited || pedited->rgbCurves.lumamode) { - keyFile.set_boolean ("RGB Curves", "LumaMode", rgbCurves.lumamode); - } - - if (!pedited || pedited->rgbCurves.rcurve) { - Glib::ArrayHandle RGBrcurve = rgbCurves.rcurve; - keyFile.set_double_list("RGB Curves", "rCurve", RGBrcurve); - } - - if (!pedited || pedited->rgbCurves.gcurve) { - Glib::ArrayHandle RGBgcurve = rgbCurves.gcurve; - keyFile.set_double_list("RGB Curves", "gCurve", RGBgcurve); - } - - if (!pedited || pedited->rgbCurves.bcurve) { - Glib::ArrayHandle RGBbcurve = rgbCurves.bcurve; - keyFile.set_double_list("RGB Curves", "bCurve", RGBbcurve); - } - - // save Color Toning - if (!pedited || pedited->colorToning.enabled) { - keyFile.set_boolean ("ColorToning", "Enabled", colorToning.enabled); - } - - if (!pedited || pedited->colorToning.method) { - keyFile.set_string ("ColorToning", "Method", colorToning.method); - } - - if (!pedited || pedited->colorToning.lumamode) { - keyFile.set_boolean ("ColorToning", "Lumamode", colorToning.lumamode); - } - - if (!pedited || pedited->colorToning.twocolor) { - keyFile.set_string ("ColorToning", "Twocolor", colorToning.twocolor); - } - - if (!pedited || pedited->colorToning.redlow) { - keyFile.set_double ("ColorToning", "Redlow", colorToning.redlow); - } - - if (!pedited || pedited->colorToning.greenlow) { - keyFile.set_double ("ColorToning", "Greenlow", colorToning.greenlow); - } - - if (!pedited || pedited->colorToning.bluelow) { - keyFile.set_double ("ColorToning", "Bluelow", colorToning.bluelow); - } - - if (!pedited || pedited->colorToning.satlow) { - keyFile.set_double ("ColorToning", "Satlow", colorToning.satlow); - } - - if (!pedited || pedited->colorToning.balance) { - keyFile.set_integer ("ColorToning", "Balance", colorToning.balance); - } - - if (!pedited || pedited->colorToning.sathigh) { - keyFile.set_double ("ColorToning", "Sathigh", colorToning.sathigh); - } - - if (!pedited || pedited->colorToning.redmed) { - keyFile.set_double ("ColorToning", "Redmed", colorToning.redmed); - } - - if (!pedited || pedited->colorToning.greenmed) { - keyFile.set_double ("ColorToning", "Greenmed", colorToning.greenmed); - } - - if (!pedited || pedited->colorToning.bluemed) { - keyFile.set_double ("ColorToning", "Bluemed", colorToning.bluemed); - } - - if (!pedited || pedited->colorToning.redhigh) { - keyFile.set_double ("ColorToning", "Redhigh", colorToning.redhigh); - } - - if (!pedited || pedited->colorToning.greenhigh) { - keyFile.set_double ("ColorToning", "Greenhigh", colorToning.greenhigh); - } - - if (!pedited || pedited->colorToning.bluehigh) { - keyFile.set_double ("ColorToning", "Bluehigh", colorToning.bluehigh); - } - - if (!pedited || pedited->colorToning.autosat) { - keyFile.set_boolean ("ColorToning", "Autosat", colorToning.autosat); - } - - if (!pedited || pedited->colorToning.opacityCurve) { - Glib::ArrayHandle curve = colorToning.opacityCurve; - keyFile.set_double_list("ColorToning", "OpacityCurve", curve); - } - - if (!pedited || pedited->colorToning.colorCurve) { - Glib::ArrayHandle curve = colorToning.colorCurve; - keyFile.set_double_list("ColorToning", "ColorCurve", curve); - } - - if (!pedited || pedited->colorToning.satprotectionthreshold) { - keyFile.set_integer ("ColorToning", "SatProtectionThreshold", colorToning.satProtectionThreshold ); - } - - if (!pedited || pedited->colorToning.saturatedopacity) { - keyFile.set_integer ("ColorToning", "SaturatedOpacity", colorToning.saturatedOpacity ); - } - - if (!pedited || pedited->colorToning.strength) { - keyFile.set_integer ("ColorToning", "Strength", colorToning.strength ); - } - - if (!pedited || pedited->colorToning.hlColSat) { - Glib::ArrayHandle thresh (colorToning.hlColSat.value, 2, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("ColorToning", "HighlightsColorSaturation", thresh); - } - - if (!pedited || pedited->colorToning.shadowsColSat) { - Glib::ArrayHandle thresh (colorToning.shadowsColSat.value, 2, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("ColorToning", "ShadowsColorSaturation", thresh); - } - - if (!pedited || pedited->colorToning.clcurve) { - Glib::ArrayHandle clcurve = colorToning.clcurve; - keyFile.set_double_list("ColorToning", "ClCurve", clcurve); - } - - if (!pedited || pedited->colorToning.cl2curve) { - Glib::ArrayHandle cl2curve = colorToning.cl2curve; - keyFile.set_double_list("ColorToning", "Cl2Curve", cl2curve); - } - - // save raw parameters - if (!pedited || pedited->raw.darkFrame) { - keyFile.set_string ("RAW", "DarkFrame", relativePathIfInside(fname, fnameAbsolute, raw.dark_frame) ); - } - - if (!pedited || pedited->raw.dfAuto) { - keyFile.set_boolean ("RAW", "DarkFrameAuto", raw.df_autoselect ); - } - - if (!pedited || pedited->raw.ff_file) { - keyFile.set_string ("RAW", "FlatFieldFile", relativePathIfInside(fname, fnameAbsolute, raw.ff_file) ); - } - - if (!pedited || pedited->raw.ff_AutoSelect) { - keyFile.set_boolean ("RAW", "FlatFieldAutoSelect", raw.ff_AutoSelect ); - } - - if (!pedited || pedited->raw.ff_BlurRadius) { - keyFile.set_integer ("RAW", "FlatFieldBlurRadius", raw.ff_BlurRadius ); - } - - if (!pedited || pedited->raw.ff_BlurType) { - keyFile.set_string ("RAW", "FlatFieldBlurType", raw.ff_BlurType ); - } - - if (!pedited || pedited->raw.ff_AutoClipControl) { - keyFile.set_boolean ("RAW", "FlatFieldAutoClipControl", raw.ff_AutoClipControl ); - } - - if (!pedited || pedited->raw.ff_clipControl) { - keyFile.set_boolean ("RAW", "FlatFieldClipControl", raw.ff_clipControl ); - } - - if (!pedited || pedited->raw.caCorrection) { - keyFile.set_boolean ("RAW", "CA", raw.ca_autocorrect ); - } - - if (!pedited || pedited->raw.caAutoStrength) { - keyFile.set_double ("RAW", "CAAutoStrength", raw.caautostrength ); - } - - if (!pedited || pedited->raw.caRed) { - keyFile.set_double ("RAW", "CARed", raw.cared ); - } - - if (!pedited || pedited->raw.caBlue) { - keyFile.set_double ("RAW", "CABlue", raw.cablue ); - } - - if (!pedited || pedited->raw.hotPixelFilter) { - keyFile.set_boolean ("RAW", "HotPixelFilter", raw.hotPixelFilter ); - } - - if (!pedited || pedited->raw.deadPixelFilter) { - keyFile.set_boolean ("RAW", "DeadPixelFilter", raw.deadPixelFilter ); - } - - if (!pedited || pedited->raw.hotDeadPixelThresh) { - keyFile.set_integer ("RAW", "HotDeadPixelThresh", raw.hotdeadpix_thresh ); - } - - if (!pedited || pedited->raw.bayersensor.method) { - keyFile.set_string ("RAW Bayer", "Method", raw.bayersensor.method ); - } - - if (!pedited || pedited->raw.bayersensor.ccSteps) { - keyFile.set_integer ("RAW Bayer", "CcSteps", raw.bayersensor.ccSteps); - } - - if (!pedited || pedited->raw.bayersensor.exBlack0) { - keyFile.set_double ("RAW Bayer", "PreBlack0", raw.bayersensor.black0 ); - } - - if (!pedited || pedited->raw.bayersensor.exBlack1) { - keyFile.set_double ("RAW Bayer", "PreBlack1", raw.bayersensor.black1 ); - } - - if (!pedited || pedited->raw.bayersensor.exBlack2) { - keyFile.set_double ("RAW Bayer", "PreBlack2", raw.bayersensor.black2 ); - } - - if (!pedited || pedited->raw.bayersensor.exBlack3) { - keyFile.set_double ("RAW Bayer", "PreBlack3", raw.bayersensor.black3 ); - } - - if (!pedited || pedited->raw.bayersensor.exTwoGreen) { - keyFile.set_boolean ("RAW Bayer", "PreTwoGreen", raw.bayersensor.twogreen ); - } - - if (!pedited || pedited->raw.bayersensor.linenoise) { - keyFile.set_integer ("RAW Bayer", "LineDenoise", raw.bayersensor.linenoise); - } - - if (!pedited || pedited->raw.bayersensor.greenEq) { - keyFile.set_integer ("RAW Bayer", "GreenEqThreshold", raw.bayersensor.greenthresh); - } - - if (!pedited || pedited->raw.bayersensor.dcbIterations) { - keyFile.set_integer ("RAW Bayer", "DCBIterations", raw.bayersensor.dcb_iterations ); - } - - if (!pedited || pedited->raw.bayersensor.dcbEnhance) { - keyFile.set_boolean ("RAW Bayer", "DCBEnhance", raw.bayersensor.dcb_enhance ); - } - - if (!pedited || pedited->raw.bayersensor.lmmseIterations) { - keyFile.set_integer ("RAW Bayer", "LMMSEIterations", raw.bayersensor.lmmse_iterations ); - } - - //if (!pedited || pedited->raw.bayersensor.allEnhance) keyFile.set_boolean ("RAW Bayer", "ALLEnhance", raw.bayersensor.all_enhance ); - - if (!pedited || pedited->raw.xtranssensor.method) { - keyFile.set_string ("RAW X-Trans", "Method", raw.xtranssensor.method ); - } - - if (!pedited || pedited->raw.xtranssensor.ccSteps) { - keyFile.set_integer ("RAW X-Trans", "CcSteps", raw.xtranssensor.ccSteps); - } - - if (!pedited || pedited->raw.xtranssensor.exBlackRed) { - keyFile.set_double ("RAW X-Trans", "PreBlackRed", raw.xtranssensor.blackred ); - } - - if (!pedited || pedited->raw.xtranssensor.exBlackGreen) { - keyFile.set_double ("RAW X-Trans", "PreBlackGreen", raw.xtranssensor.blackgreen ); - } - - if (!pedited || pedited->raw.xtranssensor.exBlackBlue) { - keyFile.set_double ("RAW X-Trans", "PreBlackBlue", raw.xtranssensor.blackblue ); - } - - - // save raw exposition - if (!pedited || pedited->raw.exPos) { - keyFile.set_double ("RAW", "PreExposure", raw.expos ); - } - - if (!pedited || pedited->raw.exPreser) { - keyFile.set_double ("RAW", "PrePreserv", raw.preser ); - } - - // save exif change list - if (!pedited || pedited->exif) { - for (ExifPairs::const_iterator i = exif.begin(); i != exif.end(); i++) { - keyFile.set_string ("Exif", i->first, i->second); + if (!pedited || pedited->wavelet.tmr) { + keyFile.set_boolean ("Wavelet", "TMr", wavelet.tmr); } - } - // save iptc change list - if (!pedited || pedited->iptc) { - for (IPTCPairs::const_iterator i = iptc.begin(); i != iptc.end(); i++) { - Glib::ArrayHandle values = i->second; - keyFile.set_string_list ("IPTC", i->first, values); + if (!pedited || pedited->wavelet.rescon) { + keyFile.set_integer ("Wavelet", "ResidualcontShadow", wavelet.rescon); } - } - sPParams = keyFile.to_data(); + if (!pedited || pedited->wavelet.resconH) { + keyFile.set_integer ("Wavelet", "ResidualcontHighlight", wavelet.resconH); + } + + if (!pedited || pedited->wavelet.thr) { + keyFile.set_integer ("Wavelet", "ThresholdResidShadow", wavelet.thr); + } + + if (!pedited || pedited->wavelet.thrH) { + keyFile.set_integer ("Wavelet", "ThresholdResidHighLight", wavelet.thrH); + } + + if (!pedited || pedited->wavelet.reschro) { + keyFile.set_integer ("Wavelet", "Residualchroma", wavelet.reschro); + } + + if (!pedited || pedited->wavelet.tmrs) { + keyFile.set_double ("Wavelet", "ResidualTM", wavelet.tmrs); + } + + if (!pedited || pedited->wavelet.gamma) { + keyFile.set_double ("Wavelet", "Residualgamma", wavelet.gamma); + } + + if (!pedited || pedited->wavelet.sky) { + keyFile.set_double ("Wavelet", "HueRangeResidual", wavelet.sky); + } + + if (!pedited || pedited->wavelet.hueskin2) { + Glib::ArrayHandle thresh (wavelet.hueskin2.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "HueRange", thresh); + } + + if (!pedited || pedited->wavelet.contrast) { + keyFile.set_integer ("Wavelet", "Contrast", wavelet.contrast); + } + + + // save directional pyramid wavelet parameters + if (!pedited || pedited->dirpyrequalizer.enabled) { + keyFile.set_boolean ("Directional Pyramid Equalizer", "Enabled", dirpyrequalizer.enabled); + } + + if (!pedited || pedited->dirpyrequalizer.gamutlab) { + keyFile.set_boolean ("Directional Pyramid Equalizer", "Gamutlab", dirpyrequalizer.gamutlab); + } + + if (!pedited || pedited->dirpyrequalizer.cbdlMethod) { + keyFile.set_string ("Directional Pyramid Equalizer", "cbdlMethod", dirpyrequalizer.cbdlMethod); + } + + for(int i = 0; i < 6; i++) { + std::stringstream ss; + ss << "Mult" << i; + + if (!pedited || pedited->dirpyrequalizer.mult[i]) { + keyFile.set_double("Directional Pyramid Equalizer", ss.str(), dirpyrequalizer.mult[i]); + } + } + + if (!pedited || pedited->dirpyrequalizer.threshold) { + keyFile.set_double ("Directional Pyramid Equalizer", "Threshold", dirpyrequalizer.threshold); + } + + if (!pedited || pedited->dirpyrequalizer.skinprotect) { + keyFile.set_double ("Directional Pyramid Equalizer", "Skinprotect", dirpyrequalizer.skinprotect); + } + + // if (!pedited || pedited->dirpyrequalizer.algo) keyFile.set_string ("Directional Pyramid Equalizer", "Algorithm", dirpyrequalizer.algo); + if (!pedited || pedited->dirpyrequalizer.hueskin) { + Glib::ArrayHandle thresh (dirpyrequalizer.hueskin.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Directional Pyramid Equalizer", "Hueskin", thresh); + } + + // save hsv wavelet parameters + if (!pedited || pedited->hsvequalizer.hcurve) { + Glib::ArrayHandle hcurve = hsvequalizer.hcurve; + keyFile.set_double_list("HSV Equalizer", "HCurve", hcurve); + } + + if (!pedited || pedited->hsvequalizer.scurve) { + Glib::ArrayHandle scurve = hsvequalizer.scurve; + keyFile.set_double_list("HSV Equalizer", "SCurve", scurve); + } + + if (!pedited || pedited->hsvequalizer.vcurve) { + Glib::ArrayHandle vcurve = hsvequalizer.vcurve; + keyFile.set_double_list("HSV Equalizer", "VCurve", vcurve); + } + + //save film simulation parameters + if ( !pedited || pedited->filmSimulation.enabled ) { + keyFile.set_boolean( "Film Simulation", "Enabled", filmSimulation.enabled ); + } + + if ( !pedited || pedited->filmSimulation.clutFilename ) { + keyFile.set_string ( "Film Simulation", "ClutFilename", filmSimulation.clutFilename ); + } + + if ( !pedited || pedited->filmSimulation.strength ) { + keyFile.set_integer( "Film Simulation", "Strength", filmSimulation.strength ); + } + + + if (!pedited || pedited->rgbCurves.lumamode) { + keyFile.set_boolean ("RGB Curves", "LumaMode", rgbCurves.lumamode); + } + + if (!pedited || pedited->rgbCurves.rcurve) { + Glib::ArrayHandle RGBrcurve = rgbCurves.rcurve; + keyFile.set_double_list("RGB Curves", "rCurve", RGBrcurve); + } + + if (!pedited || pedited->rgbCurves.gcurve) { + Glib::ArrayHandle RGBgcurve = rgbCurves.gcurve; + keyFile.set_double_list("RGB Curves", "gCurve", RGBgcurve); + } + + if (!pedited || pedited->rgbCurves.bcurve) { + Glib::ArrayHandle RGBbcurve = rgbCurves.bcurve; + keyFile.set_double_list("RGB Curves", "bCurve", RGBbcurve); + } + + // save Color Toning + if (!pedited || pedited->colorToning.enabled) { + keyFile.set_boolean ("ColorToning", "Enabled", colorToning.enabled); + } + + if (!pedited || pedited->colorToning.method) { + keyFile.set_string ("ColorToning", "Method", colorToning.method); + } + + if (!pedited || pedited->colorToning.lumamode) { + keyFile.set_boolean ("ColorToning", "Lumamode", colorToning.lumamode); + } + + if (!pedited || pedited->colorToning.twocolor) { + keyFile.set_string ("ColorToning", "Twocolor", colorToning.twocolor); + } + + if (!pedited || pedited->colorToning.redlow) { + keyFile.set_double ("ColorToning", "Redlow", colorToning.redlow); + } + + if (!pedited || pedited->colorToning.greenlow) { + keyFile.set_double ("ColorToning", "Greenlow", colorToning.greenlow); + } + + if (!pedited || pedited->colorToning.bluelow) { + keyFile.set_double ("ColorToning", "Bluelow", colorToning.bluelow); + } + + if (!pedited || pedited->colorToning.satlow) { + keyFile.set_double ("ColorToning", "Satlow", colorToning.satlow); + } + + if (!pedited || pedited->colorToning.balance) { + keyFile.set_integer ("ColorToning", "Balance", colorToning.balance); + } + + if (!pedited || pedited->colorToning.sathigh) { + keyFile.set_double ("ColorToning", "Sathigh", colorToning.sathigh); + } + + if (!pedited || pedited->colorToning.redmed) { + keyFile.set_double ("ColorToning", "Redmed", colorToning.redmed); + } + + if (!pedited || pedited->colorToning.greenmed) { + keyFile.set_double ("ColorToning", "Greenmed", colorToning.greenmed); + } + + if (!pedited || pedited->colorToning.bluemed) { + keyFile.set_double ("ColorToning", "Bluemed", colorToning.bluemed); + } + + if (!pedited || pedited->colorToning.redhigh) { + keyFile.set_double ("ColorToning", "Redhigh", colorToning.redhigh); + } + + if (!pedited || pedited->colorToning.greenhigh) { + keyFile.set_double ("ColorToning", "Greenhigh", colorToning.greenhigh); + } + + if (!pedited || pedited->colorToning.bluehigh) { + keyFile.set_double ("ColorToning", "Bluehigh", colorToning.bluehigh); + } + + if (!pedited || pedited->colorToning.autosat) { + keyFile.set_boolean ("ColorToning", "Autosat", colorToning.autosat); + } + + if (!pedited || pedited->colorToning.opacityCurve) { + Glib::ArrayHandle curve = colorToning.opacityCurve; + keyFile.set_double_list("ColorToning", "OpacityCurve", curve); + } + + if (!pedited || pedited->colorToning.colorCurve) { + Glib::ArrayHandle curve = colorToning.colorCurve; + keyFile.set_double_list("ColorToning", "ColorCurve", curve); + } + + if (!pedited || pedited->colorToning.satprotectionthreshold) { + keyFile.set_integer ("ColorToning", "SatProtectionThreshold", colorToning.satProtectionThreshold ); + } + + if (!pedited || pedited->colorToning.saturatedopacity) { + keyFile.set_integer ("ColorToning", "SaturatedOpacity", colorToning.saturatedOpacity ); + } + + if (!pedited || pedited->colorToning.strength) { + keyFile.set_integer ("ColorToning", "Strength", colorToning.strength ); + } + + if (!pedited || pedited->colorToning.hlColSat) { + Glib::ArrayHandle thresh (colorToning.hlColSat.value, 2, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("ColorToning", "HighlightsColorSaturation", thresh); + } + + if (!pedited || pedited->colorToning.shadowsColSat) { + Glib::ArrayHandle thresh (colorToning.shadowsColSat.value, 2, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("ColorToning", "ShadowsColorSaturation", thresh); + } + + if (!pedited || pedited->colorToning.clcurve) { + Glib::ArrayHandle clcurve = colorToning.clcurve; + keyFile.set_double_list("ColorToning", "ClCurve", clcurve); + } + + if (!pedited || pedited->colorToning.cl2curve) { + Glib::ArrayHandle cl2curve = colorToning.cl2curve; + keyFile.set_double_list("ColorToning", "Cl2Curve", cl2curve); + } + + // save raw parameters + if (!pedited || pedited->raw.darkFrame) { + keyFile.set_string ("RAW", "DarkFrame", relativePathIfInside(fname, fnameAbsolute, raw.dark_frame) ); + } + + if (!pedited || pedited->raw.dfAuto) { + keyFile.set_boolean ("RAW", "DarkFrameAuto", raw.df_autoselect ); + } + + if (!pedited || pedited->raw.ff_file) { + keyFile.set_string ("RAW", "FlatFieldFile", relativePathIfInside(fname, fnameAbsolute, raw.ff_file) ); + } + + if (!pedited || pedited->raw.ff_AutoSelect) { + keyFile.set_boolean ("RAW", "FlatFieldAutoSelect", raw.ff_AutoSelect ); + } + + if (!pedited || pedited->raw.ff_BlurRadius) { + keyFile.set_integer ("RAW", "FlatFieldBlurRadius", raw.ff_BlurRadius ); + } + + if (!pedited || pedited->raw.ff_BlurType) { + keyFile.set_string ("RAW", "FlatFieldBlurType", raw.ff_BlurType ); + } + + if (!pedited || pedited->raw.ff_AutoClipControl) { + keyFile.set_boolean ("RAW", "FlatFieldAutoClipControl", raw.ff_AutoClipControl ); + } + + if (!pedited || pedited->raw.ff_clipControl) { + keyFile.set_boolean ("RAW", "FlatFieldClipControl", raw.ff_clipControl ); + } + + if (!pedited || pedited->raw.caCorrection) { + keyFile.set_boolean ("RAW", "CA", raw.ca_autocorrect ); + } + + if (!pedited || pedited->raw.caAutoStrength) { + keyFile.set_double ("RAW", "CAAutoStrength", raw.caautostrength ); + } + + if (!pedited || pedited->raw.caRed) { + keyFile.set_double ("RAW", "CARed", raw.cared ); + } + + if (!pedited || pedited->raw.caBlue) { + keyFile.set_double ("RAW", "CABlue", raw.cablue ); + } + + if (!pedited || pedited->raw.hotPixelFilter) { + keyFile.set_boolean ("RAW", "HotPixelFilter", raw.hotPixelFilter ); + } + + if (!pedited || pedited->raw.deadPixelFilter) { + keyFile.set_boolean ("RAW", "DeadPixelFilter", raw.deadPixelFilter ); + } + + if (!pedited || pedited->raw.hotDeadPixelThresh) { + keyFile.set_integer ("RAW", "HotDeadPixelThresh", raw.hotdeadpix_thresh ); + } + + if (!pedited || pedited->raw.bayersensor.method) { + keyFile.set_string ("RAW Bayer", "Method", raw.bayersensor.method ); + } + + if (!pedited || pedited->raw.bayersensor.ccSteps) { + keyFile.set_integer ("RAW Bayer", "CcSteps", raw.bayersensor.ccSteps); + } + + if (!pedited || pedited->raw.bayersensor.exBlack0) { + keyFile.set_double ("RAW Bayer", "PreBlack0", raw.bayersensor.black0 ); + } + + if (!pedited || pedited->raw.bayersensor.exBlack1) { + keyFile.set_double ("RAW Bayer", "PreBlack1", raw.bayersensor.black1 ); + } + + if (!pedited || pedited->raw.bayersensor.exBlack2) { + keyFile.set_double ("RAW Bayer", "PreBlack2", raw.bayersensor.black2 ); + } + + if (!pedited || pedited->raw.bayersensor.exBlack3) { + keyFile.set_double ("RAW Bayer", "PreBlack3", raw.bayersensor.black3 ); + } + + if (!pedited || pedited->raw.bayersensor.exTwoGreen) { + keyFile.set_boolean ("RAW Bayer", "PreTwoGreen", raw.bayersensor.twogreen ); + } + + if (!pedited || pedited->raw.bayersensor.linenoise) { + keyFile.set_integer ("RAW Bayer", "LineDenoise", raw.bayersensor.linenoise); + } + + if (!pedited || pedited->raw.bayersensor.greenEq) { + keyFile.set_integer ("RAW Bayer", "GreenEqThreshold", raw.bayersensor.greenthresh); + } + + if (!pedited || pedited->raw.bayersensor.dcbIterations) { + keyFile.set_integer ("RAW Bayer", "DCBIterations", raw.bayersensor.dcb_iterations ); + } + + if (!pedited || pedited->raw.bayersensor.dcbEnhance) { + keyFile.set_boolean ("RAW Bayer", "DCBEnhance", raw.bayersensor.dcb_enhance ); + } + + if (!pedited || pedited->raw.bayersensor.lmmseIterations) { + keyFile.set_integer ("RAW Bayer", "LMMSEIterations", raw.bayersensor.lmmse_iterations ); + } + + //if (!pedited || pedited->raw.bayersensor.allEnhance) keyFile.set_boolean ("RAW Bayer", "ALLEnhance", raw.bayersensor.all_enhance ); + + if (!pedited || pedited->raw.xtranssensor.method) { + keyFile.set_string ("RAW X-Trans", "Method", raw.xtranssensor.method ); + } + + if (!pedited || pedited->raw.xtranssensor.ccSteps) { + keyFile.set_integer ("RAW X-Trans", "CcSteps", raw.xtranssensor.ccSteps); + } + + if (!pedited || pedited->raw.xtranssensor.exBlackRed) { + keyFile.set_double ("RAW X-Trans", "PreBlackRed", raw.xtranssensor.blackred ); + } + + if (!pedited || pedited->raw.xtranssensor.exBlackGreen) { + keyFile.set_double ("RAW X-Trans", "PreBlackGreen", raw.xtranssensor.blackgreen ); + } + + if (!pedited || pedited->raw.xtranssensor.exBlackBlue) { + keyFile.set_double ("RAW X-Trans", "PreBlackBlue", raw.xtranssensor.blackblue ); + } + + + // save raw exposition + if (!pedited || pedited->raw.exPos) { + keyFile.set_double ("RAW", "PreExposure", raw.expos ); + } + + if (!pedited || pedited->raw.exPreser) { + keyFile.set_double ("RAW", "PrePreserv", raw.preser ); + } + + // save exif change list + if (!pedited || pedited->exif) { + for (ExifPairs::const_iterator i = exif.begin(); i != exif.end(); i++) { + keyFile.set_string ("Exif", i->first, i->second); + } + } + + // save iptc change list + if (!pedited || pedited->iptc) { + for (IPTCPairs::const_iterator i = iptc.begin(); i != iptc.end(); i++) { + Glib::ArrayHandle values = i->second; + keyFile.set_string_list ("IPTC", i->first, values); + } + } + + sPParams = keyFile.to_data(); } catch(Glib::KeyFileError&) {} @@ -3422,7 +3422,7 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol } } -int ProcParams::write (Glib::ustring &fname, Glib::ustring &content) const +int ProcParams::write (const Glib::ustring &fname, const Glib::ustring &content) const { int error = 0; @@ -3442,7 +3442,7 @@ int ProcParams::write (Glib::ustring &fname, Glib::ustring &content) const return error; } -int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) +int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) { setlocale(LC_NUMERIC, "C"); // to set decimal point to "." @@ -4225,6 +4225,10 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) if (keyFile.has_key ("Luminance Curve", "Chromaticity")) { labCurve.chromaticity = keyFile.get_integer ("Luminance Curve", "Chromaticity"); + if (ppVersion >= 303 && ppVersion < 314 && labCurve.chromaticity == -100) { + blackwhite.enabled = true; + } + if (pedited) { pedited->labCurve.chromaticity = true; } @@ -8041,7 +8045,7 @@ PartialProfile::PartialProfile(const ProcParams* pp, const ParamsEdited* pe) } } -int PartialProfile::load (Glib::ustring fName) +int PartialProfile::load (const Glib::ustring &fName) { if (!pparams) { pparams = new ProcParams(); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 7f30f0cc9..cf02b9f10 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -528,7 +528,7 @@ public: double green; double equal; - WBEntry(Glib::ustring p, enum WBTypes t, Glib::ustring l, int temp, double green, double equal) : ppLabel(p), type(t), GUILabel(l), temperature(temp), green(green), equal(equal) {}; + WBEntry(const Glib::ustring &p, enum WBTypes t, const Glib::ustring &l, int temp, double green, double equal) : ppLabel(p), type(t), GUILabel(l), temperature(temp), green(green), equal(equal) {}; }; class WBParams @@ -1316,14 +1316,14 @@ public: * @param pedited pointer to a ParamsEdited object (optional) to store which values has to be saved * @return Error code (=0 if all supplied filenames where created correctly) */ - int save (Glib::ustring fname, Glib::ustring fname2 = "", bool fnameAbsolute = true, ParamsEdited* pedited = NULL); + int save (const Glib::ustring &fname, const Glib::ustring &fname2 = "", bool fnameAbsolute = true, ParamsEdited* pedited = NULL); /** * Loads the parameters from a file. * @param fname the name of the file * @params pedited pointer to a ParamsEdited object (optional) to store which values has been loaded * @return Error code (=0 if no error) */ - int load (Glib::ustring fname, ParamsEdited* pedited = NULL); + int load (const Glib::ustring &fname, ParamsEdited* pedited = NULL); /** Creates a new instance of ProcParams. * @return a pointer to the new ProcParams instance. */ @@ -1345,7 +1345,7 @@ private: * @param content the text to write * @return Error code (=0 if no error) * */ - int write (Glib::ustring &fname, Glib::ustring &content) const; + int write (const Glib::ustring &fname, const Glib::ustring &content) const; }; @@ -1375,7 +1375,7 @@ public: PartialProfile (const ProcParams* pp, const ParamsEdited* pe = NULL); void deleteInstance (); void clearGeneral (); - int load (Glib::ustring fName); + int load (const Glib::ustring &fName); void set (bool v); const void applyTo (ProcParams *destParams) const ; }; diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 3f4b2ac3f..919b1c7be 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -580,7 +580,9 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene if (cc) { for (int i = 0; i < 4; i++) { if (RT_blacklevel_from_constant) { - black_c4[i] = cblack[i] + cc->get_BlackLevel(i, iso_speed); + int blackFromCc = cc->get_BlackLevel(i, iso_speed); + // if black level from camconst > 0xffff it is an absolute value. + black_c4[i] = blackFromCc > 0xffff ? (blackFromCc & 0xffff) : blackFromCc + cblack[i]; } // load 4 channel white level here, will be used if available diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 2780c033f..1c04f1af3 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -587,9 +587,7 @@ void RawImageSource::transformRect (PreviewProps pp, int tran, int &ssx1, int &s } } -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -static float -calculate_scale_mul(float scale_mul[4], const float pre_mul_[4], const float c_white[4], const float c_black[4], bool isMono, int colors) +float calculate_scale_mul(float scale_mul[4], const float pre_mul_[4], const float c_white[4], const float c_black[4], bool isMono, int colors) { if (isMono || colors == 1) { for (int c = 0; c < 4; c++) { @@ -617,7 +615,7 @@ calculate_scale_mul(float scale_mul[4], const float pre_mul_[4], const float c_w return gain; } -void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw ) +void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const ColorManagementParams &cmp, const RAWParams &raw ) { MyMutex::MyLock lock(getImageMutex); @@ -727,7 +725,7 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, Pre float line_blue[imwidth] ALIGNED16; #ifdef _OPENMP - #pragma omp for + #pragma omp for schedule(dynamic,16) #endif for (int ix = 0; ix < imheight; ix++) { @@ -891,7 +889,7 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, Pre } } -DCPProfile *RawImageSource::getDCP(ColorManagementParams cmp, ColorTemp &wb) +DCPProfile *RawImageSource::getDCP(const ColorManagementParams &cmp, ColorTemp &wb, DCPProfile::ApplyState &as) { DCPProfile *dcpProf = NULL; cmsHPROFILE dummy; @@ -901,11 +899,11 @@ DCPProfile *RawImageSource::getDCP(ColorManagementParams cmp, ColorTemp &wb) return NULL; } - dcpProf->setStep2ApplyState(cmp.working, cmp.toneCurve, cmp.applyLookTable, cmp.applyBaselineExposureOffset); + dcpProf->setStep2ApplyState(cmp.working, cmp.toneCurve, cmp.applyLookTable, cmp.applyBaselineExposureOffset, as); return dcpProf; } -void RawImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams cmp, ColorTemp &wb) +void RawImageSource::convertColorSpace(Imagefloat* image, const ColorManagementParams &cmp, const ColorTemp &wb) { double pre_mul[3] = { ri->get_pre_mul(0), ri->get_pre_mul(1), ri->get_pre_mul(2) }; colorSpaceConversion (image, cmp, wb, pre_mul, embProfile, camProfile, imatrices.xyz_cam, (static_cast(getMetaData()))->getCamera()); @@ -1501,7 +1499,7 @@ void RawImageSource::vflip (Imagefloat* image) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -int RawImageSource::load (Glib::ustring fname, bool batch) +int RawImageSource::load (const Glib::ustring &fname, bool batch) { MyTime t1, t2; @@ -3715,7 +3713,7 @@ lab2ProphotoRgbD50(float L, float A, float B, float& r, float& g, float& b) } // Converts raw image including ICC input profile to working space - floating point version -void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParams &cmp, ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], const std::string &camName) +void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParams &cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], const std::string &camName) { // MyTime t1, t2, t3; @@ -3729,7 +3727,17 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam if (dcpProf != NULL) { // DCP processing - dcpProf->Apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul, camMatrix, false, cmp.applyHueSatMap, false); + const DCPProfile::Triple pre_mul_row = { + pre_mul[0], + pre_mul[1], + pre_mul[2] + }; + const DCPProfile::Matrix cam_matrix = {{ + {camMatrix[0][0], camMatrix[0][1], camMatrix[0][2]}, + {camMatrix[1][0], camMatrix[1][1], camMatrix[1][2]}, + {camMatrix[2][0], camMatrix[2][1], camMatrix[2][2]} + }}; + dcpProf->apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul_row, cam_matrix, false, cmp.applyHueSatMap, false); return; } @@ -4087,7 +4095,7 @@ bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embed in = embedded; } else if (inProfile == "(cameraICC)") { // DCPs have higher quality, so use them first - *dcpProf = dcpStore->getStdProfile(camName); + *dcpProf = DCPStore::getInstance()->getStdProfile(camName); if (*dcpProf == NULL) { in = iccStore->getStdProfile(camName); @@ -4099,8 +4107,8 @@ bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embed normalName = inProfile.substr(5); } - if (dcpStore->isValidDCPFileName(normalName)) { - *dcpProf = dcpStore->getProfile(normalName); + if (DCPStore::getInstance()->isValidDCPFileName(normalName)) { + *dcpProf = DCPStore::getInstance()->getProfile(normalName); } if (*dcpProf == NULL) { @@ -4375,7 +4383,7 @@ void RawImageSource::getAutoExpHistogram (LUTu & histogram, int& histcompr) #pragma omp parallel #endif { - LUTu tmphistogram(65536 >> histcompr); + LUTu tmphistogram(histogram.getSize()); tmphistogram.clear(); #ifdef _OPENMP #pragma omp for nowait @@ -4430,19 +4438,20 @@ void RawImageSource::getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LU const bool fourColours = ri->getSensorType() == ST_BAYER && ((mult[1] != mult[3] || cblacksom[1] != cblacksom[3]) || FC(0, 0) == 3 || FC(0, 1) == 3 || FC(1, 0) == 3 || FC(1, 1) == 3); + constexpr int histoSize = 65536; LUTu hist[4]; - hist[0](65536); + hist[0](histoSize); hist[0].clear(); if (ri->get_colors() > 1) { - hist[1](65536); + hist[1](histoSize); hist[1].clear(); - hist[2](65536); + hist[2](histoSize); hist[2].clear(); } if (fourColours) { - hist[3](65536); + hist[3](histoSize); hist[3].clear(); } @@ -4457,17 +4466,17 @@ void RawImageSource::getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LU { // we need one LUT per color and thread, which corresponds to 1 MB per thread LUTu tmphist[4]; - tmphist[0](65536); + tmphist[0](histoSize); tmphist[0].clear(); if (ri->get_colors() > 1) { - tmphist[1](65536); + tmphist[1](histoSize); tmphist[1].clear(); - tmphist[2](65536); + tmphist[2](histoSize); tmphist[2].clear(); if (fourColours) { - tmphist[3](65536); + tmphist[3](histoSize); tmphist[3].clear(); } } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 222735432..2af26c702 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -39,7 +39,8 @@ private: static DiagonalCurve *phaseOneIccCurveInv; static LUTf invGrad; // for fast_demosaic static LUTf initInvGrad (); - static void colorSpaceConversion_ (Imagefloat* im, ColorManagementParams &cmp, ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName); + static void colorSpaceConversion_ (Imagefloat* im, ColorManagementParams &cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName); + int defTransform (int tran); protected: MyMutex getImageMutex; // locks getImage @@ -97,7 +98,6 @@ protected: void hphd_green (float** hpmap); void processFalseColorCorrectionThread (Imagefloat* im, array2D &rbconv_Y, array2D &rbconv_I, array2D &rbconv_Q, array2D &rbout_I, array2D &rbout_Q, const int row_from, const int row_to); void hlRecovery (std::string method, float* red, float* green, float* blue, int i, int sx1, int width, int skip, const RAWParams &raw, float* hlmax); - int defTransform (int tran); void transformRect (PreviewProps pp, int tran, int &sx1, int &sy1, int &width, int &height, int &fw); void transformPosition (int x, int y, int tran, int& tx, int& ty); @@ -115,7 +115,7 @@ public: RawImageSource (); ~RawImageSource (); - int load (Glib::ustring fname, bool batch = false); + int load (const Glib::ustring &fname, bool batch = false); void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse); void demosaic (const RAWParams &raw); void retinex (ColorManagementParams cmp, RetinexParams deh, ToneCurveParams Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI); @@ -127,7 +127,7 @@ public: void refinement_lassus (int PassCount); void refinement(int PassCount); - bool IsrgbSourceModified() + bool IsrgbSourceModified() const { return rgbSourceModified; // tracks whether cached rgb output of demosaic has been modified } @@ -137,12 +137,12 @@ public: void cfaboxblur (RawImage *riFlatFile, float* cfablur, int boxH, int boxW ); void scaleColors (int winx, int winy, int winw, int winh, const RAWParams &raw); // raw for cblack - void getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw); - eSensorType getSensorType () + void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const ColorManagementParams &cmp, const RAWParams &raw); + eSensorType getSensorType () const { return ri != NULL ? ri->getSensorType() : ST_NONE; } - ColorTemp getWB () + ColorTemp getWB () const { return camera_wb; } @@ -153,7 +153,7 @@ public: return rawData; } - double getDefGain () + double getDefGain () const { return defGain; } @@ -184,11 +184,11 @@ public: } void getAutoExpHistogram (LUTu & histogram, int& histcompr); void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw); - DCPProfile *getDCP(ColorManagementParams cmp, ColorTemp &wb); + DCPProfile *getDCP(const ColorManagementParams &cmp, ColorTemp &wb, DCPProfile::ApplyState &as); - void convertColorSpace(Imagefloat* image, ColorManagementParams cmp, ColorTemp &wb); + void convertColorSpace(Imagefloat* image, const ColorManagementParams &cmp, const ColorTemp &wb); static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in); - static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName) + static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName) { colorSpaceConversion_ (im, cmp, wb, pre_mul, embedded, camprofile, cam, camName); } diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index e20efdbdd..3913dc6ba 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -32,12 +32,13 @@ #include "rawimagesource.h" #include "stdimagesource.h" #include -#include #include "rawimage.h" #include "jpeg.h" #include "../rtgui/ppversion.h" #include "improccoordinator.h" #include +//#define BENCHMARK +#include "StopWatch.h" extern Options options; @@ -52,7 +53,7 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, StdImageSource imgSrc; if (imgSrc.load(fname)) { - return NULL; + return nullptr; } ImageIO* img = imgSrc.getImageIO(); @@ -94,7 +95,7 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, // bilinear interpolation if (tpp->thumbImg) { delete tpp->thumbImg; - tpp->thumbImg = NULL; + tpp->thumbImg = nullptr; } if (inspectorMode) { @@ -159,7 +160,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL if( r ) { delete ri; - return NULL; + return nullptr; } rml.exifBase = ri->get_exifBase(); @@ -190,7 +191,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL printf("Could not extract thumb from %s\n", fname.data()); delete img; delete ri; - return NULL; + return nullptr; } Thumbnail* tpp = new Thumbnail (); @@ -218,7 +219,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL if (tpp->thumbImg) { delete tpp->thumbImg; - tpp->thumbImg = NULL; + tpp->thumbImg = nullptr; } if (inspectorMode) { @@ -287,7 +288,7 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati if( r ) { delete ri; - return NULL; + return nullptr; } int width = ri->get_width(); @@ -295,8 +296,8 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati rtengine::Thumbnail* tpp = new rtengine::Thumbnail; tpp->isRaw = true; - tpp->embProfile = NULL; - tpp->embProfileData = NULL; + tpp->embProfile = nullptr; + tpp->embProfileData = nullptr; tpp->embProfileLength = ri->get_profileLen(); if (ri->get_profileLen()) @@ -500,7 +501,7 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati delete tpp->thumbImg; } - tpp->thumbImg = NULL; + tpp->thumbImg = nullptr; tpp->thumbImg = resizeTo(w, h, TI_Bilinear, tmpImg); delete tmpImg; @@ -720,7 +721,6 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati void Thumbnail::init () { - RawImageSource::inverse33 (colorMatrix, iColorMatrix); //colorMatrix is rgb_cam memset (cam2xyz, 0, sizeof(cam2xyz)); @@ -735,11 +735,11 @@ void Thumbnail::init () } Thumbnail::Thumbnail () : - camProfile(NULL), thumbImg(NULL), + camProfile(nullptr), thumbImg(nullptr), camwbRed(1.0), camwbGreen(1.0), camwbBlue(1.0), redAWBMul(-1.0), greenAWBMul(-1.0), blueAWBMul(-1.0), autoWBTemp(2700), autoWBGreen(1.0), wbEqual(-1.0), - embProfileLength(0), embProfileData(NULL), embProfile(NULL), + embProfileLength(0), embProfileData(nullptr), embProfile(nullptr), redMultiplier(1.0), greenMultiplier(1.0), blueMultiplier(1.0), defGain(1.0), scaleForSave(8192), @@ -798,6 +798,7 @@ IImage8* Thumbnail::quickProcessImage (const procparams::ProcParams& params, int IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rheight, TypeInterpolation interp, std::string camName, double focalLen, double focalLen35mm, float focusDist, float shutter, float fnumber, float iso, std::string expcomp_, double& myscale) { + BENCHFUN // check if the WB's equalizer value has changed if (wbEqual < (params.wb.equal - 5e-4) || wbEqual > (params.wb.equal + 5e-4)) { wbEqual = params.wb.equal; @@ -829,24 +830,16 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei gm = camwbGreen / gm; bm = camwbBlue / bm; double mul_lum = 0.299 * rm + 0.587 * gm + 0.114 * bm; - double logDefGain = log(defGain) / log(2.0); - int rmi, gmi, bmi; - // Since HL recovery is not rendered in thumbs -// if (!isRaw || !params.toneCurve.hrenabled) { - logDefGain = 0.0; - rmi = 1024.0 * rm * defGain / mul_lum; - gmi = 1024.0 * gm * defGain / mul_lum; - bmi = 1024.0 * bm * defGain / mul_lum; - /* } - else { - rmi = 1024.0 * rm / mul_lum; - gmi = 1024.0 * gm / mul_lum; - bmi = 1024.0 * bm / mul_lum; - }*/ + double logDefGain = 0.0; + float rmi, gmi, bmi; + + rmi = rm * defGain / mul_lum; + gmi = gm * defGain / mul_lum; + bmi = bm * defGain / mul_lum; // The RAW exposure is not reflected since it's done in preprocessing. If we only have e.g. the chached thumb, // that is already preprocessed. So we simulate the effect here roughly my modifying the exposure accordingly - if (isRaw && fabs(1.0 - params.raw.expos) > 0.001) { + if (isRaw) { rmi *= params.raw.expos; gmi *= params.raw.expos; bmi *= params.raw.expos; @@ -862,6 +855,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei rwidth = int(size_t(thumbImg->width) * size_t(rheight) / size_t(thumbImg->height)); } + Imagefloat* baseImg = resizeTo(rwidth, rheight, interp, thumbImg); if (params.coarse.rotate) { @@ -878,45 +872,27 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei baseImg->vflip (); } + // apply white balance and raw white point (simulated) - int val; - unsigned short val_; - - for (int i = 0; i < rheight; i++) + for (int i = 0; i < rheight; i++) { +#ifdef _OPENMP + #pragma omp simd +#endif for (int j = 0; j < rwidth; j++) { + float red = baseImg->r(i, j) * rmi; + baseImg->r(i, j) = CLIP(red); + float green = baseImg->g(i, j) * gmi; + baseImg->g(i, j) = CLIP(green); + float blue = baseImg->b(i, j) * bmi; + baseImg->b(i, j) = CLIP(blue); - baseImg->convertTo(baseImg->r(i, j), val_); - val = static_cast(val_) * rmi >> 10; - baseImg->r(i, j) = CLIP(val); - - baseImg->convertTo(baseImg->g(i, j), val_); - val = static_cast(val_) * gmi >> 10; - baseImg->g(i, j) = CLIP(val); - - baseImg->convertTo(baseImg->b(i, j), val_); - val = static_cast(val_) * bmi >> 10; - baseImg->b(i, j) = CLIP(val); } - - /* - // apply highlight recovery, if needed -- CURRENTLY BROKEN DUE TO INCOMPATIBLE DATA TYPES, BUT HL RECOVERY AREN'T COMPUTED FOR THUMBNAILS ANYWAY... - if (isRaw && params.toneCurve.hrenabled) { - int maxval = 65535 / defGain; - if (params.toneCurve.method=="Luminance" || params.toneCurve.method=="Color") - for (int i=0; ir[i], baseImg->g[i], baseImg->b[i], baseImg->r[i], baseImg->g[i], baseImg->b[i], rwidth, maxval); - else if (params.toneCurve.method=="CIELab blending") { - double icamToD50[3][3]; - RawImageSource::inverse33 (cam2xyz, icamToD50); - for (int i=0; ir[i], baseImg->g[i], baseImg->b[i], baseImg->r[i], baseImg->g[i], baseImg->b[i], rwidth, maxval, cam2xyz, icamToD50); - } - } - */ + } // if luma denoise has to be done for thumbnails, it should be right here // perform color space transformation + if (isRaw) { double pre_mul[3] = { redMultiplier, greenMultiplier, blueMultiplier }; RawImageSource::colorSpaceConversion (baseImg, params.icm, currWB, pre_mul, embProfile, camProfile, cam2xyz, camName ); @@ -933,10 +909,9 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei ipf.updateColorProfiles (params.icm, options.rtSettings.monitorProfile, options.rtSettings.monitorIntent); LUTu hist16 (65536); - LUTu hist16C (65536); double gamma = isRaw ? Color::sRGBGamma : 0; // usually in ImageSource, but we don't have that here - ipf.firstAnalysis (baseImg, ¶ms, hist16); + ipf.firstAnalysis (baseImg, params, hist16); // perform transform if (ipf.needsTransform()) { @@ -951,7 +926,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei } // update blurmap - SHMap* shmap = NULL; + SHMap* shmap = nullptr; if (params.sh.enabled) { shmap = new SHMap (fw, fh, false); @@ -972,70 +947,70 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei int black = params.toneCurve.black; int hlcompr = params.toneCurve.hlcompr; int hlcomprthresh = params.toneCurve.hlcomprthresh; - if (params.toneCurve.autoexp && aeHistogram) { ipf.getAutoExp (aeHistogram, aeHistCompression, logDefGain, params.toneCurve.clip, expcomp, bright, contr, black, hlcompr, hlcomprthresh); - //ipf.getAutoExp (aeHistogram, aeHistCompression, logDefGain, params.toneCurve.clip, params.toneCurve.expcomp, params.toneCurve.brightness, params.toneCurve.contrast, params.toneCurve.black, params.toneCurve.hlcompr); } LUTf curve1 (65536); LUTf curve2 (65536); LUTf curve (65536); + LUTf satcurve (65536); LUTf lhskcurve (65536); + LUTf lumacurve(32770, 0); // lumacurve[32768] and lumacurve[32769] will be set to 32768 and 32769 later to allow linear interpolation LUTf clcurve (65536); - LUTf clToningcurve (65536); - LUTf cl2Toningcurve (65536); - - LUTf rCurve (65536); - LUTf gCurve (65536); - LUTf bCurve (65536); - + LUTf clToningcurve; + LUTf cl2Toningcurve; LUTu dummy; ToneCurve customToneCurve1, customToneCurve2; ColorGradientCurve ctColorCurve; OpacityCurve ctOpacityCurve; - // NoisCurve dnNoisCurve; ColorAppearance customColCurve1; ColorAppearance customColCurve2; ColorAppearance customColCurve3; ToneCurve customToneCurvebw1; ToneCurve customToneCurvebw2; - CurveFactory::complexCurve (expcomp, black / 65535.0, hlcompr, hlcomprthresh, params.toneCurve.shcompr, bright, contr, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, - hist16, dummy, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2, 16); + hist16, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2, 16); + LUTf rCurve; + LUTf gCurve; + LUTf bCurve; CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, 16); CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, 16); CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, 16); - TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); - double wp[3][3] = { - {wprof[0][0], wprof[0][1], wprof[0][2]}, - {wprof[1][0], wprof[1][1], wprof[1][2]}, - {wprof[2][0], wprof[2][1], wprof[2][2]} - }; - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params.icm.working); - double wip[3][3] = { - {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, - {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, - {wiprof[2][0], wiprof[2][1], wiprof[2][2]} - }; bool opautili = false; - params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, wip, opautili); - //params.dirpyrDenoise.getCurves(dnNoisCurve, lldenoisutili); + if(params.colorToning.enabled) { + TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); + double wp[3][3] = { + {wprof[0][0], wprof[0][1], wprof[0][2]}, + {wprof[1][0], wprof[1][1], wprof[1][2]}, + {wprof[2][0], wprof[2][1], wprof[2][2]} + }; + TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params.icm.working); + double wip[3][3] = { + {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, + {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, + {wiprof[2][0], wiprof[2][1], wiprof[2][2]} + }; + params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, wip, opautili); - bool clctoningutili = false; - bool llctoningutili = false; - CurveFactory::curveToningCL(clctoningutili, params.colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16); - CurveFactory::curveToningLL(llctoningutili, params.colorToning.cl2curve, cl2Toningcurve, scale == 1 ? 1 : 16); + clToningcurve (65536); + CurveFactory::curveToning(params.colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16); - CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, hist16, dummy, customToneCurvebw1, customToneCurvebw2, 16); + cl2Toningcurve (65536); + CurveFactory::curveToning(params.colorToning.cl2curve, cl2Toningcurve, scale == 1 ? 1 : 16); + } + + if(params.blackwhite.enabled) { + CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, hist16, dummy, customToneCurvebw1, customToneCurvebw2, 16); + } double rrm, ggm, bbm; float autor, autog, autob; @@ -1065,25 +1040,23 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei autor = autog = autob = -9000.f; // This will ask to compute the "auto" values for the B&W tool LabImage* labView = new LabImage (fw, fh); - DCPProfile *dcpProf = NULL; - + DCPProfile *dcpProf = nullptr; + DCPProfile::ApplyState as; if (isRaw) { cmsHPROFILE dummy; - RawImageSource::findInputProfile(params.icm.input, NULL, camName, &dcpProf, dummy); + RawImageSource::findInputProfile(params.icm.input, nullptr, camName, &dcpProf, dummy); - if (dcpProf != NULL) { - dcpProf->setStep2ApplyState(params.icm.working, params.icm.toneCurve, params.icm.applyLookTable, params.icm.applyBaselineExposureOffset); + if (dcpProf) { + dcpProf->setStep2ApplyState(params.icm.working, params.icm.toneCurve, params.icm.applyLookTable, params.icm.applyBaselineExposureOffset, as); } } - - ipf.rgbProc (baseImg, labView, NULL, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf); + ipf.rgbProc (baseImg, labView, nullptr, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf, as); // freeing up some memory customToneCurve1.Reset(); customToneCurve2.Reset(); ctColorCurve.Reset(); ctOpacityCurve.Reset(); -// dnNoisCurve.Reset(); customToneCurvebw1.Reset(); customToneCurvebw2.Reset(); @@ -1092,38 +1065,29 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei } // luminance histogram update - hist16.clear(); - hist16C.clear(); - - for (int i = 0; i < fh; i++) - for (int j = 0; j < fw; j++) { - hist16[CLIP((int)((labView->L[i][j])))]++; - hist16C[CLIP((int)sqrt(labView->a[i][j]*labView->a[i][j] + labView->b[i][j]*labView->b[i][j]))]++; - } + if(params.labCurve.contrast != 0) { + hist16.clear(); + for (int i = 0; i < fh; i++) + for (int j = 0; j < fw; j++) { + hist16[(int)((labView->L[i][j]))]++; + } + } // luminance processing // ipf.EPDToneMap(labView,0,6); - bool utili = false; - bool autili = false; - bool butili = false; - bool ccutili = false; - bool cclutili = false; - bool clcutili = false; - + bool utili; CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, - hist16, hist16, curve, dummy, 16, utili); + hist16, lumacurve, dummy, 16, utili); - CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, hist16C, dummy, 16); + bool clcutili; + CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, 16); - CurveFactory::complexsgnCurve (1.f, autili, butili, ccutili, cclutili, params.labCurve.chromaticity, params.labCurve.rstprotection, - params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, params.labCurve.lccurve, curve1, curve2, satcurve, lhskcurve, - hist16C, hist16C, dummy, dummy, - 16); - //ipf.luminanceCurve (labView, labView, curve); + bool autili, butili, ccutili, cclutili; + CurveFactory::complexsgnCurve (autili, butili, ccutili, cclutili, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, + params.labCurve.lccurve, curve1, curve2, satcurve, lhskcurve, 16); - - ipf.chromiLuminanceCurve (NULL, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, curve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy, dummy, dummy); + ipf.chromiLuminanceCurve (nullptr, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); ipf.vibrance(labView); @@ -1131,20 +1095,17 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei ipf.EPDToneMap(labView, 5, 6); } - //if(!params.colorappearance.enabled){ipf.EPDToneMap(labView,5,6);} - - CurveFactory::curveLightBrightColor ( - params.colorappearance.curveMode, params.colorappearance.curve, - params.colorappearance.curveMode2, params.colorappearance.curve2, - params.colorappearance.curveMode3, params.colorappearance.curve3, - hist16, hist16, dummy, - hist16C, dummy, - customColCurve1, - customColCurve2, - customColCurve3, - 16); - if(params.colorappearance.enabled) { + CurveFactory::curveLightBrightColor ( + params.colorappearance.curve, + params.colorappearance.curve2, + params.colorappearance.curve3, + hist16, dummy, + dummy, dummy, + customColCurve1, + customColCurve2, + customColCurve3, + 16); int begh = 0, endh = labView->H; bool execsharp = false; float d; @@ -1221,7 +1182,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei int Thumbnail::getImageWidth (const procparams::ProcParams& params, int rheight, float &ratio) { - if (thumbImg == NULL) { + if (!thumbImg) { return 0; // Can happen if thumb is just building and GUI comes in with resize wishes } @@ -1373,11 +1334,11 @@ void Thumbnail::transformPixel (int x, int y, int tran, int& tx, int& ty) unsigned char* Thumbnail::getGrayscaleHistEQ (int trim_width) { if (!thumbImg) { - return NULL; + return nullptr; } if (thumbImg->width < trim_width) { - return NULL; + return nullptr; } // to utilize the 8 bit color range of the thumbnail we brighten it and apply gamma correction @@ -1661,7 +1622,7 @@ bool Thumbnail::readImage (const Glib::ustring& fname) if (thumbImg) { delete thumbImg; - thumbImg = NULL; + thumbImg = nullptr; } Glib::ustring fullFName = fname + ".rtti"; @@ -1874,8 +1835,8 @@ bool Thumbnail::readEmbProfile (const Glib::ustring& fname) FILE* f = g_fopen (fname.c_str (), "rb"); if (!f) { - embProfileData = NULL; - embProfile = NULL; + embProfileData = nullptr; + embProfile = nullptr; embProfileLength = 0; } else { fseek (f, 0, SEEK_END); @@ -1947,7 +1908,7 @@ unsigned char* Thumbnail::getImage8Data() return img8->data; } - return NULL; + return nullptr; } diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 1f64a5ff4..c11ac6452 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -731,9 +731,8 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p // perform first analysis LUTu hist16 (65536); - LUTu hist16C (65536); - ipf.firstAnalysis (baseImg, ¶ms, hist16); + ipf.firstAnalysis (baseImg, params, hist16); // perform transform (excepted resizing) if (ipf.needsTransform()) { @@ -776,15 +775,15 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p LUTf curve (65536, 0); LUTf satcurve (65536, 0); LUTf lhskcurve (65536, 0); - LUTf lumacurve(65536, 0); + LUTf lumacurve(32770, 0); // lumacurve[32768] and lumacurve[32769] will be set to 32768 and 32769 later to allow linear interpolation LUTf clcurve (65536, 0); - LUTf clToningcurve (65536, 0); - LUTf cl2Toningcurve (65536, 0); + LUTf clToningcurve; + LUTf cl2Toningcurve; LUTf wavclCurve (65536, 0); - LUTf rCurve (65536, 0); - LUTf gCurve (65536, 0); - LUTf bCurve (65536, 0); + LUTf rCurve; + LUTf gCurve; + LUTf bCurve; LUTu dummy; ToneCurve customToneCurve1, customToneCurve2; @@ -797,37 +796,38 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p CurveFactory::complexCurve (expcomp, black / 65535.0, hlcompr, hlcomprthresh, params.toneCurve.shcompr, bright, contr, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, - hist16, dummy, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2 ); + hist16, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2 ); CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, 1); CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, 1); CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, 1); - TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); - TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params.icm.working); - - double wp[3][3] = { - {wprof[0][0], wprof[0][1], wprof[0][2]}, - {wprof[1][0], wprof[1][1], wprof[1][2]}, - {wprof[2][0], wprof[2][1], wprof[2][2]} - }; - double wip[3][3] = { - {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, - {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, - {wiprof[2][0], wiprof[2][1], wiprof[2][2]} - }; bool opautili = false; - params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, wip, opautili); - - bool clctoningutili = false; - CurveFactory::curveToningCL(clctoningutili, params.colorToning.clcurve, clToningcurve, 1); - bool llctoningutili = false; - CurveFactory::curveToningLL(llctoningutili, params.colorToning.cl2curve, cl2Toningcurve, 1); + if(params.colorToning.enabled) { + TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); + double wp[3][3] = { + {wprof[0][0], wprof[0][1], wprof[0][2]}, + {wprof[1][0], wprof[1][1], wprof[1][2]}, + {wprof[2][0], wprof[2][1], wprof[2][2]} + }; + TMatrix wiprof = iccStore->workingSpaceInverseMatrix (params.icm.working); + double wip[3][3] = { + {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, + {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, + {wiprof[2][0], wiprof[2][1], wiprof[2][2]} + }; + params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, wip, opautili); + clToningcurve (65536, 0); + CurveFactory::curveToning(params.colorToning.clcurve, clToningcurve, 1); + cl2Toningcurve (65536, 0); + CurveFactory::curveToning(params.colorToning.cl2curve, cl2Toningcurve, 1); + } LabImage* labView = new LabImage (fw, fh); - - CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, hist16, dummy, customToneCurvebw1, customToneCurvebw2, 1); + if(params.blackwhite.enabled) { + CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, hist16, dummy, customToneCurvebw1, customToneCurvebw2, 1); + } double rrm, ggm, bbm; float autor, autog, autob; float satLimit = float(params.colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f; @@ -853,8 +853,10 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p } autor = -9000.f; // This will ask to compute the "auto" values for the B&W tool (have to be inferior to -5000) - DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB); - ipf.rgbProc (baseImg, labView, NULL, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf); + DCPProfile::ApplyState as; + DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB, as); + + ipf.rgbProc (baseImg, labView, NULL, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, expcomp, hlcompr, hlcomprthresh, dcpProf, as); if (settings->verbose) { printf("Output image / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", autor, autog, autob); @@ -893,16 +895,15 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // start tile processing...??? - hist16.clear(); - hist16C.clear(); if(params.labCurve.contrast != 0) { //only use hist16 for contrast + hist16.clear(); #ifdef _OPENMP - #pragma omp parallel shared(hist16,labView, fh, fw) + #pragma omp parallel #endif { - LUTu hist16thr (65536); // one temporary lookup table per thread + LUTu hist16thr (hist16.getSize()); // one temporary lookup table per thread hist16thr.clear(); #ifdef _OPENMP #pragma omp for schedule(static) nowait @@ -911,38 +912,27 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p for (int i = 0; i < fh; i++) for (int j = 0; j < fw; j++) { - hist16thr[CLIP((int)((labView->L[i][j])))]++; + hist16thr[(int)((labView->L[i][j]))]++; } #pragma omp critical { - for(int i = 0; i < 65536; i++) - { - hist16[i] += hist16thr[i]; - } + hist16 += hist16thr; } } - - } - bool utili = false; - bool autili = false; - bool butili = false; - bool ccutili = false; - bool cclutili = false; - bool clcutili = false; + bool utili; + CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, hist16, lumacurve, dummy, 1, utili); - CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, hist16, hist16, lumacurve, dummy, 1, utili); - CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, hist16C, dummy, 1); + bool clcutili; + CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, 1); - CurveFactory::complexsgnCurve (1.f, autili, butili, ccutili, cclutili, params.labCurve.chromaticity, params.labCurve.rstprotection, - params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, params.labCurve.lccurve, curve1, curve2, satcurve, lhskcurve, - hist16C, hist16C, dummy, dummy, - 1); -// ipf.MSR(labView, labView->W, labView->H, 1); + bool autili, butili, ccutili, cclutili; + CurveFactory::complexsgnCurve (autili, butili, ccutili, cclutili, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, + params.labCurve.lccurve, curve1, curve2, satcurve, lhskcurve, 1); - ipf.chromiLuminanceCurve (NULL, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy, dummy, dummy); + ipf.chromiLuminanceCurve (NULL, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { ipf.EPDToneMap(labView, 5, 1); @@ -1030,11 +1020,11 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p begh = 0; endh = fh; CurveFactory::curveLightBrightColor ( - params.colorappearance.curveMode, params.colorappearance.curve, - params.colorappearance.curveMode2, params.colorappearance.curve2, - params.colorappearance.curveMode3, params.colorappearance.curve3, - hist16, hist16, dummy, - hist16C, dummy, + params.colorappearance.curve, + params.colorappearance.curve2, + params.colorappearance.curve3, + hist16, dummy, + dummy, dummy, customColCurve1, customColCurve2, customColCurve3, diff --git a/rtengine/sleef.c b/rtengine/sleef.c index c7b3fb486..2377aea79 100644 --- a/rtengine/sleef.c +++ b/rtengine/sleef.c @@ -58,7 +58,9 @@ __inline double ldexpk(double x, int q) { m = (((m + q) >> 9) - m) << 7; q = q - (m << 2); u = longBitsToDouble(((int64_t)(m + 0x3ff)) << 52); - x = x * u * u * u * u; + double u2 = u*u; + u2 = u2 * u2; + x = x * u2; u = longBitsToDouble(((int64_t)(q + 0x3ff)) << 52); return x * u; } @@ -1197,7 +1199,7 @@ __inline float xexpf(float d) { int q = (int)xrintf(d * R_LN2f); float s, u; - + s = mlaf(q, -L2Uf, d); s = mlaf(q, -L2Lf, s); @@ -1246,7 +1248,7 @@ __inline float xdivf( float d, int n){ uflint.intval -= n << 23; // add n to the exponent } return uflint.floatval; -} +} diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index aabb35a30..e422d23b2 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -83,7 +83,7 @@ StdImageSource::~StdImageSource () } } -void StdImageSource::getSampleFormat (Glib::ustring &fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement) +void StdImageSource::getSampleFormat (const Glib::ustring &fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement) { sFormat = IIOSF_UNKNOWN; @@ -125,7 +125,7 @@ void StdImageSource::getSampleFormat (Glib::ustring &fname, IIOSampleFormat &sFo * and RT's image data type (Image8, Image16 and Imagefloat), then it will * load the image into it */ -int StdImageSource::load (Glib::ustring fname, bool batch) +int StdImageSource::load (const Glib::ustring &fname, bool batch) { fileName = fname; @@ -213,7 +213,7 @@ int StdImageSource::load (Glib::ustring fname, bool batch) return 0; } -void StdImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw) +void StdImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const ColorManagementParams &cmp, const RAWParams &raw) { // the code will use OpenMP as of now. @@ -234,12 +234,12 @@ void StdImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, Pre } } -void StdImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams cmp, ColorTemp &wb) +void StdImageSource::convertColorSpace(Imagefloat* image, const ColorManagementParams &cmp, const ColorTemp &wb) { colorSpaceConversion (image, cmp, embProfile, img->getSampleFormat()); } -void StdImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, cmsHPROFILE embedded, IIOSampleFormat sampleFormat) +void StdImageSource::colorSpaceConversion (Imagefloat* im, const ColorManagementParams &cmp, cmsHPROFILE embedded, IIOSampleFormat sampleFormat) { bool skipTransform = false; diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 6017fae74..048f3b3c0 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -38,15 +38,15 @@ protected: bool rgbSourceModified; //void transformPixel (int x, int y, int tran, int& tx, int& ty); - void getSampleFormat (Glib::ustring &fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement); + void getSampleFormat (const Glib::ustring &fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement); public: StdImageSource (); ~StdImageSource (); - int load (Glib::ustring fname, bool batch = false); - void getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw); - ColorTemp getWB () + int load (const Glib::ustring &fname, bool batch = false); + void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const ColorManagementParams &cmp, const RAWParams &raw); + ColorTemp getWB () const { return wb; } @@ -60,7 +60,7 @@ public: void getAutoExpHistogram (LUTu &histogram, int& histcompr); - double getDefGain () + double getDefGain () const { return 0.0; } @@ -90,20 +90,10 @@ public: plistener = pl; } - void convertColorSpace(Imagefloat* image, ColorManagementParams cmp, ColorTemp &wb);// RAWParams raw will not be used for non-raw files (see imagesource.h) - static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, cmsHPROFILE embedded, IIOSampleFormat sampleFormat); + void convertColorSpace(Imagefloat* image, const ColorManagementParams &cmp, const ColorTemp &wb);// RAWParams raw will not be used for non-raw files (see imagesource.h) + static void colorSpaceConversion (Imagefloat* im, const ColorManagementParams &cmp, cmsHPROFILE embedded, IIOSampleFormat sampleFormat); - static inline double intpow (double a, int b) - { - double r = 1.0; - - for (int i = 0; i < b; i++) { - r *= a; - } - - return r; - } - bool IsrgbSourceModified() + bool IsrgbSourceModified() const { return rgbSourceModified; } diff --git a/rtengine/utils.h b/rtengine/utils.h index 1e742ffb3..c46999219 100644 --- a/rtengine/utils.h +++ b/rtengine/utils.h @@ -16,8 +16,9 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#ifndef _SIMPLEUTILS_ -#define _SIMPLEUTILS_ +#pragma once + +#include namespace rtengine { @@ -35,5 +36,10 @@ void rotate (unsigned char* img, int& w, int& h, int deg); void hflip (unsigned char* img, int w, int h); void vflip (unsigned char* img, int w, int h); +template +typename std::underlying_type::type toUnderlying(ENUM value) +{ + return static_cast::type>(value); +} + } -#endif diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 188135558..ed4c9be95 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -25,8 +25,7 @@ #include "rtimage.h" #include "../rtengine/improccoordinator.h" #include "../rtengine/color.h" - - +#include "../rtengine/opthelper.h" using namespace rtengine; extern Options options; @@ -966,7 +965,7 @@ void HistogramArea::updateBackBuffer () // make double copies of LUT, one for faster access, another one to scale down the raw histos LUTu rhchanged(256), ghchanged(256), bhchanged(256); - unsigned int lhisttemp[256], chisttemp[256], rhtemp[256], ghtemp[256], bhtemp[256]; + unsigned int lhisttemp[256] ALIGNED16 {0}, chisttemp[256] ALIGNED16 {0}, rhtemp[256] ALIGNED16 {0}, ghtemp[256] ALIGNED16 {0}, bhtemp[256] ALIGNED16 {0}; const int scale = (rawMode ? 8 : 1); for(int i = 0; i < 256; i++) { @@ -1025,31 +1024,48 @@ void HistogramArea::updateBackBuffer () if (!fullMode) { int area = 0; - if(!rawMode) - for (int i = 0; i < fullhistheight; i++) { - for (int j = 0; j < 256; j++) - if ((needLuma && lhisttemp[j] > i) || (needChroma && chisttemp[j] > i) || (needRed && rhtemp[j] > i) || (needGreen && ghtemp[j] > i) || (needBlue && bhtemp[j] > i)) { - area++; - } +#ifdef __SSE2__ + vint onev = _mm_set1_epi32(1); + vint iv = (vint)ZEROV; +#endif - if ((double)area / (256 * (i + 1)) < 0.3) { - realhistheight = i; - break; - } - } - else - for (int i = 0; i < fullhistheight; i++) { - for (int j = 0; j < 256; j++) - if ((needRed && rhtemp[j] > i) || (needGreen && ghtemp[j] > i) || (needBlue && bhtemp[j] > i)) { - area++; - } + for (int i = 0; i < fullhistheight; i++) { +#ifdef __SSE2__ + vint areatempv = (vint)ZEROV; + + for (int j = 0; j < 256; j += 4) { + vmask mask1v = _mm_cmpgt_epi32(LVI(lhisttemp[j]), iv); + vmask mask2v = _mm_cmpgt_epi32(LVI(rhtemp[j]), iv); + vmask mask3v = _mm_cmpgt_epi32(LVI(ghtemp[j]), iv); + vmask mask4v = _mm_cmpgt_epi32(LVI(bhtemp[j]), iv); + mask1v = _mm_or_si128(mask1v, mask2v); + mask3v = _mm_or_si128(mask3v, mask4v); + mask2v = _mm_cmpgt_epi32(LVI(chisttemp[j]), iv); + mask1v = _mm_or_si128(mask1v, mask3v); + mask1v = _mm_or_si128(mask1v, mask2v); + areatempv = _mm_add_epi32(areatempv, _mm_and_si128(mask1v, onev)); - if ((double)area / (256 * (i + 1)) < 0.3) { - realhistheight = i; - break; - } } + areatempv = _mm_add_epi32(areatempv, (vint)_mm_movehl_ps((vfloat)areatempv, (vfloat)areatempv)); + areatempv = _mm_add_epi32(areatempv, _mm_shuffle_epi32(areatempv, 1)); + area += _mm_cvtsi128_si32(areatempv); + iv = _mm_add_epi32(iv, onev); + +#else + + for (int j = 0; j < 256; j++) + if (lhisttemp[j] > i || rhtemp[j] > i || ghtemp[j] > i || bhtemp[j] > i || chisttemp[j] > i) { + area++; + } + +#endif + + if ((double)area / (256 * (i + 1)) < 0.3) { + realhistheight = i; + break; + } + } } if (realhistheight < winh - 2) { diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index b6da75167..7f0f6cfd0 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -372,9 +372,9 @@ void ICMPanel::updateDCP (int dcpIlluminant, Glib::ustring dcp_name) DCPProfile* dcp = NULL; if(dcp_name == "(cameraICC)") { - dcp = dcpStore->getStdProfile(camName); - } else if (ifromfile->get_active() && dcpStore->isValidDCPFileName(dcp_name)) { - dcp = dcpStore->getProfile(dcp_name); + dcp = DCPStore::getInstance()->getStdProfile(camName); + } else if (ifromfile->get_active() && DCPStore::getInstance()->isValidDCPFileName(dcp_name)) { + dcp = DCPStore::getInstance()->getProfile(dcp_name); } if (dcp) { @@ -396,24 +396,21 @@ void ICMPanel::updateDCP (int dcpIlluminant, Glib::ustring dcp_name) ckbApplyHueSatMap->set_sensitive (true); } - int i1, i2; - double temp1, temp2; - bool willInterpolate; - dcp->getIlluminants(i1, temp1, i2, temp2, willInterpolate); + const DCPProfile::Illuminants illuminants = dcp->getIlluminants(); - if (willInterpolate) { - if (dcpTemperatures[0] != temp1 || dcpTemperatures[1] != temp2) { + if (illuminants.will_interpolate) { + if (dcpTemperatures[0] != illuminants.temperature_1 || dcpTemperatures[1] != illuminants.temperature_2) { char tempstr1[64], tempstr2[64]; - sprintf(tempstr1, "%.0fK", temp1); - sprintf(tempstr2, "%.0fK", temp2); + sprintf(tempstr1, "%.0fK", illuminants.temperature_1); + sprintf(tempstr2, "%.0fK", illuminants.temperature_2); int curr_active = dcpIll->get_active_row_number(); ignoreDcpSignal = true; dcpIll->remove_all (); dcpIll->append (M("TP_ICM_DCPILLUMINANT_INTERPOLATED")); dcpIll->append (tempstr1); dcpIll->append (tempstr2); - dcpTemperatures[0] = temp1; - dcpTemperatures[1] = temp2; + dcpTemperatures[0] = illuminants.temperature_1; + dcpTemperatures[1] = illuminants.temperature_2; dcpIll->set_active (curr_active); ignoreDcpSignal = false; } @@ -642,10 +639,10 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) DCPProfile* dcp = NULL; - if (ifromfile->get_active() && pp->icm.input.substr(0, 5) == "file:" && dcpStore->isValidDCPFileName(pp->icm.input.substr(5))) { - dcp = dcpStore->getProfile(pp->icm.input.substr(5)); + if (ifromfile->get_active() && pp->icm.input.substr(0, 5) == "file:" && DCPStore::getInstance()->isValidDCPFileName(pp->icm.input.substr(5))) { + dcp = DCPStore::getInstance()->getProfile(pp->icm.input.substr(5)); } else if(icameraICC->get_active()) { - dcp = dcpStore->getStdProfile(camName); + dcp = DCPStore::getInstance()->getStdProfile(camName); } if (dcp) { @@ -931,7 +928,7 @@ void ICMPanel::setRawMeta (bool raw, const rtengine::ImageData* pMeta) iembedded->set_active (!raw); icamera->set_sensitive (raw); camName = pMeta->getCamera(); - icameraICC->set_sensitive (raw && (iccStore->getStdProfile(pMeta->getCamera()) != NULL || dcpStore->getStdProfile(pMeta->getCamera()) != NULL)); + icameraICC->set_sensitive (raw && (iccStore->getStdProfile(pMeta->getCamera()) != NULL || DCPStore::getInstance()->getStdProfile(pMeta->getCamera()) != NULL)); iembedded->set_sensitive (!raw); enableListener (); diff --git a/rtgui/lensgeom.cc b/rtgui/lensgeom.cc index d4487aa80..e56b3b025 100644 --- a/rtgui/lensgeom.cc +++ b/rtgui/lensgeom.cc @@ -44,6 +44,11 @@ LensGeometry::LensGeometry () : FoldableToolPanel(this, "lensgeom", M("TP_LENSGE show_all (); } +LensGeometry::~LensGeometry () +{ + g_idle_remove_by_data(this); +} + void LensGeometry::read (const ProcParams* pp, const ParamsEdited* pedited) { @@ -114,3 +119,30 @@ void LensGeometry::setBatchMode (bool batchMode) ToolPanel::setBatchMode (batchMode); removeIfThere (this, autoCrop); } + +void LensGeometry::disableAutoFillIfActive () +{ + g_idle_add(doDisableAutoFillIfActive, this); +} + +int LensGeometry::doDisableAutoFillIfActive (void* data) +{ + GThreadLock lock; // Is this really needed? + + LensGeometry* const instance = static_cast(data); + + if (!instance->batchMode) { + if (instance->fill->get_active()) { + instance->fillConn.block (true); + instance->fill->set_active(false); + + if (instance->listener) { + instance->listener->panelChanged (EvTransAutoFill, M("GENERAL_DISABLED")); + } + + instance->fillConn.block (false); + } + } + + return 0; +} diff --git a/rtgui/lensgeom.h b/rtgui/lensgeom.h index f6b41b632..51a6e108c 100644 --- a/rtgui/lensgeom.h +++ b/rtgui/lensgeom.h @@ -32,11 +32,12 @@ protected: Gtk::CheckButton* fill; bool lastFill; sigc::connection fillConn; - ToolParamBlock* packBox; + ToolParamBlock* packBox; public: LensGeometry (); + ~LensGeometry (); Gtk::Box* getPackBox () { @@ -53,6 +54,11 @@ public: { rlistener = l; } + void disableAutoFillIfActive (); + +private: + static int doDisableAutoFillIfActive (void* data); + }; #endif diff --git a/rtgui/lensprofile.cc b/rtgui/lensprofile.cc index a7a634443..71c54e2b5 100644 --- a/rtgui/lensprofile.cc +++ b/rtgui/lensprofile.cc @@ -67,7 +67,7 @@ LensProfilePanel::LensProfilePanel () : FoldableToolPanel(this, "lensprof", M("T conLCPFile = fcbLCPFile->signal_file_set().connect( sigc::mem_fun(*this, &LensProfilePanel::onLCPFileChanged), true); btnReset->signal_clicked().connect( sigc::mem_fun(*this, &LensProfilePanel::onLCPFileReset), true); - ckbUseDist->signal_toggled().connect( sigc::mem_fun(*this, &LensProfilePanel::onUseDistChanged) ); + conUseDist = ckbUseDist->signal_toggled().connect( sigc::mem_fun(*this, &LensProfilePanel::onUseDistChanged) ); ckbUseVign->signal_toggled().connect( sigc::mem_fun(*this, &LensProfilePanel::onUseVignChanged) ); ckbUseCA->signal_toggled().connect( sigc::mem_fun(*this, &LensProfilePanel::onUseCAChanged) ); @@ -77,6 +77,7 @@ LensProfilePanel::LensProfilePanel () : FoldableToolPanel(this, "lensprof", M("T void LensProfilePanel::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited) { disableListener (); + conUseDist.block(true); if (!pp->lensProf.lcpFile.empty() && lcpStore->isValidLCPFileName(pp->lensProf.lcpFile)) { fcbLCPFile->set_filename (pp->lensProf.lcpFile); @@ -102,6 +103,7 @@ void LensProfilePanel::read(const rtengine::procparams::ProcParams* pp, const Pa lcpFileChanged = useDistChanged = useVignChanged = useCAChanged = false; enableListener (); + conUseDist.block(false); } void LensProfilePanel::setRawMeta(bool raw, const rtengine::ImageMetaData* pMeta) @@ -142,6 +144,10 @@ void LensProfilePanel::write( rtengine::procparams::ProcParams* pp, ParamsEdited void LensProfilePanel::onLCPFileChanged() { + + // Disable Auto-Fill when enabling LCP Distortion Correction, #1791 + lensgeomLcpFill->disableAutoFillIfActive(); + lcpFileChanged = true; updateDisabled(lcpStore->isValidLCPFileName(fcbLCPFile->get_filename())); @@ -164,6 +170,12 @@ void LensProfilePanel::onLCPFileReset() void LensProfilePanel::onUseDistChanged() { + + // Disable Auto-Fill when enabling LCP Distortion Correction, #1791 + if (ckbUseDist->get_active()) { + lensgeomLcpFill->disableAutoFillIfActive(); + } + useDistChanged = true; if (listener) { diff --git a/rtgui/lensprofile.h b/rtgui/lensprofile.h index 0397388d5..cb3a5cc6c 100644 --- a/rtgui/lensprofile.h +++ b/rtgui/lensprofile.h @@ -22,6 +22,7 @@ #include #include "toolpanel.h" #include "guiutils.h" +#include "lensgeom.h" class LensProfilePanel : public ToolParamBlock, public FoldableToolPanel { @@ -38,6 +39,7 @@ protected: void updateDisabled(bool enable); bool allowFocusDep; bool isRaw; + LensGeometry *lensgeomLcpFill; public: @@ -52,6 +54,10 @@ public: void onUseDistChanged(); void onUseVignChanged(); void onUseCAChanged(); + void setLensGeomRef( LensGeometry *foo) + { + lensgeomLcpFill = foo ; + }; }; #endif diff --git a/rtgui/myflatcurve.cc b/rtgui/myflatcurve.cc index 7911ac279..c544f6871 100644 --- a/rtgui/myflatcurve.cc +++ b/rtgui/myflatcurve.cc @@ -1792,6 +1792,7 @@ void MyFlatCurve::setPoints (const std::vector& p) stopNumericalAdjustment(); FlatCurveType t = (FlatCurveType)p[ix++]; curve.type = t; + lit_point = -1; if (t == FCT_MinMaxCPoints) { curve.x.clear (); diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index c647f2ed2..1a9e4cda2 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -53,6 +53,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(nullptr), editDataProvider(n colortoning = Gtk::manage (new ColorToning ()); lensgeom = Gtk::manage (new LensGeometry ()); lensProf = Gtk::manage (new LensProfilePanel ()); + lensProf->setLensGeomRef(lensgeom); distortion = Gtk::manage (new Distortion ()); rotate = Gtk::manage (new Rotate ()); vibrance = Gtk::manage (new Vibrance ());