diff --git a/README.md b/README.md index e90807b73..9dfd4c324 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 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. +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. 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 24f883766..76bcf0ccd 100644 --- a/rtengine/LUT.h +++ b/rtengine/LUT.h @@ -59,8 +59,17 @@ #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 @@ -69,21 +78,6 @@ #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 { @@ -161,6 +155,41 @@ 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; @@ -186,7 +215,7 @@ public: * For a LUT(500), it will return 500 * @return number of element in the array */ - unsigned int getSize() const + int getSize() { return size; } @@ -195,7 +224,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 */ - unsigned int getUpperBound() const + int getUpperBound() { return size > 0 ? upperBound : 0; } @@ -229,12 +258,11 @@ public: return *this; } - // 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> + // handy to sum up per thread histograms. #pragma omp simd speeds up the loop by about factor 3 for LUTu (unsigned int). LUT & operator+=(LUT &rhs) { if (rhs.size == this->size) { -#ifdef _RT_NESTED_OPENMP // temporary solution to fix Issue #3324 +#ifdef _OPENMP #pragma omp simd #endif @@ -246,37 +274,6 @@ 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 { @@ -351,7 +348,6 @@ public: } */ #ifdef __SSE4_1__ - template::value>::type> vfloat operator[](vint idxv ) const { vfloat tempv, p1v; @@ -391,7 +387,6 @@ public: return p1v; } #else - template::value>::type> vfloat operator[](vint idxv ) const { vfloat tempv, p1v; @@ -436,7 +431,6 @@ 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 @@ -462,10 +456,9 @@ 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) { @@ -533,122 +526,79 @@ public: upperBound = 0; maxs = 0; } - - // 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(divisor == 1.f) { - for(unsigned int i = 0; i < size; i++) { - data[i] = i; - } - } else { - 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 - } - - }; + + +// 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() + { + 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; + } + + 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); + } + } +}; + + #endif /* LUT_H_ */ diff --git a/rtengine/camconst.json b/rtengine/camconst.json index c7bef9ee2..d56eb05a6 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 https://github.com/Beep6581/RawTherapee/issues so we can +If you do so please report at http://code.google.com/p/rawtherapee/issues so we can extend the distributed version of this file so your provided camera information becomes available to all. @@ -58,20 +58,9 @@ 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 @@ -79,18 +68,14 @@ 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 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) + // 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) 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. }, { @@ -586,6 +571,31 @@ 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 @@ -742,65 +752,8 @@ 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 600D", "Canon EOS Rebel T3i", "Canon EOS Kiss X5", "Canon EOS 1200D", "Canon EOS Rebel T5", "Canon EOS Kiss X70" ], + "make_model": [ "Canon EOS 1200D", "Canon EOS Rebel T5", "Canon EOS 600D", "Canon EOS Rebel T3i" ], "dcraw_matrix": [ 6461,-907,-882,-4300,12184,2378,-819,1944,5931 ], // dcp D65 colormatrix2 "ranges": { "white": [ @@ -819,13 +772,41 @@ 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.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 } // ] } }, { // 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 Kiss X6i", "Canon EOS 700D", "Canon EOS Rebel T5i", "Canon EOS Kiss X7i" ], + "make_model": [ "Canon EOS 650D", "Canon EOS Rebel T4i", "Canon EOS 700D", "Canon EOS Rebel T5i" ], "dcraw_matrix": [ 6602,-841,-939,-4472,12458,2247,-975,2039,6148 ], "ranges": { "white": [ @@ -845,13 +826,14 @@ 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.2, "scale_factor": 1.000 }, // + { "aperture": 3.5, "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 Kiss X8i", "Canon EOS 760D", "Canon EOS Rebel T6s", "Canon EOS 8000D" ], + "make_model": [ "Canon EOS 750D", "Canon EOS Rebel T6i", "Canon EOS 760D", "Canon EOS Rebel T6s" ], "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 ], @@ -879,38 +861,6 @@ 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 ], @@ -970,7 +920,6 @@ 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 @@ -998,16 +947,33 @@ Quality X: unknown, ie we knowing to little about the camera properties to know ] } }, - -// 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 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 } // + ] + } }, { // Quality B, experimental infrared support commented out @@ -1018,17 +984,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 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 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 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 @@ -1040,14 +1006,6 @@ 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 @@ -1056,9 +1014,8 @@ 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 G5 X", "Canon PowerShot G9 X" ], + "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 @@ -1066,6 +1023,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 A, changes for raw crop which is wrong (larger) in Dcraw "make_model": "Canon PowerShot S120", "dcraw_matrix": [ 6961,-1685,-695,-4625,12945,1836,-1114,2152,5518 ], @@ -1074,6 +1039,15 @@ 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 @@ -1112,19 +1086,12 @@ 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 @@ -1143,7 +1110,6 @@ 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 @@ -1188,9 +1154,6 @@ 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", @@ -1256,22 +1219,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 + { // Quality B, aperture scaling used to scale WL at safer levels "make_model": "Nikon D5300", "dcraw_matrix": [ 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 ], // adobe dng_v8.8 d65 - "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 + "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 }, - { // Quality B + { // Quality B, aperture scaling used to scale WL at safer levels "make_model": "Nikon D5500", "dcraw_matrix": [ 8821,-2938,-785,-4178,12142,2287,-824,1651,6860 ], // adobe dng_v9.0 d65 - "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 + "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 }, - { // Quality B + { // Quality B, color matrix from DNG_v9.0 instead of internal Dcraw_v9.25_r1.475, "make_model": "Nikon D7200", "dcraw_matrix": [ 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 ], // adobe dng_v9.0 d65 - "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, + "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, }, { // quality B, samples by joachip at RT forums, are measures at long exposures with LongExposureNoiseReduction @@ -1289,12 +1252,12 @@ Quality X: unknown, ie we knowing to little about the camera properties to know ], "white_max": 16383 } - }, - { // quality B, missing WL measures at intermediate ISOs (160-250-320 ..) and at long exposures with LongExposureNoiseReduction set to ON + }, + { // quality B, lacks WL measures at intermediate ISOs (160-250-320 ..) and measures at long exposures with LongExposureNoiseReduction // 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 ], + "raw_crop": [ 0, 0, 6034, 4028 ], // Dcraw has no raw crop for D610 "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 @@ -1304,24 +1267,25 @@ 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 ], // illuminant A + // "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, "ranges": { "white": [ 15500, 15500, 15500 ] } - // 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 - }, + // 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 + }, - { // 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 } // WL values for 14-bit files, RT auto adapts it for 12-bit files. TypicalWL 16383 set to 16300 for safety - }, + "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 + }, - { // 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": { @@ -1331,18 +1295,17 @@ 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 values for 14-bit files, RT auto adapts it for 12-bit files. Typical WL at 16383 + "ranges": { "white": 16300 } // WL 16300 is for 14-bit raws, for 12-bit files RT auto calculates the correct WL. 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 + "raw_crop": [ 0, 0, -6, -6 ], // largest valid, full 64Mp 9280x6938, official crop 0 0 9216 6912 - safe 5755 "ranges": { "white": [ { "iso": [ 100, 200 ], "levels": 3950 }, // normal 4080-4095, HR Dpreview 4047, IR 3956 @@ -1354,7 +1317,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 ], // Highres mode largest valid, full 80Mp 10400X7796, official crop 10 10 10368 7776 + // "raw_crop": [ 0, 0, 10372, -7780 ], // 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 @@ -1395,15 +1358,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 offset. - Dcraw/RT read the base black 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 offstet. + Dcraw/RT read the base offset 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 offset. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. 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 @@ -1415,20 +1378,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 offset. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. 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 offset. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. 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 offset. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. 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 @@ -1436,12 +1399,11 @@ Quality X: unknown, ie we knowing to little about the camera properties to know ] } }, - { // Quality A, samples by helices at Rt forums and Chris Power at github + { // Quality A, samples by helices at Rt forums "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 offset. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. 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 @@ -1452,13 +1414,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 offset. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "ranges": { "black": 15, "white": 4050 } // 15 is BL offstet. 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 offset. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset + "ranges": { "black": 14, "white": 4050 } // 15 is BL offstet. 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" ], @@ -1484,7 +1446,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 offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. 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 @@ -1495,21 +1457,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 offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. 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 offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. 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 offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. 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 @@ -1521,21 +1483,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 offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. 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 offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. 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 offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. 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 @@ -1547,7 +1509,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 offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. 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 @@ -1559,7 +1521,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 offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 16, // 16 is BL offstet. 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 @@ -1571,7 +1533,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 offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 16, // 16 is BL offstet. 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 @@ -1584,7 +1546,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 offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset 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 @@ -1597,7 +1559,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 offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset 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 @@ -1608,7 +1570,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 offset. Dcraw/RT read the base black from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 15 is BL offstet. Dcraw/RT read the base offset from exif and calculates total BL = BLbase+BLoffset "white": [ { "iso": 125, "levels": 3100 }, { "iso": 160, "levels": 3600 }, @@ -1621,7 +1583,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 base black from exif and calculates total BL = BLbase+BLoffset + "black": 16, // 16 is BL offset. Dcraw/RT read the BLbase 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 @@ -1633,7 +1595,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 offset. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset + "black": 15, // 16 is BL offstet. 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 @@ -1646,7 +1608,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. Dcraw/RT read the base BL from exif and calculates total BL = BLbase+BLoffset. + "black": 15, // 15 is BL offset calculated from exif data. "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 f10ae4b31..83ff98f95 100644 --- a/rtengine/ciecam02.cc +++ b/rtengine/ciecam02.cc @@ -180,36 +180,39 @@ void Ciecam02::curveJ (double br, double contr, int db, LUTf & outCurve, LUTu & } } -void Ciecam02::curveJfloat (float br, float contr, const LUTu & histogram, LUTf & outCurve) +void Ciecam02::curveJfloat (float br, float contr, int db, LUTf & outCurve, LUTu & histogram ) { + LUTf dcurve(65536, 0); + int skip = 1; // check if brightness curve is needed if (br > 0.00001f || br < -0.00001f) { - std::vector brightcurvePoints(9); - brightcurvePoints[0] = double(DCT_NURBS); + std::vector brightcurvePoints; + brightcurvePoints.resize(9); + brightcurvePoints.at(0) = double(DCT_NURBS); - brightcurvePoints[1] = 0.f; // black point. Value in [0 ; 1] range - brightcurvePoints[2] = 0.f; // black point. Value in [0 ; 1] range + brightcurvePoints.at(1) = 0.f; // black point. Value in [0 ; 1] range + brightcurvePoints.at(2) = 0.f; // black point. Value in [0 ; 1] range if (br > 0) { - brightcurvePoints[3] = 0.1f; // toe point - brightcurvePoints[4] = 0.1f + br / 150.0f; //value at toe point + brightcurvePoints.at(3) = 0.1f; // toe point + brightcurvePoints.at(4) = 0.1f + br / 150.0f; //value at toe point - brightcurvePoints[5] = 0.7f; // shoulder point - brightcurvePoints[6] = min(1.0f, 0.7f + br / 300.0f); //value at shoulder point + brightcurvePoints.at(5) = 0.7f; // shoulder point + brightcurvePoints.at(6) = min(1.0f, 0.7f + br / 300.0f); //value at shoulder point } else { - brightcurvePoints[3] = 0.1f - br / 150.0f; // toe point - brightcurvePoints[4] = 0.1f; // value at toe point + brightcurvePoints.at(3) = 0.1f - br / 150.0f; // toe point + brightcurvePoints.at(4) = 0.1f; // value at toe point - brightcurvePoints[5] = min(1.0f, 0.7f - br / 300.0f); // shoulder point - brightcurvePoints[6] = 0.7f; // value at shoulder point + brightcurvePoints.at(5) = min(1.0f, 0.7f - br / 300.0f); // shoulder point + brightcurvePoints.at(6) = 0.7f; // value at shoulder point } - brightcurvePoints[7] = 1.f; // white point - brightcurvePoints[8] = 1.f; // value at white point + brightcurvePoints.at(7) = 1.f; // white point + brightcurvePoints.at(8) = 1.f; // value at white point - DiagonalCurve brightcurve(brightcurvePoints, CURVES_MIN_POLY_POINTS); + DiagonalCurve* brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS / skip); // Applying brightness curve for (int i = 0; i < 32768; i++) { @@ -218,56 +221,67 @@ void Ciecam02::curveJfloat (float br, float contr, const LUTu & histogram, LUTf float val = (float)i / 32767.0f; // apply brightness curve - val = brightcurve.getVal (val); + val = brightcurve->getVal (val); - // store result - outCurve[i] = CLIPD(val); + // store result in a temporary array + dcurve[i] = CLIPD(val); } + delete brightcurve; } else { - // set the identity curve - outCurve.makeIdentity(32767.f); + // 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); + } } if (contr > 0.00001f || contr < -0.00001f) { // compute mean luminance of the image with the curve applied - float sum = 0.f; - float avg = 0.f; + int sum = 0; + float avg = 0; + //float sqavg = 0; for (int i = 0; i < 32768; i++) { - avg += outCurve[i] * histogram[i];//approximation for average : usage of L (lab) instead of J + avg += dcurve[i] * histogram[i];//approximation for average : usage of L (lab) instead of J sum += histogram[i]; } avg /= sum; - std::vector contrastcurvePoints(9); + //printf("avg=%f\n",avg); + std::vector contrastcurvePoints; + contrastcurvePoints.resize(9); + contrastcurvePoints.at(0) = double(DCT_NURBS); - contrastcurvePoints[0] = double(DCT_NURBS); + 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[1] = 0.f; // black point. Value in [0 ; 1] range - contrastcurvePoints[2] = 0.f; // black point. Value in [0 ; 1] range + 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[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(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[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 + contrastcurvePoints.at(7) = 1.f; // white point + contrastcurvePoints.at(8) = 1.f; // value at white point - contrastcurvePoints[7] = 1.f; // white point - contrastcurvePoints[8] = 1.f; // value at white point - - DiagonalCurve contrastcurve(contrastcurvePoints, CURVES_MIN_POLY_POINTS); + DiagonalCurve* contrastcurve = new DiagonalCurve (contrastcurvePoints, CURVES_MIN_POLY_POINTS / skip); // apply contrast enhancement - for (int i = 0; i < 32768; i++) { - outCurve[i] = contrastcurve.getVal(outCurve[i]); + for (int i = 0; i < (32768 * db); i++) { + dcurve[i] = contrastcurve->getVal (dcurve[i]); } + delete contrastcurve; } - outCurve *= 32767.f; + // 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]; + } } /** @@ -843,7 +857,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 a551b2504..e5b61d466 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, const LUTu & histogram, LUTf & outCurve ) ; + static void curveJfloat (float br, float contr, int db, LUTf & outCurve , LUTu & histogram ) ; /** * 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 4e180690e..3684891df 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -139,6 +139,7 @@ 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); @@ -184,14 +185,11 @@ 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); - } - gamma2curve.share(gammatab_srgb, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); // shares the buffer with gammatab_srgb but has different clip flags + 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 } + #ifdef _OPENMP #pragma omp section #endif diff --git a/rtengine/colortemp.cc b/rtengine/colortemp.cc index c99e4bd41..2ccbcba8d 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, const Glib::ustring &m) : temp(t), green(g), equal(e), method(m) +ColorTemp::ColorTemp (double t, double g, double e, 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) const +void ColorTemp::mul2temp (const double rmul, const double gmul, const double bmul, const double equal, double& temp, double& green) { 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) const +int ColorTemp::XYZtoCorColorTemp(double x0, double y0, double z0, double &temp) { 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) const +void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul, double& gmul, double& bmul) { clip (temp, green, equal); diff --git a/rtengine/colortemp.h b/rtengine/colortemp.h index a1a805092..c79ebb4bf 100644 --- a/rtengine/colortemp.h +++ b/rtengine/colortemp.h @@ -47,14 +47,12 @@ 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, const Glib::ustring &m); + ColorTemp (double t, double g, double e, 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) @@ -69,40 +67,42 @@ public: this->equal = equal; } - inline std::string getMethod() const + inline std::string getMethod() { return method; } - inline double getTemp () const + inline double getTemp () { return temp; } - inline double getGreen () const + inline double getGreen () { return green; } - inline double getEqual () const + inline double getEqual () { return equal; } - void getMultipliers (double &mulr, double &mulg, double &mulb) const + void getMultipliers (double &mulr, double &mulg, double &mulb) { 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) const; + 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); 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) const + bool operator== (const ColorTemp& other) { return fabs(temp - other.temp) < 1e-10 && fabs(green - other.green) < 1e-10; } - bool operator!= (const ColorTemp& other) const + bool operator!= (const ColorTemp& other) { return !(*this == other); } diff --git a/rtengine/curves.cc b/rtengine/curves.cc index 9b68cc9ee..158086cfd 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -16,13 +16,12 @@ * 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 @@ -44,7 +43,7 @@ using namespace std; namespace rtengine { -Curve::Curve () : N(0), x(nullptr), y(nullptr), ypp(nullptr), hashSize(1000 /* has to be initialized to the maximum value */) {} +Curve::Curve () : N(0), x(NULL), y(NULL), ypp(NULL), hashSize(1000 /* has to be initialized to the maximum value */ ) {} void Curve::AddPolygons () { @@ -70,18 +69,6 @@ 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); @@ -168,9 +155,11 @@ void Curve::getControlPoint(int cpNum, double &x, double &y) const const double CurveFactory::sRGBGamma = 2.2; const double CurveFactory::sRGBGammaCurve = 2.4; -void fillCurveArray(DiagonalCurve* diagCurve, LUTf &outCurve, int skip, bool needed) +SSEFUNCTION 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 @@ -178,157 +167,353 @@ void fillCurveArray(DiagonalCurve* diagCurve, LUTf &outCurve, int skip, bool nee // apply custom/parametric/NURBS curve, if any val = diagCurve->getVal (val); // store result in a temporary array - outCurve[i] = val; + lutCurve[i] = (val); } // if skip>1, let apply linear interpolation in the skipped points of the curve if (skip > 1) { - float skipmul = 1.f / (float) skip; + int prev = 0; - 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; + for (int i = 1; i <= 0xffff - skip; i++) { + if (i % skip == 0) { + prev += skip; + continue; } + + lutCurve[i] = ( lutCurve[prev] * (skip - i % skip) + lutCurve[prev + skip] * (i % skip) ) / skip; } } - outCurve *= 65535.f; + for (int i = 0; i <= 0xffff; i++) { + outCurve[i] = (65535.f * lutCurve[i]); + } } else { - outCurve.makeIdentity(); +#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] ; + } } } -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) + +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) { 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) { - DiagonalCurve tcurve(curvePoints3, CURVES_MIN_POLY_POINTS / skip); + tcurve = new DiagonalCurve (curvePoints3, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogramC) { - histogramC.compressTo(outBeforeCCurveHistogramC, 48000); + if (outBeforeCCurveHistogramC /*&& histogramCropped*/) { + histNeededC = true; } - if (!tcurve.isIdentity()) { - customColCurve3.Set(tcurve); - } } + if (tcurve) { + if (tcurve->isIdentity()) { + delete tcurve; + tcurve = NULL; + } else { + customColCurve3.Set(tcurve); + } + + delete tcurve; + tcurve = NULL; + } customColCurve2.Reset(); if (!curvePoints2.empty() && curvePoints2[0] > DCT_Linear && curvePoints2[0] < DCT_Unchanged) { - DiagonalCurve tcurve(curvePoints2, CURVES_MIN_POLY_POINTS / skip); + tcurve = new DiagonalCurve (curvePoints2, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogram) { + if (outBeforeCCurveHistogram /*&& histogramCropped*/) { histNeeded = true; } - if (!tcurve.isIdentity()) { - customColCurve2.Set(tcurve); - } } + if (tcurve) { + if (tcurve->isIdentity()) { + delete tcurve; + tcurve = NULL; + } else { + 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) { - DiagonalCurve tcurve(curvePoints1, CURVES_MIN_POLY_POINTS / skip); + tcurve = new DiagonalCurve (curvePoints1, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogram) { + if (outBeforeCCurveHistogram /*&& histogramCropped*/) { histNeeded = true; } - if (!tcurve.isIdentity()) { + } + + if (tcurve) { + if (tcurve->isIdentity()) { + delete tcurve; + tcurve = NULL; + } else { customColCurve1.Set(tcurve); + delete tcurve; + tcurve = NULL; } } if (histNeeded) { - histogram.compressTo(outBeforeCCurveHistogram, 32768); + 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; } } -void CurveFactory::curveBW ( const std::vector& curvePointsbw, const std::vector& curvePointsbw2, - const LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw,//for Luminance - ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip) -{ +void CurveFactory::curveBW ( + const std::vector& curvePointsbw, const std::vector& curvePointsbw2, + 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) { - DiagonalCurve tcurve(curvePointsbw2, CURVES_MIN_POLY_POINTS / skip); + tcurve = new DiagonalCurve (curvePointsbw2, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogrambw) { + if (outBeforeCCurveHistogrambw /*&& histogramCropped*/) { histNeeded = true; } - if (!tcurve.isIdentity()) { - customToneCurvebw2.Set(tcurve, gamma_); - } } + if (tcurve) { + if (!tcurve->isIdentity()) { + customToneCurvebw2.Set(tcurve, gamma_, start, slope, mul, add); + } + + delete tcurve; + tcurve = NULL; + } customToneCurvebw1.Reset(); if (!curvePointsbw.empty() && curvePointsbw[0] > DCT_Linear && curvePointsbw[0] < DCT_Unchanged) { - DiagonalCurve tcurve(curvePointsbw, CURVES_MIN_POLY_POINTS / skip); + tcurve = new DiagonalCurve (curvePointsbw, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogrambw ) { + if (outBeforeCCurveHistogrambw /*&& histogramCropped*/) { histNeeded = true; } - if (!tcurve.isIdentity()) { - customToneCurvebw1.Set(tcurve, gamma_); - } } + if (tcurve) { + if (!tcurve->isIdentity()) { + customToneCurvebw1.Set(tcurve, gamma_, start, slope, mul, add); + } + + delete tcurve; + tcurve = NULL; + } // create first curve if needed if (histNeeded) { - histogrambw.compressTo(outBeforeCCurveHistogrambw, 32768); - } -} + 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] ; + } + } + + if (tcurve) { + delete tcurve; + } + +} // add curve Lab : C=f(L) -void CurveFactory::curveCL ( bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, int skip) +void CurveFactory::curveCL ( bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, LUTu & histogramcl, LUTu & outBeforeCLurveHistogram, int skip) { - clcutili = false; - std::unique_ptr dCurve; + bool needed; + DiagonalCurve* dCurve = NULL; + + if (outBeforeCLurveHistogram) { + outBeforeCLurveHistogram.clear(); + } + + bool histNeededCL = false; + + needed = false; if (!clcurvePoints.empty() && clcurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(clcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = new DiagonalCurve (clcurvePoints, CURVES_MIN_POLY_POINTS / skip); + + if (outBeforeCLurveHistogram) { + histNeededCL = true; + } if (dCurve && !dCurve->isIdentity()) { + needed = true; clcutili = true; } } - fillCurveArray(dCurve.get(), clCurve, skip, clcutili); + 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; + } } -void CurveFactory::mapcurve ( bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram) +void CurveFactory::mapcurve ( bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, LUTu & histogram, LUTu & outBeforeCurveHistogram) { bool needed = false; - std::unique_ptr dCurve; + DiagonalCurve* dCurve = NULL; outBeforeCurveHistogram.clear(); bool histNeeded = false; if (!mapcurvePoints.empty() && mapcurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(mapcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = new DiagonalCurve (mapcurvePoints, CURVES_MIN_POLY_POINTS / skip); if (outBeforeCurveHistogram) { histNeeded = true; @@ -341,21 +526,33 @@ void CurveFactory::mapcurve ( bool & mapcontlutili, const std::vector& m } if (histNeeded) { - histogram.compressTo(outBeforeCurveHistogram, 32768); + for (int i = 0; i < 32768; i++) { + double hval = CLIPD((double)i / 32767.0); + int hi = (int)(255.0 * hval); + outBeforeCurveHistogram[hi] += histogram[i] ; + } } - fillCurveArray(dCurve.get(), mapcurve, skip, needed); + fillCurveArray(dCurve, mapcurve, skip, needed); + + if (dCurve) { + delete dCurve; + dCurve = NULL; + } } -void CurveFactory::curveDehaContL ( bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram) + + + +void CurveFactory::curveDehaContL ( bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, LUTu & histogram, LUTu & outBeforeCurveHistogram) { bool needed = false; - std::unique_ptr dCurve; + DiagonalCurve* dCurve = NULL; outBeforeCurveHistogram.clear(); bool histNeeded = false; if (!dehaclcurvePoints.empty() && dehaclcurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(dehaclcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = new DiagonalCurve (dehaclcurvePoints, CURVES_MIN_POLY_POINTS / skip); if (outBeforeCurveHistogram) { histNeeded = true; @@ -368,20 +565,37 @@ void CurveFactory::curveDehaContL ( bool & dehacontlutili, const std::vector& wavclcurvePoints, LUTf & wavclCurve, /*LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,*/int skip) { - bool needed = false; - std::unique_ptr dCurve; + bool needed; + DiagonalCurve* dCurve = NULL; + + // if (outBeforeWavCLurveHistogram) + // outBeforeWavCLurveHistogram.clear(); + bool histNeededCL = false; + + needed = false; if (!wavclcurvePoints.empty() && wavclcurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(wavclcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = new DiagonalCurve (wavclcurvePoints, CURVES_MIN_POLY_POINTS / skip); + // if (outBeforeWavCLurveHistogram) + // histNeededCL = true; if (dCurve && !dCurve->isIdentity()) { needed = true; @@ -389,89 +603,212 @@ void CurveFactory::curveWavContL ( bool & wavcontlutili, const std::vector& curvePoints, LUTf & ToningCurve, int skip) +// add curve Colortoning : C=f(L) +void CurveFactory::curveToningCL ( bool & clctoningutili, const std::vector& clcurvePoints, LUTf & clToningCurve, int skip) { - bool needed = false; - std::unique_ptr dCurve; + bool needed; + DiagonalCurve* dCurve = NULL; - if (!curvePoints.empty() && curvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); + needed = false; + + if (!clcurvePoints.empty() && clcurvePoints[0] != 0) { + dCurve = new DiagonalCurve (clcurvePoints, CURVES_MIN_POLY_POINTS / skip); if (dCurve && !dCurve->isIdentity()) { needed = true; + clctoningutili = true; } } - fillCurveArray(dCurve.get(), ToningCurve, skip, needed); + fillCurveArray(dCurve, clToningCurve, skip, needed); + + // clToningCurve.dump("CLToning"); + if (dCurve) { + delete dCurve; + dCurve = NULL; + } } +// 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 (bool & autili, bool & butili, bool & ccutili, bool & cclutili, +void CurveFactory::complexsgnCurve (float adjustr, bool & autili, bool & butili, bool & ccutili, bool & cclutili, double saturation, double rstprotection, 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) { - autili = butili = ccutili = cclutili = false; - std::unique_ptr dCurve; + + //----------------------------------------------------- + + 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; // create a curve if needed if (!acurvePoints.empty() && acurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(acurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = new DiagonalCurve (acurvePoints, CURVES_MIN_POLY_POINTS / skip); if (dCurve && !dCurve->isIdentity()) { + needed = true; autili = true; } } - fillCurveArray(dCurve.get(), aoutCurve, skip, autili); + fillCurveArray(dCurve, aoutCurve, skip, needed); + //if(autili) aoutCurve.dump("acurve"); - dCurve = nullptr; + if (dCurve) { + delete dCurve; + dCurve = NULL; + } //----------------------------------------------------- + needed = false; + if (!bcurvePoints.empty() && bcurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(bcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = new DiagonalCurve (bcurvePoints, CURVES_MIN_POLY_POINTS / skip); if (dCurve && !dCurve->isIdentity()) { + needed = true; butili = true; } } - fillCurveArray(dCurve.get(), boutCurve, skip, butili); + fillCurveArray(dCurve, boutCurve, skip, needed); - dCurve = nullptr; + if (dCurve) { + delete dCurve; + dCurve = NULL; + } //----------------------------------------------- + needed = false; if (!cccurvePoints.empty() && cccurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(cccurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = new DiagonalCurve (cccurvePoints, CURVES_MIN_POLY_POINTS / skip); + + if (outBeforeCCurveHistogram /*&& histogramCropped*/) { + histNeededC = true; + } if (dCurve && !dCurve->isIdentity()) { + needed = true; ccutili = true; } } - fillCurveArray(dCurve.get(), satCurve, skip, ccutili); + 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] ; + } + } - dCurve = nullptr; + fillCurveArray(dCurve, satCurve, skip, needed); + + if (dCurve) { + delete dCurve; + dCurve = NULL; + } //---------------------------- + needed = false; if (!lccurvePoints.empty() && lccurvePoints[0] != 0) { - dCurve = std::unique_ptr(new DiagonalCurve(lccurvePoints, CURVES_MIN_POLY_POINTS / skip)); + dCurve = new DiagonalCurve (lccurvePoints, CURVES_MIN_POLY_POINTS / skip); + + if (outBeforeLCurveHistogram /*&& histogramCropped*/) { + histNeededLC = true; + } if (dCurve && !dCurve->isIdentity()) { + needed = true; cclutili = true; } } - fillCurveArray(dCurve.get(), lhskCurve, skip, cclutili); + 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; + } } @@ -483,7 +820,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 & histogram, LUTu & histogramCropped, LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, ToneCurve & customToneCurve1, @@ -509,35 +846,36 @@ 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 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - std::unique_ptr brightcurve; + DiagonalCurve* brightcurve = NULL; // check if brightness curve is needed if (br > 0.00001 || br < -0.00001) { - std::vector brightcurvePoints(9); - brightcurvePoints[0] = DCT_NURBS; + std::vector brightcurvePoints; + brightcurvePoints.resize(9); + brightcurvePoints.at(0) = double(DCT_NURBS); - brightcurvePoints[1] = 0.; //black point. Value in [0 ; 1] range - brightcurvePoints[2] = 0.; //black point. Value in [0 ; 1] range + brightcurvePoints.at(1) = 0.; //black point. Value in [0 ; 1] range + brightcurvePoints.at(2) = 0.; //black point. Value in [0 ; 1] range if(br > 0) { - brightcurvePoints[3] = 0.1; //toe point - brightcurvePoints[4] = 0.1 + br / 150.0; //value at toe point + brightcurvePoints.at(3) = 0.1; //toe point + brightcurvePoints.at(4) = 0.1 + br / 150.0; //value at toe point - brightcurvePoints[5] = 0.7; //shoulder point - brightcurvePoints[6] = min(1.0, 0.7 + br / 300.0); //value at shoulder point + brightcurvePoints.at(5) = 0.7; //shoulder point + brightcurvePoints.at(6) = min(1.0, 0.7 + br / 300.0); //value at shoulder point } else { - brightcurvePoints[3] = max(0.0, 0.1 - br / 150.0); //toe point - brightcurvePoints[4] = 0.1; //value at toe point + brightcurvePoints.at(3) = max(0.0, 0.1 - br / 150.0); //toe point + brightcurvePoints.at(4) = 0.1; //value at toe point - brightcurvePoints[5] = 0.7 - br / 300.0; //shoulder point - brightcurvePoints[6] = 0.7; //value at shoulder point + brightcurvePoints.at(5) = 0.7 - br / 300.0; //shoulder point + brightcurvePoints.at(6) = 0.7; //value at shoulder point } - brightcurvePoints[7] = 1.; // white point - brightcurvePoints[8] = 1.; // value at white point + brightcurvePoints.at(7) = 1.; // white point + brightcurvePoints.at(8) = 1.; // value at white point - brightcurve = std::unique_ptr(new DiagonalCurve(brightcurvePoints, CURVES_MIN_POLY_POINTS / skip)); + brightcurve = new DiagonalCurve (brightcurvePoints, CURVES_MIN_POLY_POINTS / skip); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -547,52 +885,26 @@ 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) { - hlCurve.makeConstant(exp_scale); - } else { - hlCurve.makeConstant(exp_scale, shoulder + 1); + 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; + } float scalemshoulder = scale - shoulder; -#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 + for (int i = shoulder + 1; i < 0x10000; i++) { // 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 - } @@ -603,11 +915,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 = Color::gammatab_srgb[0] / 65535.f; + val = gamma (val, gamma_, start, slope, mul, add); // apply brightness curve if (brightcurve) { @@ -617,25 +929,30 @@ 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 = i / 65535.f; + float val; + val = (float)i / 65535.0f; float val2 = simplebasecurve (val, black, 0.015 * shcompr); - shCurve[i] = val2 / val; + shCurve[i] = CLIPD(val2) / val; // gamma correction - val = Color::gammatab_srgb[i] / 65535.f; + val = gamma (val, gamma_, start, slope, mul, add); // apply brightness curve if (brightcurve) { - val = CLIPD(brightcurve->getVal (val)); // TODO: getVal(double) is very slow! Optimize with a LUTf + val = brightcurve->getVal (val); // TODO: getVal(double) is very slow! Optimize with a LUTf } // store result in a temporary array - dcurve[i] = val; + dcurve[i] = CLIPD(val); } - brightcurve = nullptr; + if (brightcurve) { + delete brightcurve; + } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -648,57 +965,71 @@ 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 * hlCurve[i]; + float fi = i; + fi *= 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(9); - contrastcurvePoints[0] = DCT_NURBS; + std::vector contrastcurvePoints; + contrastcurvePoints.resize(9); + contrastcurvePoints.at(0) = double(DCT_NURBS); - contrastcurvePoints[1] = 0; //black point. Value in [0 ; 1] range - contrastcurvePoints[2] = 0; //black point. Value in [0 ; 1] range + contrastcurvePoints.at(1) = 0; //black point. Value in [0 ; 1] range + contrastcurvePoints.at(2) = 0; //black point. Value in [0 ; 1] range - 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(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[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(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[7] = 1.; // white point - contrastcurvePoints[8] = 1.; // value at white point + contrastcurvePoints.at(7) = 1.; // white point + contrastcurvePoints.at(8) = 1.; // value at white point - const DiagonalCurve contrastcurve(contrastcurvePoints, CURVES_MIN_POLY_POINTS / skip); + DiagonalCurve* contrastcurve = new DiagonalCurve (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) { - const DiagonalCurve tcurve(curvePoints2, CURVES_MIN_POLY_POINTS / skip); + tcurve = new DiagonalCurve (curvePoints2, CURVES_MIN_POLY_POINTS / skip); - if (!tcurve.isIdentity()) { - customToneCurve2.Set(tcurve, gamma_); - } - - if (outBeforeCCurveHistogram ) { + if (outBeforeCCurveHistogram /*&& histogramCropped*/) { histNeeded = true; } } + if (tcurve) { + if (!tcurve->isIdentity()) { + customToneCurve2.Set(tcurve, gamma_, start, slope, mul, add); + } + + delete tcurve; + tcurve = NULL; + } + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -707,52 +1038,90 @@ SSEFUNCTION void CurveFactory::complexCurve (double ecomp, double black, double customToneCurve1.Reset(); if (!curvePoints.empty() && curvePoints[0] > DCT_Linear && curvePoints[0] < DCT_Unchanged) { - const DiagonalCurve tcurve(curvePoints, CURVES_MIN_POLY_POINTS / skip); + tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS / skip); - if (!tcurve.isIdentity()) { - customToneCurve1.Set(tcurve, gamma_); - } - - if (outBeforeCCurveHistogram) { + if (outBeforeCCurveHistogram /*&& histogramCropped*/) { histNeeded = true; } } - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + if (tcurve) { + if (!tcurve->isIdentity()) { + customToneCurve1.Set(tcurve, gamma_, start, slope, mul, add); + } -#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); + delete tcurve; + tcurve = NULL; } -#else + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + // 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; + } + } + */ + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 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); } -#endif - - 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] ; - } + if (tcurve) { + delete tcurve; } + + /*if (outBeforeCCurveHistogram) { + for (int i=0; i<256; i++) printf("i= %d bchist= %d \n",i,outBeforeCCurveHistogram[i]); + }*/ } @@ -761,11 +1130,13 @@ SSEFUNCTION void CurveFactory::complexCurve (double ecomp, double black, double //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void CurveFactory::complexLCurve (double br, double contr, const std::vector& curvePoints, - const LUTu & histogram, LUTf & outCurve, + LUTu & histogram, LUTu & histogramCropped, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, int skip, bool & utili) { - utili = false; + // curve without contrast + LUTf dcurve(65536, 0); + // clear array that stores histogram valid before applying the custom curve if (outBeforeCCurveHistogram) { outBeforeCCurveHistogram.clear(); @@ -803,7 +1174,7 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vectorgetVal (val); // store result in a temporary array - outCurve[i] = CLIPD(val); + dcurve[i] = CLIPD(val); } + delete brightcurve; } else { - outCurve.makeIdentity(32767.f); + 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; + } } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -831,21 +1206,27 @@ 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 += outCurve[i] * histogram[i]; + avg += dcurve[i] * histogram[i]; + //sqavg += dcurve[i]*dcurve[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); @@ -861,10 +1242,12 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vector contrastcurvePoints; contrastcurvePoints.resize(5); contrastcurvePoints.at(0) = double(DCT_NURBS); @@ -874,34 +1257,35 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vectorgetVal (dcurve[i]); } + delete contrastcurve; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // create a curve if needed - std::unique_ptr tcurve; + DiagonalCurve* tcurve = NULL; bool histNeeded = false; if (!curvePoints.empty() && curvePoints[0] != 0) { - tcurve = std::unique_ptr(new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS / skip)); + tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS / skip); - if (outBeforeCCurveHistogram) { + if (outBeforeCCurveHistogram /*&& histogramCropped*/) { histNeeded = true; } } if (tcurve && tcurve->isIdentity()) { - tcurve = nullptr; + delete tcurve; + tcurve = NULL; } if (tcurve) { @@ -912,32 +1296,41 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vectorgetVal (outCurve[i]); + val = tcurve->getVal (dcurve[i]); - outCurve[i] = (32767.f * val); + outCurve[i] = (32767.0 * 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 - if(histNeeded) { - histogram.compressTo(outBeforeCCurveHistogram, 32768, outCurve); + 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]; } - - outCurve *= 32767.f; - } - for (int i = 32768; i < 32770; i++) { // set last two elements of lut to 32768 and 32769 to allow linear interpolation + for (int i = 32768; i < 65536; i++) { 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]); + }*/ } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -947,15 +1340,19 @@ void CurveFactory::complexLCurve (double br, double contr, const std::vector& curvePoints, LUTf & outCurve, int skip) { + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // create a curve if needed - std::unique_ptr tcurve; + DiagonalCurve* tcurve = NULL; if (!curvePoints.empty() && curvePoints[0] != 0) { - tcurve = std::unique_ptr(new DiagonalCurve(curvePoints, CURVES_MIN_POLY_POINTS / skip)); + tcurve = new DiagonalCurve (curvePoints, CURVES_MIN_POLY_POINTS / skip); } if (tcurve && tcurve->isIdentity()) { - tcurve = nullptr; + delete tcurve; + tcurve = NULL; } if (tcurve) { @@ -965,14 +1362,23 @@ 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 = Color::gamma2curve[i] / 65535.f; + float val = float(i) / 65535.f; + val = CurveFactory::gamma2 (val); val = tcurve->getVal(val); - outCurve[i] = Color::igammatab_srgb[val * 65535.f]; + val = CurveFactory::igamma2 (val); + //float val = tcurve->getVal ((float)i/65536.0f); + outCurve[i] = (65536.0f * val); } - } else { // let the LUTf empty for identity curves + + delete tcurve; + } + // let the LUTf empty for identity curves + else { outCurve.reset(); } + } @@ -982,12 +1388,12 @@ void ColorAppearance::Reset() } // Fill a LUT with X/Y, ranged 0xffff -void ColorAppearance::Set(const Curve &pCurve) +void ColorAppearance::Set(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.; } } @@ -1063,34 +1469,20 @@ void ToneCurve::Reset() } // Fill a LUT with X/Y, ranged 0xffff -void ToneCurve::Set(const Curve &pCurve, float gamma) +void ToneCurve::Set(Curve *pCurve, float gamma, float start, float slope, float mul, float add) { 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; } @@ -1120,17 +1512,18 @@ void OpacityCurve::Set(const Curve *pCurve) void OpacityCurve::Set(const std::vector &curvePoints, bool &opautili) { - std::unique_ptr tcurve; + FlatCurve* tcurve = NULL; if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { - tcurve = std::unique_ptr(new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); + tcurve = new FlatCurve (curvePoints, false, CURVES_MIN_POLY_POINTS / 2); tcurve->setIdentityValue(0.); } if (tcurve) { - Set(tcurve.get()); + Set(tcurve); opautili = true; - tcurve = nullptr; + delete tcurve; + tcurve = NULL; } } @@ -1503,14 +1896,16 @@ 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) { - std::unique_ptr tcurve; + FlatCurve* tcurve = NULL; if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { - tcurve = std::unique_ptr(new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); + tcurve = new FlatCurve (curvePoints, false, CURVES_MIN_POLY_POINTS / 2); } if (tcurve) { - SetXYZ(tcurve.get(), xyz_rgb, rgb_xyz, satur, lumin); + SetXYZ(tcurve, xyz_rgb, rgb_xyz, satur, lumin); + delete tcurve; + tcurve = NULL; } } @@ -1602,14 +1997,16 @@ 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]) { - std::unique_ptr tcurve; + FlatCurve* tcurve = NULL; if (!curvePoints.empty() && curvePoints[0] > FCT_Linear && curvePoints[0] < FCT_Unchanged) { - tcurve = std::unique_ptr(new FlatCurve(curvePoints, false, CURVES_MIN_POLY_POINTS / 2)); + tcurve = new FlatCurve (curvePoints, false, CURVES_MIN_POLY_POINTS / 2); } if (tcurve) { - SetRGB(tcurve.get(), xyz_rgb, rgb_xyz); + SetRGB(tcurve, xyz_rgb, rgb_xyz); + delete tcurve; + tcurve = NULL; } } diff --git a/rtengine/curves.h b/rtengine/curves.h index a06502c71..0adc735be 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -159,9 +159,7 @@ 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.0) { - return x; - } else if (b < 0) { + 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 @@ -177,7 +175,7 @@ protected: double y = (m - b) * slope; if (x <= m) { - return clower (x / m, slope * m / y, sr) * y; + return b == 0 ? x * slope : clower (x / m, slope * m / y, sr) * y; } else { return y + (x - m) * slope; } @@ -240,18 +238,13 @@ public: } static inline float gamma (float x, float gamma, float start, float slope, float mul, float add) { - return (x <= start ? x*slope : xexpf(xlogf(x) / gamma) * mul - add); + return (x <= start ? x*slope : expf(logf(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 : xexpf(xlogf((x + add) / mul) * gamma) ); + return (x <= start * slope ? x / slope : expf(logf((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) { @@ -278,31 +271,42 @@ 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, LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, ToneCurve & outToneCurve, ToneCurve & outToneCurve2, + + LUTu & histogram, LUTu & histogramCropped, + 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, const LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw, + static void curveBW (const std::vector& curvePointsbw, const std::vector& curvePointsbw2, LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw, ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip); - static void curveCL ( bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, int skip); + static void curveCL ( bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, LUTu & histogramcl, LUTu & outBeforeCLurveHistogram, 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, 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 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 curveToning ( const std::vector& curvePoints, LUTf & ToningCurve, int skip); + 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 complexsgnCurve ( bool & autili, bool & butili, bool & ccutili, bool & clcutili, const std::vector& acurvePoints, + static void complexsgnCurve ( float adjustr, bool & autili, bool & butili, bool & ccutili, bool & clcutili, double saturation, double rstprotection, 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, const LUTu & histogram, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, int skip, bool & utili); + 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 curveLightBrightColor ( - const std::vector& curvePoints, - const std::vector& curvePoints2, - const std::vector& curvePoints3, - const LUTu & histogram, LUTu & outBeforeCCurveHistogram, - const LUTu & histogramC, LUTu & outBeforeCCurveHistogramC, + 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, ColorAppearance & outColCurve1, ColorAppearance & outColCurve2, ColorAppearance & outColCurve3, @@ -333,7 +337,6 @@ 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] @@ -355,11 +358,11 @@ protected: } static inline double p01 (double x, double prot) { - 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; + 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; } static inline double p10 (double x, double prot) { - 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; + 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; } static inline double pfull (double x, double prot, double sh, double hl) { @@ -367,7 +370,6 @@ protected: } void fillHash(); - void fillDyByDx(); public: Curve (); @@ -405,7 +407,7 @@ public: class FlatCurve : public Curve { -private: +protected: FlatCurveType kind; double* leftTangent; double* rightTangent; @@ -486,7 +488,7 @@ public: virtual ~ToneCurve() {}; void Reset(); - void Set(const Curve &pCurve, float gamma = 0); + void Set(Curve *pCurve, float gamma = 0, float start = 0, float slope = 0, float mul = 0, float add = 0); operator bool (void) const { return lutToneCurve; @@ -710,7 +712,7 @@ public: virtual ~ColorAppearance() {}; void Reset(); - void Set(const Curve &pCurve); + void Set(Curve *pCurve); operator bool (void) const { return lutColCurve; diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 775428a4e..c05230738 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -16,7 +16,6 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ - #include #include "dcp.h" @@ -26,46 +25,305 @@ #include "improcfun.h" #include "rt_math.h" +using namespace std; using namespace rtengine; using namespace rtexif; -namespace -{ +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 +}; // This sRGB gamma is taken from DNG reference code, with the added linear extension past 1.0, as we run clipless here -float srgbGammaForward(float x) +static float sRGBGammaForward (const float x) { - 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; + 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); + } } -float srgbGammaInverse(float y) +static void Invert3x3(const double (*A)[3], double (*B)[3]) { - 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); -} -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]; + 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]; temp[0][0] = a11 * a22 - a21 * a12; temp[0][1] = a21 * a02 - a01 * a22; @@ -77,79 +335,79 @@ void invert3x3(const DCPProfile::Matrix& a, DCPProfile::Matrix& b) temp[2][1] = a20 * a01 - a00 * a21; temp[2][2] = a00 * a11 - a10 * a01; - const double det = a00 * temp[0][0] + a01 * temp[1][0] + a02 * temp[2][0]; + 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; } } } -void multiply3x3(const DCPProfile::Matrix& a, const DCPProfile::Matrix& b, DCPProfile::Matrix& c) +static void Multiply3x3(const double (*A)[3], const double (*B)[3], double (*C)[3]) { - // Use temp to support having output same as input - DCPProfile::Matrix m; - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - m[i][j] = 0; + // use temp to support having output same as input + double M[3][3]; - for (int k = 0; k < 3; ++k) { - m[i][j] += a[i][k] * b[k][j]; + 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]; } } } - c = m; + memcpy(C, M, 3 * 3 * sizeof(double)); } -void multiply3x3_v3(const DCPProfile::Matrix& a, const DCPProfile::Triple& b, DCPProfile::Triple& c) +static void Multiply3x3_v3(const double (*A)[3], const double B[3], double C[3]) { - // Use temp to support having output same as input - DCPProfile::Triple m = {}; - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - m[i] += a[i][j] * b[j]; + // 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]; } } - c = m; + memcpy(C, M, 3 * sizeof(double)); } -void mix3x3(const DCPProfile::Matrix& a, double mul_a, const DCPProfile::Matrix& b, double mul_b, DCPProfile::Matrix& c) +static void Mix3x3(const double (*A)[3], double mulA, const double (*B)[3], double mulB, double (*C)[3]) { - DCPProfile::Matrix m; - 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; + 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; } } - c = m; + memcpy(C, M, 3 * 3 * sizeof(double)); } -void mapWhiteMatrix(const DCPProfile::Triple& white1, const DCPProfile::Triple& white2, DCPProfile::Matrix& b) +static void MapWhiteMatrix(const double white1[3], const double white2[3], double (*B)[3]) { - // 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 } - }}; + // code adapted from dng_color_spec::MapWhiteMatrix - DCPProfile::Triple w1; - multiply3x3_v3(mb, white1, w1); - DCPProfile::Triple w2; - multiply3x3_v3(mb, white2, w2); + // 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); // Negative white coordinates are kind of meaningless. w1[0] = std::max(w1[0], 0.0); @@ -160,34 +418,36 @@ void mapWhiteMatrix(const DCPProfile::Triple& white1, const DCPProfile::Triple& w2[2] = std::max(w2[2], 0.0); // Limit scaling to something reasonable. - 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 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 temp; - invert3x3(mb, temp); - multiply3x3(temp, a, temp); - multiply3x3(temp, mb, b); + double temp[3][3]; + Invert3x3(Mb, temp); + Multiply3x3(temp, A, temp); + Multiply3x3(temp, Mb, B); } -void xyzToXy(const DCPProfile::Triple& xyz, double xy[2]) +static void XYZtoXY(const double XYZ[3], double XY[2]) { - const double total = xyz[0] + xyz[1] + xyz[2]; + double X = XYZ[0]; + double Y = XYZ[1]; + double Z = XYZ[2]; + double total = X + Y + Z; if (total > 0.0) { - xy[0] = xyz[0] / total; - xy[1] = xyz[1] / total; + XY[0] = X / total; + XY[1] = Y / total; } else { - xy[0] = 0.3457; - xy[1] = 0.3585; + XY[0] = 0.3457; + XY[1] = 0.3585; } } -void xyToXyz(const double xy[2], DCPProfile::Triple& xyz) +static void XYtoXYZ(const double XY[2], double XYZ[3]) { - 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. @@ -200,1209 +460,106 @@ void xyToXyz(const double xy[2], DCPProfile::Triple& xyz) 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]; } -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 (LightSource(light)) { - case LightSource::STANDARD_LIGHT_A: - case LightSource::TUNGSTEN: { - return 2850.0; - } - - case LightSource::ISO_STUDIO_TUNGSTEN: { - return 3200.0; - } - - case LightSource::D50: { - return 5000.0; - } - - case LightSource::D55: - case LightSource::DAYLIGHT: - case LightSource::FINE_WEATHER: - case LightSource::FLASH: - case LightSource::STANDARD_LIGHT_B: { - return 5500.0; - } - - case LightSource::D65: - case LightSource::STANDARD_LIGHT_C: - case LightSource::CLOUDY_WEATHER: { - return 6500.0; - } - - case LightSource::D75: - case LightSource::SHADE: { - return 7500.0; - } - - case LightSource::DAYLIGHT_FLUORESCENT: { - return (5700.0 + 7100.0) * 0.5; - } - - case LightSource::DAYWHITE_FLUORESCENT: { - return (4600.0 + 5500.0) * 0.5; - } - - case LightSource::COOL_WHITE_FLUORESCENT: - case LightSource::FLUORESCENT: { - return (3800.0 + 4500.0) * 0.5; - } - - case LightSource::WHITE_FLUORESCENT: { - return (3250.0 + 3800.0) * 0.5; - } - - case LightSource::WARM_WHITE_FLUORESCENT: { - return (2600.0 + 3250.0) * 0.5; - } - - default: { - return 0.0; - } - } -} - -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; +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 }; -DCPProfile::ApplyState::ApplyState() : - data(new Data{}) +// should probably be moved to colortemp.cc +static double calibrationIlluminantToTemperature(int light) { -} -DCPProfile::ApplyState::~ApplyState() -{ -} + // these temperatures are those found in DNG SDK reference code. + switch (light) { + case lsStandardLightA: + case lsTungsten: + return 2850.0; -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; + case lsISOStudioTungsten: + return 3200.0; - 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 - }; + case lsD50: + return 5000.0; - 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 - }; + case lsD55: + case lsDaylight: + case lsFineWeather: + case lsFlash: + case lsStandardLightB: + return 5500.0; - FILE* const file = g_fopen(filename.c_str(), "rb"); + case lsD65: + case lsStandardLightC: + case lsCloudyWeather: + return 6500.0; - std::unique_ptr tagDir(ExifManager::parseTIFF(file, false)); + case lsD75: + case lsShade: + return 7500.0; - 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); + case lsDaylightFluorescent: + return (5700.0 + 7100.0) * 0.5; - 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 + case lsDayWhiteFluorescent: + return (4600.0 + 5500.0) * 0.5; - // Fetch Forward Matrices, if any - tag = tagDir->getTag(toUnderlying(TagKey::FORWARD_MATRIX_1)); + case lsCoolWhiteFluorescent: + case lsFluorescent: + return (3800.0 + 4500.0) * 0.5; - if (tag) { - has_forward_matrix_1 = true; + case lsWhiteFluorescent: + return (3250.0 + 3800.0) * 0.5; - 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); - } - } - } + case lsWarmWhiteFluorescent: + return (2600.0 + 3250.0) * 0.5; - 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); + default: + return 0.0; } } - -DCPProfile::~DCPProfile() +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 -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 + double neutral[3]; // 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; - white_balance.getMultipliers(r, g, b); + wb.getMultipliers(r, g, b); // camWbMatrix == imatrices.xyz_cam - 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 cam_xyz[3][3]; + Invert3x3(camWbMatrix, cam_xyz); + double cam_rgb[3][3]; + 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; @@ -1427,67 +584,67 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu 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]; - neutralToXy(neutral, preferred_illuminant, white_xy); + dngref_NeutralToXY(neutral, preferredIlluminant, white_xy); - 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; + bool hasFwd1 = hasForwardMatrix1; + bool hasFwd2 = hasForwardMatrix2; + bool hasCol1 = hasColorMatrix1; + bool hasCol2 = hasColorMatrix2; - if (preferred_illuminant == 1) { - if (has_fwd_1) { - has_fwd_2 = false; + if (preferredIlluminant == 1) { + if (hasFwd1) { + hasFwd2 = false; } - if (has_col_1) { - has_col_2 = false; + if (hasCol1) { + hasCol2 = false; } - } else if (preferred_illuminant == 2) { - if (has_fwd_2) { - has_fwd_1 = false; + } else if (preferredIlluminant == 2) { + if (hasFwd2) { + hasFwd1 = false; } - if (has_col_2) { - has_col_1 = false; + if (hasCol2) { + hasCol1 = false; } } - // Mix if we have two matrices + // mix if we have two matrices double mix = 1.0; - if ((has_col_1 && has_col_2) || (has_fwd_1 && has_fwd_2)) { + if ((hasCol1 && hasCol2) || (hasFwd1 && hasFwd2)) { 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. */ - xyCoordToTemperature(white_xy, &wbtemp, nullptr); + dngref_XYCoord2Temperature(white_xy, &wbtemp, NULL); - if (wbtemp <= temperature_1) { + if (wbtemp <= temperature1) { mix = 1.0; - } else if (wbtemp >= temperature_2) { + } else if (wbtemp >= temperature2) { mix = 0.0; } else { double invT = 1.0 / wbtemp; - mix = (invT - (1.0 / temperature_2)) / ((1.0 / temperature_1) - (1.0 / temperature_2)); + mix = (invT - (1.0 / temperature2)) / ((1.0 / temperature1) - (1.0 / temperature2)); } } // Colormatrix - Matrix color_matrix; + double mCol[3][3]; - if (has_col_1 && has_col_2) { + if (hasCol1 && hasCol2) { // interpolate if (mix >= 1.0) { - color_matrix = color_matrix_1; + memcpy(mCol, mColorMatrix1, sizeof(mCol)); } else if (mix <= 0.0) { - color_matrix = color_matrix_2; + memcpy(mCol, mColorMatrix2, sizeof(mCol)); } else { - mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix, color_matrix); + Mix3x3(mColorMatrix1, mix, mColorMatrix2, 1.0 - mix, mCol); } - } else if (has_col_1) { - color_matrix = color_matrix_1; + } else if (hasCol1) { + memcpy(mCol, mColorMatrix1, sizeof(mCol)); } else { - color_matrix = color_matrix_2; + memcpy(mCol, mColorMatrix2, sizeof(mCol)); } /* @@ -1498,53 +655,49 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu will show incorrect color. */ - Triple white_xyz; - xyToXyz(white_xy, white_xyz); + double white_xyz[3]; + XYtoXYZ(white_xy, white_xyz); - Matrix cam_xyz; + double cam_xyz[3][3]; - if (has_fwd_1 || has_fwd_2) { - // Always prefer ForwardMatrix to ColorMatrix - Matrix fwd; + if (hasFwd1 || hasFwd2) { + // always prefer ForwardMatrix ahead of ColorMatrix + double mFwd[3][3]; - if (has_fwd_1 && has_fwd_2) { - // Interpolate + if (hasFwd1 && hasFwd2) { + // interpolate if (mix >= 1.0) { - fwd = forward_matrix_1; + memcpy(mFwd, mForwardMatrix1, sizeof(mFwd)); } else if (mix <= 0.0) { - fwd = forward_matrix_2; + memcpy(mFwd, mForwardMatrix2, sizeof(mFwd)); } else { - mix3x3(forward_matrix_1, mix, forward_matrix_2, 1.0 - mix, fwd); + Mix3x3(mForwardMatrix1, mix, mForwardMatrix2, 1.0 - mix, mFwd); } - } else if (has_fwd_1) { - fwd = forward_matrix_1; + } else if (hasFwd1) { + memcpy(mFwd, mForwardMatrix1, sizeof(mFwd)); } else { - fwd = forward_matrix_2; + memcpy(mFwd, mForwardMatrix2, sizeof(mFwd)); } // adapted from dng_color_spec::SetWhiteXY - Triple camera_white; - multiply3x3_v3(color_matrix, white_xyz, camera_white); + double CameraWhite[3]; + Multiply3x3_v3(mCol, white_xyz, CameraWhite); - 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 whiteDiag[3][3] = {{CameraWhite[0], 0, 0}, {0, CameraWhite[1], 0}, {0, 0, CameraWhite[2]}}; + double whiteDiagInv[3][3]; + Invert3x3(whiteDiag, whiteDiagInv); - Matrix xyz_cam; - multiply3x3(fwd, white_diag_inv, xyz_cam); - invert3x3(xyz_cam, cam_xyz); + double xyz_cam[3][3]; + Multiply3x3(mFwd, whiteDiagInv, xyz_cam); + Invert3x3(xyz_cam, cam_xyz); } else { - 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); + 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); } - // 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 @@ -1552,342 +705,1085 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu int i, j, k; // Multiply out XYZ colorspace - double cam_rgb[3][3] = {}; + double cam_rgb[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; - 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] = {}; - RawImageSource::inverse33(cam_rgb, rgb_cam); + double rgb_cam[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + RawImageSource::inverse33 (cam_rgb, rgb_cam); - 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++) { + mXYZCAM[i][j] = 0; } - } - 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]; + 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]; } - } - } } } -std::vector DCPProfile::makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const +const DCPProfile::HSBModify* DCPProfile::MakeHueSatMap(ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const { - if (deltas_1.empty()) { - return std::vector(); + + *deleteHandle = NULL; + + if (!aDeltas1) { + return NULL; } - if (deltas_2.empty()) { - return deltas_1; + if (!aDeltas2) { + return aDeltas1; } - if (preferred_illuminant == 1) { - return deltas_1; - } else if (preferred_illuminant == 2) { - return deltas_2; + if (preferredIlluminant == 1) { + return aDeltas1; + } else if (preferredIlluminant == 2) { + return aDeltas2; } - // Interpolate based on color temperature - if ( - temperature_1 <= 0.0 - || temperature_2 <= 0.0 - || temperature_1 == temperature_2 - ) { - return deltas_1; + // Interpolate based on color temperature. + if (temperature1 <= 0.0 || temperature2 <= 0.0 || temperature1 == temperature2) { + return aDeltas1; } - const bool reverse = temperature_1 > temperature_2; - const double t1 = - reverse - ? temperature_2 - : temperature_1; - const double t2 = - reverse - ? temperature_1 - : temperature_2; + bool reverseOrder = temperature1 > temperature2; + double t1, t2; + + if (reverseOrder) { + t1 = temperature2; + t2 = temperature1; + } else { + t1 = temperature1; + t2 = temperature2; + } double mix; - if (white_balance.getTemp() <= t1) { + + if (wb.getTemp() <= t1) { mix = 1.0; - } else if (white_balance.getTemp() >= t2) { + } else if (wb.getTemp() >= t2) { mix = 0.0; } else { - const double invT = 1.0 / white_balance.getTemp(); + double invT = 1.0 / wb.getTemp(); mix = (invT - (1.0 / t2)) / ((1.0 / t1) - (1.0 / t2)); } - if (reverse) { + if (reverseOrder) { mix = 1.0 - mix; } if (mix >= 1.0) { - return deltas_1; + return aDeltas1; } else if (mix <= 0.0) { - return deltas_2; + return aDeltas2; } // Interpolate between the tables. - std::vector res(delta_info.array_count); + HSBModify *aDeltas = new HSBModify[DeltaInfo.iArrayCount]; + *deleteHandle = aDeltas; + float w1 = (float)mix; + float w2 = 1.0f - (float)mix; - 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; + 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; } - return res; + return aDeltas; } -void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const +DCPProfile::DCPProfile(Glib::ustring fname) { - // Apply the HueSatMap. Ported from Adobes reference implementation. - float hue_shift; - float sat_scale; - float val_scale; - float v_encoded = v; + 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; - 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; + aDeltas1 = aDeltas2 = aLookTable = NULL; - int h_index0 = max(h_scaled, 0); - const int s_index0 = std::max(std::min(s_scaled, table_info.pc.max_sat_index0), 0); + FILE *pFile = g_fopen(fname.c_str (), "rb"); - int h_index1 = h_index0 + 1; + TagDirectory *tagDir = ExifManager::parseTIFF(pFile, false); - if (h_index0 >= table_info.pc.max_hue_index0) { - h_index0 = table_info.pc.max_hue_index0; - h_index1 = 0; + 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); + } } - - const float h_fract1 = h_scaled - static_cast(h_index0); - const float s_fract1 = s_scaled - static_cast(s_index0); - - const float h_fract0 = 1.0f - h_fract1; - const float s_fract0 = 1.0f - s_fract1; - - 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; - - 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; - - ++e00_index; - ++e01_index; - - 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; - - if (table_info.srgb_gamma) { - v_encoded = srgbGammaForward(v); - } - - const float v_scaled = v_encoded * table_info.pc.v_scale; - - 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 h_index1 = h_index0 + 1; - - if (h_index0 >= table_info.pc.max_hue_index0) { - h_index0 = table_info.pc.max_hue_index0; - h_index1 = 0; - } - - 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); - - const float h_fract0 = 1.0f - h_fract1; - const float s_fract0 = 1.0f - s_fract1; - const float v_fract0 = 1.0f - v_fract1; - - 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 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); - - ++e00_index; - ++e01_index; - ++e10_index; - ++e11_index; - - 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); - - hue_shift = s_fract0 * hueShift0 + s_fract1 * hueShift1; - sat_scale = s_fract0 * satScale0 + s_fract1 * satScale1; - val_scale = s_fract0 * valScale0 + s_fract1 * valScale1; } - hue_shift *= 6.0f / 360.0f; // Convert to internal hue range. + tag = tagDir->getTag(TagForwardMatrix2); - h += hue_shift; - s *= sat_scale; // No clipping here, we are RT float :-) + 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); + } + + // 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; + } + + tag = tagDir->getTag(TagProfileHueSatMapDims); + + if (tag != NULL) { + DeltaInfo.iHueDivisions = tag->toInt(0); + DeltaInfo.iSatDivisions = tag->toInt(4); + DeltaInfo.iValDivisions = tag->toInt(8); + + tag = tagDir->getTag(TagProfileHueSatMapEncoding); + DeltaInfo.sRGBGamma = tag != NULL && tag->toInt(0); + + tag = tagDir->getTag(TagProfileHueSatMapData1); + DeltaInfo.iArrayCount = tag->getCount() / 3; + + 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; - if (table_info.srgb_gamma) { - v = srgbGammaInverse(v_encoded * val_scale); } else { - v *= val_scale; + + float hScaled = h * ti.pc.hScale; + float sScaled = s * ti.pc.sScale; + + if (ti.sRGBGamma) { + vEncoded = sRGBGammaForward(v); + } + + float vScaled = vEncoded * ti.pc.vScale; + + 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 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 vFract1 = vScaled - (float) vIndex0; + + float hFract0 = 1.0f - hFract1; + float sFract0 = 1.0f - sFract1; + float vFract0 = 1.0f - vFract1; + + const HSBModify *entry00 = tableBase + vIndex0 * ti.pc.valStep + hIndex0 * ti.pc.hueStep + sIndex0; + + const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * ti.pc.hueStep; + + const HSBModify *entry10 = entry00 + ti.pc.valStep; + const HSBModify *entry11 = entry01 + ti.pc.valStep; + + float hueShift0 = vFract0 * (hFract0 * entry00->fHueShift + + hFract1 * entry01->fHueShift) + + vFract1 * (hFract0 * entry10->fHueShift + + hFract1 * entry11->fHueShift); + + 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; + } + + hueShift *= (6.0f / 360.0f); // Convert to internal hue range. + + h += hueShift; + s *= satScale; // no clipping here, we are RT float :-) + + if (ti.sRGBGamma) { + v = sRGBGammaInverse(vEncoded * valScale); + } else { + v *= valScale; } } +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_; } -void DCPStore::init(const Glib::ustring& rt_profile_dir) +// Reads all profiles from the given profiles dir +void DCPStore::init (Glib::ustring rtProfileDir) { - MyMutex::MyLock lock(mutex); + MyMutex::MyLock lock(mtx); - file_std_profiles.clear(); + fileStdProfiles.clear(); - if (!rt_profile_dir.empty()) { - std::deque dirs = { - rt_profile_dir - }; + Glib::ustring rootDirName = rtProfileDir; - while (!dirs.empty()) { - // Process directory - Glib::ustring dirname = dirs.back(); - dirs.pop_back(); + if (rootDirName != "") { + std::deque qDirs; - std::unique_ptr dir; + qDirs.push_front(rootDirName); + + while (!qDirs.empty()) { + // process directory + Glib::ustring dirname = qDirs.back(); + qDirs.pop_back(); + + Glib::Dir* dir = NULL; try { - if (!Glib::file_test(dirname, Glib::FILE_TEST_IS_DIR)) { + if (!Glib::file_test (dirname, Glib::FILE_TEST_IS_DIR)) { return; } - dir.reset(new Glib::Dir(dirname)); - } catch (Glib::Exception& exception) { + dir = new Glib::Dir (dirname); + } catch (Glib::Exception& fe) { return; } - dirname += '/'; + dirname = dirname + "/"; - for (const Glib::ustring& sname : *dir) { - const Glib::ustring fname = dirname + sname; + for (Glib::DirIterator i = dir->begin(); i != dir->end(); ++i) { + Glib::ustring fname = dirname + *i; + Glib::ustring sname = *i; - if (!Glib::file_test(fname, Glib::FILE_TEST_IS_DIR)) { - // File - const auto lastdot = sname.rfind('.'); + // ignore directories + if (!Glib::file_test (fname, Glib::FILE_TEST_IS_DIR)) { + size_t lastdot = sname.find_last_of ('.'); - 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 + 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 } } else { - // Directory - dirs.push_front(fname); + qDirs.push_front(fname); // for later scanning } } + + delete dir; } } } -bool DCPStore::isValidDCPFileName(const Glib::ustring& filename) const +DCPProfile* DCPStore::getProfile (Glib::ustring filename) { - if (!Glib::file_test(filename, Glib::FILE_TEST_EXISTS) || Glib::file_test(filename, Glib::FILE_TEST_IS_DIR)) { - return false; - } + MyMutex::MyLock lock(mtx); - const auto pos = filename.rfind('.'); - return - pos > 0 - && ( - !filename.casefold().compare(pos, 4, ".dcp") - || !filename.casefold().compare(pos, 4, ".dng") - ); -} + std::map::iterator r = profileCache.find (filename); -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()) { + if (r != profileCache.end()) { return r->second; } - DCPProfile* const res = new DCPProfile(filename); - // Add profile - profile_cache[filename] = res; + profileCache[filename] = new DCPProfile(filename); - return res; + return profileCache[filename]; } -DCPProfile* DCPStore::getStdProfile(const Glib::ustring& cam_short_name) const +DCPProfile* DCPStore::getStdProfile(Glib::ustring camShortName) { - const Glib::ustring name = cam_short_name.uppercase(); + Glib::ustring name2 = camShortName.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); + for (std::map::iterator i = fileStdProfiles.begin(); i != fileStdProfiles.end(); i++) + if (name2 == (*i).first) { + return getProfile((*i).second); } - return nullptr; + 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)) { + return false; + } + + size_t pos = filename.find_last_of ('.'); + return pos > 0 && (!filename.casefold().compare (pos, 4, ".dcp") || !filename.casefold().compare (pos, 4, ".dng")); } diff --git a/rtengine/dcp.h b/rtengine/dcp.h index ace32869a..7a960edc9 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -17,159 +17,117 @@ * along with RawTherapee. If not, see . */ -#pragma once - -#include -#include -#include -#include - -#include +#ifndef _DCP_ +#define _DCP_ #include "imagefloat.h" #include "curves.h" #include "colortemp.h" - #include "../rtgui/threadutils.h" +#include +#include +#include namespace rtengine { -class DCPProfile final +class DCPProfile { -public: - class ApplyState final - { - public: - ApplyState(); - ~ApplyState(); - - private: - struct Data; - - std::unique_ptr data; - - friend class DCPProfile; + struct HSBModify { + float fHueShift; + float fSatScale; + float fValScale; }; - - 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 HSDTableInfo { + int iHueDivisions, iSatDivisions, iValDivisions; + int iHueStep, iValStep, iArrayCount; + bool sRGBGamma; struct { - 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; + float hScale, sScale, vScale; + int maxHueIndex0, maxSatIndex0, maxValIndex0; + int hueStep, valStep; } pc; }; - 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; + 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; - 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; + AdobeToneCurve toneCurve; + struct { + double m2ProPhoto[3][3]; + double m2Work[3][3]; + bool alreadyProPhoto; + bool useToneCurve; + bool applyLookTable; + float blScale; + } applyState; - AdobeToneCurve tone_curve; + 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; }; -class DCPStore final +class DCPStore { -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; + MyMutex mtx; // these contain standard profiles from RT. keys are all in uppercase, file path is value - std::map file_std_profiles; + std::map fileStdProfiles; // Maps file name to profile as cache - mutable std::map profile_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(); }; +#define dcpStore DCPStore::getInstance() } +#endif diff --git a/rtengine/dcraw.c b/rtengine/dcraw.c index 441f967da..cf1afe4ac 100644 --- a/rtengine/dcraw.c +++ b/rtengine/dcraw.c @@ -1,6 +1,6 @@ /* dcraw.c -- Dave Coffin's raw photo decoder - Copyright 1997-2016 by Dave Coffin, dcoffin a cybercom o net + Copyright 1997-2015 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.477 $ - $Date: 2016/05/10 21:30:43 $ + $Revision: 1.475 $ + $Date: 2015/04/11 00:08:36 $ */ -#define DCRAW_VERSION "9.27" +#define DCRAW_VERSION "9.25" #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -89,6 +89,15 @@ 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 @@ -149,7 +158,6 @@ 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 { @@ -171,7 +179,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((int)(x),0,65535) +#define CLIP(x) LIM(x,0,65535) #define SWAP(a,b) { a=a+b; b=a-b; a=a-b; } /* @@ -805,22 +813,27 @@ 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 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) { - ushort c, tag, len; + int c, tag, len; uchar data[0x10000]; const uchar *dp; memset (jh, 0, sizeof *jh); jh->restart = INT_MAX; - if ((fgetc(ifp),fgetc(ifp)) != 0xd8) return 0; + fread (data, 2, 1, ifp); + if (data[1] != 0xd8) return 0; do { - if (!fread (data, 2, 2, ifp)) return 0; + fread (data, 2, 2, ifp); tag = data[0] << 8 | data[1]; len = (data[2] << 8 | data[3]) - 2; if (tag <= 0xff00) return 0; @@ -828,9 +841,7 @@ 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]; @@ -839,25 +850,20 @@ 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++) & -20); ) + for (dp = data; dp < data+len && (c = *dp++) < 4; ) 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->huff[0]) return 0; - FORC(19) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c]; + 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->sraw) { FORC(4) jh->huff[2+c] = jh->huff[1]; FORC(jh->sraw) jh->huff[1+c] = jh->huff[0]; @@ -1036,59 +1042,23 @@ void CLASS adobe_copy_pixel (unsigned row, unsigned col, ushort **rp) { int c; - if (tiff_samples == 2 && shot_select) (*rp)++; + if (is_raw == 2 && shot_select) (*rp)++; if (raw_image) { if (row < raw_height && col < raw_width) RAW(row,col) = curve[**rp]; - *rp += tiff_samples; + *rp += is_raw; } else { if (row < height && col < width) FORC(tiff_samples) image[row*width+col][c] = curve[(*rp)[c]]; *rp += tiff_samples; } - 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); + if (is_raw == 2 && shot_select) (*rp)--; } void CLASS lossless_dng_load_raw() { - unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col, i, j; + unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col; struct jhead jh; ushort *rp; @@ -1099,32 +1069,14 @@ void CLASS lossless_dng_load_raw() if (!ljpeg_start (&jh, 0)) break; jwide = jh.wide; if (filters) jwide *= jh.clrs; - 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); - } - } + 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); + } } fseek (ifp, save+4, SEEK_SET); if ((tcol += tile_width) >= raw_width) @@ -1769,7 +1721,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.format != 8)) - ph1.black + i = (pixel[col] << 2) - ph1.black + cblack[row][col >= ph1.split_col] + rblack[col][row >= ph1.split_row]; if (i > 0) RAW(row,col) = i; @@ -2861,8 +2813,6 @@ 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); @@ -5311,7 +5261,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_bps); + FORC4 cblack[c ^ c >> 1] = get2() >> (14-tiff_ifd[2].bps); if (tag == 0x81 && type == 4) { data_offset = get4(); fseek (ifp, data_offset + 41, SEEK_SET); @@ -5341,8 +5291,7 @@ nf: order = 0x4949; break; case 102: fseek (ifp, 6, SEEK_CUR); - FORC4 cam_mul[c ^ (c >> 1)] = get2(); - break; + goto get2_rggb; case 103: fseek (ifp, 16, SEEK_CUR); FORC4 cam_mul[c] = get2(); @@ -5376,7 +5325,7 @@ nf: order = 0x4949; if (tag == 0x200 && len == 4) FORC4 cblack[c ^ c >> 1] = get2(); if (tag == 0x201 && len == 4) - FORC4 cam_mul[c ^ (c >> 1)] = get2(); + goto get2_rggb; if (tag == 0x220 && type == 7) meta_offset = ftell(ifp); if (tag == 0x401 && type == 4 && len == 4) @@ -5422,7 +5371,7 @@ get2_256: } if ((tag | 0x70) == 0x2070 && (type == 4 || type == 13)) fseek (ifp, get4()+base, SEEK_SET); - if (tag == 0x2020 && !strncmp(buf,"OLYMP",5)) + if (tag == 0x2020) parse_thumb_note (base, 257, 258); if (tag == 0x2040) parse_makernote (base, 0x2040); @@ -5433,12 +5382,11 @@ 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(); - for (i+=18; i <= len; i+=10) { - get2(); - FORC4 sraw_mul[c ^ (c >> 1)] = get2(); - if (sraw_mul[1] == 1170) break; - } + i = len >> 3 == 164 || len == 1506 ? 112:22; + fseek (ifp, i, SEEK_CUR); + FORC4 sraw_mul[c ^ (c >> 1)] = get2(); } if (tag == 0x4021 && get4() && get4()) FORC4 cam_mul[c] = 1024; @@ -5491,14 +5439,12 @@ void CLASS parse_exif (int base) 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: 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; @@ -5736,8 +5682,6 @@ 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; @@ -5899,7 +5843,7 @@ int CLASS parse_tiff_ifd (int base) parse_kodak_ifd (base); break; case 33434: /* ExposureTime */ - tiff_ifd[ifd].shutter = shutter = getreal(type); + shutter = getreal(type); break; case 33437: /* FNumber */ aperture = getreal(type); @@ -6027,14 +5971,6 @@ 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; @@ -6048,7 +5984,10 @@ guess_cfa_pc: filters -= !filters; break; case 50711: /* CFALayout */ - if (get2() == 2) fuji_width = 1; + if (get2() == 2) { + fuji_width = 1; + filters = 0x49494949; + } break; case 291: case 50712: /* LinearizationTable */ @@ -6071,7 +6010,7 @@ guess_cfa_pc: break; case 50715: /* BlackLevelDeltaH */ case 50716: /* BlackLevelDeltaV */ - for (num=i=0; i < (len & 0xffff); i++) + for (num=i=0; i < len; i++) num += getreal(type); black += num/len + 0.5; break; @@ -6189,7 +6128,7 @@ int CLASS parse_tiff (int base) void CLASS apply_tiff() { - int max_samp=0, ties=0, os, ns, raw=-1, thm=-1, i; + int max_samp=0, raw=-1, thm=-1, i; struct jhead jh; thumb_misc = 16; @@ -6201,25 +6140,13 @@ 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 && - ns && ((ns > os && (ties = 1)) || - (ns == os && shot_select == ties++))) { + tiff_ifd[i].width*tiff_ifd[i].height > raw_width*raw_height) { raw_width = tiff_ifd[i].width; raw_height = tiff_ifd[i].height; tiff_bps = tiff_ifd[i].bps; @@ -6229,11 +6156,9 @@ 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--; ) @@ -6310,8 +6235,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 && strncmp(make,"Phase",5) && - !strcasestr(make,"Kodak") && !strstr(model2,"DEBUG RAW"))) + || (tiff_bps == 8 && !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 && @@ -6452,7 +6377,9 @@ void CLASS ciff_block_1030() bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); vbits += 16; } - white[row][col] = bitbuf >> (vbits -= bpp) & ~(-1 << bpp); + white[row][col] = + bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp); + vbits -= bpp; } } @@ -6731,7 +6658,7 @@ void CLASS parse_fuji (int offset) } else if (tag == 0xc000) { c = order; order = 0x4949; - while ((tag = get4()) > raw_width); + if ((tag = get4()) > 10000) tag = get4(); width = tag; height = get4(); order = c; @@ -6753,7 +6680,7 @@ int CLASS parse_jpeg (int offset) order = 0x4d4d; len = get2() - 2; save = ftell(ifp); - if (mark == 0xc0 || mark == 0xc3 || mark == 0xc9) { + if (mark == 0xc0 || mark == 0xc3) { fgetc(ifp); raw_height = get2(); raw_width = get2(); @@ -7047,8 +6974,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, - { 6250,-711,-808,-5153,12794,2636,-1249,2198,5610 } }, + { "Canon EOS 5DS", 0, 0x3c96, /* DJC */ + { 6885,-753,-856,-4416,11752,2665,-1266,2393,5468 } }, { "Canon EOS 5D Mark III", 0, 0x3c80, { 6722,-635,-963,-4287,12460,2028,-908,2162,5668 } }, { "Canon EOS 5D Mark II", 0, 0x3cf0, @@ -7077,8 +7004,6 @@ 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, @@ -7099,22 +7024,12 @@ 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, @@ -7133,8 +7048,6 @@ 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, @@ -7163,20 +7076,14 @@ 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, @@ -7235,8 +7142,6 @@ 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 */ @@ -7251,8 +7156,6 @@ 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, @@ -7333,31 +7236,25 @@ 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, /* also X-T10 */ + { "Fujifilm X-T1", 0, 0, { 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 } }, @@ -7499,12 +7396,8 @@ 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, @@ -7515,8 +7408,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, - { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, + { "Nikon D7200", 0, 0, /* DJC */ + { 6111,-2759,-358,-5108,10766,4343,-769,1691,8030 } }, { "Nikon D750", 0, 0, { 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 } }, { "Nikon D700", 0, 0, @@ -7581,8 +7474,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, - { 7520,-2518,-645,-3844,12102,1945,-913,2249,6835 } }, + { "Nikon 1 J5", 0, 0, /* DJC */ + { 2621,-856,500,-4471,8761,5711,-1321,2644,11945 } }, { "Nikon 1 S2", 200, 0, { 6612,-1342,-618,-3338,11055,2623,-174,1792,5075 } }, { "Nikon 1 V2", 0, 0, @@ -7593,8 +7486,6 @@ 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, @@ -7665,7 +7556,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, /* also E-M10 Mark II */ + { "Olympus E-M10", 0, 0, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-M1", 0, 0, { 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 } }, @@ -7673,10 +7564,6 @@ 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, @@ -7693,8 +7580,6 @@ 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, @@ -7729,12 +7614,6 @@ 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, @@ -7745,10 +7624,6 @@ 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, @@ -7759,10 +7634,6 @@ 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, @@ -7843,8 +7714,6 @@ 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, @@ -7857,8 +7726,6 @@ 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, @@ -7875,12 +7742,6 @@ 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, @@ -7889,20 +7750,6 @@ 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, @@ -7917,14 +7764,8 @@ 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, @@ -7933,8 +7774,6 @@ 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 */ @@ -7951,8 +7790,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, - { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, + { "Samsung NX500", 0, 0, /* DJC */ + { 10196,-4532,-272,-3888,11489,2400,-1203,2424,9173 } }, { "Samsung NX5", 0, 0, { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, { "Samsung NX1", 0, 0, @@ -7969,19 +7808,17 @@ 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", 0, 0, + { "Sony DSC-R1", 512, 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", 0, 0, /* M2, M3, and M4 */ + { "Sony DSC-RX100M", 200, 0, /* M2 and M3 */ { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, - { "Sony DSC-RX100", 0, 0, + { "Sony DSC-RX100", 200, 0, { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } }, - { "Sony DSC-RX10", 0, 0, /* also RX10M2 */ + { "Sony DSC-RX10", 200, 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, + { "Sony DSC-RX1", 128, 0, { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, { "Sony DSLR-A100", 0, 0xfeb, { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } }, @@ -7999,77 +7836,71 @@ 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", 0, 0xfeb, + { "Sony DSLR-A450", 128, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, - { "Sony DSLR-A580", 0, 0xfeb, + { "Sony DSLR-A580", 128, 0xfeb, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, - { "Sony DSLR-A500", 0, 0xfeb, + { "Sony DSLR-A500", 128, 0xfeb, { 6046,-1127,-278,-5574,13076,2786,-691,1419,7625 } }, - { "Sony DSLR-A5", 0, 0xfeb, + { "Sony DSLR-A5", 128, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, - { "Sony DSLR-A700", 0, 0, + { "Sony DSLR-A700", 128, 0, { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } }, - { "Sony DSLR-A850", 0, 0, + { "Sony DSLR-A850", 128, 0, { 5413,-1162,-365,-5665,13098,2866,-608,1179,8440 } }, - { "Sony DSLR-A900", 0, 0, + { "Sony DSLR-A900", 128, 0, { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } }, - { "Sony ILCA-68", 0, 0, - { 6435,-1903,-536,-4722,12449,2550,-663,1363,6517 } }, - { "Sony ILCA-77M2", 0, 0, + { "Sony ILCA-77M2", 128, 0, { 5991,-1732,-443,-4100,11989,2381,-704,1467,5992 } }, - { "Sony ILCE-6300", 0, 0, - { 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 } }, - { "Sony ILCE-7M2", 0, 0, + { "Sony ILCE-7M2", 128, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, - { "Sony ILCE-7S", 0, 0, /* also ILCE-7SM2 */ + { "Sony ILCE-7S", 128, 0, { 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 } }, - { "Sony ILCE-7RM2", 0, 0, - { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, - { "Sony ILCE-7R", 0, 0, + { "Sony ILCE-7R", 128, 0, { 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 } }, - { "Sony ILCE-7", 0, 0, + { "Sony ILCE-7", 128, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, - { "Sony ILCE", 0, 0, /* 3000, 5000, 5100, 6000, and QX1 */ + { "Sony ILCE", 128, 0, /* 3000, 5000, 5100, 6000, and QX1 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony NEX-5N", 0, 0, + { "Sony NEX-5N", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony NEX-5R", 0, 0, + { "Sony NEX-5R", 128, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, - { "Sony NEX-5T", 0, 0, + { "Sony NEX-5T", 128, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, - { "Sony NEX-3N", 0, 0, + { "Sony NEX-3N", 128, 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", 0, 0, /* Adobe */ + { "Sony NEX-3", 128, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, - { "Sony NEX-5", 0, 0, /* Adobe */ + { "Sony NEX-5", 128, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, - { "Sony NEX-6", 0, 0, + { "Sony NEX-6", 128, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, - { "Sony NEX-7", 0, 0, + { "Sony NEX-7", 128, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, - { "Sony NEX", 0, 0, /* NEX-C3, NEX-F3 */ + { "Sony NEX", 128, 0, /* NEX-C3, NEX-F3 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A33", 0, 0, + { "Sony SLT-A33", 128, 0, { 6069,-1221,-366,-5221,12779,2734,-1024,2066,6834 } }, - { "Sony SLT-A35", 0, 0, + { "Sony SLT-A35", 128, 0, { 5986,-1618,-415,-4557,11820,3120,-681,1404,6971 } }, - { "Sony SLT-A37", 0, 0, + { "Sony SLT-A37", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A55", 0, 0, + { "Sony SLT-A55", 128, 0, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, - { "Sony SLT-A57", 0, 0, + { "Sony SLT-A57", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A58", 0, 0, + { "Sony SLT-A58", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A65", 0, 0, + { "Sony SLT-A65", 128, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, - { "Sony SLT-A77", 0, 0, + { "Sony SLT-A77", 128, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, - { "Sony SLT-A99", 0, 0, + { "Sony SLT-A99", 128, 0, { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, }; double cam_xyz[4][3]; @@ -8226,8 +8057,6 @@ 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 { @@ -8241,7 +8070,6 @@ 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" }, @@ -8251,12 +8079,9 @@ 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" }, { 0x382, "Canon EOS 5DS" }, - { 0x404, "EOS 1300D" }, { 0x401, "Canon EOS 5DS R" }, + { 0x327, "EOS 1200D" }, { 0x346, "EOS 100D" }, }, sonique[] = { { 0x002, "DSC-R1" }, { 0x100, "DSLR-A100" }, @@ -8284,10 +8109,7 @@ void CLASS identify() { 0x139, "ILCE-5000" }, { 0x13d, "DSC-RX100M3" }, { 0x13e, "ILCE-7S" }, { 0x13f, "ILCA-77M2" }, { 0x153, "ILCE-5100" }, { 0x154, "ILCE-7M2" }, - { 0x155, "DSC-RX100M4" },{ 0x156, "DSC-RX10M2" }, - { 0x158, "DSC-RX1RM2" }, { 0x15a, "ILCE-QX1" }, - { 0x15b, "ILCE-7RM2" }, { 0x15e, "ILCE-7SM2" }, - { 0x161, "ILCA-68" }, { 0x165, "ILCE-6300" }, + { 0x15a, "ILCE-QX1" }, }; static const struct { unsigned fsize; @@ -8324,7 +8146,6 @@ 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" }, @@ -8383,8 +8204,6 @@ 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" }, @@ -8401,7 +8220,7 @@ void CLASS identify() static const char *corp[] = { "AgfaPhoto", "Canon", "Casio", "Epson", "Fujifilm", "Mamiya", "Minolta", "Motorola", "Kodak", "Konica", "Leica", - "Nikon", "Nokia", "Olympus", "Ricoh", "Pentax", "Phase One", + "Nikon", "Nokia", "Olympus", "Pentax", "Phase One", "Ricoh", "Samsung", "Sigma", "Sinar", "Sony" }; char head[32], *cp; int hlen, flen, fsize, zero_fsize=1, i, c; @@ -8568,7 +8387,7 @@ void CLASS identify() parse_foveon(); else if (!memcmp (head,"CI",2)) parse_cine(); - if (make[0] == 0) + else for (zero_fsize=i=0; i < sizeof table / sizeof *table; i++) if (fsize == table[i].fsize) { strcpy (make, table[i].make ); @@ -8663,10 +8482,9 @@ 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; @@ -8718,8 +8536,6 @@ 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; @@ -8734,10 +8550,6 @@ 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; @@ -8913,7 +8725,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 || width == 6032) left_margin = 0; + if (width == 4032 || width == 4952) left_margin = 0; if (width == 3328 && (width -= 66)) left_margin = 34; if (width == 4936) left_margin = 4; if (!strcmp(model,"HS50EXR") || @@ -9156,8 +8968,6 @@ 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; @@ -9185,29 +8995,16 @@ 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--; @@ -9219,6 +9016,8 @@ 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; @@ -9283,7 +9082,6 @@ 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; @@ -9362,7 +9160,7 @@ dng_skip: if (raw_color) adobe_coeff ("Apple","Quicktake"); if (fuji_width) { fuji_width = width >> !fuji_layout; - filters = fuji_width & 1 ? 0x94949494 : 0x49494949; + if (~fuji_width & 1) filters = 0x49494949; width = (height >> fuji_layout) + fuji_width; height = width - 1; pixel_aspect = 1; @@ -9476,14 +9274,10 @@ 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, aces_rgb }; + { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb }; static const char *name[] = - { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ", "ACES" }; + { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ" }; static const unsigned phead[] = { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, 0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d }; @@ -9504,7 +9298,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 > 6; + output_color < 1 || output_color > 5; if (!raw_color) { oprof = (unsigned *) calloc (phead[0], 1); merror (oprof, "convert_to_rgb()"); @@ -9667,25 +9461,21 @@ struct tiff_hdr { char desc[512], make[64], model[64], soft[32], date[20], artist[64]; }; -void CLASS tiff_set (struct tiff_hdr *th, ushort *ntag, +void CLASS tiff_set (ushort *ntag, ushort tag, ushort type, int count, int val) { struct tiff_tag *tt; int c; tt = (struct tiff_tag *)(ntag+1) + (*ntag)++; - tt->val.i = val; - if (type == 1 && count <= 4) - FORC(4) tt->val.c[c] = val >> (c << 3); - 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); - tt->count = count; - tt->type = type; tt->tag = tag; + tt->type = type; + tt->count = count; + if (type < 3 && count <= 4) + FORC(4) tt->val.c[c] = val >> (c << 3); + else if (type == 3 && count <= 2) + FORC(2) tt->val.s[c] = val >> (c << 4); + else tt->val.i = val; } #define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) @@ -9699,6 +9489,55 @@ 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; @@ -9713,55 +9552,6 @@ 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() @@ -9882,7 +9672,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-6] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ,ACES)")); + puts(_("-o [0-5] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ)")); #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 8ebc073d1..c0dbd816d 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -12,7 +12,7 @@ /* dcraw.c -- Dave Coffin's raw photo decoder - Copyright 1997-2016 by Dave Coffin, dcoffin a cybercom o net + Copyright 1997-2015 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.477 $ - $Date: 2016/05/10 21:30:43 $ + $Revision: 1.475 $ + $Date: 2015/04/11 00:08:36 $ */ -#define DCRAW_VERSION "9.27" +#define DCRAW_VERSION "9.25" #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -100,6 +100,15 @@ 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; @@ -778,15 +787,17 @@ struct jhead { int CLASS ljpeg_start (struct jhead *jh, int info_only) { - ushort c, tag, len; + int c, tag; + ushort len; uchar data[0x10000]; const uchar *dp; memset (jh, 0, sizeof *jh); jh->restart = INT_MAX; - if ((fgetc(ifp),fgetc(ifp)) != 0xd8) return 0; + fread (data, 2, 1, ifp); + if (data[1] != 0xd8) return 0; do { - if (!fread (data, 2, 2, ifp)) return 0; + fread (data, 2, 2, ifp); tag = data[0] << 8 | data[1]; len = (data[2] << 8 | data[3]) - 2; if (tag <= 0xff00) return 0; @@ -794,9 +805,7 @@ 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]; @@ -805,25 +814,20 @@ 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++) & -20); ) + for (dp = data; dp < data+len && (c = *dp++) < 4; ) 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->huff[0]) return 0; - FORC(19) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c]; + 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->sraw) { FORC(4) jh->huff[2+c] = jh->huff[1]; FORC(jh->sraw) jh->huff[1+c] = jh->huff[0]; @@ -1002,59 +1006,23 @@ void CLASS adobe_copy_pixel (unsigned row, unsigned col, ushort **rp) { int c; - if (tiff_samples == 2 && shot_select) (*rp)++; + if (is_raw == 2 && shot_select) (*rp)++; if (raw_image) { if (row < raw_height && col < raw_width) RAW(row,col) = curve[**rp]; - *rp += tiff_samples; + *rp += is_raw; } else { if (row < height && col < width) FORC(tiff_samples) image[row*width+col][c] = curve[(*rp)[c]]; *rp += tiff_samples; } - 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); + if (is_raw == 2 && shot_select) (*rp)--; } void CLASS lossless_dng_load_raw() { - unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col, i, j; + unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col; struct jhead jh; ushort *rp; @@ -1065,32 +1033,15 @@ void CLASS lossless_dng_load_raw() if (!ljpeg_start (&jh, 0)) break; jwide = jh.wide; if (filters) jwide *= jh.clrs; - 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); - } - } } + 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); + } + } fseek (ifp, save+4, SEEK_SET); if ((tcol += tile_width) >= raw_width) trow += tile_length + (tcol = 0); @@ -1734,7 +1685,8 @@ void CLASS phase_one_load_raw_c() pixel[col] = curve[pixel[col]]; } for (col=0; col < raw_width; col++) { - i = (pixel[col] << 2*(ph1.format != 8)) - 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; @@ -3159,8 +3111,6 @@ 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); @@ -5287,7 +5237,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_bps); + FORC4 cblack[c ^ c >> 1] = get2() >> (14-tiff_ifd[2].bps); if (tag == 0x81 && type == 4) { data_offset = get4(); fseek (ifp, data_offset + 41, SEEK_SET); @@ -5317,8 +5267,7 @@ nf: order = 0x4949; break; case 102: fseek (ifp, 6, SEEK_CUR); - FORC4 cam_mul[c ^ (c >> 1)] = get2(); - break; + goto get2_rggb; case 103: fseek (ifp, 16, SEEK_CUR); FORC4 cam_mul[c] = get2(); @@ -5352,7 +5301,7 @@ nf: order = 0x4949; if (tag == 0x200 && len == 4) FORC4 cblack[c ^ c >> 1] = get2(); if (tag == 0x201 && len == 4) - FORC4 cam_mul[c ^ (c >> 1)] = get2(); + goto get2_rggb; if (tag == 0x220 && type == 7) meta_offset = ftell(ifp); if (tag == 0x401 && type == 4 && len == 4) @@ -5398,7 +5347,7 @@ get2_256: } if ((tag | 0x70) == 0x2070 && (type == 4 || type == 13)) fseek (ifp, get4()+base, SEEK_SET); - if (tag == 0x2020 && !strncmp(buf,"OLYMP",5)) + if (tag == 0x2020) parse_thumb_note (base, 257, 258); if (tag == 0x2040) parse_makernote (base, 0x2040); @@ -5409,12 +5358,11 @@ 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(); - for (i+=18; i <= len; i+=10) { - get2(); - FORC4 sraw_mul[c ^ (c >> 1)] = get2(); - if (sraw_mul[1] == 1170) break; - } + i = len >> 3 == 164 || len == 1506 ? 112:22; + fseek (ifp, i, SEEK_CUR); + FORC4 sraw_mul[c ^ (c >> 1)] = get2(); } if (tag == 0x4021 && get4() && get4()) FORC4 cam_mul[c] = 1024; @@ -5467,14 +5415,13 @@ void CLASS parse_exif (int base) 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: 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; @@ -5717,8 +5664,6 @@ 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; @@ -5890,7 +5835,7 @@ int CLASS parse_tiff_ifd (int base) parse_kodak_ifd (base); break; case 33434: /* ExposureTime */ - tiff_ifd[ifd].shutter = shutter = getreal(type); + shutter = getreal(type); break; case 33437: /* FNumber */ aperture = getreal(type); @@ -6019,12 +5964,7 @@ int CLASS parse_tiff_ifd (int base) 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; - } + fgets (model3, 64, ifp); break; case 50710: /* CFAPlaneColor */ if (filters == 9) break; @@ -6039,7 +5979,10 @@ guess_cfa_pc: filters -= !filters; break; case 50711: /* CFALayout */ - if (get2() == 2) fuji_width = 1; + if (get2() == 2) { + fuji_width = 1; + filters = 0x49494949; + } break; case 291: case 50712: /* LinearizationTable */ @@ -6071,7 +6014,7 @@ guess_cfa_pc: break; case 50715: /* BlackLevelDeltaH */ case 50716: /* BlackLevelDeltaV */ - for (num=i=0; i < (len & 0xffff); i++) + for (num=i=0; i < len; i++) num += getreal(type); black += num/len + 0.5; break; @@ -6201,7 +6144,7 @@ int CLASS parse_tiff (int base) void CLASS apply_tiff() { - int max_samp=0, ties=0, os, ns, raw=-1, thm=-1, i; + int max_samp=0, raw=-1, thm=-1, i; struct jhead jh; thumb_misc = 16; @@ -6213,26 +6156,13 @@ 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 && - ns && ((ns > os && (ties = 1)) || - (ns == os && shot_select == ties++))) { + tiff_ifd[i].width*tiff_ifd[i].height > raw_width*raw_height) { raw_width = tiff_ifd[i].width; raw_height = tiff_ifd[i].height; tiff_bps = tiff_ifd[i].bps; @@ -6242,11 +6172,9 @@ 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--; ) @@ -6329,8 +6257,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 && strncmp(make,"Phase",5) && - !strcasestr(make,"Kodak") && !strstr(model2,"DEBUG RAW"))) + || (tiff_bps == 8 && !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 && @@ -6472,7 +6400,9 @@ void CLASS ciff_block_1030() bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); vbits += 16; } - white[row][col] = bitbuf >> (vbits -= bpp) & ~(-1 << bpp); + white[row][col] = + bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp); + vbits -= bpp; } } @@ -6752,7 +6682,7 @@ void CLASS parse_fuji (int offset) } else if (tag == 0xc000) { c = order; order = 0x4949; - while ((tag = get4()) > raw_width); + while ((tag = get4()) > 10000); width = tag; height = get4(); order = c; @@ -6774,7 +6704,7 @@ int CLASS parse_jpeg (int offset) order = 0x4d4d; len = get2() - 2; save = ftell(ifp); - if (mark == 0xc0 || mark == 0xc3 || mark == 0xc9) { + if (mark == 0xc0 || mark == 0xc3) { fgetc(ifp); raw_height = get2(); raw_width = get2(); @@ -7073,8 +7003,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, - { 6250,-711,-808,-5153,12794,2636,-1249,2198,5610 } }, + { "Canon EOS 5DS", 0, 0x3c96, /* DJC */ + { 6885,-753,-856,-4416,11752,2665,-1266,2393,5468 } }, { "Canon EOS 5D Mark III", 0, 0x3c80, { 6722,-635,-963,-4287,12460,2028,-908,2162,5668 } }, { "Canon EOS 5D Mark II", 0, 0x3cf0, @@ -7103,8 +7033,6 @@ 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, @@ -7125,22 +7053,12 @@ 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, @@ -7159,8 +7077,6 @@ 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, @@ -7189,20 +7105,14 @@ 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, @@ -7261,8 +7171,6 @@ 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 */ @@ -7277,8 +7185,6 @@ 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, @@ -7359,31 +7265,25 @@ 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, /* also X-T10 */ + { "Fujifilm X-T1", 0, 0, { 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 } }, @@ -7525,12 +7425,8 @@ 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, @@ -7541,8 +7437,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, - { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, + { "Nikon D7200", 0, 0, /* DJC */ + { 6111,-2759,-358,-5108,10766,4343,-769,1691,8030 } }, { "Nikon D750", 0, 0, { 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 } }, { "Nikon D700", 0, 0, @@ -7607,8 +7503,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, - { 7520,-2518,-645,-3844,12102,1945,-913,2249,6835 } }, + { "Nikon 1 J5", 0, 0, /* DJC */ + { 2621,-856,500,-4471,8761,5711,-1321,2644,11945 } }, { "Nikon 1 S2", 200, 0, { 6612,-1342,-618,-3338,11055,2623,-174,1792,5075 } }, { "Nikon 1 V2", 0, 0, @@ -7619,8 +7515,6 @@ 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, @@ -7691,7 +7585,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, /* also E-M10 Mark II */ + { "Olympus E-M10", 0, 0, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-M1", 0, 0, { 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 } }, @@ -7699,10 +7593,6 @@ 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, @@ -7719,8 +7609,6 @@ 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, @@ -7755,12 +7643,6 @@ 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, @@ -7771,10 +7653,6 @@ 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, @@ -7785,10 +7663,6 @@ 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, @@ -7869,8 +7743,6 @@ 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, @@ -7883,8 +7755,6 @@ 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, @@ -7901,12 +7771,6 @@ 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, @@ -7915,20 +7779,6 @@ 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, @@ -7943,14 +7793,8 @@ 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, @@ -7959,8 +7803,6 @@ 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 */ @@ -7977,8 +7819,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, - { 10686,-4042,-1052,-3595,13238,276,-464,1259,5931 } }, + { "Samsung NX500", 0, 0, /* DJC */ + { 10196,-4532,-272,-3888,11489,2400,-1203,2424,9173 } }, { "Samsung NX5", 0, 0, { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, { "Samsung NX1", 0, 0, @@ -7995,20 +7837,18 @@ 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", 0, 0, + { "Sony DSC-R1", 512, 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", 0, 0, /* M2, M3, and M4 */ + { "Sony DSC-RX100M", 200, 0, /* M2 and M3 */ { 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 } }, - { "Sony DSC-RX100", 0, 0, + { "Sony DSC-RX100", 200, 0, { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } }, - { "Sony DSC-RX10", 0, 0, + { "Sony DSC-RX10", 200, 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 } }, + { "Sony DSC-RX1", 128, 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, @@ -8025,77 +7865,71 @@ 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", 0, 0xfeb, + { "Sony DSLR-A450", 128, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, - { "Sony DSLR-A580", 0, 0xfeb, + { "Sony DSLR-A580", 128, 0xfeb, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, - { "Sony DSLR-A500", 0, 0xfeb, + { "Sony DSLR-A500", 128, 0xfeb, { 6046,-1127,-278,-5574,13076,2786,-691,1419,7625 } }, - { "Sony DSLR-A5", 0, 0xfeb, + { "Sony DSLR-A5", 128, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, - { "Sony DSLR-A700", 0, 0, + { "Sony DSLR-A700", 128, 0, { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } }, - { "Sony DSLR-A850", 0, 0, + { "Sony DSLR-A850", 128, 0, { 5413,-1162,-365,-5665,13098,2866,-608,1179,8440 } }, - { "Sony DSLR-A900", 0, 0, + { "Sony DSLR-A900", 128, 0, { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } }, - { "Sony ILCA-68", 0, 0, - { 6435,-1903,-536,-4722,12449,2550,-663,1363,6517 } }, - { "Sony ILCA-77M2", 0, 0, + { "Sony ILCA-77M2", 128, 0, { 5991,-1732,-443,-4100,11989,2381,-704,1467,5992 } }, - { "Sony ILCE-6300", 0, 0, - { 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 } }, - { "Sony ILCE-7M2", 0, 0, + { "Sony ILCE-7M2", 128, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, - { "Sony ILCE-7S", 0, 0, /* also ILCE-7SM2 */ + { "Sony ILCE-7S", 128, 0, { 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 } }, - { "Sony ILCE-7RM2", 0, 0, - { 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 } }, - { "Sony ILCE-7R", 0, 0, + { "Sony ILCE-7R", 128, 0, { 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 } }, - { "Sony ILCE-7", 0, 0, + { "Sony ILCE-7", 128, 0, { 5271,-712,-347,-6153,13653,2763,-1601,2366,7242 } }, - { "Sony ILCE", 0, 0, /* 3000, 5000, 5100, 6000, and QX1 */ + { "Sony ILCE", 128, 0, /* 3000, 5000, 5100, 6000, and QX1 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony NEX-5N", 0, 0, + { "Sony NEX-5N", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony NEX-5R", 0, 0, + { "Sony NEX-5R", 128, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, - { "Sony NEX-5T", 0, 0, + { "Sony NEX-5T", 128, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, - { "Sony NEX-3N", 0, 0, + { "Sony NEX-3N", 128, 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", 0, 0, /* Adobe */ + { "Sony NEX-3", 128, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, - { "Sony NEX-5", 0, 0, /* Adobe */ + { "Sony NEX-5", 128, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, - { "Sony NEX-6", 0, 0, + { "Sony NEX-6", 128, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, - { "Sony NEX-7", 0, 0, + { "Sony NEX-7", 128, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, - { "Sony NEX", 0, 0, /* NEX-C3, NEX-F3 */ + { "Sony NEX", 128, 0, /* NEX-C3, NEX-F3 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A33", 0, 0, + { "Sony SLT-A33", 128, 0, { 6069,-1221,-366,-5221,12779,2734,-1024,2066,6834 } }, - { "Sony SLT-A35", 0, 0, + { "Sony SLT-A35", 128, 0, { 5986,-1618,-415,-4557,11820,3120,-681,1404,6971 } }, - { "Sony SLT-A37", 0, 0, + { "Sony SLT-A37", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A55", 0, 0, + { "Sony SLT-A55", 128, 0, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, - { "Sony SLT-A57", 0, 0, + { "Sony SLT-A57", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A58", 0, 0, + { "Sony SLT-A58", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, - { "Sony SLT-A65", 0, 0, + { "Sony SLT-A65", 128, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, - { "Sony SLT-A77", 0, 0, + { "Sony SLT-A77", 128, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, - { "Sony SLT-A99", 0, 0, + { "Sony SLT-A99", 128, 0, { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, }; double cam_xyz[4][3]; @@ -8279,8 +8113,6 @@ 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 { @@ -8294,7 +8126,6 @@ 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" }, @@ -8304,12 +8135,9 @@ 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" }, { 0x382, "Canon EOS 5DS" }, - { 0x404, "EOS 1300D" }, { 0x401, "Canon EOS 5DS R" }, + { 0x327, "EOS 1200D" }, { 0x346, "EOS 100D" }, }, sonique[] = { { 0x002, "DSC-R1" }, { 0x100, "DSLR-A100" }, @@ -8337,10 +8165,7 @@ void CLASS identify() { 0x139, "ILCE-5000" }, { 0x13d, "DSC-RX100M3" }, { 0x13e, "ILCE-7S" }, { 0x13f, "ILCA-77M2" }, { 0x153, "ILCE-5100" }, { 0x154, "ILCE-7M2" }, - { 0x155, "DSC-RX100M4" },{ 0x156, "DSC-RX10M2" }, - { 0x158, "DSC-RX1RM2" }, { 0x15a, "ILCE-QX1" }, - { 0x15b, "ILCE-7RM2" }, { 0x15e, "ILCE-7SM2" }, - { 0x161, "ILCA-68" }, { 0x165, "ILCE-6300" }, + { 0x15a, "ILCE-QX1" }, }; static const struct { unsigned fsize; @@ -8377,7 +8202,6 @@ 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" }, @@ -8436,8 +8260,6 @@ 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" }, @@ -8454,7 +8276,7 @@ void CLASS identify() static const char *corp[] = { "AgfaPhoto", "Canon", "Casio", "Epson", "Fujifilm", "Mamiya", "Minolta", "Motorola", "Kodak", "Konica", "Leica", - "Nikon", "Nokia", "Olympus", "Ricoh", "Pentax", "Phase One", + "Nikon", "Nokia", "Olympus", "Pentax", "Phase One", "Ricoh", "Samsung", "Sigma", "Sinar", "Sony" }; char head[32], *cp; int hlen, flen, fsize, zero_fsize=1, i, c; @@ -8629,7 +8451,7 @@ void CLASS identify() parse_foveon(); else if (!memcmp (head,"CI",2)) parse_cine(); - if (make[0] == 0) + else for (zero_fsize=i=0; i < sizeof table / sizeof *table; i++) if (fsize == table[i].fsize) { strcpy (make, table[i].make ); @@ -8726,10 +8548,9 @@ 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; @@ -8782,8 +8603,6 @@ 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; @@ -8799,10 +8618,6 @@ 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; @@ -8978,7 +8793,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 || width == 6032) left_margin = 0; + if (width == 4032 || width == 4952) left_margin = 0; if (width == 3328 && (width -= 66)) left_margin = 34; if (width == 4936) left_margin = 4; if (!strcmp(model,"HS50EXR") || @@ -9252,8 +9067,6 @@ 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; @@ -9281,29 +9094,16 @@ 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--; @@ -9315,6 +9115,8 @@ 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; @@ -9379,7 +9181,6 @@ 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; @@ -9470,7 +9271,7 @@ dng_skip: if (raw_color) adobe_coeff ("Apple","Quicktake"); if (fuji_width) { fuji_width = width >> !fuji_layout; - filters = fuji_width & 1 ? 0x94949494 : 0x49494949; + if (~fuji_width & 1) filters = 0x49494949; width = (height >> fuji_layout) + fuji_width; height = width - 1; pixel_aspect = 1; diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index 405f202bd..856da84d1 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -127,7 +127,6 @@ 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 { @@ -140,8 +139,8 @@ protected: } hbd; 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; }; struct tiff_tag { @@ -218,8 +217,6 @@ 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 2b4ee4102..88a56068c 100644 --- a/rtengine/dcraw.patch +++ b/rtengine/dcraw.patch @@ -1,5 +1,5 @@ ---- dcraw.c 2016-05-29 22:32:01.173135400 +0200 -+++ dcraw.cc 2016-05-29 21:57:44.144527700 +0200 +--- dcraw.c 2016-02-11 22:56:58.043957200 +0100 ++++ dcraw.cc 2016-02-11 23:13:28.708268000 +0100 @@ -1,3 +1,15 @@ +/*RT*/#include +/*RT*/#include @@ -15,7 +15,7 @@ + /* dcraw.c -- Dave Coffin's raw photo decoder - Copyright 1997-2016 by Dave Coffin, dcoffin a cybercom o net + Copyright 1997-2015 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 -@@ -89,89 +100,38 @@ - #define _(String) (String) +@@ -98,88 +109,38 @@ + #define LONG_BIT (8 * sizeof (long)) #endif -#if !defined(uchar) @@ -123,7 +123,6 @@ -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 { @@ -148,7 +147,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((int)(x),0,65535) +-#define CLIP(x) LIM(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)) @@ -157,7 +156,7 @@ #define SWAP(a,b) { a=a+b; b=a-b; a=a-b; } /* -@@ -247,6 +207,7 @@ +@@ -255,6 +216,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]; @@ -165,7 +164,7 @@ return FC(row,col); } -@@ -289,6 +250,7 @@ +@@ -297,6 +259,7 @@ fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp)); } data_error++; @@ -173,7 +172,7 @@ } ushort CLASS sget2 (uchar *s) -@@ -362,7 +324,7 @@ +@@ -370,7 +333,7 @@ { if (fread (pixel, 2, count, ifp) < count) derror(); if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) @@ -182,7 +181,7 @@ } void CLASS cubic_spline (const int *x_, const int *y_, const int len) -@@ -589,10 +551,10 @@ +@@ -597,10 +560,10 @@ return 0; } @@ -196,45 +195,17 @@ unsigned c; if (nbits > 25) return 0; -@@ -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; - }; +@@ -824,7 +787,8 @@ int CLASS ljpeg_start (struct jhead *jh, int info_only) -@@ -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 c, tag, len; ++ int c, tag; ++ ushort len; + uchar data[0x10000]; + const uchar *dp; + +@@ -1284,14 +1248,14 @@ int i, nz; char tail[424]; @@ -251,7 +222,7 @@ void CLASS ppm_thumb() { -@@ -1701,10 +1666,10 @@ +@@ -1653,10 +1617,10 @@ } } @@ -265,7 +236,17 @@ unsigned c; if (nbits == -1) -@@ -1779,6 +1744,338 @@ +@@ -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 @@ maximum = 0xfffc - ph1.black; } @@ -604,7 +585,7 @@ void CLASS hasselblad_load_raw() { struct jhead jh; -@@ -2002,10 +2299,10 @@ +@@ -1954,10 +2251,10 @@ maximum = curve[0x3ff]; } @@ -618,7 +599,7 @@ int byte; if (!nbits) return vbits=0; -@@ -2188,7 +2485,7 @@ +@@ -2140,7 +2437,7 @@ void CLASS kodak_radc_load_raw() { @@ -627,7 +608,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, -@@ -2294,11 +2591,11 @@ +@@ -2246,11 +2543,11 @@ METHODDEF(boolean) fill_input_buffer (j_decompress_ptr cinfo) { @@ -641,7 +622,7 @@ cinfo->src->next_input_byte = jpeg_buffer; cinfo->src->bytes_in_buffer = nbytes; return TRUE; -@@ -2648,10 +2945,9 @@ +@@ -2600,10 +2897,9 @@ maximum = (1 << (thumb_misc & 31)) - 1; } @@ -654,7 +635,7 @@ if (start) { for (p=0; p < 4; p++) pad[p] = key = key * 48828125 + 1; -@@ -2736,11 +3032,13 @@ +@@ -2688,11 +2984,13 @@ bit += 7; } for (i=0; i < 16; i++, col+=2) @@ -669,7 +650,7 @@ } void CLASS samsung_load_raw() -@@ -3038,7 +3336,7 @@ +@@ -2988,7 +3286,7 @@ void CLASS foveon_decoder (unsigned size, unsigned code) { @@ -678,7 +659,7 @@ struct decode *cur; int i, len; -@@ -3135,7 +3433,7 @@ +@@ -3085,7 +3383,7 @@ pred[c] += diff[dindex->leaf]; if (pred[c] >> 16 && ~pred[c] >> 16) derror(); } @@ -687,7 +668,7 @@ } } } -@@ -3746,6 +4044,8 @@ +@@ -3696,6 +3994,8 @@ if (load_raw == &CLASS phase_one_load_raw || load_raw == &CLASS phase_one_load_raw_c) phase_one_correct(); @@ -696,7 +677,7 @@ if (fuji_width) { for (row=0; row < raw_height-top_margin*2; row++) { for (col=0; col < fuji_width << !fuji_layout; col++) { -@@ -3761,10 +4061,13 @@ +@@ -3711,10 +4011,13 @@ } } } else { @@ -712,7 +693,7 @@ if (mask[0][3] > 0) goto mask_set; if (load_raw == &CLASS canon_load_raw || load_raw == &CLASS lossless_jpeg_load_raw) { -@@ -4366,239 +4669,8 @@ +@@ -4316,239 +4619,8 @@ } } @@ -721,7 +702,8 @@ - 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); @@ -904,8 +886,7 @@ - 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")); - @@ -953,7 +934,7 @@ void CLASS cielab (ushort rgb[3], short lab[3]) { -@@ -4864,112 +4936,7 @@ +@@ -4814,112 +4886,7 @@ } #undef fcol @@ -971,7 +952,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); @@ -979,7 +960,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) { - @@ -1066,7 +1047,7 @@ #undef TS void CLASS median_filter() -@@ -5139,7 +5106,7 @@ +@@ -5089,7 +5056,7 @@ } } @@ -1075,7 +1056,7 @@ void CLASS parse_makernote (int base, int uptag) { -@@ -5244,6 +5211,11 @@ +@@ -5194,6 +5161,11 @@ tag |= uptag << 16; if (tag == 2 && strstr(make,"NIKON") && !iso_speed) iso_speed = (get2(),get2()); @@ -1087,7 +1068,7 @@ if (tag == 4 && len > 26 && len < 35) { if ((i=(get4(),get2())) != 0x7fff && !iso_speed) iso_speed = 50 * pow (2, i/32.0 - 4); -@@ -5296,12 +5268,16 @@ +@@ -5246,12 +5218,16 @@ cam_mul[2] = get4() << 2; } } @@ -1105,25 +1086,15 @@ if (tag == 0x1d) while ((c = fgetc(ifp)) && c != EOF) serial = serial*10 + (isdigit(c) ? c - '0' : c % 10); -@@ -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; +@@ -5442,6 +5418,7 @@ + case 33434: 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 = -+ 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 @@ +@@ -5613,28 +5590,33 @@ } } @@ -1163,7 +1134,7 @@ entries = get2(); if (entries > 512) return 1; while (entries--) { -@@ -5758,7 +5739,8 @@ +@@ -5702,7 +5684,8 @@ fgets (make, 64, ifp); break; case 272: /* Model */ @@ -1173,7 +1144,7 @@ break; case 280: /* Panasonic RW2 offset */ if (type != 4) break; -@@ -5818,6 +5800,9 @@ +@@ -5762,6 +5745,9 @@ case 315: /* Artist */ fread (artist, 64, 1, ifp); break; @@ -1183,7 +1154,7 @@ case 322: /* TileWidth */ tiff_ifd[ifd].tile_width = getint(type); break; -@@ -5833,6 +5818,9 @@ +@@ -5777,6 +5763,9 @@ is_raw = 5; } break; @@ -1193,7 +1164,7 @@ case 330: /* SubIFDs */ if (!strcmp(model,"DSLR-A100") && tiff_ifd[ifd].width == 3872) { load_raw = &CLASS sony_arw_load_raw; -@@ -5846,6 +5834,9 @@ +@@ -5790,6 +5779,9 @@ fseek (ifp, i+4, SEEK_SET); } break; @@ -1203,7 +1174,17 @@ case 400: strcpy (make, "Sarnoff"); maximum = 0xfff; -@@ -6063,12 +6054,21 @@ +@@ -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 @@ case 61450: cblack[4] = cblack[5] = MIN(sqrt(len),64); case 50714: /* BlackLevel */ @@ -1230,8 +1211,8 @@ + break; case 50715: /* BlackLevelDeltaH */ case 50716: /* BlackLevelDeltaV */ - for (num=i=0; i < (len & 0xffff); i++) -@@ -6085,13 +6085,13 @@ + for (num=i=0; i < len; i++) +@@ -6024,13 +6028,13 @@ case 50721: /* ColorMatrix1 */ case 50722: /* ColorMatrix2 */ FORCC for (j=0; j < 3; j++) @@ -1247,7 +1228,7 @@ break; case 50727: /* AnalogBalance */ FORCC ab[c] = getreal(type); -@@ -6114,6 +6114,11 @@ +@@ -6053,6 +6057,11 @@ case 50752: read_shorts (cr2_slice, 3); break; @@ -1259,7 +1240,7 @@ case 50829: /* ActiveArea */ top_margin = getint(type); left_margin = getint(type); -@@ -6146,21 +6151,27 @@ +@@ -6085,21 +6094,27 @@ fread (buf, sony_length, 1, ifp); sony_decrypt (buf, sony_length/4, 1, sony_key); sfp = ifp; @@ -1295,7 +1276,7 @@ cam_xyz_coeff (cmatrix, cam_xyz); } if (asn[0]) { -@@ -6168,13 +6179,14 @@ +@@ -6107,13 +6122,14 @@ FORCC cam_mul[c] = 1 / asn[c]; } if (!use_cm) @@ -1311,15 +1292,7 @@ fseek (ifp, base, SEEK_SET); order = get2(); -@@ -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 @@ +@@ -6191,7 +6207,12 @@ case 8: load_raw = &CLASS eight_bit_load_raw; break; case 12: if (tiff_ifd[raw].phint == 2) load_flags = 6; @@ -1333,7 +1306,7 @@ case 14: load_flags = 0; case 16: load_raw = &CLASS unpacked_load_raw; if (!strncmp(make,"OLYMPUS",7) && -@@ -6305,6 +6323,7 @@ +@@ -6230,6 +6251,7 @@ case 32803: load_raw = &CLASS kodak_65000_load_raw; } case 32867: case 34892: break; @@ -1341,7 +1314,7 @@ default: is_raw = 0; } if (!dng_version) -@@ -6390,7 +6409,7 @@ +@@ -6315,7 +6337,7 @@ { const char *file, *ext; char *jname, *jfile, *jext; @@ -1350,7 +1323,7 @@ ext = strrchr (ifname, '.'); file = strrchr (ifname, '/'); -@@ -6412,13 +6431,14 @@ +@@ -6337,13 +6359,14 @@ } else while (isdigit(*--jext)) { if (*jext != '9') { @@ -1367,7 +1340,7 @@ if (verbose) fprintf (stderr,_("Reading metadata from %s ...\n"), jname); parse_tiff (12); -@@ -6693,6 +6713,7 @@ +@@ -6620,6 +6643,7 @@ load_raw = ph1.format < 3 ? &CLASS phase_one_load_raw : &CLASS phase_one_load_raw_c; maximum = 0xffff; @@ -1375,7 +1348,16 @@ strcpy (make, "Phase One"); if (model[0]) return; switch (raw_height) { -@@ -6761,7 +6782,11 @@ +@@ -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 @@ order = get2(); hlen = get4(); if (get4() == 0x48454150) /* "HEAP" */ @@ -1387,7 +1369,7 @@ if (parse_tiff (save+6)) apply_tiff(); fseek (ifp, save+len, SEEK_SET); } -@@ -7033,7 +7058,8 @@ +@@ -6960,7 +6988,8 @@ { static const struct { const char *prefix; @@ -1397,22 +1379,7 @@ } table[] = { { "AgfaPhoto DC-833m", 0, 0, /* DJC */ { 11438,-3762,-1115,-2409,9914,2497,-1227,2295,5300 } }, -@@ -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 @@ +@@ -7919,6 +7948,33 @@ } break; } @@ -1446,7 +1413,7 @@ } void CLASS simple_coeff (int index) -@@ -8410,7 +8463,7 @@ +@@ -8229,7 +8285,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; @@ -1455,7 +1422,7 @@ iso_speed = shutter = aperture = focal_len = unique_id = 0; tiff_nifds = 0; memset (tiff_ifd, 0, sizeof tiff_ifd); -@@ -8442,13 +8495,20 @@ +@@ -8261,13 +8317,20 @@ fread (head, 1, 32, ifp); fseek (ifp, 0, SEEK_END); flen = fsize = ftell(ifp); @@ -1478,7 +1445,7 @@ parse_ciff (hlen, flen-hlen, 0); load_raw = &CLASS canon_load_raw; } else if (parse_tiff(0)) apply_tiff(); -@@ -8494,6 +8554,7 @@ +@@ -8313,6 +8376,7 @@ fseek (ifp, 100+28*(shot_select > 0), SEEK_SET); parse_tiff (data_offset = get4()); parse_tiff (thumb_offset+12); @@ -1486,7 +1453,7 @@ apply_tiff(); } else if (!memcmp (head,"RIFF",4)) { fseek (ifp, 0, SEEK_SET); -@@ -8607,9 +8668,10 @@ +@@ -8426,9 +8490,10 @@ if (make[0] == 0) parse_smal (0, flen); if (make[0] == 0) { parse_jpeg(0); @@ -1500,7 +1467,7 @@ strcpy (make, "OmniVision"); data_offset = ftell(ifp) + 0x8000-32; width = raw_width; -@@ -8618,6 +8680,7 @@ +@@ -8437,6 +8502,7 @@ filters = 0x16161616; } else is_raw = 0; } @@ -1508,7 +1475,7 @@ for (i=0; i < sizeof corp / sizeof *corp; i++) if (strcasestr (make, corp[i])) /* Simplify company names */ -@@ -8649,7 +8712,7 @@ +@@ -8468,7 +8534,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"))) @@ -1517,15 +1484,15 @@ if (width >= 4960 && !strncmp(model,"K-5",3)) { left_margin = 10; width = 4950; filters = 0x16161616; } if (width == 4736 && !strcmp(model,"K-7")) -@@ -8669,6 +8732,7 @@ - case 0: +@@ -8487,6 +8553,7 @@ + switch (tiff_compress) { 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; } -@@ -8725,6 +8789,7 @@ +@@ -8541,6 +8608,7 @@ if (height > width) pixel_aspect = 2; filters = 0; simple_coeff(0); @@ -1533,7 +1500,7 @@ } else if (!strcmp(make,"Canon") && tiff_bps == 15) { switch (width) { case 3344: width -= 66; -@@ -9034,24 +9099,53 @@ +@@ -8846,24 +8914,53 @@ if (load_raw == &CLASS lossless_jpeg_load_raw) load_raw = &CLASS hasselblad_load_raw; if (raw_width == 7262) { @@ -1592,7 +1559,7 @@ } else if (raw_width == 4090) { strcpy (model, "V96C"); height -= (top_margin = 6); -@@ -9109,6 +9203,7 @@ +@@ -8921,6 +9018,7 @@ filters = 0x16161616; } } else if (!strcmp(make,"Leica") || !strcmp(make,"Panasonic")) { @@ -1600,7 +1567,7 @@ if ((flen - data_offset) / (raw_width*8/7) == raw_height) load_raw = &CLASS panasonic_load_raw; if (!load_raw) { -@@ -9126,6 +9221,7 @@ +@@ -8938,6 +9036,7 @@ } filters = 0x01010101 * (uchar) "\x94\x61\x49\x16" [((filters-1) ^ (left_margin & 1) ^ (top_margin << 1)) & 3]; @@ -1608,7 +1575,7 @@ } else if (!strcmp(model,"C770UZ")) { height = 1718; width = 2304; -@@ -9357,6 +9453,18 @@ +@@ -9155,6 +9254,18 @@ memcpy (rgb_cam, cmatrix, sizeof cmatrix); raw_color = 0; } @@ -1627,7 +1594,7 @@ if (raw_color) adobe_coeff (make, model); if (load_raw == &CLASS kodak_radc_load_raw) if (raw_color) adobe_coeff ("Apple","Quicktake"); -@@ -9371,9 +9479,9 @@ +@@ -9169,9 +9280,9 @@ if (raw_width < width ) raw_width = width; } if (!tiff_bps) tiff_bps = 12; @@ -1639,7 +1606,7 @@ is_raw = 0; #ifdef NO_JASPER if (load_raw == &CLASS redcine_load_raw) { -@@ -9452,199 +9560,250 @@ +@@ -9250,194 +9361,249 @@ } #endif @@ -1667,14 +1634,10 @@ - { { 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, aces_rgb }; +- { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb }; - static const char *name[] = -- { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ", "ACES" }; +- { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ" }; - static const unsigned phead[] = - { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, - 0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d }; @@ -1695,7 +1658,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 > 6; +- output_color < 1 || output_color > 5; - if (!raw_color) { - oprof = (unsigned *) calloc (phead[0], 1); - merror (oprof, "convert_to_rgb()"); @@ -2060,42 +2023,37 @@ + + 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; - int count; -@@ -9667,594 +9826,11 @@ +@@ -9461,590 +9627,11 @@ char desc[512], make[64], model[64], soft[32], date[20], artist[64]; }; --void CLASS tiff_set (struct tiff_hdr *th, ushort *ntag, +-void CLASS tiff_set (ushort *ntag, - ushort tag, ushort type, int count, int val) -{ - struct tiff_tag *tt; - int c; - - tt = (struct tiff_tag *)(ntag+1) + (*ntag)++; -- tt->val.i = val; -- if (type == 1 && count <= 4) -- FORC(4) tt->val.c[c] = val >> (c << 3); -- 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); -- tt->count = count; -- tt->type = type; - tt->tag = tag; +- tt->type = type; +- tt->count = count; +- if (type < 3 && count <= 4) +- FORC(4) tt->val.c[c] = val >> (c << 3); +- else if (type == 3 && count <= 2) +- FORC(2) tt->val.s[c] = val >> (c << 4); +- else tt->val.i = val; -} - -#define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) @@ -2109,6 +2067,55 @@ - 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; @@ -2123,55 +2130,6 @@ - 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() @@ -2292,7 +2250,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-6] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ,ACES)")); +- puts(_("-o [0-5] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ)")); -#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 bfe9c1c9a..77f0598b4 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -773,13 +773,11 @@ void Crop::update (int todo) if (todo & M_RGBCURVE) { double rrm, ggm, bbm; - DCPProfile::ApplyState as; - DCPProfile *dcpProf = parent->imgsrc->getDCP(params.icm, parent->currWB, as); - + DCPProfile *dcpProf = parent->imgsrc->getDCP(params.icm, parent->currWB); 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, as); + parent->bwAutoR, parent->bwAutoG, parent->bwAutoB, dcpProf); } /*xref=000;yref=000; @@ -816,7 +814,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); + 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.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 72f801bab..c6d66e4bf 100644 --- a/rtengine/demosaic_algos.cc +++ b/rtengine/demosaic_algos.cc @@ -1414,7 +1414,10 @@ 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); - gamtab->makeIdentity(65535.f); + + for(int i = 0; i < 65536; i++) { + (*gamtab)[i] = (float)i / 65535.f; + } } diff --git a/rtengine/diagonalcurves.cc b/rtengine/diagonalcurves.cc index a5505391e..f09eb3459 100644 --- a/rtengine/diagonalcurves.cc +++ b/rtengine/diagonalcurves.cc @@ -72,15 +72,11 @@ 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) { @@ -264,8 +260,6 @@ 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 @@ -307,10 +301,10 @@ double DiagonalCurve::getVal (double t) const } // do a binary search for the right interval: - unsigned int k_lo = 0, k_hi = N - 1; + int k_lo = 0, k_hi = N - 1; - while (k_hi > 1 + k_lo) { - unsigned int k = (k_hi + k_lo) / 2; + while (k_hi - k_lo > 1) { + int k = (k_hi + k_lo) / 2; if (x[k] > t) { k_hi = k; @@ -329,7 +323,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) * 0.1666666666666666666666666666666; + 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; return CLIPD(r); } @@ -340,7 +334,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 (UNLIKELY(i > (hashSize + 1))) { + if (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; @@ -353,7 +347,7 @@ double DiagonalCurve::getVal (double t) const k_hi = hash.at(i).higherValue; // do a binary search for the right interval : - while (k_hi > 1 + k_lo) { + while (k_hi - k_lo > 1) { unsigned int k = (k_hi + k_lo) / 2; if (poly_x[k] > t) { @@ -363,7 +357,13 @@ double DiagonalCurve::getVal (double t) const } } - return poly_y[k_lo] + (t - poly_x[k_lo]) * dyByDx[k_lo]; + 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; break; } diff --git a/rtengine/flatcurves.cc b/rtengine/flatcurves.cc index 5a4dfeacf..ee4d6d29c 100644 --- a/rtengine/flatcurves.cc +++ b/rtengine/flatcurves.cc @@ -16,14 +16,21 @@ * 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(nullptr), rightTangent(nullptr), identityValue(0.5), periodic(isPeriodic) +FlatCurve::FlatCurve (const std::vector& p, bool isPeriodic, int poly_pn) : kind(FCT_Empty), leftTangent(NULL), rightTangent(NULL), identityValue(0.5), periodic(isPeriodic) { ppn = poly_pn > 65500 ? 65500 : poly_pn; @@ -334,7 +341,17 @@ 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]); - fillDyByDx(); + /* + // 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 (); + */ } double FlatCurve::getVal (double t) const @@ -350,10 +367,10 @@ double FlatCurve::getVal (double t) const } // do a binary search for the right interval: - unsigned int k_lo = 0, k_hi = poly_x.size() - 1; + int k_lo = 0, k_hi = poly_x.size() - 1; - while (k_hi > 1 + k_lo) { - unsigned int k = (k_hi + k_lo) / 2; + while (k_hi - k_lo > 1) { + int k = (k_hi + k_lo) / 2; if (poly_x[k] > t) { k_hi = k; @@ -362,7 +379,9 @@ double FlatCurve::getVal (double t) const } } - return poly_y[k_lo] + (t - poly_x[k_lo]) * dyByDx[k_lo]; + 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; break; } diff --git a/rtengine/helpersse2.h b/rtengine/helpersse2.h index 0f1fc5759..da1691748 100644 --- a/rtengine/helpersse2.h +++ b/rtengine/helpersse2.h @@ -26,20 +26,17 @@ 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 1f82ea3e6..4b0450e54 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -818,21 +818,33 @@ public: } } } else if (interp == TI_Bilinear) { - float heightByNh = float(height) / float(nh); - float widthByNw = float(width) / float(nw); - float syf = 0.f; + for (int i = 0; i < nh; i++) { + int sy = i * height / nh; - 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; + if (sy >= height) { + sy = height - 1; + } - float sxf = 0.f; + float dy = float(i) * float(height) / float(nh) - float(sy); + int ny = sy + 1; - 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; + 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; + } 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)); @@ -998,6 +1010,9 @@ 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++; } @@ -1601,6 +1616,9 @@ 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 f252dc1bb..905c8c50e 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 (const Glib::ustring &fname, bool batch = false) = 0; + virtual int load (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() const = 0; // tracks whether cached rgb output of demosaic has been modified + virtual bool IsrgbSourceModified() = 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 (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hlp, const ColorManagementParams &cmp, const RAWParams &raw) = 0; + virtual void getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hlp, ColorManagementParams cmp, RAWParams raw) {} 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, 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 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 getAutoWBMultipliers (double &rm, double &gm, double &bm) = 0; - virtual ColorTemp getWB () const = 0; + virtual ColorTemp getWB () = 0; virtual ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal) = 0; - virtual double getDefGain () const + virtual double getDefGain () { return 1.0; } @@ -109,7 +109,7 @@ public: virtual ImageData* getImageData () = 0; virtual ImageMatrices* getImageMatrices () = 0; virtual bool isRAW() const = 0; - virtual DCPProfile* getDCP(const ColorManagementParams &cmp, ColorTemp &wb, DCPProfile::ApplyState &as) + virtual DCPProfile* getDCP(ColorManagementParams cmp, ColorTemp &wb) { return NULL; }; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index f585acacf..7434776d5 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -23,9 +23,7 @@ #include "../rtgui/ppversion.h" #include "colortemp.h" #include "improcfun.h" -#ifdef _OPENMP -#include -#endif + namespace rtengine { @@ -42,7 +40,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(32770, 0), // lumacurve[32768] and lumacurve[32769] will be set to 32768 and 32769 later to allow linear interpolation + lumacurve(65536, 0), chroma_acurve(65536, 0), chroma_bcurve(65536, 0), satcurve(65536, 0), @@ -54,10 +52,13 @@ ImProcCoordinator::ImProcCoordinator () Noisecurve(65536, 0), NoiseCCcurve(65536, 0), vhist16(65536), vhist16bw(65536), - lhist16CAM(65536), + lhist16(65536), lhist16Cropped(65536), + lhist16CAM(65536), lhist16CroppedCAM(65536), lhist16CCAM(65536), lhist16RETI(), - lhist16LClad(65536), + histCropped(65536), + lhist16Clad(65536), lhist16CLlad(65536), + lhist16LClad(65536), lhist16LLClad(65536), histRed(256), histRedRaw(256), histGreen(256), histGreenRaw(256), histBlue(256), histBlueRaw(256), @@ -66,6 +67,7 @@ ImProcCoordinator::ImProcCoordinator () histToneCurveBW(256), histLCurve(256), histCCurve(256), + histCLurve(256), histLLCurve(256), histLCAM(256), @@ -365,7 +367,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) */ imgsrc->convertColorSpace(orig_prev, params.icm, currWB); - ipf.firstAnalysis (orig_prev, params, vhist16); + ipf.firstAnalysis (orig_prev, ¶ms, vhist16); } readyphase++; @@ -442,36 +444,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, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, scale == 1 ? 1 : 1); + vhist16, histCropped, 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); - 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); - } + 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.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); @@ -535,11 +537,9 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) double ggm = 33.; double bbm = 33.; - DCPProfile::ApplyState as; - DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB, as); - + DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB); 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, as); + 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); if(params.blackwhite.enabled && params.blackwhite.autoc && abwListener) { if (settings->verbose) { @@ -561,46 +561,55 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } // compute L channel histogram - int x1, y1, x2, y2; + int x1, y1, x2, y2, pos; 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 | 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) || (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) { + autili = false; + butili = false; + ccutili = false; + cclutili = false; + clcutili = false; - CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, scale == 1 ? 1 : 16); + CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, lhist16CLlad, histCLurve, scale == 1 ? 1 : 16); + float adjustr = 1.0f; - 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 (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); } if (todo & (M_LUMINANCE + M_COLOR) ) { @@ -608,9 +617,8 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) progress ("Applying Color Boost...", 100 * readyphase / numofphases); // ipf.MSR(nprevl, nprevl->W, nprevl->H, 1); - 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.chromiLuminanceCurve (NULL, pW, nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, histCCurve, histCLurve, histLLCurve, histLCurve); ipf.vibrance(nprevl); if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { @@ -672,7 +680,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, scale == 1 ? 1 : 16); + CurveFactory::curveWavContL(wavcontlutili, params.wavelet.wavclCurve, wavclCurve , /*lhist16CLlad, histCLurve,*/ scale == 1 ? 1 : 16); if((params.wavelet.enabled)) { @@ -691,24 +699,39 @@ 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; + int x1, y1, x2, y2, pos, posc; params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); lhist16CAM.clear(); + lhist16CroppedCAM.clear(); lhist16CCAM.clear(); - 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])); + 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])); lhist16CAM[pos]++; lhist16CCAM[posc]++; } - } - CurveFactory::curveLightBrightColor (params.colorappearance.curve, params.colorappearance.curve2, params.colorappearance.curve3, - lhist16CAM, histLCAM, lhist16CCAM, histCCAM, - customColCurve1, customColCurve2, customColCurve3, 1); + 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 + ); float fnum = imgsrc->getMetaData()->getFNumber (); // F number float fiso = imgsrc->getMetaData()->getISOSpeed () ; // ISO float fspeed = imgsrc->getMetaData()->getShutterSpeed () ; // Speed @@ -1285,6 +1308,7 @@ void ImProcCoordinator::startProcessing(int changeCode) void ImProcCoordinator::process () { + if (plistener) { plistener->setProgressState (true); } diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 4f1a6a691..6a6c203d2 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -107,14 +107,16 @@ protected: LUTf NoiseCCcurve; LUTu vhist16, vhist16bw; - LUTu lhist16CAM; + LUTu lhist16, lhist16Cropped; + LUTu lhist16CAM, lhist16CroppedCAM; LUTu lhist16CCAM; LUTu lhist16RETI; - LUTu lhist16CLlad, lhist16LClad; + LUTu histCropped; + LUTu lhist16Clad, lhist16CLlad, lhist16LClad, lhist16LLClad; LUTu histRed, histRedRaw; LUTu histGreen, histGreenRaw; LUTu histBlue, histBlueRaw; - LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve; + LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve, histCLurve; LUTu histLLCurve, histLCAM, histCCAM, histClad, bcabhist, histChroma, histLRETI; LUTf CAMBrightCurveJ, CAMBrightCurveQ; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 264ff1e2a..bc70bf5e5 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -40,10 +40,6 @@ #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) @@ -58,15 +54,15 @@ extern const Settings* settings; ImProcFunctions::~ImProcFunctions () { - if (monitorTransform) { + if (monitorTransform != NULL) { cmsDeleteTransform (monitorTransform); } - if (output2monitorTransform) { + if (output2monitorTransform != NULL) { cmsDeleteTransform (output2monitorTransform); } - if (lab2outputTransform) { + if (lab2outputTransform != NULL) { cmsDeleteTransform (lab2outputTransform); } } @@ -76,24 +72,52 @@ 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) { + if (monitorTransform != NULL) { cmsDeleteTransform (monitorTransform); } - if (output2monitorTransform) { + if (output2monitorTransform != NULL) { cmsDeleteTransform (output2monitorTransform); } - if (lab2outputTransform) { + if (lab2outputTransform != NULL) { cmsDeleteTransform (lab2outputTransform); } - monitorTransform = nullptr; - output2monitorTransform = nullptr; - lab2outputTransform = nullptr; + monitorTransform = NULL; + output2monitorTransform = NULL; + lab2outputTransform = NULL; #if !defined(__APPLE__) // No support for monitor profiles on OS X, all data is sRGB @@ -101,7 +125,7 @@ void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, con if (monitor) { MyMutex::MyLock lcmsLock (*lcmsMutex); - cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr); + cmsHPROFILE iprof = cmsCreateLab4Profile(NULL); monitorTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_8, monitorIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); // NOCACHE is for thread safety, NOOPTIMIZE for precision @@ -123,66 +147,59 @@ void ImProcFunctions::updateColorProfiles (const ColorManagementParams& icm, con #endif } -void ImProcFunctions::firstAnalysis (const Imagefloat* const original, const ProcParams ¶ms, LUTu & histogram) +void ImProcFunctions::firstAnalysis (Imagefloat* original, const ProcParams* params, LUTu & histogram) { - 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])}; + Glib::ustring wprofile = params->icm.working; // calculate histogram of the y channel needed for contrast curve calculation in exposure adjustments - histogram.clear(); + + int T = 1; +#ifdef _OPENMP if(multiThread) { + T = omp_get_max_threads(); + } -#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++) { + unsigned int** hist = new unsigned int* [T]; - 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]++; - } - } + for (int i = 0; i < T; i++) { + hist[i] = new unsigned int[65536]; + memset (hist[i], 0, 65536 * sizeof(int)); + } #ifdef _OPENMP - #pragma omp critical -#endif - histogram += hist; + #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; - } - } else { - 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); - histogram[y]++; - } + 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]; + } + + for (int i = 0; i < T; i++) { + delete [] hist[i]; + } + + delete [] hist; } // Copyright (c) 2012 Jacques Desmis @@ -1443,20 +1460,41 @@ 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 - LUTu hist16JCAM; - LUTu hist16_CCAM; - - if(pW != 1 && params->colorappearance.datacie) { //only with improccoordinator - hist16JCAM(32768); + if(pW != 1) { //only with improccoordinator + dLcurve(65536, 0); + dLcurve.clear(); + hist16JCAM(65536); hist16JCAM.clear(); - hist16_CCAM(48000); + + 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.clear(); } @@ -1467,16 +1505,15 @@ 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; + float f, nc, yb, la, c, xw, yw, zw, f2, c2, nc2, yb2, la2; float fl, n, nbb, ncb, aw; //d float xwd, ywd, zwd; int alg = 0; bool algepd = false; + float sum = 0.f; - 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)); + const bool ciedata = (params->colorappearance.datacie && pW != 1); + bool jp = ciedata; ColorTemp::temp2mulxyz (params->wb.temperature, params->wb.green, params->wb.method, Xw, Zw); //compute white Xw Yw Zw : white current WB @@ -1518,7 +1555,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; } @@ -1552,7 +1589,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; @@ -1572,7 +1609,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; } @@ -1585,7 +1622,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } } - const float la2 = float(params->colorappearance.adaplum); + la2 = float(params->colorappearance.adaplum); // level of adaptation const float deg = (params->colorappearance.degree) / 100.0f; @@ -1667,6 +1704,132 @@ 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) { @@ -1692,7 +1855,9 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int } else { yb = 90.0f; } - } else if(settings->viewinggreySc == 1) { + } + + if(settings->viewinggreySc == 1) { yb = 18.0f; //fixed } @@ -1732,145 +1897,16 @@ 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] = { @@ -1993,16 +2029,18 @@ 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]; //lightness CIECAM02 + contrast + Jpro = CAMBrightCurveJ[Jpro * 327.68f] / 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); - } else if(alg == 1) { + } + + if(alg == 1) { // Lightness saturation - Jpro = CAMBrightCurveJ[Jpro * 327.68f]; //lightness CIECAM02 + contrast + Jpro = CAMBrightCurveJ[Jpro * 327.68f] / 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) @@ -2015,7 +2053,8 @@ 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) { - Qpro = CAMBrightCurveQ[(float)(Qpro * coefQ)]; //brightness and contrast + float coef = 32767.f / wh; + Qpro = (CAMBrightCurveQ[(float)(Qpro * coef)]) / coef; //brightness and contrast float Mp, sres; Mp = Mpro / 100.0f; Ciecam02::curvecolorfloat(mchr, Mp , sres, 2.5f); @@ -2028,8 +2067,14 @@ 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) */ - Qpro = CAMBrightCurveQ[(float)(Qpro * coefQ)]; //brightness and contrast + } 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 + } float Mp, sres; Mp = Mpro / 100.0f; @@ -2048,7 +2093,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int Jpro = 99.9f; } - Jpro = CAMBrightCurveJ[(float)(Jpro * 327.68f)]; //lightness CIECAM02 + contrast + Jpro = (CAMBrightCurveJ[(float)(Jpro * 327.68f)]) / 327.68f; //lightness CIECAM02 + contrast float Sp = spro / 100.0f; Ciecam02::curvecolorfloat(schr, Sp , sres, 1.5f); dred = 100.f; // in C mode @@ -2267,6 +2312,7 @@ 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; @@ -2281,6 +2327,7 @@ 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" @@ -2291,13 +2338,20 @@ 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; @@ -2328,40 +2382,57 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int if(!params->colorappearance.tonecie || !settings->autocielab || !epdEnabled) { - if(ciedata) { //only with improccoordinator + if(ciedata) { // Data for J Q M s and C histograms int posl, posc; float brli = 327.f; float chsacol = 327.f; - float libr; - float colch; + int libr = 0; + int colch = 0; - //update histogram if(curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) { brli = 70.0f; - libr = Q; //40.0 to 100.0 approximative factor for Q - 327 for J - } else { /*if(curveMode == ColorAppearanceParams::TC_MODE_LIGHT)*/ + libr = 1; + } else if(curveMode == ColorAppearanceParams::TC_MODE_LIGHT) { brli = 327.f; - libr = J; //327 for J + libr = 0; } - posl = (int)(libr * brli); - hist16JCAM[posl]++; - if (curveMode3 == ColorAppearanceParams::TC_MODE_CHROMA) { chsacol = 327.f; - colch = C; //450.0 approximative factor for s 320 for M + colch = 0; } else if(curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { chsacol = 450.0f; - colch = s; - } else { /*if(curveMode3 == ColorAppearanceParams::TC_MODE_COLORF)*/ + colch = 1; + } else if(curveMode3 == ColorAppearanceParams::TC_MODE_COLORF) { chsacol = 327.0f; - colch = M; + colch = 2; } - posc = (int)(colch * chsacol); - hist16_CCAM[posc]++; + //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 + } + 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) { @@ -2379,9 +2450,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 = xx * 655.35f; - y = yy * 655.35f; - z = zz * 655.35f; + x = (float)xx * 655.35f; + y = (float)yy * 655.35f; + z = (float)zz * 655.35f; float Ll, aa, bb; //convert xyz=>lab Color::XYZ2Lab(x, y, z, Ll, aa, bb); @@ -2502,13 +2573,25 @@ 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 - hist16JCAM.compressTo(histLCAM); - //update histogram C - hist16_CCAM.compressTo(histCCAM); + 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] ; + } + } } } @@ -2640,8 +2723,6 @@ 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 ); @@ -2651,8 +2732,14 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int //EPDToneMapCIE adated to CIECAM - constexpr float eps = 0.0001f; + const 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 @@ -2690,33 +2777,54 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int int posl, posc; float brli = 327.f; float chsacol = 327.f; - float libr; - float colch; + int libr = 0; + int colch = 0; + float sa_t; if(curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) { brli = 70.0f; - 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)*/ + libr = 1; + } else if(curveMode == ColorAppearanceParams::TC_MODE_LIGHT) { brli = 327.f; - libr = ncie->J_p[i][j]; //327 for J + libr = 0; } - posl = (int)(libr * brli); - hist16JCAM[posl]++; - if (curveMode3 == ColorAppearanceParams::TC_MODE_CHROMA) { chsacol = 327.f; - colch = ncie_C_p; + colch = 0; } else if(curveMode3 == ColorAppearanceParams::TC_MODE_SATUR) { chsacol = 450.0f; - colch = 100.f * sqrtf(ncie_C_p / ncie->Q_p[i][j]); - } else { /*if(curveMode3 == ColorAppearanceParams::TC_MODE_COLORF)*/ + colch = 1; + } else if(curveMode3 == ColorAppearanceParams::TC_MODE_COLORF) { chsacol = 327.0f; - colch = ncie->M_p[i][j]; + colch = 2; } - posc = (int)(colch * chsacol); - hist16_CCAM[posc]++; + //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]++; + } } //end histograms @@ -2756,10 +2864,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, wip, highlight, 0.15f, 0.96f, neg, more_rgb); + Color::gamutLchonly(sincosval, Lprov1, Chprov1, wipa, highlight, 0.15f, 0.96f, neg, more_rgb); #else //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); + Color::gamutLchonly(sincosval, Lprov1, Chprov1, wipa, highlight, 0.15f, 0.96f); #endif lab->L[i][j] = Lprov1 * 327.68f; @@ -2818,10 +2926,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, wip, highlight, 0.15f, 0.96f, neg, more_rgb); + Color::gamutLchonly(sincosval, Lprov1, Chprov1, wipa, highlight, 0.15f, 0.96f, neg, more_rgb); #else //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); + Color::gamutLchonly(sincosval, Lprov1, Chprov1, wipa, highlight, 0.15f, 0.96f); #endif lab->L[i][j] = Lprov1 * 327.68f; lab->a[i][j] = 327.68f * Chprov1 * sincosval.y; @@ -2842,12 +2950,24 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int //show CIECAM histograms if(ciedata) { //update histogram J and Q - //update histogram J - hist16JCAM.compressTo(histLCAM); + 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 color histogram M,s,C - hist16_CCAM.compressTo(histCCAM); + 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] ; + } + } } + } } } @@ -2947,22 +3067,23 @@ 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 DCPProfile::ApplyState &asIn ) + 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 ) { - 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); + 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); } // 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 DCPProfile::ApplyState &asIn ) + 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) { - Imagefloat *tmpImage = nullptr; + LUTf fGammaLUTf; + Imagefloat *tmpImage = NULL; // NOTE: We're getting all 3 pointers here, but this function may not need them all, so one could optimize this - Imagefloat* editImgFloat = nullptr; - LabImage* editLab = nullptr; - PlanarWhateverData* editWhatever = nullptr; + Imagefloat* editImgFloat = NULL; + LabImage* editLab = NULL; + PlanarWhateverData* editWhatever = NULL; EditUniqueID editID = pipetteBuffer ? pipetteBuffer->getEditID() : EUID_None; if (editID != EUID_None) { @@ -2988,8 +3109,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 && (params->sh.highlights > 0 || params->sh.shadows > 0); - bool processLCE = params->sh.enabled && shmap && params->sh.localcontrast > 0; + 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; double lceamount = params->sh.localcontrast / 200.0; TMatrix wprof = iccStore->workingSpaceMatrix (params->icm.working); @@ -3049,7 +3170,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (hCurve->isIdentity()) { delete hCurve; - hCurve = nullptr; + hCurve = NULL; hCurveEnabled = false; } } @@ -3059,7 +3180,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (sCurve->isIdentity()) { delete sCurve; - sCurve = nullptr; + sCurve = NULL; sCurveEnabled = false; } } @@ -3069,7 +3190,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (vCurve->isIdentity()) { delete vCurve; - vCurve = nullptr; + vCurve = NULL; vCurveEnabled = false; } } @@ -3079,14 +3200,14 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (bwlCurve->isIdentity()) { delete bwlCurve; - bwlCurve = nullptr; + bwlCurve = NULL; bwlCurveEnabled = false; } } std::shared_ptr hald_clut; bool clutAndWorkingProfilesAreSame = false; - TMatrix xyz2clut, clut2xyz; + TMatrix work2xyz, xyz2clut, clut2xyz, xyz2work; #ifdef __SSE2__ vfloat v_work2xyz[3][3] ALIGNED16; vfloat v_xyz2clut[3][3] ALIGNED16; @@ -3101,20 +3222,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(wprof[i][j]); + v_work2xyz[i][j] = F2V(work2xyz[i][j]); v_xyz2clut[i][j] = F2V(xyz2clut[i][j]); - v_xyz2work[i][j] = F2V(wiprof[i][j]); + v_xyz2work[i][j] = F2V(xyz2work[i][j]); v_clut2xyz[i][j] = F2V(clut2xyz[i][j]); } } - #endif } @@ -3269,6 +3390,13 @@ 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); } @@ -3276,6 +3404,15 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer int W = working->width; int H = working->height; + + + + + + + + + #define TS 112 #ifdef _OPENMP @@ -3283,8 +3420,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer #endif { char *buffer; - char *editIFloatBuffer = nullptr; - char *editWhateverBuffer = nullptr; + char *editIFloatBuffer = NULL; + char *editWhateverBuffer = NULL; buffer = (char *) malloc(3 * sizeof(float) * TS * TS + 20 * 64 + 63); char *data; @@ -3427,8 +3564,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } } - if (dcpProf) { - dcpProf->step2ApplyTile(rtemp, gtemp, btemp, tW - jstart, tH - istart, TS, asIn); + if (dcpProf != NULL) { + dcpProf->step2ApplyTile(rtemp, gtemp, btemp, tW - jstart, tH - istart, TS); } for (int i = istart, ti = 0; i < tH; i++, ti++) { @@ -3473,9 +3610,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] = 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; + 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); } } } @@ -3544,9 +3681,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] = 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; + 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); } } } @@ -3603,19 +3740,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] = Color::gamma2curve[rtemp[ti * TS + tj]] / 65536.f; + editWhateverTmp[ti * TS + tj] = fGammaLUTf[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] = Color::gamma2curve[gtemp[ti * TS + tj]] / 65536.f; + editWhateverTmp[ti * TS + tj] = fGammaLUTf[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] = Color::gamma2curve[btemp[ti * TS + tj]] / 65536.f; + editWhateverTmp[ti * TS + tj] = fGammaLUTf[btemp[ti * TS + tj]] / 65536.f; } } } @@ -4048,9 +4185,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] = 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; + 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); } } } else if (editID == EUID_BlackWhiteLuminance) { @@ -4226,7 +4363,6 @@ 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]); @@ -4242,7 +4378,6 @@ 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++) { @@ -4251,7 +4386,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, wprof ); + Color::rgbxyz(sourceR, sourceG, sourceB, x, y, z, work2xyz); Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, xyz2clut); } } @@ -4294,7 +4429,6 @@ 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]); @@ -4310,7 +4444,6 @@ 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++) { @@ -4320,7 +4453,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, wiprof ); + Color::xyz2rgb(x, y, z, sourceR, sourceG, sourceB, xyz2work); } } } @@ -4351,9 +4484,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float fx, fy, fz; - 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)); + 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)); lab->L[i][j] = (116.0f * fy - 5242.88f); //5242.88=16.0*327.68; lab->a[i][j] = (500.0f * (fx - fy) ); @@ -4509,7 +4642,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) = Color::gamma2curve[tmpImage->r(i, j)] / 65535.f; // assuming that r=g=b + editWhatever->v(i, j) = CLIP(fGammaLUTf[tmpImage->r(i, j)] / 65535.f); // assuming that r=g=b } } } @@ -5474,7 +5607,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 &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 &histCLurve, LUTu &histLLCurve, LUTu &histLCurve) { int W = lold->W; int H = lold->H; @@ -5482,9 +5615,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 = nullptr; - LabImage* editLab = nullptr; - PlanarWhateverData* editWhatever = nullptr; + Imagefloat* editImgFloat = NULL; + LabImage* editLab = NULL; + PlanarWhateverData* editWhatever = NULL; EditUniqueID editID = EUID_None; bool editPipette = false; @@ -5510,7 +5643,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu } } - FlatCurve* chCurve = nullptr;// curve C=f(H) + FlatCurve* chCurve = NULL;// curve C=f(H) bool chutili = false; if (params->labCurve.chromaticity > -100) { @@ -5519,7 +5652,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu if (!chCurve || chCurve->isIdentity()) { if (chCurve) { delete chCurve; - chCurve = nullptr; + chCurve = NULL; } }//do not use "Munsell" if Chcurve not used else { @@ -5527,7 +5660,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu } } - FlatCurve* lhCurve = nullptr;//curve L=f(H) + FlatCurve* lhCurve = NULL;//curve L=f(H) bool lhutili = false; if (params->labCurve.chromaticity > -100) { @@ -5536,7 +5669,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu if (!lhCurve || lhCurve->isIdentity()) { if (lhCurve) { delete lhCurve; - lhCurve = nullptr; + lhCurve = NULL; } }//do not use "Munsell" if Chcurve not used else { @@ -5544,7 +5677,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu } } - FlatCurve* hhCurve = nullptr;//curve H=f(H) + FlatCurve* hhCurve = NULL;//curve H=f(H) bool hhutili = false; if (params->labCurve.chromaticity > -100) { @@ -5553,7 +5686,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu if (!hhCurve || hhCurve->isIdentity()) { if (hhCurve) { delete hhCurve; - hhCurve = nullptr; + hhCurve = NULL; } }//do not use "Munsell" if Chcurve not used else { @@ -5561,15 +5694,31 @@ 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); - hist16Clad.clear(); 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.clear(); } @@ -5607,10 +5756,7 @@ 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; - 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; + const bool bwToning = params->labCurve.chromaticity == - 100 /*|| params->blackwhite.method=="Ch" || params->blackwhite.enabled */ || bwonly; //if(chromaticity==-100) chromaticity==-99; const bool LCredsk = params->labCurve.lcredsk; const bool ccut = ccutili; @@ -6068,7 +6214,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu //update histogram C if(pW != 1) { //only with improccoordinator - int posp = (int)sqrt(atmp * atmp + btmp * btmp); + int posp = CLIP((int)sqrt((atmp * atmp + btmp * btmp))); hist16Clad[posp]++; } @@ -6124,7 +6270,7 @@ SSEFUNCTION void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBu //update histo LC if(pW != 1) { //only with improccoordinator - int posl = Lprov1 * 327.68f; + int posl = CLIP((int(Lprov1 * 327.68f))); hist16Llad[posl]++; } @@ -6212,11 +6358,20 @@ 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 - //update histogram C with data chromaticity and not with CC curve - hist16Clad.compressTo(histCCurve); - //update histogram L with data luminance - hist16Llad.compressTo(histLCurve); + 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] ; + } } #ifdef _DEBUG @@ -6617,15 +6772,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] * maxL * (1.f / gamm) + minL; - } + 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; } -void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double defgain, double clip, +void ImProcFunctions::getAutoExp (LUTu & histogram, int histcompr, double defgain, double clip, double& expcomp, int& bright, int& contr, int& black, int& hlcompr, int& hlcomprthresh) { @@ -6638,7 +6793,12 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double float ave = 0.f, hidev = 0.f, lodev = 0.f; //find average luminance - histogram.getSumAndAverage(sum, ave); + for (int i = 0; i < imax; i++) { + sum += histogram[i]; + ave += histogram[i] * (float)i; + } + + ave /= (sum); //find median of luminance int median = 0, count = histogram[0]; @@ -6663,37 +6823,25 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double float octile[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}, ospread = 0.f; count = 0; - int i = 0; - - for (; i < min((int)ave, imax); i++) { + for (int i = 0; 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); + octile[count] = log(1. + (float)i) / log(2.f); count++;// = min(count+1,7); } } - //lodev += SQR(ave-i)*histogram[i]; - lodev += (xlog(ave + 1.f) - xlog((float)i + 1.)) * histogram[i]; - losum += histogram[i]; - } - - 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); - } + 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]; } - - //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 @@ -6756,7 +6904,7 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double int clipped = 0; int rawmax = (imax) - 1; - while (histogram[rawmax] + clipped <= 0 && rawmax > 1) { + while (rawmax > 1 && histogram[rawmax] + clipped <= 0) { clipped += histogram[rawmax]; rawmax--; } @@ -6848,18 +6996,12 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double //take gamma into account double whiteclipg = (int)(CurveFactory::gamma2 (whiteclip * corr / 65536.0) * 65536.0); - float gavg = 0.; + double gavg = 0.; - 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; + for (int i = 0; i<65536 >> histcompr; i++) { + gavg += histogram[i] * CurveFactory::gamma2((float)(corr * (i << histcompr) < 65535 ? corr * (i << histcompr) : 65535)) / sum; } - 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 @@ -6928,7 +7070,6 @@ void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double } bright = max(-100, min(bright, 100)); - } @@ -6943,13 +7084,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) { + if (thumb == NULL) { return 0.0; } Thumbnail* raw = rtengine::Thumbnail::loadFromRaw (fname, ri, w_raw, h_raw, 1, 1.0, FALSE); - if (!raw) { + if (raw == NULL) { delete thumb; return 0.0; } @@ -6973,7 +7114,7 @@ double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_si thumbGray = thumb->getGrayscaleHistEQ (width); rawGray = raw->getGrayscaleHistEQ (width); - if (!thumbGray || !rawGray) { + if (thumbGray == NULL || rawGray == NULL) { if (thumbGray) { delete thumbGray; } diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index ccc77ab9f..90a046149 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -75,6 +75,7 @@ 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 (); @@ -228,15 +229,15 @@ public: bool needsTransform (); bool needsPCVignetting (); - void firstAnalysis (const Imagefloat* const working, const ProcParams ¶ms, LUTu & vhist16); + void firstAnalysis (Imagefloat* working, const ProcParams* params, 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 DCPProfile::ApplyState &asIn ); + const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf); 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, const DCPProfile::ApplyState &asIn ); + double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf); 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); @@ -254,7 +255,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 &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 &histCLurve, LUTu &histLCurve, LUTu &histLurve); void vibrance (LabImage* lab);//Jacques' vibrance void colorCurve (LabImage* lold, LabImage* lnew); void sharpening (LabImage* lab, float** buffer, SharpeningParams &sharpenParam); @@ -376,7 +377,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 (const LUTu & histogram, int histcompr, double defgain, double clip, double& expcomp, int& bright, int& contr, int& black, int& hlcompr, int& hlcomprthresh); + static void getAutoExp (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 3b2c5fbdc..d2509b620 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::getInstance()->init (baseDir + "/dcpprofiles"); + dcpStore->init (baseDir + "/dcpprofiles"); CameraConstantsStore::getInstance ()->init (baseDir, userSettingsDir); profileStore.init (); diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 3e87afe0f..66e630d0f 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[R]) >> 8; - data[ix++] = ((int)Color::gamma2curve[G]) >> 8; - data[ix++] = ((int)Color::gamma2curve[B]) >> 8; + data[ix++] = ((int)Color::gamma2curve[CLIP (R)]) >> 8; + data[ix++] = ((int)Color::gamma2curve[CLIP (G)]) >> 8; + data[ix++] = ((int)Color::gamma2curve[CLIP (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[R] >> 8; - image->data[ix++] = (int)Color::gamma2curve[G] >> 8; - image->data[ix++] = (int)Color::gamma2curve[B] >> 8; + 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; } } } diff --git a/rtengine/ipvibrance.cc b/rtengine/ipvibrance.cc index 1d152c737..3e6ff97f2 100644 --- a/rtengine/ipvibrance.cc +++ b/rtengine/ipvibrance.cc @@ -59,7 +59,9 @@ void fillCurveArrayVib(DiagonalCurve* diagCurve, LUTf &outCurve) outCurve[i] = 65535.f * diagCurve->getVal( double(i) / 65535.0 ); } } else { - outCurve.makeIdentity(); + for (int i = 0; i <= 0xffff; i++) { + outCurve[i] = float(i); + } } } diff --git a/rtengine/previewimage.cc b/rtengine/previewimage.cc index 16355a8c0..9de5c81cb 100644 --- a/rtengine/previewimage.cc +++ b/rtengine/previewimage.cc @@ -110,8 +110,15 @@ 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 25d5df212..67b02a650 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -19,7 +19,7 @@ #include #include "procparams.h" #include "rt_math.h" -#include "curves.h" +#include "dcp.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(const Glib::ustring &procparams_fname, const Glib::ustring &prefix, Glib::ustring embedded_fname) +static Glib::ustring expandRelativePath(Glib::ustring procparams_fname, 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(const Glib::ustring &procparams_fname, c return absPath; } -static Glib::ustring relativePathIfInside(const Glib::ustring &procparams_fname, bool fnameAbsolute, Glib::ustring embedded_fname) +static Glib::ustring relativePathIfInside(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(const Glib::ustring &procparams_fname, return prefix + embedded_fname.substr(dir1.length()); } -int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, bool fnameAbsolute, ParamsEdited* pedited) +int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsolute, ParamsEdited* pedited) { if (fname.empty () && fname2.empty ()) { @@ -1332,2076 +1332,2076 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b 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; - } - - 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; - } - - 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->general.rank) { + keyFile.set_integer ("General", "Rank", rank); + } - 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.colorlabel) { + keyFile.set_integer ("General", "ColorLabel", colorlabel); + } - keyFile.set_string ("Black & White", "BeforeCurveMode", mode); - } + if (!pedited || pedited->general.intrash) { + keyFile.set_boolean ("General", "InTrash", inTrash); + } - if (!pedited || pedited->blackwhite.afterCurveMode) { - Glib::ustring mode; + // save tone curve + if (!pedited || pedited->toneCurve.autoexp) { + keyFile.set_boolean ("Exposure", "Auto", toneCurve.autoexp); + } - switch (blackwhite.afterCurveMode) { - case (BlackWhiteParams::TC_MODE_STD_BW): - mode = "Standard"; - break; + if (!pedited || pedited->toneCurve.clip) { + keyFile.set_double ("Exposure", "Clip", toneCurve.clip); + } - case (BlackWhiteParams::TC_MODE_WEIGHTEDSTD_BW): - mode = "WeightedStd"; - break; + if (!pedited || pedited->toneCurve.expcomp) { + keyFile.set_double ("Exposure", "Compensation", toneCurve.expcomp); + } - default: - break; - } + if (!pedited || pedited->toneCurve.brightness) { + keyFile.set_integer ("Exposure", "Brightness", toneCurve.brightness); + } - keyFile.set_string ("Black & White", "AfterCurveMode", mode); - } + if (!pedited || pedited->toneCurve.contrast) { + keyFile.set_integer ("Exposure", "Contrast", toneCurve.contrast); + } - if (!pedited || pedited->blackwhite.beforeCurve) { - Glib::ArrayHandle tcurvebw = blackwhite.beforeCurve; - keyFile.set_double_list("Black & White", "BeforeCurve", tcurvebw); - } + if (!pedited || pedited->toneCurve.saturation) { + keyFile.set_integer ("Exposure", "Saturation", toneCurve.saturation); + } - if (!pedited || pedited->blackwhite.afterCurve) { - Glib::ArrayHandle tcurvebw = blackwhite.afterCurve; - keyFile.set_double_list("Black & White", "AfterCurve", tcurvebw); - } + if (!pedited || pedited->toneCurve.black) { + keyFile.set_integer ("Exposure", "Black", toneCurve.black); + } - // 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->toneCurve.hlcompr) { + keyFile.set_integer ("Exposure", "HighlightCompr", toneCurve.hlcompr); + } - if (!pedited || pedited->labCurve.chromaticity) { - keyFile.set_integer ("Luminance Curve", "Chromaticity", labCurve.chromaticity); - } + if (!pedited || pedited->toneCurve.hlcomprthresh) { + keyFile.set_integer ("Exposure", "HighlightComprThreshold", toneCurve.hlcomprthresh); + } - if (!pedited || pedited->labCurve.avoidcolorshift) { - keyFile.set_boolean ("Luminance Curve", "AvoidColorShift", labCurve.avoidcolorshift); - } + if (!pedited || pedited->toneCurve.shcompr) { + keyFile.set_integer ("Exposure", "ShadowCompr", toneCurve.shcompr); + } - if (!pedited || pedited->labCurve.rstprotection) { - keyFile.set_double ("Luminance Curve", "RedAndSkinTonesProtection", labCurve.rstprotection); - } + // save highlight recovery settings + if (!pedited || pedited->toneCurve.hrenabled) { + keyFile.set_boolean ("HLRecovery", "Enabled", toneCurve.hrenabled); + } - if (!pedited || pedited->labCurve.lcredsk) { - keyFile.set_boolean ("Luminance Curve", "LCredsk", labCurve.lcredsk); - } + if (!pedited || pedited->toneCurve.method) { + keyFile.set_string ("HLRecovery", "Method", toneCurve.method); + } - if (!pedited || pedited->labCurve.lcurve) { - Glib::ArrayHandle lcurve = labCurve.lcurve; - keyFile.set_double_list("Luminance Curve", "LCurve", lcurve); - } + if (!pedited || pedited->toneCurve.curveMode) { + Glib::ustring method; - if (!pedited || pedited->labCurve.acurve) { - Glib::ArrayHandle acurve = labCurve.acurve; - keyFile.set_double_list("Luminance Curve", "aCurve", acurve); - } + switch (toneCurve.curveMode) { + case (ToneCurveParams::TC_MODE_STD): + method = "Standard"; + break; - if (!pedited || pedited->labCurve.bcurve) { - Glib::ArrayHandle bcurve = labCurve.bcurve; - keyFile.set_double_list("Luminance Curve", "bCurve", bcurve); - } + case (ToneCurveParams::TC_MODE_FILMLIKE): + method = "FilmLike"; + break; - if (!pedited || pedited->labCurve.cccurve) { - Glib::ArrayHandle cccurve = labCurve.cccurve; - keyFile.set_double_list("Luminance Curve", "ccCurve", cccurve); - } + case (ToneCurveParams::TC_MODE_SATANDVALBLENDING): + method = "SatAndValueBlending"; + break; - if (!pedited || pedited->labCurve.chcurve) { - Glib::ArrayHandle chcurve = labCurve.chcurve; - keyFile.set_double_list("Luminance Curve", "chCurve", chcurve); - } + case (ToneCurveParams::TC_MODE_WEIGHTEDSTD): + method = "WeightedStd"; + break; - if (!pedited || pedited->labCurve.lhcurve) { - Glib::ArrayHandle lhcurve = labCurve.lhcurve; - keyFile.set_double_list("Luminance Curve", "lhCurve", lhcurve); - } + case (ToneCurveParams::TC_MODE_LUMINANCE): + method = "Luminance"; + break; - if (!pedited || pedited->labCurve.hhcurve) { - Glib::ArrayHandle hhcurve = labCurve.hhcurve; - keyFile.set_double_list("Luminance Curve", "hhCurve", hhcurve); + case (ToneCurveParams::TC_MODE_PERCEPTUAL): + method = "Perceptual"; + break; } - if (!pedited || pedited->labCurve.lccurve) { - Glib::ArrayHandle lccurve = labCurve.lccurve; - keyFile.set_double_list("Luminance Curve", "LcCurve", lccurve); - } + keyFile.set_string ("Exposure", "CurveMode", method); + } - if (!pedited || pedited->labCurve.clcurve) { - Glib::ArrayHandle clcurve = labCurve.clcurve; - keyFile.set_double_list("Luminance Curve", "ClCurve", clcurve); - } + if (!pedited || pedited->toneCurve.curveMode2) { + Glib::ustring method; - // save sharpening - if (!pedited || pedited->sharpening.enabled) { - keyFile.set_boolean ("Sharpening", "Enabled", sharpening.enabled); - } + switch (toneCurve.curveMode2) { + case (ToneCurveParams::TC_MODE_STD): + method = "Standard"; + break; - if (!pedited || pedited->sharpening.method) { - keyFile.set_string ("Sharpening", "Method", sharpening.method); - } + case (ToneCurveParams::TC_MODE_FILMLIKE): + method = "FilmLike"; + break; - if (!pedited || pedited->sharpening.radius) { - keyFile.set_double ("Sharpening", "Radius", sharpening.radius); - } + case (ToneCurveParams::TC_MODE_SATANDVALBLENDING): + method = "SatAndValueBlending"; + break; - if (!pedited || pedited->sharpening.amount) { - keyFile.set_integer ("Sharpening", "Amount", sharpening.amount); - } + case (ToneCurveParams::TC_MODE_WEIGHTEDSTD): + method = "WeightedStd"; + 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_LUMINANCE): + method = "Luminance"; + break; - if (!pedited || pedited->sharpening.edgesonly) { - keyFile.set_boolean ("Sharpening", "OnlyEdges", sharpening.edgesonly); + case (ToneCurveParams::TC_MODE_PERCEPTUAL): + method = "Perceptual"; + break; } - if (!pedited || pedited->sharpening.edges_radius) { - keyFile.set_double ("Sharpening", "EdgedetectionRadius", sharpening.edges_radius); - } + keyFile.set_string ("Exposure", "CurveMode2", method); + } - if (!pedited || pedited->sharpening.edges_tolerance) { - keyFile.set_integer ("Sharpening", "EdgeTolerance", sharpening.edges_tolerance); - } + if (!pedited || pedited->toneCurve.curve) { + Glib::ArrayHandle tcurve = toneCurve.curve; + keyFile.set_double_list("Exposure", "Curve", tcurve); + } - if (!pedited || pedited->sharpening.halocontrol) { - keyFile.set_boolean ("Sharpening", "HalocontrolEnabled", sharpening.halocontrol); - } + if (!pedited || pedited->toneCurve.curve2) { + Glib::ArrayHandle tcurve = toneCurve.curve2; + keyFile.set_double_list("Exposure", "Curve2", tcurve); + } - if (!pedited || pedited->sharpening.halocontrol_amount) { - keyFile.set_integer ("Sharpening", "HalocontrolAmount", sharpening.halocontrol_amount); - } + //save retinex - if (!pedited || pedited->sharpening.deconvradius) { - keyFile.set_double ("Sharpening", "DeconvRadius", sharpening.deconvradius); - } + if (!pedited || pedited->retinex.str) { + keyFile.set_integer ("Retinex", "Str", retinex.str); + } - if (!pedited || pedited->sharpening.deconvamount) { - keyFile.set_integer ("Sharpening", "DeconvAmount", sharpening.deconvamount); - } + if (!pedited || pedited->retinex.scal) { + keyFile.set_integer ("Retinex", "Scal", retinex.scal); + } - if (!pedited || pedited->sharpening.deconvdamping) { - keyFile.set_integer ("Sharpening", "DeconvDamping", sharpening.deconvdamping); - } + if (!pedited || pedited->retinex.iter) { + keyFile.set_integer ("Retinex", "Iter", retinex.iter); + } - if (!pedited || pedited->sharpening.deconviter) { - keyFile.set_integer ("Sharpening", "DeconvIterations", sharpening.deconviter); - } + if (!pedited || pedited->retinex.grad) { + keyFile.set_integer ("Retinex", "Grad", retinex.grad); + } - // save vibrance - if (!pedited || pedited->vibrance.enabled) { - keyFile.set_boolean ("Vibrance", "Enabled", vibrance.enabled); - } + if (!pedited || pedited->retinex.grads) { + keyFile.set_integer ("Retinex", "Grads", retinex.grads); + } - if (!pedited || pedited->vibrance.pastels) { - keyFile.set_integer ("Vibrance", "Pastels", vibrance.pastels); - } + if (!pedited || pedited->retinex.gam) { + keyFile.set_double ("Retinex", "Gam", retinex.gam); + } - if (!pedited || pedited->vibrance.saturated) { - keyFile.set_integer ("Vibrance", "Saturated", vibrance.saturated); - } + if (!pedited || pedited->retinex.slope) { + keyFile.set_double ("Retinex", "Slope", retinex.slope); + } - 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.enabled) { + keyFile.set_boolean ("Retinex", "Enabled", retinex.enabled); + } - if (!pedited || pedited->vibrance.protectskins) { - keyFile.set_boolean ("Vibrance", "ProtectSkins", vibrance.protectskins); - } + if (!pedited || pedited->retinex.medianmap) { + keyFile.set_boolean ("Retinex", "Median", retinex.medianmap); + } - 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); - } + if (!pedited || pedited->retinex.neigh) { + keyFile.set_integer ("Retinex", "Neigh", retinex.neigh); + } - //save edge sharpening - if (!pedited || pedited->sharpenEdge.enabled) { - keyFile.set_boolean ("SharpenEdge", "Enabled", sharpenEdge.enabled); - } + if (!pedited || pedited->retinex.gain) { + keyFile.set_integer ("Retinex", "Gain", retinex.gain); + } - if (!pedited || pedited->sharpenEdge.passes) { - keyFile.set_integer ("SharpenEdge", "Passes", sharpenEdge.passes); - } + if (!pedited || pedited->retinex.offs) { + keyFile.set_integer ("Retinex", "Offs", retinex.offs); + } - if (!pedited || pedited->sharpenEdge.amount) { - keyFile.set_double ("SharpenEdge", "Strength", sharpenEdge.amount); - } + if (!pedited || pedited->retinex.vart) { + keyFile.set_integer ("Retinex", "Vart", retinex.vart); + } - if (!pedited || pedited->sharpenEdge.threechannels) { - keyFile.set_boolean ("SharpenEdge", "ThreeChannels", sharpenEdge.threechannels); - } + if (!pedited || pedited->retinex.limd) { + keyFile.set_integer ("Retinex", "Limd", retinex.limd); + } - //save micro-contrast sharpening - if (!pedited || pedited->sharpenMicro.enabled) { - keyFile.set_boolean ("SharpenMicro", "Enabled", sharpenMicro.enabled); - } + if (!pedited || pedited->retinex.highl) { + keyFile.set_integer ("Retinex", "highl", retinex.highl); + } - if (!pedited || pedited->sharpenMicro.matrix) { - keyFile.set_boolean ("SharpenMicro", "Matrix", sharpenMicro.matrix); - } + if (!pedited || pedited->retinex.baselog) { + keyFile.set_double ("Retinex", "baselog", retinex.baselog); + } - if (!pedited || pedited->sharpenMicro.amount) { - keyFile.set_double ("SharpenMicro", "Strength", sharpenMicro.amount); - } + if (!pedited || pedited->retinex.skal) { + keyFile.set_integer ("Retinex", "skal", retinex.skal); + } - if (!pedited || pedited->sharpenMicro.uniformity) { - keyFile.set_double ("SharpenMicro", "Uniformity", sharpenMicro.uniformity); - } + if (!pedited || pedited->retinex.retinexMethod) { + keyFile.set_string ("Retinex", "RetinexMethod", retinex.retinexMethod); + } - /* - // 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->retinex.mapMethod) { + keyFile.set_string ("Retinex", "mapMethod", retinex.mapMethod); + } - if (!pedited || pedited->wb.temperature) { - keyFile.set_integer ("White Balance", "Temperature", wb.temperature); - } + if (!pedited || pedited->retinex.viewMethod) { + keyFile.set_string ("Retinex", "viewMethod", retinex.viewMethod); + } - if (!pedited || pedited->wb.green) { - keyFile.set_double ("White Balance", "Green", wb.green); - } + 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->wb.equal) { - keyFile.set_double ("White Balance", "Equal", wb.equal); - } + 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); + } - /* - // 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->blackwhite.mixerMagenta) { + keyFile.set_integer ("Black & White", "MixerMagenta", blackwhite.mixerMagenta); + } - if (!pedited || pedited->colorappearance.degree) { - keyFile.set_integer ("Color appearance", "Degree", colorappearance.degree); - } + if (!pedited || pedited->blackwhite.mixerPurple) { + keyFile.set_integer ("Black & White", "MixerPurple", blackwhite.mixerPurple); + } - if (!pedited || pedited->colorappearance.autodegree) { - keyFile.set_boolean ("Color appearance", "AutoDegree", colorappearance.autodegree); - } + if (!pedited || pedited->blackwhite.gammaRed) { + keyFile.set_integer ("Black & White", "GammaRed", blackwhite.gammaRed); + } - if (!pedited || pedited->colorappearance.surround) { - keyFile.set_string ("Color appearance", "Surround", colorappearance.surround); - } + 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; - } - - keyFile.set_string ("Color appearance", "CurveMode", method); + case (ColorAppearanceParams::TC_MODE_BRIGHT): + method = "Brightness"; + break; } - if (!pedited || pedited->colorappearance.curveMode2) { - Glib::ustring method; + keyFile.set_string ("Color appearance", "CurveMode", method); + } - switch (colorappearance.curveMode2) { - case (ColorAppearanceParams::TC_MODE_LIGHT): - method = "Lightness"; - break; + if (!pedited || pedited->colorappearance.curveMode2) { + Glib::ustring method; - case (ColorAppearanceParams::TC_MODE_BRIGHT): - method = "Brightness"; - break; - } + switch (colorappearance.curveMode2) { + case (ColorAppearanceParams::TC_MODE_LIGHT): + method = "Lightness"; + break; - keyFile.set_string ("Color appearance", "CurveMode2", method); + case (ColorAppearanceParams::TC_MODE_BRIGHT): + method = "Brightness"; + break; } - if (!pedited || pedited->colorappearance.curveMode3) { - Glib::ustring method; + keyFile.set_string ("Color appearance", "CurveMode2", method); + } - switch (colorappearance.curveMode3) { - case (ColorAppearanceParams::TC_MODE_CHROMA): - method = "Chroma"; - break; + if (!pedited || pedited->colorappearance.curveMode3) { + Glib::ustring method; - case (ColorAppearanceParams::TC_MODE_SATUR): - method = "Saturation"; - break; + switch (colorappearance.curveMode3) { + case (ColorAppearanceParams::TC_MODE_CHROMA): + method = "Chroma"; + break; - case (ColorAppearanceParams::TC_MODE_COLORF): - method = "Colorfullness"; - break; + case (ColorAppearanceParams::TC_MODE_SATUR): + method = "Saturation"; + break; - } + case (ColorAppearanceParams::TC_MODE_COLORF): + method = "Colorfullness"; + break; - 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); - } + keyFile.set_string ("Color appearance", "CurveMode3", method); + } - if (!pedited || pedited->colorappearance.curve2) { - Glib::ArrayHandle tcurve = colorappearance.curve2; - keyFile.set_double_list("Color appearance", "Curve2", tcurve); - } + if (!pedited || pedited->colorappearance.curve) { + Glib::ArrayHandle tcurve = colorappearance.curve; + keyFile.set_double_list("Color appearance", "Curve", tcurve); + } - if (!pedited || pedited->colorappearance.curve3) { - Glib::ArrayHandle tcurve = colorappearance.curve3; - keyFile.set_double_list("Color appearance", "Curve3", 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); + } - // 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"; - } - - keyFile.set_string ("Directional Pyramid Denoising", "CMethod", dirpyrDenoise.Cmethod); - } - - if (!pedited || pedited->dirpyrDenoise.C2method) { - if(dirpyrDenoise.C2method == "PREV") { - dirpyrDenoise.C2method = "MANU"; - } - - 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->dirpyrDenoise.luma) { + keyFile.set_double ("Directional Pyramid Denoising", "Luma", dirpyrDenoise.luma); + } - if (!pedited || pedited->vignetting.radius) { - keyFile.set_integer ("Vignetting Correction", "Radius", vignetting.radius); - } + if (!pedited || pedited->dirpyrDenoise.Ldetail) { + keyFile.set_double ("Directional Pyramid Denoising", "Ldetail", dirpyrDenoise.Ldetail); + } - if (!pedited || pedited->vignetting.strength) { - keyFile.set_integer ("Vignetting Correction", "Strength", vignetting.strength); - } + if (!pedited || pedited->dirpyrDenoise.chroma) { + keyFile.set_double ("Directional Pyramid Denoising", "Chroma", dirpyrDenoise.chroma); + } - if (!pedited || pedited->vignetting.centerX) { - keyFile.set_integer ("Vignetting Correction", "CenterX", vignetting.centerX); - } + 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->vignetting.centerY) { - keyFile.set_integer ("Vignetting Correction", "CenterY", vignetting.centerY); - } + keyFile.set_string ("Directional Pyramid Denoising", "CMethod", dirpyrDenoise.Cmethod); + } + + if (!pedited || pedited->dirpyrDenoise.C2method) { + if(dirpyrDenoise.C2method == "PREV") { + dirpyrDenoise.C2method = "MANU"; + } + 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); + } - if (!pedited || pedited->resize.enabled) { - keyFile.set_boolean ("Resize", "Enabled", resize.enabled); - } + //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->resize.scale) { - keyFile.set_double ("Resize", "Scale", resize.scale); - } + if (!pedited || pedited->vignetting.centerX) { + keyFile.set_integer ("Vignetting Correction", "CenterX", vignetting.centerX); + } - if (!pedited || pedited->resize.appliesTo) { - keyFile.set_string ("Resize", "AppliesTo", resize.appliesTo); - } + if (!pedited || pedited->vignetting.centerY) { + keyFile.set_integer ("Vignetting Correction", "CenterY", vignetting.centerY); + } - 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.enabled) { + keyFile.set_boolean ("Resize", "Enabled", resize.enabled); + } - if (!pedited || pedited->resize.width) { - keyFile.set_integer ("Resize", "Width", resize.width); - } + if (!pedited || pedited->resize.scale) { + keyFile.set_double ("Resize", "Scale", resize.scale); + } - if (!pedited || pedited->resize.height) { - keyFile.set_integer ("Resize", "Height", resize.height); - } + if (!pedited || pedited->resize.appliesTo) { + keyFile.set_string ("Resize", "AppliesTo", resize.appliesTo); + } - if (!pedited || pedited->prsharpening.enabled) { - keyFile.set_boolean ("PostResizeSharpening", "Enabled", prsharpening.enabled); - } + if (!pedited || pedited->resize.method) { + keyFile.set_string ("Resize", "Method", resize.method); + } - if (!pedited || pedited->prsharpening.method) { - keyFile.set_string ("PostResizeSharpening", "Method", prsharpening.method); - } + if (!pedited || pedited->resize.dataspec) { + keyFile.set_integer ("Resize", "DataSpecified", resize.dataspec); + } - if (!pedited || pedited->prsharpening.radius) { - keyFile.set_double ("PostResizeSharpening", "Radius", prsharpening.radius); - } + if (!pedited || pedited->resize.width) { + keyFile.set_integer ("Resize", "Width", resize.width); + } - if (!pedited || pedited->prsharpening.amount) { - keyFile.set_integer ("PostResizeSharpening", "Amount", prsharpening.amount); - } + if (!pedited || pedited->resize.height) { + keyFile.set_integer ("Resize", "Height", resize.height); + } - 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.enabled) { + keyFile.set_boolean ("PostResizeSharpening", "Enabled", prsharpening.enabled); + } - if (!pedited || pedited->prsharpening.edgesonly) { - keyFile.set_boolean ("PostResizeSharpening", "OnlyEdges", prsharpening.edgesonly); - } + if (!pedited || pedited->prsharpening.method) { + keyFile.set_string ("PostResizeSharpening", "Method", prsharpening.method); + } - if (!pedited || pedited->prsharpening.edges_radius) { - keyFile.set_double ("PostResizeSharpening", "EdgedetectionRadius", prsharpening.edges_radius); - } + if (!pedited || pedited->prsharpening.radius) { + keyFile.set_double ("PostResizeSharpening", "Radius", prsharpening.radius); + } - if (!pedited || pedited->prsharpening.edges_tolerance) { - keyFile.set_integer ("PostResizeSharpening", "EdgeTolerance", prsharpening.edges_tolerance); - } + if (!pedited || pedited->prsharpening.amount) { + keyFile.set_integer ("PostResizeSharpening", "Amount", prsharpening.amount); + } - if (!pedited || pedited->prsharpening.halocontrol) { - keyFile.set_boolean ("PostResizeSharpening", "HalocontrolEnabled", prsharpening.halocontrol); - } + 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.halocontrol_amount) { - keyFile.set_integer ("PostResizeSharpening", "HalocontrolAmount", prsharpening.halocontrol_amount); - } + if (!pedited || pedited->prsharpening.edgesonly) { + keyFile.set_boolean ("PostResizeSharpening", "OnlyEdges", prsharpening.edgesonly); + } - if (!pedited || pedited->prsharpening.deconvradius) { - keyFile.set_double ("PostResizeSharpening", "DeconvRadius", prsharpening.deconvradius); - } + if (!pedited || pedited->prsharpening.edges_radius) { + keyFile.set_double ("PostResizeSharpening", "EdgedetectionRadius", prsharpening.edges_radius); + } - if (!pedited || pedited->prsharpening.deconvamount) { - keyFile.set_integer ("PostResizeSharpening", "DeconvAmount", prsharpening.deconvamount); - } + if (!pedited || pedited->prsharpening.edges_tolerance) { + keyFile.set_integer ("PostResizeSharpening", "EdgeTolerance", prsharpening.edges_tolerance); + } - if (!pedited || pedited->prsharpening.deconvdamping) { - keyFile.set_integer ("PostResizeSharpening", "DeconvDamping", prsharpening.deconvdamping); - } + if (!pedited || pedited->prsharpening.halocontrol) { + keyFile.set_boolean ("PostResizeSharpening", "HalocontrolEnabled", prsharpening.halocontrol); + } - if (!pedited || pedited->prsharpening.deconviter) { - keyFile.set_integer ("PostResizeSharpening", "DeconvIterations", prsharpening.deconviter); - } + 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); + } - // save color management settings - if (!pedited || pedited->icm.input) { - keyFile.set_string ("Color Management", "InputProfile", relativePathIfInside(fname, fnameAbsolute, icm.input)); - } + if (!pedited || pedited->prsharpening.deconvamount) { + keyFile.set_integer ("PostResizeSharpening", "DeconvAmount", prsharpening.deconvamount); + } - if (!pedited || pedited->icm.toneCurve) { - keyFile.set_boolean ("Color Management", "ToneCurve", icm.toneCurve); - } + if (!pedited || pedited->prsharpening.deconvdamping) { + keyFile.set_integer ("PostResizeSharpening", "DeconvDamping", prsharpening.deconvdamping); + } - if (!pedited || pedited->icm.applyLookTable) { - keyFile.set_boolean ("Color Management", "ApplyLookTable", icm.applyLookTable); - } + if (!pedited || pedited->prsharpening.deconviter) { + keyFile.set_integer ("PostResizeSharpening", "DeconvIterations", prsharpening.deconviter); + } - 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); - } + // save color management settings + if (!pedited || pedited->icm.input) { + keyFile.set_string ("Color Management", "InputProfile", relativePathIfInside(fname, fnameAbsolute, icm.input)); + } - if (!pedited || pedited->icm.blendCMSMatrix) { - keyFile.set_boolean ("Color Management", "BlendCMSMatrix", icm.blendCMSMatrix); - } + if (!pedited || pedited->icm.toneCurve) { + keyFile.set_boolean ("Color Management", "ToneCurve", icm.toneCurve); + } - if (!pedited || pedited->icm.dcpIlluminant) { - keyFile.set_integer ("Color Management", "DCPIlluminant", icm.dcpIlluminant); - } + if (!pedited || pedited->icm.applyLookTable) { + keyFile.set_boolean ("Color Management", "ApplyLookTable", icm.applyLookTable); + } - if (!pedited || pedited->icm.working) { - keyFile.set_string ("Color Management", "WorkingProfile", icm.working); - } + if (!pedited || pedited->icm.applyBaselineExposureOffset) { + keyFile.set_boolean ("Color Management", "ApplyBaselineExposureOffset", icm.applyBaselineExposureOffset); + } - if (!pedited || pedited->icm.output) { - keyFile.set_string ("Color Management", "OutputProfile", icm.output); - } + if (!pedited || pedited->icm.applyHueSatMap) { + keyFile.set_boolean ("Color Management", "ApplyHueSatMap", icm.applyHueSatMap); + } - if (!pedited || pedited->icm.outputIntent) { - Glib::ustring intent; + if (!pedited || pedited->icm.blendCMSMatrix) { + keyFile.set_boolean ("Color Management", "BlendCMSMatrix", icm.blendCMSMatrix); + } - switch (icm.outputIntent) { - default: - case RI_PERCEPTUAL: - intent = "Perceptual"; - break; + if (!pedited || pedited->icm.dcpIlluminant) { + keyFile.set_integer ("Color Management", "DCPIlluminant", icm.dcpIlluminant); + } - case RI_RELATIVE: - intent = "Relative"; - break; + if (!pedited || pedited->icm.working) { + keyFile.set_string ("Color Management", "WorkingProfile", icm.working); + } - case RI_SATURATION: - intent = "Saturation"; - break; + if (!pedited || pedited->icm.output) { + keyFile.set_string ("Color Management", "OutputProfile", icm.output); + } - case RI_ABSOLUTE: - intent = "Absolute"; - break; - } + if (!pedited || pedited->icm.outputIntent) { + Glib::ustring intent; - keyFile.set_string ("Color Management", "OutputProfileIntent", intent); - } + switch (icm.outputIntent) { + default: + case RI_PERCEPTUAL: + intent = "Perceptual"; + break; - if (!pedited || pedited->icm.gamma) { - keyFile.set_string ("Color Management", "Gammafree", icm.gamma); - } + case RI_RELATIVE: + intent = "Relative"; + break; - if (!pedited || pedited->icm.freegamma) { - keyFile.set_boolean ("Color Management", "Freegamma", icm.freegamma); - } + case RI_SATURATION: + intent = "Saturation"; + break; - if (!pedited || pedited->icm.gampos) { - keyFile.set_double ("Color Management", "GammaValue", icm.gampos); + case RI_ABSOLUTE: + intent = "Absolute"; + break; } - if (!pedited || pedited->icm.slpos) { - keyFile.set_double ("Color Management", "GammaSlope", icm.slpos); - } + 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); + } - // save wavelet parameters - if (!pedited || pedited->wavelet.enabled) { - keyFile.set_boolean ("Wavelet", "Enabled", wavelet.enabled); - } + if (!pedited || pedited->icm.gampos) { + keyFile.set_double ("Color Management", "GammaValue", icm.gampos); + } - if (!pedited || pedited->wavelet.strength) { - keyFile.set_integer ("Wavelet", "Strength", wavelet.strength); - } + if (!pedited || pedited->icm.slpos) { + keyFile.set_double ("Color Management", "GammaSlope", icm.slpos); + } - 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); - } + // save wavelet parameters + if (!pedited || pedited->wavelet.enabled) { + keyFile.set_boolean ("Wavelet", "Enabled", wavelet.enabled); + } - if (!pedited || pedited->wavelet.Tilesmethod) { - keyFile.set_string ("Wavelet", "TilesMethod", wavelet.Tilesmethod); - } + if (!pedited || pedited->wavelet.strength) { + keyFile.set_integer ("Wavelet", "Strength", wavelet.strength); + } - if (!pedited || pedited->wavelet.daubcoeffmethod) { - keyFile.set_string ("Wavelet", "DaubMethod", wavelet.daubcoeffmethod); - } + if (!pedited || pedited->wavelet.balance) { + keyFile.set_integer ("Wavelet", "Balance", wavelet.balance); + } - if (!pedited || pedited->wavelet.CLmethod) { - keyFile.set_string ("Wavelet", "ChoiceLevMethod", wavelet.CLmethod); - } + if (!pedited || pedited->wavelet.iter) { + keyFile.set_integer ("Wavelet", "Iter", wavelet.iter); + } - if (!pedited || pedited->wavelet.Backmethod) { - keyFile.set_string ("Wavelet", "BackMethod", wavelet.Backmethod); - } + if (!pedited || pedited->wavelet.thres) { + keyFile.set_integer ("Wavelet", "MaxLev", wavelet.thres); + } - if (!pedited || pedited->wavelet.Lmethod) { - keyFile.set_string ("Wavelet", "LevMethod", wavelet.Lmethod); - } + if (!pedited || pedited->wavelet.Tilesmethod) { + keyFile.set_string ("Wavelet", "TilesMethod", wavelet.Tilesmethod); + } - if (!pedited || pedited->wavelet.Dirmethod) { - keyFile.set_string ("Wavelet", "DirMethod", wavelet.Dirmethod); - } + if (!pedited || pedited->wavelet.daubcoeffmethod) { + keyFile.set_string ("Wavelet", "DaubMethod", wavelet.daubcoeffmethod); + } - if (!pedited || pedited->wavelet.greenhigh) { - keyFile.set_integer ("Wavelet", "CBgreenhigh", wavelet.greenhigh); - } + if (!pedited || pedited->wavelet.CLmethod) { + keyFile.set_string ("Wavelet", "ChoiceLevMethod", wavelet.CLmethod); + } - if (!pedited || pedited->wavelet.greenmed) { - keyFile.set_integer ("Wavelet", "CBgreenmed", wavelet.greenmed); - } + if (!pedited || pedited->wavelet.Backmethod) { + keyFile.set_string ("Wavelet", "BackMethod", wavelet.Backmethod); + } - if (!pedited || pedited->wavelet.greenlow) { - keyFile.set_integer ("Wavelet", "CBgreenlow", wavelet.greenlow); - } + if (!pedited || pedited->wavelet.Lmethod) { + keyFile.set_string ("Wavelet", "LevMethod", wavelet.Lmethod); + } - if (!pedited || pedited->wavelet.bluehigh) { - keyFile.set_integer ("Wavelet", "CBbluehigh", wavelet.bluehigh); - } + if (!pedited || pedited->wavelet.Dirmethod) { + keyFile.set_string ("Wavelet", "DirMethod", wavelet.Dirmethod); + } - if (!pedited || pedited->wavelet.bluemed) { - keyFile.set_integer ("Wavelet", "CBbluemed", wavelet.bluemed); - } + if (!pedited || pedited->wavelet.greenhigh) { + keyFile.set_integer ("Wavelet", "CBgreenhigh", wavelet.greenhigh); + } - if (!pedited || pedited->wavelet.bluelow) { - keyFile.set_integer ("Wavelet", "CBbluelow", wavelet.bluelow); - } + if (!pedited || pedited->wavelet.greenmed) { + keyFile.set_integer ("Wavelet", "CBgreenmed", wavelet.greenmed); + } - if (!pedited || pedited->wavelet.expcontrast) { - keyFile.set_boolean ("Wavelet", "Expcontrast", wavelet.expcontrast); - } + if (!pedited || pedited->wavelet.greenlow) { + keyFile.set_integer ("Wavelet", "CBgreenlow", wavelet.greenlow); + } - if (!pedited || pedited->wavelet.expchroma) { - keyFile.set_boolean ("Wavelet", "Expchroma", wavelet.expchroma); - } + if (!pedited || pedited->wavelet.bluehigh) { + keyFile.set_integer ("Wavelet", "CBbluehigh", wavelet.bluehigh); + } - if (!pedited || pedited->wavelet.expedge) { - keyFile.set_boolean ("Wavelet", "Expedge", wavelet.expedge); - } + if (!pedited || pedited->wavelet.bluemed) { + keyFile.set_integer ("Wavelet", "CBbluemed", wavelet.bluemed); + } - if (!pedited || pedited->wavelet.expresid) { - keyFile.set_boolean ("Wavelet", "Expresid", wavelet.expresid); - } + if (!pedited || pedited->wavelet.bluelow) { + keyFile.set_integer ("Wavelet", "CBbluelow", wavelet.bluelow); + } - if (!pedited || pedited->wavelet.expfinal) { - keyFile.set_boolean ("Wavelet", "Expfinal", wavelet.expfinal); - } + if (!pedited || pedited->wavelet.expcontrast) { + keyFile.set_boolean ("Wavelet", "Expcontrast", wavelet.expcontrast); + } - if (!pedited || pedited->wavelet.exptoning) { - keyFile.set_boolean ("Wavelet", "Exptoning", wavelet.exptoning); - } + if (!pedited || pedited->wavelet.expchroma) { + keyFile.set_boolean ("Wavelet", "Expchroma", wavelet.expchroma); + } - if (!pedited || pedited->wavelet.expnoise) { - keyFile.set_boolean ("Wavelet", "Expnoise", wavelet.expnoise); - } + if (!pedited || pedited->wavelet.expedge) { + keyFile.set_boolean ("Wavelet", "Expedge", wavelet.expedge); + } - for(int i = 0; i < 9; i++) { - std::stringstream ss; - ss << "Contrast" << (i + 1); + if (!pedited || pedited->wavelet.expresid) { + keyFile.set_boolean ("Wavelet", "Expresid", wavelet.expresid); + } - if (!pedited || pedited->wavelet.c[i]) { - keyFile.set_integer("Wavelet", ss.str(), wavelet.c[i]); - } - } + if (!pedited || pedited->wavelet.expfinal) { + keyFile.set_boolean ("Wavelet", "Expfinal", wavelet.expfinal); + } - for(int i = 0; i < 9; i++) { - std::stringstream ss; - ss << "Chroma" << (i + 1); + if (!pedited || pedited->wavelet.exptoning) { + keyFile.set_boolean ("Wavelet", "Exptoning", wavelet.exptoning); + } - if (!pedited || pedited->wavelet.ch[i]) { - keyFile.set_integer("Wavelet", ss.str(), wavelet.ch[i]); - } - } + if (!pedited || pedited->wavelet.expnoise) { + keyFile.set_boolean ("Wavelet", "Expnoise", wavelet.expnoise); + } - if (!pedited || pedited->wavelet.sup) { - keyFile.set_integer ("Wavelet", "ContExtra", wavelet.sup); - } + for(int i = 0; i < 9; i++) { + std::stringstream ss; + ss << "Contrast" << (i + 1); - if (!pedited || pedited->wavelet.HSmethod) { - keyFile.set_string ("Wavelet", "HSMethod", wavelet.HSmethod); + if (!pedited || pedited->wavelet.c[i]) { + keyFile.set_integer("Wavelet", ss.str(), wavelet.c[i]); } + } - if (!pedited || pedited->wavelet.hllev) { - Glib::ArrayHandle thresh (wavelet.hllev.value, 4, Glib::OWNERSHIP_NONE); - keyFile.set_integer_list("Wavelet", "HLRange", thresh); - } + for(int i = 0; i < 9; i++) { + std::stringstream ss; + ss << "Chroma" << (i + 1); - 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.ch[i]) { + keyFile.set_integer("Wavelet", ss.str(), wavelet.ch[i]); } + } - 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.sup) { + keyFile.set_integer ("Wavelet", "ContExtra", wavelet.sup); + } - 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.HSmethod) { + keyFile.set_string ("Wavelet", "HSMethod", wavelet.HSmethod); + } - 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.hllev) { + Glib::ArrayHandle thresh (wavelet.hllev.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "HLRange", 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.bllev) { + Glib::ArrayHandle thresh (wavelet.bllev.value, 4, Glib::OWNERSHIP_NONE); + keyFile.set_integer_list("Wavelet", "SHRange", 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.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.threshold) { - keyFile.set_integer ("Wavelet", "ThresholdHighlight", wavelet.threshold); - } - - if (!pedited || pedited->wavelet.threshold2) { - keyFile.set_integer ("Wavelet", "ThresholdShadow", wavelet.threshold2); - } + 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.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.level2noise) { + Glib::ArrayHandle thresh (wavelet.level2noise.value, 2, Glib::OWNERSHIP_NONE); + keyFile.set_double_list("Wavelet", "Level2noise", thresh); + } - 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.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.avoid) { + keyFile.set_boolean ("Wavelet", "AvoidColorShift", wavelet.avoid); + } - if (!pedited || pedited->wavelet.thrH) { - keyFile.set_integer ("Wavelet", "ThresholdResidHighLight", wavelet.thrH); - } + if (!pedited || pedited->wavelet.tmr) { + keyFile.set_boolean ("Wavelet", "TMr", wavelet.tmr); + } - if (!pedited || pedited->wavelet.reschro) { - keyFile.set_integer ("Wavelet", "Residualchroma", wavelet.reschro); - } + if (!pedited || pedited->wavelet.rescon) { + keyFile.set_integer ("Wavelet", "ResidualcontShadow", wavelet.rescon); + } - if (!pedited || pedited->wavelet.tmrs) { - keyFile.set_double ("Wavelet", "ResidualTM", wavelet.tmrs); - } + if (!pedited || pedited->wavelet.resconH) { + keyFile.set_integer ("Wavelet", "ResidualcontHighlight", wavelet.resconH); + } - if (!pedited || pedited->wavelet.gamma) { - keyFile.set_double ("Wavelet", "Residualgamma", wavelet.gamma); - } + if (!pedited || pedited->wavelet.thr) { + keyFile.set_integer ("Wavelet", "ThresholdResidShadow", wavelet.thr); + } - 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); - } + if (!pedited || pedited->wavelet.thrH) { + keyFile.set_integer ("Wavelet", "ThresholdResidHighLight", wavelet.thrH); + } + if (!pedited || pedited->wavelet.reschro) { + keyFile.set_integer ("Wavelet", "Residualchroma", wavelet.reschro); + } - // 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->wavelet.tmrs) { + keyFile.set_double ("Wavelet", "ResidualTM", wavelet.tmrs); + } - if (!pedited || pedited->hsvequalizer.vcurve) { - Glib::ArrayHandle vcurve = hsvequalizer.vcurve; - keyFile.set_double_list("HSV Equalizer", "VCurve", vcurve); - } + if (!pedited || pedited->wavelet.gamma) { + keyFile.set_double ("Wavelet", "Residualgamma", wavelet.gamma); + } - //save film simulation parameters - if ( !pedited || pedited->filmSimulation.enabled ) { - keyFile.set_boolean( "Film Simulation", "Enabled", filmSimulation.enabled ); - } + if (!pedited || pedited->wavelet.sky) { + keyFile.set_double ("Wavelet", "HueRangeResidual", wavelet.sky); + } - if ( !pedited || pedited->filmSimulation.clutFilename ) { - keyFile.set_string ( "Film Simulation", "ClutFilename", filmSimulation.clutFilename ); - } + 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->filmSimulation.strength ) { - keyFile.set_integer( "Film Simulation", "Strength", filmSimulation.strength ); - } + if (!pedited || pedited->wavelet.contrast) { + keyFile.set_integer ("Wavelet", "Contrast", wavelet.contrast); + } - if (!pedited || pedited->rgbCurves.lumamode) { - keyFile.set_boolean ("RGB Curves", "LumaMode", rgbCurves.lumamode); - } + // 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->rgbCurves.rcurve) { - Glib::ArrayHandle RGBrcurve = rgbCurves.rcurve; - keyFile.set_double_list("RGB Curves", "rCurve", RGBrcurve); - } + if (!pedited || pedited->dirpyrequalizer.skinprotect) { + keyFile.set_double ("Directional Pyramid Equalizer", "Skinprotect", dirpyrequalizer.skinprotect); + } - if (!pedited || pedited->rgbCurves.gcurve) { - Glib::ArrayHandle RGBgcurve = rgbCurves.gcurve; - keyFile.set_double_list("RGB Curves", "gCurve", RGBgcurve); - } + // 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->rgbCurves.bcurve) { - Glib::ArrayHandle RGBbcurve = rgbCurves.bcurve; - keyFile.set_double_list("RGB Curves", "bCurve", RGBbcurve); - } + if (!pedited || pedited->hsvequalizer.scurve) { + Glib::ArrayHandle scurve = hsvequalizer.scurve; + keyFile.set_double_list("HSV Equalizer", "SCurve", scurve); + } - // save Color Toning - if (!pedited || pedited->colorToning.enabled) { - keyFile.set_boolean ("ColorToning", "Enabled", colorToning.enabled); - } + 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->colorToning.method) { - keyFile.set_string ("ColorToning", "Method", colorToning.method); - } + if (!pedited || pedited->raw.caCorrection) { + keyFile.set_boolean ("RAW", "CA", raw.ca_autocorrect ); + } - if (!pedited || pedited->colorToning.lumamode) { - keyFile.set_boolean ("ColorToning", "Lumamode", colorToning.lumamode); - } + if (!pedited || pedited->raw.caAutoStrength) { + keyFile.set_double ("RAW", "CAAutoStrength", raw.caautostrength ); + } - if (!pedited || pedited->colorToning.twocolor) { - keyFile.set_string ("ColorToning", "Twocolor", colorToning.twocolor); - } + 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->colorToning.redlow) { - keyFile.set_double ("ColorToning", "Redlow", colorToning.redlow); - } + 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->colorToning.greenlow) { - keyFile.set_double ("ColorToning", "Greenlow", colorToning.greenlow); - } + if (!pedited || pedited->raw.hotDeadPixelThresh) { + keyFile.set_integer ("RAW", "HotDeadPixelThresh", raw.hotdeadpix_thresh ); + } - if (!pedited || pedited->colorToning.bluelow) { - keyFile.set_double ("ColorToning", "Bluelow", colorToning.bluelow); - } + if (!pedited || pedited->raw.bayersensor.method) { + keyFile.set_string ("RAW Bayer", "Method", raw.bayersensor.method ); + } - if (!pedited || pedited->colorToning.satlow) { - keyFile.set_double ("ColorToning", "Satlow", colorToning.satlow); - } + if (!pedited || pedited->raw.bayersensor.ccSteps) { + keyFile.set_integer ("RAW Bayer", "CcSteps", raw.bayersensor.ccSteps); + } - if (!pedited || pedited->colorToning.balance) { - keyFile.set_integer ("ColorToning", "Balance", colorToning.balance); - } + if (!pedited || pedited->raw.bayersensor.exBlack0) { + keyFile.set_double ("RAW Bayer", "PreBlack0", raw.bayersensor.black0 ); + } - if (!pedited || pedited->colorToning.sathigh) { - keyFile.set_double ("ColorToning", "Sathigh", colorToning.sathigh); - } + if (!pedited || pedited->raw.bayersensor.exBlack1) { + keyFile.set_double ("RAW Bayer", "PreBlack1", raw.bayersensor.black1 ); + } - if (!pedited || pedited->colorToning.redmed) { - keyFile.set_double ("ColorToning", "Redmed", colorToning.redmed); - } + if (!pedited || pedited->raw.bayersensor.exBlack2) { + keyFile.set_double ("RAW Bayer", "PreBlack2", raw.bayersensor.black2 ); + } - if (!pedited || pedited->colorToning.greenmed) { - keyFile.set_double ("ColorToning", "Greenmed", colorToning.greenmed); - } + if (!pedited || pedited->raw.bayersensor.exBlack3) { + keyFile.set_double ("RAW Bayer", "PreBlack3", raw.bayersensor.black3 ); + } - if (!pedited || pedited->colorToning.bluemed) { - keyFile.set_double ("ColorToning", "Bluemed", colorToning.bluemed); - } + if (!pedited || pedited->raw.bayersensor.exTwoGreen) { + keyFile.set_boolean ("RAW Bayer", "PreTwoGreen", raw.bayersensor.twogreen ); + } - if (!pedited || pedited->colorToning.redhigh) { - keyFile.set_double ("ColorToning", "Redhigh", colorToning.redhigh); - } + if (!pedited || pedited->raw.bayersensor.linenoise) { + keyFile.set_integer ("RAW Bayer", "LineDenoise", raw.bayersensor.linenoise); + } - if (!pedited || pedited->colorToning.greenhigh) { - keyFile.set_double ("ColorToning", "Greenhigh", colorToning.greenhigh); - } + if (!pedited || pedited->raw.bayersensor.greenEq) { + keyFile.set_integer ("RAW Bayer", "GreenEqThreshold", raw.bayersensor.greenthresh); + } - if (!pedited || pedited->colorToning.bluehigh) { - keyFile.set_double ("ColorToning", "Bluehigh", colorToning.bluehigh); - } + if (!pedited || pedited->raw.bayersensor.dcbIterations) { + keyFile.set_integer ("RAW Bayer", "DCBIterations", raw.bayersensor.dcb_iterations ); + } - if (!pedited || pedited->colorToning.autosat) { - keyFile.set_boolean ("ColorToning", "Autosat", colorToning.autosat); - } + if (!pedited || pedited->raw.bayersensor.dcbEnhance) { + keyFile.set_boolean ("RAW Bayer", "DCBEnhance", raw.bayersensor.dcb_enhance ); + } - if (!pedited || pedited->colorToning.opacityCurve) { - Glib::ArrayHandle curve = colorToning.opacityCurve; - keyFile.set_double_list("ColorToning", "OpacityCurve", curve); - } + if (!pedited || pedited->raw.bayersensor.lmmseIterations) { + keyFile.set_integer ("RAW Bayer", "LMMSEIterations", raw.bayersensor.lmmse_iterations ); + } - if (!pedited || pedited->colorToning.colorCurve) { - Glib::ArrayHandle curve = colorToning.colorCurve; - keyFile.set_double_list("ColorToning", "ColorCurve", curve); - } + //if (!pedited || pedited->raw.bayersensor.allEnhance) keyFile.set_boolean ("RAW Bayer", "ALLEnhance", raw.bayersensor.all_enhance ); - if (!pedited || pedited->colorToning.satprotectionthreshold) { - keyFile.set_integer ("ColorToning", "SatProtectionThreshold", colorToning.satProtectionThreshold ); - } + if (!pedited || pedited->raw.xtranssensor.method) { + keyFile.set_string ("RAW X-Trans", "Method", raw.xtranssensor.method ); + } - if (!pedited || pedited->colorToning.saturatedopacity) { - keyFile.set_integer ("ColorToning", "SaturatedOpacity", colorToning.saturatedOpacity ); - } + if (!pedited || pedited->raw.xtranssensor.ccSteps) { + keyFile.set_integer ("RAW X-Trans", "CcSteps", raw.xtranssensor.ccSteps); + } - if (!pedited || pedited->colorToning.strength) { - keyFile.set_integer ("ColorToning", "Strength", colorToning.strength ); - } + if (!pedited || pedited->raw.xtranssensor.exBlackRed) { + keyFile.set_double ("RAW X-Trans", "PreBlackRed", raw.xtranssensor.blackred ); + } - 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->raw.xtranssensor.exBlackGreen) { + keyFile.set_double ("RAW X-Trans", "PreBlackGreen", raw.xtranssensor.blackgreen ); + } - 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->raw.xtranssensor.exBlackBlue) { + keyFile.set_double ("RAW X-Trans", "PreBlackBlue", raw.xtranssensor.blackblue ); + } - 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 exposition + if (!pedited || pedited->raw.exPos) { + keyFile.set_double ("RAW", "PreExposure", raw.expos ); + } - // 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 ); - } + 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 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); - } + // 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(); + sPParams = keyFile.to_data(); } catch(Glib::KeyFileError&) {} @@ -3422,7 +3422,7 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b } } -int ProcParams::write (const Glib::ustring &fname, const Glib::ustring &content) const +int ProcParams::write (Glib::ustring &fname, Glib::ustring &content) const { int error = 0; @@ -3442,7 +3442,7 @@ int ProcParams::write (const Glib::ustring &fname, const Glib::ustring &content) return error; } -int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited) +int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) { setlocale(LC_NUMERIC, "C"); // to set decimal point to "." @@ -4225,10 +4225,6 @@ int ProcParams::load (const 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; } @@ -8045,7 +8041,7 @@ PartialProfile::PartialProfile(const ProcParams* pp, const ParamsEdited* pe) } } -int PartialProfile::load (const Glib::ustring &fName) +int PartialProfile::load (Glib::ustring fName) { if (!pparams) { pparams = new ProcParams(); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index cf02b9f10..7f30f0cc9 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -528,7 +528,7 @@ public: double green; double 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) {}; + 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) {}; }; 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 (const Glib::ustring &fname, const Glib::ustring &fname2 = "", bool fnameAbsolute = true, ParamsEdited* pedited = NULL); + int save (Glib::ustring fname, 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 (const Glib::ustring &fname, ParamsEdited* pedited = NULL); + int load (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 (const Glib::ustring &fname, const Glib::ustring &content) const; + int write (Glib::ustring &fname, Glib::ustring &content) const; }; @@ -1375,7 +1375,7 @@ public: PartialProfile (const ProcParams* pp, const ParamsEdited* pe = NULL); void deleteInstance (); void clearGeneral (); - int load (const Glib::ustring &fName); + int load (Glib::ustring fName); void set (bool v); const void applyTo (ProcParams *destParams) const ; }; diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 919b1c7be..3f4b2ac3f 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -580,9 +580,7 @@ int RawImage::loadRaw (bool loadData, bool closeFile, ProgressListener *plistene if (cc) { for (int i = 0; i < 4; i++) { if (RT_blacklevel_from_constant) { - 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]; + black_c4[i] = cblack[i] + cc->get_BlackLevel(i, iso_speed); } // load 4 channel white level here, will be used if available diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 1c04f1af3..2780c033f 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -587,7 +587,9 @@ void RawImageSource::transformRect (PreviewProps pp, int tran, int &ssx1, int &s } } -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) +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +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) { if (isMono || colors == 1) { for (int c = 0; c < 4; c++) { @@ -615,7 +617,7 @@ float calculate_scale_mul(float scale_mul[4], const float pre_mul_[4], const flo return gain; } -void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const ColorManagementParams &cmp, const RAWParams &raw ) +void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw ) { MyMutex::MyLock lock(getImageMutex); @@ -725,7 +727,7 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima float line_blue[imwidth] ALIGNED16; #ifdef _OPENMP - #pragma omp for schedule(dynamic,16) + #pragma omp for #endif for (int ix = 0; ix < imheight; ix++) { @@ -889,7 +891,7 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima } } -DCPProfile *RawImageSource::getDCP(const ColorManagementParams &cmp, ColorTemp &wb, DCPProfile::ApplyState &as) +DCPProfile *RawImageSource::getDCP(ColorManagementParams cmp, ColorTemp &wb) { DCPProfile *dcpProf = NULL; cmsHPROFILE dummy; @@ -899,11 +901,11 @@ DCPProfile *RawImageSource::getDCP(const ColorManagementParams &cmp, ColorTemp & return NULL; } - dcpProf->setStep2ApplyState(cmp.working, cmp.toneCurve, cmp.applyLookTable, cmp.applyBaselineExposureOffset, as); + dcpProf->setStep2ApplyState(cmp.working, cmp.toneCurve, cmp.applyLookTable, cmp.applyBaselineExposureOffset); return dcpProf; } -void RawImageSource::convertColorSpace(Imagefloat* image, const ColorManagementParams &cmp, const ColorTemp &wb) +void RawImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams cmp, 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()); @@ -1499,7 +1501,7 @@ void RawImageSource::vflip (Imagefloat* image) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -int RawImageSource::load (const Glib::ustring &fname, bool batch) +int RawImageSource::load (Glib::ustring fname, bool batch) { MyTime t1, t2; @@ -3713,7 +3715,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, const 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, ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], const std::string &camName) { // MyTime t1, t2, t3; @@ -3727,17 +3729,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam if (dcpProf != NULL) { // DCP processing - 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); + dcpProf->Apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul, camMatrix, false, cmp.applyHueSatMap, false); return; } @@ -4095,7 +4087,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::getInstance()->getStdProfile(camName); + *dcpProf = dcpStore->getStdProfile(camName); if (*dcpProf == NULL) { in = iccStore->getStdProfile(camName); @@ -4107,8 +4099,8 @@ bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embed normalName = inProfile.substr(5); } - if (DCPStore::getInstance()->isValidDCPFileName(normalName)) { - *dcpProf = DCPStore::getInstance()->getProfile(normalName); + if (dcpStore->isValidDCPFileName(normalName)) { + *dcpProf = dcpStore->getProfile(normalName); } if (*dcpProf == NULL) { @@ -4383,7 +4375,7 @@ void RawImageSource::getAutoExpHistogram (LUTu & histogram, int& histcompr) #pragma omp parallel #endif { - LUTu tmphistogram(histogram.getSize()); + LUTu tmphistogram(65536 >> histcompr); tmphistogram.clear(); #ifdef _OPENMP #pragma omp for nowait @@ -4438,20 +4430,19 @@ 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](histoSize); + hist[0](65536); hist[0].clear(); if (ri->get_colors() > 1) { - hist[1](histoSize); + hist[1](65536); hist[1].clear(); - hist[2](histoSize); + hist[2](65536); hist[2].clear(); } if (fourColours) { - hist[3](histoSize); + hist[3](65536); hist[3].clear(); } @@ -4466,17 +4457,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](histoSize); + tmphist[0](65536); tmphist[0].clear(); if (ri->get_colors() > 1) { - tmphist[1](histoSize); + tmphist[1](65536); tmphist[1].clear(); - tmphist[2](histoSize); + tmphist[2](65536); tmphist[2].clear(); if (fourColours) { - tmphist[3](histoSize); + tmphist[3](65536); tmphist[3].clear(); } } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 2af26c702..222735432 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -39,8 +39,7 @@ private: static DiagonalCurve *phaseOneIccCurveInv; static LUTf invGrad; // for fast_demosaic static LUTf initInvGrad (); - 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); + 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); protected: MyMutex getImageMutex; // locks getImage @@ -98,6 +97,7 @@ 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 (const Glib::ustring &fname, bool batch = false); + int load (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() const + bool IsrgbSourceModified() { 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 (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const ColorManagementParams &cmp, const RAWParams &raw); - eSensorType getSensorType () const + void getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw); + eSensorType getSensorType () { return ri != NULL ? ri->getSensorType() : ST_NONE; } - ColorTemp getWB () const + ColorTemp getWB () { return camera_wb; } @@ -153,7 +153,7 @@ public: return rawData; } - double getDefGain () const + double getDefGain () { return defGain; } @@ -184,11 +184,11 @@ public: } void getAutoExpHistogram (LUTu & histogram, int& histcompr); void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw); - DCPProfile *getDCP(const ColorManagementParams &cmp, ColorTemp &wb, DCPProfile::ApplyState &as); + DCPProfile *getDCP(ColorManagementParams cmp, ColorTemp &wb); - void convertColorSpace(Imagefloat* image, const ColorManagementParams &cmp, const ColorTemp &wb); + void convertColorSpace(Imagefloat* image, ColorManagementParams cmp, ColorTemp &wb); static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in); - 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) + static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, 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 3913dc6ba..e20efdbdd 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -32,13 +32,12 @@ #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; @@ -53,7 +52,7 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, StdImageSource imgSrc; if (imgSrc.load(fname)) { - return nullptr; + return NULL; } ImageIO* img = imgSrc.getImageIO(); @@ -95,7 +94,7 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, // bilinear interpolation if (tpp->thumbImg) { delete tpp->thumbImg; - tpp->thumbImg = nullptr; + tpp->thumbImg = NULL; } if (inspectorMode) { @@ -160,7 +159,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL if( r ) { delete ri; - return nullptr; + return NULL; } rml.exifBase = ri->get_exifBase(); @@ -191,7 +190,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL printf("Could not extract thumb from %s\n", fname.data()); delete img; delete ri; - return nullptr; + return NULL; } Thumbnail* tpp = new Thumbnail (); @@ -219,7 +218,7 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL if (tpp->thumbImg) { delete tpp->thumbImg; - tpp->thumbImg = nullptr; + tpp->thumbImg = NULL; } if (inspectorMode) { @@ -288,7 +287,7 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati if( r ) { delete ri; - return nullptr; + return NULL; } int width = ri->get_width(); @@ -296,8 +295,8 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati rtengine::Thumbnail* tpp = new rtengine::Thumbnail; tpp->isRaw = true; - tpp->embProfile = nullptr; - tpp->embProfileData = nullptr; + tpp->embProfile = NULL; + tpp->embProfileData = NULL; tpp->embProfileLength = ri->get_profileLen(); if (ri->get_profileLen()) @@ -501,7 +500,7 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati delete tpp->thumbImg; } - tpp->thumbImg = nullptr; + tpp->thumbImg = NULL; tpp->thumbImg = resizeTo(w, h, TI_Bilinear, tmpImg); delete tmpImg; @@ -721,6 +720,7 @@ 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(nullptr), thumbImg(nullptr), + camProfile(NULL), thumbImg(NULL), 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(nullptr), embProfile(nullptr), + embProfileLength(0), embProfileData(NULL), embProfile(NULL), redMultiplier(1.0), greenMultiplier(1.0), blueMultiplier(1.0), defGain(1.0), scaleForSave(8192), @@ -798,7 +798,6 @@ 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; @@ -830,16 +829,24 @@ 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 = 0.0; - float rmi, gmi, bmi; - - rmi = rm * defGain / mul_lum; - gmi = gm * defGain / mul_lum; - bmi = bm * defGain / mul_lum; + 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; + }*/ // 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) { + if (isRaw && fabs(1.0 - params.raw.expos) > 0.001) { rmi *= params.raw.expos; gmi *= params.raw.expos; bmi *= params.raw.expos; @@ -855,7 +862,6 @@ 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) { @@ -872,27 +878,45 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei baseImg->vflip (); } - // apply white balance and raw white point (simulated) - 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); + int val; + unsigned short val_; + for (int i = 0; i < rheight; i++) + for (int j = 0; j < rwidth; j++) { + + 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 ); @@ -909,9 +933,10 @@ 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, params, hist16); + ipf.firstAnalysis (baseImg, ¶ms, hist16); // perform transform if (ipf.needsTransform()) { @@ -926,7 +951,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei } // update blurmap - SHMap* shmap = nullptr; + SHMap* shmap = NULL; if (params.sh.enabled) { shmap = new SHMap (fw, fh, false); @@ -947,70 +972,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; - LUTf cl2Toningcurve; + LUTf clToningcurve (65536); + LUTf cl2Toningcurve (65536); + + LUTf rCurve (65536); + LUTf gCurve (65536); + LUTf bCurve (65536); + 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, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2, 16); + hist16, dummy, 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; - 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); + params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, wip, opautili); + //params.dirpyrDenoise.getCurves(dnNoisCurve, lldenoisutili); - clToningcurve (65536); - CurveFactory::curveToning(params.colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16); + 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); - 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); - } + CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, hist16, dummy, customToneCurvebw1, customToneCurvebw2, 16); double rrm, ggm, bbm; float autor, autog, autob; @@ -1040,23 +1065,25 @@ 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 = nullptr; - DCPProfile::ApplyState as; + DCPProfile *dcpProf = NULL; + if (isRaw) { cmsHPROFILE dummy; - RawImageSource::findInputProfile(params.icm.input, nullptr, camName, &dcpProf, dummy); + RawImageSource::findInputProfile(params.icm.input, NULL, camName, &dcpProf, dummy); - if (dcpProf) { - dcpProf->setStep2ApplyState(params.icm.working, params.icm.toneCurve, params.icm.applyLookTable, params.icm.applyBaselineExposureOffset, as); + if (dcpProf != NULL) { + dcpProf->setStep2ApplyState(params.icm.working, params.icm.toneCurve, params.icm.applyLookTable, params.icm.applyBaselineExposureOffset); } } - 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); + + 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); // freeing up some memory customToneCurve1.Reset(); customToneCurve2.Reset(); ctColorCurve.Reset(); ctOpacityCurve.Reset(); +// dnNoisCurve.Reset(); customToneCurvebw1.Reset(); customToneCurvebw2.Reset(); @@ -1065,29 +1092,38 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei } // luminance histogram update - 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]))]++; - } - } + 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]))]++; + } // luminance processing // ipf.EPDToneMap(labView,0,6); - bool utili; + bool utili = false; + bool autili = false; + bool butili = false; + bool ccutili = false; + bool cclutili = false; + bool clcutili = false; + CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, - hist16, lumacurve, dummy, 16, utili); + hist16, hist16, curve, dummy, 16, utili); - bool clcutili; - CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, 16); + CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, hist16C, dummy, 16); - 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); + 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); - ipf.chromiLuminanceCurve (nullptr, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); + + ipf.chromiLuminanceCurve (NULL, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, curve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy, dummy, dummy); ipf.vibrance(labView); @@ -1095,17 +1131,20 @@ 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; @@ -1182,7 +1221,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei int Thumbnail::getImageWidth (const procparams::ProcParams& params, int rheight, float &ratio) { - if (!thumbImg) { + if (thumbImg == NULL) { return 0; // Can happen if thumb is just building and GUI comes in with resize wishes } @@ -1334,11 +1373,11 @@ void Thumbnail::transformPixel (int x, int y, int tran, int& tx, int& ty) unsigned char* Thumbnail::getGrayscaleHistEQ (int trim_width) { if (!thumbImg) { - return nullptr; + return NULL; } if (thumbImg->width < trim_width) { - return nullptr; + return NULL; } // to utilize the 8 bit color range of the thumbnail we brighten it and apply gamma correction @@ -1622,7 +1661,7 @@ bool Thumbnail::readImage (const Glib::ustring& fname) if (thumbImg) { delete thumbImg; - thumbImg = nullptr; + thumbImg = NULL; } Glib::ustring fullFName = fname + ".rtti"; @@ -1835,8 +1874,8 @@ bool Thumbnail::readEmbProfile (const Glib::ustring& fname) FILE* f = g_fopen (fname.c_str (), "rb"); if (!f) { - embProfileData = nullptr; - embProfile = nullptr; + embProfileData = NULL; + embProfile = NULL; embProfileLength = 0; } else { fseek (f, 0, SEEK_END); @@ -1908,7 +1947,7 @@ unsigned char* Thumbnail::getImage8Data() return img8->data; } - return nullptr; + return NULL; } diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index c11ac6452..1f64a5ff4 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -731,8 +731,9 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p // perform first analysis LUTu hist16 (65536); + LUTu hist16C (65536); - ipf.firstAnalysis (baseImg, params, hist16); + ipf.firstAnalysis (baseImg, ¶ms, hist16); // perform transform (excepted resizing) if (ipf.needsTransform()) { @@ -775,15 +776,15 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p LUTf curve (65536, 0); LUTf satcurve (65536, 0); LUTf lhskcurve (65536, 0); - LUTf lumacurve(32770, 0); // lumacurve[32768] and lumacurve[32769] will be set to 32768 and 32769 later to allow linear interpolation + LUTf lumacurve(65536, 0); LUTf clcurve (65536, 0); - LUTf clToningcurve; - LUTf cl2Toningcurve; + LUTf clToningcurve (65536, 0); + LUTf cl2Toningcurve (65536, 0); LUTf wavclCurve (65536, 0); - LUTf rCurve; - LUTf gCurve; - LUTf bCurve; + LUTf rCurve (65536, 0); + LUTf gCurve (65536, 0); + LUTf bCurve (65536, 0); LUTu dummy; ToneCurve customToneCurve1, customToneCurve2; @@ -796,38 +797,37 @@ 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, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2 ); + hist16, dummy, 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); - bool opautili = false; + 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); - if(params.blackwhite.enabled) { - CurveFactory::curveBW (params.blackwhite.beforeCurve, params.blackwhite.afterCurve, hist16, dummy, customToneCurvebw1, customToneCurvebw2, 1); - } + + 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,10 +853,8 @@ 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::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); + 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); if (settings->verbose) { printf("Output image / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", autor, autog, autob); @@ -895,15 +893,16 @@ 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 + #pragma omp parallel shared(hist16,labView, fh, fw) #endif { - LUTu hist16thr (hist16.getSize()); // one temporary lookup table per thread + LUTu hist16thr (65536); // one temporary lookup table per thread hist16thr.clear(); #ifdef _OPENMP #pragma omp for schedule(static) nowait @@ -912,27 +911,38 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p for (int i = 0; i < fh; i++) for (int j = 0; j < fw; j++) { - hist16thr[(int)((labView->L[i][j]))]++; + hist16thr[CLIP((int)((labView->L[i][j])))]++; } #pragma omp critical { - hist16 += hist16thr; + for(int i = 0; i < 65536; i++) + { + hist16[i] += hist16thr[i]; + } } } + + } - bool utili; - CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, hist16, lumacurve, dummy, 1, utili); + bool utili = false; + bool autili = false; + bool butili = false; + bool ccutili = false; + bool cclutili = false; + bool clcutili = false; - bool clcutili; - CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, 1); + 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 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); + 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); - ipf.chromiLuminanceCurve (NULL, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); + ipf.chromiLuminanceCurve (NULL, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy, dummy, dummy); if((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { ipf.EPDToneMap(labView, 5, 1); @@ -1020,11 +1030,11 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p begh = 0; endh = fh; CurveFactory::curveLightBrightColor ( - params.colorappearance.curve, - params.colorappearance.curve2, - params.colorappearance.curve3, - hist16, dummy, - dummy, dummy, + 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, diff --git a/rtengine/sleef.c b/rtengine/sleef.c index 2377aea79..c7b3fb486 100644 --- a/rtengine/sleef.c +++ b/rtengine/sleef.c @@ -58,9 +58,7 @@ __inline double ldexpk(double x, int q) { m = (((m + q) >> 9) - m) << 7; q = q - (m << 2); u = longBitsToDouble(((int64_t)(m + 0x3ff)) << 52); - double u2 = u*u; - u2 = u2 * u2; - x = x * u2; + x = x * u * u * u * u; u = longBitsToDouble(((int64_t)(q + 0x3ff)) << 52); return x * u; } @@ -1199,7 +1197,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); @@ -1248,7 +1246,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 e422d23b2..aabb35a30 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -83,7 +83,7 @@ StdImageSource::~StdImageSource () } } -void StdImageSource::getSampleFormat (const Glib::ustring &fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement) +void StdImageSource::getSampleFormat (Glib::ustring &fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement) { sFormat = IIOSF_UNKNOWN; @@ -125,7 +125,7 @@ void StdImageSource::getSampleFormat (const Glib::ustring &fname, IIOSampleForma * and RT's image data type (Image8, Image16 and Imagefloat), then it will * load the image into it */ -int StdImageSource::load (const Glib::ustring &fname, bool batch) +int StdImageSource::load (Glib::ustring fname, bool batch) { fileName = fname; @@ -213,7 +213,7 @@ int StdImageSource::load (const Glib::ustring &fname, bool batch) return 0; } -void StdImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const ColorManagementParams &cmp, const RAWParams &raw) +void StdImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw) { // the code will use OpenMP as of now. @@ -234,12 +234,12 @@ void StdImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima } } -void StdImageSource::convertColorSpace(Imagefloat* image, const ColorManagementParams &cmp, const ColorTemp &wb) +void StdImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams cmp, ColorTemp &wb) { colorSpaceConversion (image, cmp, embProfile, img->getSampleFormat()); } -void StdImageSource::colorSpaceConversion (Imagefloat* im, const ColorManagementParams &cmp, cmsHPROFILE embedded, IIOSampleFormat sampleFormat) +void StdImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, cmsHPROFILE embedded, IIOSampleFormat sampleFormat) { bool skipTransform = false; diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 048f3b3c0..6017fae74 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 (const Glib::ustring &fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement); + void getSampleFormat (Glib::ustring &fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement); public: StdImageSource (); ~StdImageSource (); - 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 + 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 () { return wb; } @@ -60,7 +60,7 @@ public: void getAutoExpHistogram (LUTu &histogram, int& histcompr); - double getDefGain () const + double getDefGain () { return 0.0; } @@ -90,10 +90,20 @@ public: plistener = pl; } - 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); + 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); - bool IsrgbSourceModified() const + 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() { return rgbSourceModified; } diff --git a/rtengine/utils.h b/rtengine/utils.h index c46999219..1e742ffb3 100644 --- a/rtengine/utils.h +++ b/rtengine/utils.h @@ -16,9 +16,8 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#pragma once - -#include +#ifndef _SIMPLEUTILS_ +#define _SIMPLEUTILS_ namespace rtengine { @@ -36,10 +35,5 @@ 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 ed4c9be95..188135558 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -25,7 +25,8 @@ #include "rtimage.h" #include "../rtengine/improccoordinator.h" #include "../rtengine/color.h" -#include "../rtengine/opthelper.h" + + using namespace rtengine; extern Options options; @@ -965,7 +966,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] ALIGNED16 {0}, chisttemp[256] ALIGNED16 {0}, rhtemp[256] ALIGNED16 {0}, ghtemp[256] ALIGNED16 {0}, bhtemp[256] ALIGNED16 {0}; + unsigned int lhisttemp[256], chisttemp[256], rhtemp[256], ghtemp[256], bhtemp[256]; const int scale = (rawMode ? 8 : 1); for(int i = 0; i < 256; i++) { @@ -1024,48 +1025,31 @@ void HistogramArea::updateBackBuffer () if (!fullMode) { int area = 0; -#ifdef __SSE2__ - vint onev = _mm_set1_epi32(1); - vint iv = (vint)ZEROV; -#endif + 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++; + } - 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)); - - } - - 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++; + if ((double)area / (256 * (i + 1)) < 0.3) { + realhistheight = i; + break; } - -#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++; + } + + 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 7f0f6cfd0..b6da75167 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::getInstance()->getStdProfile(camName); - } else if (ifromfile->get_active() && DCPStore::getInstance()->isValidDCPFileName(dcp_name)) { - dcp = DCPStore::getInstance()->getProfile(dcp_name); + dcp = dcpStore->getStdProfile(camName); + } else if (ifromfile->get_active() && dcpStore->isValidDCPFileName(dcp_name)) { + dcp = dcpStore->getProfile(dcp_name); } if (dcp) { @@ -396,21 +396,24 @@ void ICMPanel::updateDCP (int dcpIlluminant, Glib::ustring dcp_name) ckbApplyHueSatMap->set_sensitive (true); } - const DCPProfile::Illuminants illuminants = dcp->getIlluminants(); + int i1, i2; + double temp1, temp2; + bool willInterpolate; + dcp->getIlluminants(i1, temp1, i2, temp2, willInterpolate); - if (illuminants.will_interpolate) { - if (dcpTemperatures[0] != illuminants.temperature_1 || dcpTemperatures[1] != illuminants.temperature_2) { + if (willInterpolate) { + if (dcpTemperatures[0] != temp1 || dcpTemperatures[1] != temp2) { char tempstr1[64], tempstr2[64]; - sprintf(tempstr1, "%.0fK", illuminants.temperature_1); - sprintf(tempstr2, "%.0fK", illuminants.temperature_2); + sprintf(tempstr1, "%.0fK", temp1); + sprintf(tempstr2, "%.0fK", temp2); 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] = illuminants.temperature_1; - dcpTemperatures[1] = illuminants.temperature_2; + dcpTemperatures[0] = temp1; + dcpTemperatures[1] = temp2; dcpIll->set_active (curr_active); ignoreDcpSignal = false; } @@ -639,10 +642,10 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) DCPProfile* dcp = NULL; - 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)); + 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)); } else if(icameraICC->get_active()) { - dcp = DCPStore::getInstance()->getStdProfile(camName); + dcp = dcpStore->getStdProfile(camName); } if (dcp) { @@ -928,7 +931,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::getInstance()->getStdProfile(pMeta->getCamera()) != NULL)); + icameraICC->set_sensitive (raw && (iccStore->getStdProfile(pMeta->getCamera()) != NULL || dcpStore->getStdProfile(pMeta->getCamera()) != NULL)); iembedded->set_sensitive (!raw); enableListener (); diff --git a/rtgui/lensgeom.cc b/rtgui/lensgeom.cc index e56b3b025..d4487aa80 100644 --- a/rtgui/lensgeom.cc +++ b/rtgui/lensgeom.cc @@ -44,11 +44,6 @@ 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) { @@ -119,30 +114,3 @@ 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 51a6e108c..f6b41b632 100644 --- a/rtgui/lensgeom.h +++ b/rtgui/lensgeom.h @@ -32,12 +32,11 @@ protected: Gtk::CheckButton* fill; bool lastFill; sigc::connection fillConn; - ToolParamBlock* packBox; + ToolParamBlock* packBox; public: LensGeometry (); - ~LensGeometry (); Gtk::Box* getPackBox () { @@ -54,11 +53,6 @@ public: { rlistener = l; } - void disableAutoFillIfActive (); - -private: - static int doDisableAutoFillIfActive (void* data); - }; #endif diff --git a/rtgui/lensprofile.cc b/rtgui/lensprofile.cc index 71c54e2b5..a7a634443 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); - conUseDist = ckbUseDist->signal_toggled().connect( sigc::mem_fun(*this, &LensProfilePanel::onUseDistChanged) ); + 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,7 +77,6 @@ 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); @@ -103,7 +102,6 @@ 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) @@ -144,10 +142,6 @@ 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())); @@ -170,12 +164,6 @@ 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 cb3a5cc6c..0397388d5 100644 --- a/rtgui/lensprofile.h +++ b/rtgui/lensprofile.h @@ -22,7 +22,6 @@ #include #include "toolpanel.h" #include "guiutils.h" -#include "lensgeom.h" class LensProfilePanel : public ToolParamBlock, public FoldableToolPanel { @@ -39,7 +38,6 @@ protected: void updateDisabled(bool enable); bool allowFocusDep; bool isRaw; - LensGeometry *lensgeomLcpFill; public: @@ -54,10 +52,6 @@ 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 c544f6871..7911ac279 100644 --- a/rtgui/myflatcurve.cc +++ b/rtgui/myflatcurve.cc @@ -1792,7 +1792,6 @@ 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 1a9e4cda2..c647f2ed2 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -53,7 +53,6 @@ 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 ());