diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 3def47d59..700691c7f 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -1381,6 +1381,7 @@ TP_COLORTONING_HIGHLIGHT;Hautes lumières TP_COLORTONING_HUE;Teinte TP_COLORTONING_LAB;Mixage Lab TP_COLORTONING_LABEL;Virage Partiel +TP_COLORTONING_LABGRID_VALUES;HL: a=%1 b=%2\nO: a=%3 b=%4 TP_COLORTONING_LUMA;Luminance TP_COLORTONING_LUMAMODE;Préserver la luminance TP_COLORTONING_LUMAMODE_TOOLTIP;Si activé, lorsque vous changez la couleur (rouge, vert, cyan, bleu, etc.), la luminance de chaque pixel est préservé diff --git a/rtdata/languages/default b/rtdata/languages/default index 7e125a3b8..46783f2ce 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -844,6 +844,7 @@ HISTORY_MSG_598;Local - Bottom HISTORY_MSG_599;Local - Noise bilateral HISTORY_MSG_600;Local - Noise Equal. Black-White HISTORY_MSG_601;Local - Shape Rt-spot method +HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - Color correction HISTORY_MSG_LOCALCONTRAST_AMOUNT;Local Contrast - Amount HISTORY_MSG_LOCALCONTRAST_DARKNESS;Local Contrast - Darkness HISTORY_MSG_LOCALCONTRAST_ENABLED;Local Contrast @@ -1542,6 +1543,8 @@ TP_COLORTONING_HIGHLIGHT;Highlights TP_COLORTONING_HUE;Hue TP_COLORTONING_LAB;L*a*b* blending TP_COLORTONING_LABEL;Color Toning +TP_COLORTONING_LABGRID;L*a*b* color correction grid +TP_COLORTONING_LABGRID_VALUES;HL: a=%1 b=%2\nS: a=%3 b=%4 TP_COLORTONING_LUMA;Luminance TP_COLORTONING_LUMAMODE;Preserve luminance TP_COLORTONING_LUMAMODE_TOOLTIP;If enabled, when you change color (red, green, cyan, blue, etc.) the luminance of each pixel is preserved. diff --git a/rtengine/color.cc b/rtengine/color.cc index 07cb3d05e..2d6064d37 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -568,44 +568,6 @@ void Color::rgb2hsl(float r, float g, float b, float &h, float &s, float &l) } } -void Color::rgb2hslfloat(float r, float g, float b, float &h, float &s, float &l) -{ - - float m = min(r, g, b); - float M = max(r, g, b); - float C = M - m; - - l = (M + m) * 7.6295109e-6f; // (0.5f / 65535.f) - - if (fabsf(C) < 0.65535f) { // 0.00001f * 65535.f - h = 0.f; - s = 0.f; - } else { - - if (l <= 0.5f) { - s = (M - m) / (M + m); - } else { - s = (M - m) / (131070.f - M - m); // 131070.f = 2.f * 65535.f - } - - if (r == M) { - h = (g - b); - } else if (g == M) { - h = (2.f * C) + (b - r); - } else { - h = (4.f * C) + (r - g); - } - - h /= (6.f * C); - - if (h < 0.f) { - h += 1.f; - } else if (h > 1.f) { - h -= 1.f; - } - } -} - #ifdef __SSE2__ void Color::rgb2hsl(vfloat r, vfloat g, vfloat b, vfloat &h, vfloat &s, vfloat &l) { @@ -624,9 +586,8 @@ void Color::rgb2hsl(vfloat r, vfloat g, vfloat b, vfloat &h, vfloat &s, vfloat & h /= (F2V(6.f) * C); vfloat onev = F2V(1.f); h = vself(vmaskf_lt(h, ZEROV), h + onev, h); - h = vself(vmaskf_gt(h, onev), h - onev, h); - vmask zeromask = vmaskf_lt(vabsf(C), F2V(0.65535f)); + vmask zeromask = vmaskf_lt(C, F2V(0.65535f)); h = vself(zeromask, ZEROV, h); s = vself(zeromask, ZEROV, s); } @@ -712,28 +673,6 @@ void Color::hsl2rgb(float h, float s, float l, float &r, float &g, float &b) } } -void Color::hsl2rgbfloat(float h, float s, float l, float &r, float &g, float &b) -{ - - if (s == 0.f) { - r = g = b = 65535.f * l; // achromatic - } else { - float m2; - - if (l <= 0.5f) { - m2 = l * (1.f + s); - } else { - m2 = l + s - l * s; - } - - float m1 = 2.f * l - m2; - - r = 65535.f * hue2rgbfloat(m1, m2, h * 6.f + 2.f); - g = 65535.f * hue2rgbfloat(m1, m2, h * 6.f); - b = 65535.f * hue2rgbfloat(m1, m2, h * 6.f - 2.f); - } -} - #ifdef __SSE2__ void Color::hsl2rgb(vfloat h, vfloat s, vfloat l, vfloat &r, vfloat &g, vfloat &b) { diff --git a/rtengine/color.h b/rtengine/color.h index df218cbc4..49cb8d37a 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -206,7 +206,64 @@ public: * @param l luminance channel [0; 1] (return value) */ static void rgb2hsl(float r, float g, float b, float &h, float &s, float &l); - static void rgb2hslfloat(float r, float g, float b, float &h, float &s, float &l); + + static inline void rgb2slfloat(float r, float g, float b, float &s, float &l) + { + + float m = min(r, g, b); + float M = max(r, g, b); + float C = M - m; + + l = (M + m) * 7.6295109e-6f; // (0.5f / 65535.f) + + if (C < 0.65535f) { // 0.00001f * 65535.f + s = 0.f; + } else { + + if (l <= 0.5f) { + s = C / (M + m); + } else { + s = C / (131070.f - (M + m)); // 131070.f = 2.f * 65535.f + } + } + } + + static inline void rgb2hslfloat(float r, float g, float b, float &h, float &s, float &l) + { + + float m = min(r, g, b); + float M = max(r, g, b); + float C = M - m; + + l = (M + m) * 7.6295109e-6f; // (0.5f / 65535.f) + + if (C < 0.65535f) { // 0.00001f * 65535.f + h = 0.f; + s = 0.f; + } else { + + if (l <= 0.5f) { + s = C / (M + m); + } else { + s = C / (131070.f - (M + m)); // 131070.f = 2.f * 65535.f + } + + if ( r == M ) { + h = (g - b); + } else if ( g == M ) { + h = (2.f * C) + (b - r); + } else { + h = (4.f * C) + (r - g); + } + + h /= (6.f * C); + + if ( h < 0.f ) { + h += 1.f; + } + } + } + #ifdef __SSE2__ static void rgb2hsl(vfloat r, vfloat g, vfloat b, vfloat &h, vfloat &s, vfloat &l); #endif @@ -221,7 +278,29 @@ public: * @param b blue channel [0 ; 65535] (return value) */ static void hsl2rgb(float h, float s, float l, float &r, float &g, float &b); - static void hsl2rgbfloat(float h, float s, float l, float &r, float &g, float &b); + + static inline void hsl2rgbfloat (float h, float s, float l, float &r, float &g, float &b) + { + + if (s == 0.f) { + r = g = b = 65535.f * l; // achromatic + } else { + float m2; + + if (l <= 0.5f) { + m2 = l * (1.f + s); + } else { + m2 = l + s - l * s; + } + + float m1 = 2.f * l - m2; + + r = 65535.f * hue2rgbfloat (m1, m2, h * 6.f + 2.f); + g = 65535.f * hue2rgbfloat (m1, m2, h * 6.f); + b = 65535.f * hue2rgbfloat (m1, m2, h * 6.f - 2.f); + } + } + #ifdef __SSE2__ static void hsl2rgb(vfloat h, vfloat s, vfloat l, vfloat &r, vfloat &g, vfloat &b); #endif @@ -255,11 +334,7 @@ public: float var_Max = max(r, g, b); float del_Max = var_Max - var_Min; - if (del_Max < 0.00001f) { - return 0.f; - } else { - return del_Max / var_Max; - } + return del_Max / (var_Max == 0.f ? 1.f : var_Max); } static inline bool rgb2hsvdcp(float r, float g, float b, float &h, float &s, float &v) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index f9cdd1c73..82ea35f0f 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -1074,7 +1074,7 @@ void DCPProfile::apply( float s; float v; - if(Color::rgb2hsvdcp(newr, newg, newb, h , s, v)) { + if (LIKELY(Color::rgb2hsvdcp(newr, newg, newb, h , s, v))) { hsdApply(delta_info, delta_base, h, s, v); diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 1b6a4ad20..0e404fa91 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -1439,16 +1439,16 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) } if (iptcdata) { - rtexif::Tag* iptcTag = new rtexif::Tag (nullptr, rtexif::lookupAttrib (rtexif::ifdAttribs, "IPTCData")); - iptcTag->initLongArray((char*)iptcdata, iptclen); + rtexif::Tag iptcTag(nullptr, rtexif::lookupAttrib (rtexif::ifdAttribs, "IPTCData")); + iptcTag.initLongArray((char*)iptcdata, iptclen); #if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::MOTOROLA; #else bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::INTEL; #endif if (needsReverse) { - unsigned char *ptr = iptcTag->getValue(); - for (int a = 0; a < iptcTag->getCount(); ++a) { + unsigned char *ptr = iptcTag.getValue(); + for (int a = 0; a < iptcTag.getCount(); ++a) { unsigned char cc; cc = ptr[3]; ptr[3] = ptr[0]; @@ -1459,7 +1459,7 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed) ptr += 4; } } - TIFFSetField (out, TIFFTAG_RICHTIFFIPTC, iptcTag->getCount(), (long*)iptcTag->getValue()); + TIFFSetField (out, TIFFTAG_RICHTIFFIPTC, iptcTag.getCount(), (long*)iptcTag.getValue()); iptc_data_free_buf (iptc, iptcdata); } diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 261995f08..5a71bb532 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -69,7 +69,7 @@ public: virtual int load (const Glib::ustring &fname) = 0; virtual void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse, bool prepareDenoise = true) {}; virtual void demosaic (const RAWParams &raw) {}; - virtual void retinex (const ColorManagementParams& cmp, const 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) {}; + virtual void retinex (const ColorManagementParams& cmp, const RetinexParams &deh, const 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) {}; virtual void retinexPrepareCurves (const RetinexParams &retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, RetinexgaintransmissionCurve &retinexgaintransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) {}; virtual void retinexPrepareBuffers (const ColorManagementParams& cmp, const RetinexParams &retinexParams, multi_array2D &conversionBuffer, LUTu &lhist16RETI) {}; virtual void flushRawData () {}; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 86b0c5bd6..6b100f021 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -659,7 +659,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, Crop* cropCall) int satPR = 30; int indi = 0; - if (params.colorToning.enabled && params.colorToning.autosat) { //for colortoning evaluation of saturation settings + if (params.colorToning.enabled && params.colorToning.autosat && params.colorToning.method != "LabGrid") { //for colortoning evaluation of saturation settings float moyS = 0.f; float eqty = 0.f; ipf.moyeqt(oprevi, moyS, eqty); //return image : mean saturation and standard dev of saturation diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 81b59b342..47e8c78f4 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -3507,7 +3507,8 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer userToneCurve.initApplyState(ptc2ApplyState, params->icm.working); } - bool hasColorToning = params->colorToning.enabled && bool (ctOpacityCurve) && bool (ctColorCurve); + bool hasColorToning = params->colorToning.enabled && bool (ctOpacityCurve) && bool (ctColorCurve) && params->colorToning.method != "LabGrid"; + bool hasColorToningLabGrid = params->colorToning.enabled && params->colorToning.method == "LabGrid"; // float satLimit = float(params->colorToning.satProtectionThreshold)/100.f*0.7f+0.3f; // float satLimitOpacity = 1.f-(float(params->colorToning.saturatedOpacity)/100.f); float strProtect = (float (params->colorToning.strength) / 100.f); @@ -4033,23 +4034,21 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer if (hasColorToning && !blackwhite) { if (params->colorToning.method == "Splitlr") { - float balanS, balanH; - float reducac = 0.4f; + constexpr float reducac = 0.4f; int preser = 0; if (params->colorToning.lumamode) { preser = 1; } - balanS = 1.f + Balan / 100.f; //balan between 0 and 2 - balanH = 1.f - Balan / 100.f; + const float balanS = 1.f + Balan / 100.f; //balan between 0 and 2 + const float balanH = 1.f - Balan / 100.f; float rh, gh, bh; float rl, gl, bl; float xh, yh, zh; float xl, yl, zl; - float iplow, iphigh; - iplow = (float)ctColorCurve.low; - iphigh = (float)ctColorCurve.high; + const float iplow = (float)ctColorCurve.low; + const float iphigh = (float)ctColorCurve.high; //2 colours ctColorCurve.getVal(iphigh, xh, yh, zh); ctColorCurve.getVal(iplow, xl, yl, zl); @@ -4058,20 +4057,18 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer Color::xyz2rgb(xl, yl, zl, rl, gl, bl, wip); //reteave rgb value with s and l =1 retreavergb(rl, gl, bl); + const float krl = rl / (rl + gl + bl); + const float kgl = gl / (rl + gl + bl); + const float kbl = bl / (rl + gl + bl); retreavergb(rh, gh, bh); - //printf("rl=%f gl=%f bl=%f\n",rl,gl,bl); + const float krh = rh / (rh + gh + bh); + const float kgh = gh / (rh + gh + bh); + const float kbh = bh / (rh + gh + bh); for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { - float r = rtemp[ti * TS + tj]; - float g = gtemp[ti * TS + tj]; - float b = btemp[ti * TS + tj]; - float ro, go, bo; int mode = 0; - toning2col(r, g, b, ro, go, bo, iplow, iphigh, rl, gl, bl, rh, gh, bh, SatLow, SatHigh, balanS, balanH, reducac, mode, preser, strProtect); - rtemp[ti * TS + tj] = ro; - gtemp[ti * TS + tj] = go; - btemp[ti * TS + tj] = bo; + toning2col(rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], rtemp[ti * TS + tj], gtemp[ti * TS + tj], btemp[ti * TS + tj], iplow, iphigh, krl, kgl, kbl, krh, kgh, kbh, SatLow, SatHigh, balanS, balanH, reducac, mode, preser, strProtect); } } } @@ -4198,29 +4195,25 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer // Luminance = (0.299f*r + 0.587f*g + 0.114f*b) - float h, s, l; - Color::rgb2hsl(r, g, b, h, s, l); + float s, l; + Color::rgb2slfloat (r, g, b, s, l); - float l_ = Color::gamma_srgb(l * 65535.f) / 65535.f; + float l_ = Color::gammatab_srgb1[l * 65535.f]; // get the opacity and tweak it to preserve saturated colors - float opacity; + float opacity = 0.f; if (ctOpacityCurve) { opacity = (1.f - min (s / satLimit, 1.f) * (1.f - satLimitOpacity)) * ctOpacityCurve.lutOpacityCurve[l_ * 500.f]; } - if (!ctOpacityCurve) { - opacity = 0.f; - } - float r2, g2, b2; ctColorCurve.getVal(l_, r2, g2, b2); // get the color from the color curve float h2, s2, l2; - Color::rgb2hsl(r2, g2, b2, h2, s2, l2); // transform this new color to hsl + Color::rgb2hslfloat (r2, g2, b2, h2, s2, l2); // transform this new color to hsl - Color::hsl2rgb(h2, s + ((1.f - s) * (1.f - l) * 0.7f), l, r2, g2, b2); + Color::hsl2rgbfloat (h2, s + ((1.f - s) * (1.f - l) * 0.7f), l, r2, g2, b2); rtemp[ti * TS + tj] = r + (r2 - r) * opacity; // merge the color to the old color, depending on the opacity gtemp[ti * TS + tj] = g + (g2 - g) * opacity; @@ -4545,6 +4538,9 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = istart, ti = 0; i < tH; i++, ti++) { Color::RGB2Lab(&rtemp[ti * TS], >emp[ti * TS], &btemp[ti * TS], &(lab->L[i][jstart]), &(lab->a[i][jstart]), &(lab->b[i][jstart]), toxyz, tW - jstart); } + if (hasColorToningLabGrid) { + colorToningLabGrid(lab, jstart, tW, istart, tH, false); + } } else { // black & white // Auto channel mixer needs whole image, so we now copy to tmpImage and close the tiled processing for (int i = istart, ti = 0; i < tH; i++, ti++) { @@ -4778,23 +4774,21 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer } else if (params->colorToning.method == "Splitlr") { - float balanS, balanH; - float reducac = 0.4f; + constexpr float reducac = 0.4f; int preser = 0; if (params->colorToning.lumamode) { preser = 1; } - balanS = 1.f + Balan / 100.f; //balan between 0 and 2 - balanH = 1.f - Balan / 100.f; + const float balanS = 1.f + Balan / 100.f; //balan between 0 and 2 + const float balanH = 1.f - Balan / 100.f; float rh, gh, bh; float rl, gl, bl; float xh, yh, zh; float xl, yl, zl; - float iplow, iphigh; - iplow = (float)ctColorCurve.low; - iphigh = (float)ctColorCurve.high; + const float iplow = ctColorCurve.low; + const float iphigh = ctColorCurve.high; //2 colours ctColorCurve.getVal(iphigh, xh, yh, zh); @@ -4805,23 +4799,23 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer //retrieve rgb value with s and l =1 retreavergb(rl, gl, bl); + const float krl = rl / (rl + gl + bl); + const float kgl = gl / (rl + gl + bl); + const float kbl = bl / (rl + gl + bl); + retreavergb(rh, gh, bh); + const float krh = rh / (rh + gh + bh); + const float kgh = gh / (rh + gh + bh); + const float kbh = bh / (rh + gh + bh); + #ifdef _OPENMP #pragma omp parallel for schedule(dynamic, 5) #endif for (int i = 0; i < tH; i++) { for (int j = 0; j < tW; j++) { - float r = tmpImage->r(i, j); - float g = tmpImage->g(i, j); - float b = tmpImage->b(i, j); - - float ro, go, bo; int mode = 1; - toning2col(r, g, b, ro, go, bo, iplow, iphigh, rl, gl, bl, rh, gh, bh, SatLow, SatHigh, balanS, balanH, reducac, mode, preser, strProtect); - tmpImage->r(i, j) = ro; - tmpImage->g(i, j) = go; - tmpImage->b(i, j) = bo; + toning2col(tmpImage->r(i, j), tmpImage->g(i, j), tmpImage->b(i, j), tmpImage->r(i, j), tmpImage->g(i, j), tmpImage->b(i, j), iplow, iphigh, krl, kgl, kbl, krh, kgh, kbh, SatLow, SatHigh, balanS, balanH, reducac, mode, preser, strProtect); } } } @@ -4903,25 +4897,25 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer // Luminance = (0.299f*r + 0.587f*g + 0.114f*b) - float h, s, l; - Color::rgb2hsl(r, g, b, h, s, l); + float s, l; + Color::rgb2slfloat(r, g, b, s, l); - float l_ = Color::gamma_srgb(l * 65535.f) / 65535.f; + float l_ = Color::gammatab_srgb1[l * 65535.f]; - // get the opacity and tweak it to preserve saturated colors + // get the opacity and tweak it to preserve saturated colours float opacity = ctOpacityCurve.lutOpacityCurve[l_ * 500.f] / 4.f; float r2, g2, b2; - ctColorCurve.getVal(l_, r2, g2, b2); // get the color from the color curve + ctColorCurve.getVal(l_, r2, g2, b2); // get the colour from the colour curve float h2, s2, l2; - Color::rgb2hsl(r2, g2, b2, h2, s2, l2); // transform this new color to hsl + Color::rgb2hslfloat(r2, g2, b2, h2, s2, l2); // transform this new colour to hsl - Color::hsl2rgb(h2, s2, l, r2, g2, b2); + Color::hsl2rgbfloat(h2, s2, l, r2, g2, b2); - tmpImage->r(i, j) = r + (r2 - r) * opacity; - tmpImage->g(i, j) = g + (g2 - g) * opacity; - tmpImage->b(i, j) = b + (b2 - b) * opacity; + tmpImage->r(i, j) = intp(opacity, r2, r); + tmpImage->g(i, j) = intp(opacity, g2, g); + tmpImage->b(i, j) = intp(opacity, b2, b); } } } @@ -4956,6 +4950,9 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { Color::RGB2Lab(tmpImage->r(i), tmpImage->g(i), tmpImage->b(i), lab->L[i], lab->a[i], lab->b[i], toxyz, tW); + if (hasColorToningLabGrid) { + colorToningLabGrid(lab, 0, tW, i, i + 1, false); + } } @@ -5053,11 +5050,8 @@ void ImProcFunctions::secondeg_end(float reducac, float vinf, float &aa, float & **/ void ImProcFunctions::secondeg_begin(float reducac, float vend, float &aam, float &bbm) { - float zrmd = reducac; //linear = 0.5 - float v0m = vend; - float mem = vend / 2.f; //(0. + 0.8)/2.f - aam = (1.f - zrmd * v0m / mem) / (v0m * v0m - mem * v0m); // - bbm = (1.f - aam * v0m * v0m) / v0m; + aam = (2.f - 4.f * reducac) / (vend * vend); + bbm = 1.f / vend - aam * vend; } @@ -5353,79 +5347,57 @@ void ImProcFunctions::toningsmh(float r, float g, float b, float &ro, float &go, * @param balanH [0..1] balance for highlights (same slider than for balanS) * @param reducac value of the reduction in the middle of the range for second degree, increase or decrease action **/ -void ImProcFunctions::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 ImProcFunctions::toning2col (float r, float g, float b, float &ro, float &go, float &bo, float iplow, float iphigh, float krl, float kgl, float kbl, float krh, float kgh, float kbh, float SatLow, float SatHigh, float balanS, float balanH, float reducac, int mode, int preser, float strProtect) { - float lumbefore = 0.299f * r + 0.587f * g + 0.114f * b; - float h, s, l; - Color::rgb2hsl(r, g, b, h, s, l); - float v; - Color::rgb2hsv(r, g, b, h, s, v); - float ksat = 1.f; - float ksatlow = 1.f; - /* - if(mode==0) {//color - if(s < s_0) ksat=SQR((1.f/s_0)*s); - if(s > s_1) ksat=SQR((1.f/(s_1-1.f))*s - (1.f/(s_1-1.f))); - } - */ - float kl = 1.f; - float rlo = 1.f; - float rlh = 2.2f; - rlo *= pow_F(strProtect, 0.4f); //0.5 ==> 0.75 transfered value for more action - rlh *= pow_F(strProtect, 0.4f); + const float lumbefore = 0.299f * r + 0.587f * g + 0.114f * b; + const float v = max(r, g, b) / 65535.f; + + const float rlo = pow_F (strProtect, 0.4f); //0.5 ==> 0.75 transfered value for more action + const float rlh = 2.2f * pow_F (strProtect, 0.4f); + //low tones //second degree float aa, bb, cc; //fixed value of reducac =0.4; secondeg_end(reducac, iplow, aa, bb, cc); - float aab, bbb; + float aab, bbb; secondeg_begin(0.7f, iplow, aab, bbb); - if (v > iplow) { - kl = aa * v * v + bb * v + cc; - } else if (mode == 0) { - kl = aab * v * v + bbb * v; - } - - if (SatLow > 0.f) { - //rl gl bl - float krl = rl / (rl + gl + bl); - float kgl = gl / (rl + gl + bl); - float kbl = bl / (rl + gl + bl); - float RedL, GreenL, BlueL; - - if (g < 20000.f || b < 20000.f || r < 20000.f) { - float kmgb = min(r, g, b); //I have tested ...0.85 compromise... - kl *= pow((kmgb / 20000.f), 0.85f); + float kl = 1.f; + if (v > iplow) { + kl = aa * v * v + bb * v + cc; + } else if (mode == 0) { + kl = aab * v * v + bbb * v; + } + const float kmgb = min(r, g, b); + if (kmgb < 20000.f) { + //I have tested ...0.85 compromise... + kl *= pow_F ((kmgb / 20000.f), 0.85f); } - RedL = 1.f + (SatLow * krl) * kl * ksat * rlo * balanS; //0.4 + const float factor = 20000.f * SatLow * kl * rlo * balanS; if (krl > 0.f) { - g -= 20000.f * (RedL - 1.f) * ksatlow; - b -= 20000.f * (RedL - 1.f) * ksatlow; + g -= factor * krl; + b -= factor * krl; } g = CLIP(g); b = CLIP(b); - GreenL = 1.f + (SatLow * kgl) * kl * ksat * rlo * balanS; //0.4 - if (kgl > 0.f) { - r -= 20000.f * (GreenL - 1.f) * ksatlow; - b -= 20000.f * (GreenL - 1.f) * ksatlow; + r -= factor * kgl; + b -= factor * kgl; } r = CLIP(r); b = CLIP(b); - BlueL = 1.f + (SatLow * kbl) * kl * ksat * rlo * balanS; //0.4 - if (kbl > 0.f) { - r -= 20000.f * (BlueL - 1.f) * ksatlow; - g -= 20000.f * (BlueL - 1.f) * ksatlow; + r -= factor * kbl; + g -= factor * kbl; } r = CLIP(r); @@ -5433,84 +5405,43 @@ void ImProcFunctions::toning2col(float r, float g, float b, float &ro, float &go } //high tones - float kh = 1.f; float aa0, bb0; //fixed value of reducac ==0.4; secondeg_begin(reducac, iphigh, aa0, bb0); - if (v > iphigh) { - kh = (-1.f / (1.f - iphigh)) * v + (1.f) / (1.f - iphigh); //Low light ==> decrease action after iplow - } else { - kh = aa0 * v * v + bb0 * v; - } - - - if (g > 45535.f || b > 45535.f || r > 45535.f) { - float kmgb = max(r, g, b); - float cora = 1.f / (45535.f - 65535.f); - float corb = 1.f - cora * 45535.f; - float cor = kmgb * cora + corb; - kh *= cor; - /* best algo if necessary with non linear response...little differences and more time! - float aa=1.f /(pow(45535.f,0.65f) - pow(65535.f,0.65f)); - float bb=1.f-aa*pow(45535.f,0.65f); - float cor=aa*pow(kmbg,0.65f)+bb; - kh*=cor;*/ - } - - if (SatHigh > 0.f) { - float RedH, GreenH, BlueH; - float krh = rh / (rh + gh + bh); - float kgh = gh / (rh + gh + bh); - float kbh = bh / (rh + gh + bh); - RedH = 1.f + (SatHigh * krh) * kh * rlh * balanH; //1.2 - - if (krh > 0.f) { - r += 20000.f * (RedH - 1.f); - r = CLIP(r); + float kh = 1.f; + if (v > iphigh) { + kh = (1.f - v) / (1.f - iphigh); //Low light ==> decrease action after iplow + } else { + kh = aa0 * v * v + bb0 * v; } - g = CLIP(g); - b = CLIP(b); - - GreenH = 1.f + (SatHigh * kgh) * kh * rlh * balanH; //1.2 - - if (kgh > 0.f) { - g += 20000.f * (GreenH - 1.f); - g = CLIP(g); - } - - r = CLIP(r); - b = CLIP(b); - BlueH = 1.f + (SatHigh * kbh) * kh * rlh * balanH; //1.2 - - if (kbh > 0.f) { - b += 20000.f * (BlueH - 1.f); - b = CLIP(b); + const float kmgb = max(r, g, b); + if (kmgb > 45535.f) { + constexpr float cora = 1.f / (45535.f - 65535.f); + constexpr float corb = 1.f - cora * 45535.f; + kh *= kmgb * cora + corb; } + const float factor = 20000.f * SatHigh * kh * rlh * balanH; + r += factor * (krh > 0.f ? krh : 0.f); + g += factor * (kgh > 0.f ? kgh : 0.f); + b += factor * (kbh > 0.f ? kbh : 0.f); r = CLIP(r); g = CLIP(g); + b = CLIP(b); } - float lumafter = 0.299f * r + 0.587f * g + 0.114f * b; float preserv = 1.f; - if (preser == 1) { + float lumafter = 0.299f * r + 0.587f * g + 0.114f * b; preserv = lumbefore / lumafter; } - //float preserv=lumbefore/lumafter; - ro = r; - go = g; - bo = b; - ro *= preserv; - go *= preserv; - bo *= preserv; - ro = CLIP(ro); - go = CLIP(go); - bo = CLIP(bo); + ro = CLIP(r * preserv); + go = CLIP(g * preserv); + bo = CLIP(b * preserv); } /** @@ -7307,4 +7238,41 @@ SSEFUNCTION void ImProcFunctions::lab2rgb(const LabImage &src, Imagefloat &dst, //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +// adapted from the "color correction" module of Darktable. Original copyright follows +/* + copyright (c) 2009--2010 johannes hanika. + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +*/ +void ImProcFunctions::colorToningLabGrid(LabImage *lab, int xstart, int xend, int ystart, int yend, bool MultiThread) +{ + const float factor = ColorToningParams::LABGRID_CORR_MAX * 3.f; + float a_scale = (params->colorToning.labgridAHigh - params->colorToning.labgridALow) / factor; + float a_base = params->colorToning.labgridALow; + float b_scale = (params->colorToning.labgridBHigh - params->colorToning.labgridBLow) / factor; + float b_base = params->colorToning.labgridBLow; + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = ystart; y < yend; ++y) { + for (int x = xstart; x < xend; ++x) { + lab->a[y][x] += lab->L[y][x] * a_scale + a_base; + lab->b[y][x] += lab->L[y][x] * b_scale + b_base; + } + } +} + } diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 058846512..7ac556a84 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -405,8 +405,8 @@ public: void BadpixelsLab(LabImage * src, LabImage * dst, double radius, int thresh, int mode, float skinprot, float chrom); void ToneMapFattal02(Imagefloat *rgb); - //void localContrast(float *r, float *g, float *b, int width, int height); void localContrast(LabImage *lab); + void colorToningLabGrid(LabImage *lab, int xstart, int xend, int ystart, int yend, bool MultiThread); Image8* lab2rgb(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm); Imagefloat* lab2rgbOut (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, GammaValues *ga = nullptr); diff --git a/rtengine/ipresize.cc b/rtengine/ipresize.cc index 1a48e5c43..ba559b2a0 100644 --- a/rtengine/ipresize.cc +++ b/rtengine/ipresize.cc @@ -106,6 +106,9 @@ void ImProcFunctions::Lanczos (const Imagefloat* src, Imagefloat* dst, float sca // weights for interpolation in y direction float w[support]; + for (auto& f : w) { + f = 0.f; + } // sum of weights used for normalization float ws = 0.0f; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 90ad6de9c..e499e588b 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -622,6 +622,8 @@ bool LocalContrastParams::operator!=(const LocalContrastParams &other) const } +const double ColorToningParams::LABGRID_CORR_MAX = 12000.f; + ColorToningParams::ColorToningParams() : enabled(false), autosat(true), @@ -692,7 +694,11 @@ greenhigh(0.0), bluehigh(0.0), satlow(0.0), sathigh(0.0), -lumamode(true) + lumamode(true), + labgridALow(0.0), + labgridBLow(0.0), + labgridAHigh(0.0), + labgridBHigh(0.0) { } @@ -724,7 +730,11 @@ bool ColorToningParams::operator ==(const ColorToningParams& other) const && bluehigh == other.bluehigh && satlow == other.satlow && sathigh == other.sathigh - && lumamode == other.lumamode; + && lumamode == other.lumamode + && labgridALow == other.labgridALow + && labgridBLow == other.labgridBLow + && labgridAHigh == other.labgridAHigh + && labgridBHigh == other.labgridBHigh; } bool ColorToningParams::operator !=(const ColorToningParams& other) const @@ -3835,6 +3845,10 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->colorToning.shadowsColSat, "ColorToning", "ShadowsColorSaturation", colorToning.shadowsColSat.toVector(), keyFile); saveToKeyfile(!pedited || pedited->colorToning.clcurve, "ColorToning", "ClCurve", colorToning.clcurve, keyFile); saveToKeyfile(!pedited || pedited->colorToning.cl2curve, "ColorToning", "Cl2Curve", colorToning.cl2curve, keyFile); + saveToKeyfile(!pedited || pedited->colorToning.labgridALow, "ColorToning", "LabGridALow", colorToning.labgridALow, keyFile); + saveToKeyfile(!pedited || pedited->colorToning.labgridBLow, "ColorToning", "LabGridBLow", colorToning.labgridBLow, keyFile); + saveToKeyfile(!pedited || pedited->colorToning.labgridAHigh, "ColorToning", "LabGridAHigh", colorToning.labgridAHigh, keyFile); + saveToKeyfile(!pedited || pedited->colorToning.labgridBHigh, "ColorToning", "LabGridBHigh", colorToning.labgridBHigh, keyFile); // Raw saveToKeyfile(!pedited || pedited->raw.darkFrame, "RAW", "DarkFrame", relativePathIfInside(fname, fnameAbsolute, raw.dark_frame), keyFile); @@ -5241,6 +5255,11 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "ColorToning", "Redhigh", pedited, colorToning.redhigh, pedited->colorToning.redhigh); assignFromKeyfile(keyFile, "ColorToning", "Greenhigh", pedited, colorToning.greenhigh, pedited->colorToning.greenhigh); assignFromKeyfile(keyFile, "ColorToning", "Bluehigh", pedited, colorToning.bluehigh, pedited->colorToning.bluehigh); + + assignFromKeyfile(keyFile, "ColorToning", "LabGridALow", pedited, colorToning.labgridALow, pedited->colorToning.labgridALow); + assignFromKeyfile(keyFile, "ColorToning", "LabGridBLow", pedited, colorToning.labgridBLow, pedited->colorToning.labgridBLow); + assignFromKeyfile(keyFile, "ColorToning", "LabGridAHigh", pedited, colorToning.labgridAHigh, pedited->colorToning.labgridAHigh); + assignFromKeyfile(keyFile, "ColorToning", "LabGridBHigh", pedited, colorToning.labgridBHigh, pedited->colorToning.labgridBHigh); } if (keyFile.has_group("RAW")) { diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 36d21f719..d3e614510 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -426,6 +426,7 @@ struct ColorToningParams { * Lch : * RGBSliders : * RGBCurves : + * LabGrid : */ Glib::ustring method; @@ -449,6 +450,12 @@ struct ColorToningParams { double sathigh; bool lumamode; + double labgridALow; + double labgridBLow; + double labgridAHigh; + double labgridBHigh; + static const double LABGRID_CORR_MAX; + ColorToningParams(); bool operator ==(const ColorToningParams& other) const; diff --git a/rtengine/profilestore.cc b/rtengine/profilestore.cc index 4d06b6f6b..e79c8e322 100644 --- a/rtengine/profilestore.cc +++ b/rtengine/profilestore.cc @@ -49,6 +49,7 @@ bool ProfileStore::init (bool loadAll) if ((storeState == STORESTATE_NOTINITIALIZED || storeState == STORESTATE_DIRTY) && loadAll) { storeState = STORESTATE_BEINGINITIALIZED; _parseProfiles (); + std::stable_partition(entries.begin(), entries.end(), [](const ProfileStoreEntry *e) { return e->type == PSET_FOLDER; }); storeState = STORESTATE_INITIALIZED; } diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 46b51f035..8c19a8e9a 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2373,7 +2373,7 @@ void RawImageSource::retinexPrepareCurves(const RetinexParams &retinexParams, LU retinexParams.getCurves(retinextransmissionCurve, retinexgaintransmissionCurve); } -void RawImageSource::retinex(const ColorManagementParams& cmp, const 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) +void RawImageSource::retinex(const ColorManagementParams& cmp, const RetinexParams &deh, const 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) { MyTime t4, t5; t4.set(); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index a9dd1add8..beaefc9dd 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -119,7 +119,7 @@ public: int load(const Glib::ustring &fname); void preprocess(const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse, bool prepareDenoise = true); void demosaic(const RAWParams &raw); - void retinex(const ColorManagementParams& cmp, const 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); + void retinex (const ColorManagementParams& cmp, const RetinexParams &deh, const 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); void retinexPrepareCurves(const RetinexParams &retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, RetinexgaintransmissionCurve &retinexgaintransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI); void retinexPrepareBuffers(const ColorManagementParams& cmp, const RetinexParams &retinexParams, multi_array2D &conversionBuffer, LUTu &lhist16RETI); void flushRawData(); diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 8ae966c9c..348b91031 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -1159,7 +1159,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT float satLimit = float (params.colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f; float satLimitOpacity = 1.f - (float (params.colorToning.saturatedOpacity) / 100.f); - if (params.colorToning.enabled && params.colorToning.autosat) { //for colortoning evaluation of saturation settings + if (params.colorToning.enabled && params.colorToning.autosat && params.colorToning.method != "LabGrid") { //for colortoning evaluation of saturation settings float moyS = 0.f; float eqty = 0.f; ipf.moyeqt (baseImg, moyS, eqty);//return image : mean saturation and standard dev of saturation diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index f85853e61..8ba0853cc 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -56,19 +56,48 @@ void adjust_radius(const T &default_param, double scale_factor, T ¶m) class ImageProcessor { public: - ImageProcessor(ProcessingJob* pjob, int& errorCode, - ProgressListener* pl, bool flush): + ImageProcessor( + ProcessingJob* pjob, + int& errorCode, + ProgressListener* pl, + bool flush + ) : job(static_cast(pjob)), errorCode(errorCode), pl(pl), flush(flush), // internal state - ipf_p(nullptr), ii(nullptr), imgsrc(nullptr), - fw(-1), - fh(-1), - pp(0, 0, 0, 0, 0) + fw(0), + fh(0), + tr(0), + pp(0, 0, 0, 0, 0), + calclum(nullptr), + autoNR(0.f), + autoNRmax(0.f), + tilesize(0), + overlap(0), + ch_M(nullptr), + max_r(nullptr), + max_b(nullptr), + min_b(nullptr), + min_r(nullptr), + lumL(nullptr), + chromC(nullptr), + ry(nullptr), + sk(nullptr), + pcsk(nullptr), + expcomp(0.0), + bright(0), + contr(0), + black(0), + hlcompr(0), + hlcomprthresh(0), + baseImg(nullptr), + labView(nullptr), + autili(false), + butili(false) { } @@ -921,7 +950,7 @@ private: float satLimit = float (params.colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f; float satLimitOpacity = 1.f - (float (params.colorToning.saturatedOpacity) / 100.f); - if (params.colorToning.enabled && params.colorToning.autosat) { //for colortoning evaluation of saturation settings + if (params.colorToning.enabled && params.colorToning.autosat && params.colorToning.method != "LabGrid") { //for colortoning evaluation of saturation settings float moyS = 0.f; float eqty = 0.f; ipf.moyeqt(baseImg, moyS, eqty); //return image : mean saturation and standard dev of saturation diff --git a/rtengine/tmo_fattal02.cc b/rtengine/tmo_fattal02.cc index 7ef490807..055868344 100644 --- a/rtengine/tmo_fattal02.cc +++ b/rtengine/tmo_fattal02.cc @@ -1116,9 +1116,15 @@ void ImProcFunctions::ToneMapFattal02 (Imagefloat *rgb) Array2Df Yr (w, h); - const float epsilon = 1e-4f; - const float luminance_noise_floor = 65.535f; - const float min_luminance = 1.f; + constexpr float epsilon = 1e-4f; + constexpr float luminance_noise_floor = 65.535f; + constexpr float min_luminance = 1.f; + const auto unclipped = + [rgb](int y, int x) -> bool + { + constexpr float c = 65500.f; + return rgb->r(y, x) < c && rgb->g(y, x) < c && rgb->b(y, x) < c; + }; TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix (params->icm.working); float max_Y = 0.f; @@ -1136,7 +1142,7 @@ void ImProcFunctions::ToneMapFattal02 (Imagefloat *rgb) for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { Yr (x, y) = std::max (luminance (rgb->r (y, x), rgb->g (y, x), rgb->b (y, x), ws), min_luminance); // clip really black pixels - if (Yr(x, y) > max_YThr) { + if (Yr(x, y) > max_YThr && unclipped(y, x)) { max_YThr = Yr(x, y); max_xThr = x; max_yThr = y; @@ -1194,16 +1200,16 @@ void ImProcFunctions::ToneMapFattal02 (Imagefloat *rgb) const float wr = float(w2) / float(w); const float scale = 65535.f / std::max(L(max_x * wr + 1, max_y * hr + 1), epsilon) * (65535.f / Yr(max_x, max_y)); - + #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) if(multiThread) #endif for (int y = 0; y < h; y++) { int yy = y * hr + 1; - + for (int x = 0; x < w; x++) { int xx = x * wr + 1; - + float Y = Yr (x, y); float l = std::max (L (xx, yy), epsilon) * (scale / Y); rgb->r (y, x) = std::max (rgb->r (y, x), 0.f) * l; diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 00183a916..baba236c2 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -152,6 +152,7 @@ set(NONCLISOURCEFILES localcontrast.cc eventmapper.cc metadatapanel.cc + labgrid.cc ) include_directories(BEFORE "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/rtgui/blackwhite.cc b/rtgui/blackwhite.cc index 2b410846f..0788a465d 100644 --- a/rtgui/blackwhite.cc +++ b/rtgui/blackwhite.cc @@ -1003,7 +1003,7 @@ void BlackWhite::autoch_toggled () bool wasEnabled = disableListener(); if (mixerRed->getAddMode()) { - mixerRed->resetValue(false); + mixerRed->resetValue(true); } if (mixerGreen->getAddMode()) { @@ -1053,14 +1053,14 @@ void BlackWhite::autoch_toggled () } else { if (autoch->get_active()) { bool wasEnabled = disableListener(); - mixerRed->setValue(33); - mixerGreen->setValue(33); - mixerBlue->setValue(33); - mixerOrange->setValue(33); - mixerYellow->setValue(33); - mixerMagenta->setValue(33); - mixerPurple->setValue(33); - mixerCyan->setValue(33); + mixerRed->resetValue(false); + mixerGreen->resetValue(false); + mixerBlue->resetValue(false); + mixerOrange->resetValue(false); + mixerYellow->resetValue(false); + mixerMagenta->resetValue(false); + mixerPurple->resetValue(false); + mixerCyan->resetValue(false); setting->set_active (11); filter->set_active (0); diff --git a/rtgui/colortoning.cc b/rtgui/colortoning.cc index 180b4235a..2ca099769 100644 --- a/rtgui/colortoning.cc +++ b/rtgui/colortoning.cc @@ -4,10 +4,13 @@ #include "colortoning.h" #include "mycurve.h" #include "rtimage.h" +#include "eventmapper.h" +#include "labgrid.h" using namespace rtengine; using namespace rtengine::procparams; + ColorToning::ColorToning () : FoldableToolPanel(this, "colortoning", M("TP_COLORTONING_LABEL"), false, true) { nextbw = 0; @@ -21,6 +24,7 @@ ColorToning::ColorToning () : FoldableToolPanel(this, "colortoning", M("TP_COLOR method->append (M("TP_COLORTONING_RGBCURVES")); method->append (M("TP_COLORTONING_SPLITCOCO")); method->append (M("TP_COLORTONING_SPLITLR")); + method->append(M("TP_COLORTONING_LABGRID")); method->set_active (0); method->set_tooltip_text (M("TP_COLORTONING_METHOD_TOOLTIP")); @@ -312,6 +316,26 @@ ColorToning::ColorToning () : FoldableToolPanel(this, "colortoning", M("TP_COLOR greenhigh->setAdjusterListener (this); bluehigh->setAdjusterListener (this); + //------------------------------------------------------------------------ + // LAB grid + auto m = ProcEventMapper::getInstance(); + EvColorToningLabGridValue = m->newEvent(RGBCURVE, "HISTORY_MSG_COLORTONING_LABGRID_VALUE"); + labgridBox = Gtk::manage(new Gtk::HBox()); + labgrid = Gtk::manage(new LabGrid(EvColorToningLabGridValue)); + labgridBox->pack_start(*labgrid, true, true); + labgridReset = Gtk::manage(new Gtk::Button ()); + labgridReset->add (*Gtk::manage(new RTImage ("gtk-undo-ltr-small.png", "gtk-undo-rtl-small.png"))); + setExpandAlignProperties(labgridReset, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_START); + labgridReset->set_relief(Gtk::RELIEF_NONE); + labgridReset->set_tooltip_text(M("ADJUSTER_RESET_TO_DEFAULT")); + labgridReset->get_style_context()->add_class(GTK_STYLE_CLASS_FLAT); + labgridReset->set_can_focus(false); + labgridReset->set_size_request(-1, 20); + labgridReset->signal_button_release_event().connect([=](GdkEventButton* release_event) { labgrid->reset(release_event->state & GDK_CONTROL_MASK ? true : false); return false; }); + labgridBox->pack_start(*labgridReset, false, false); + pack_start(*labgridBox, Gtk::PACK_EXPAND_WIDGET, 4); + //------------------------------------------------------------------------ + show_all(); disableListener(); @@ -329,6 +353,13 @@ ColorToning::~ColorToning() delete cl2CurveEditorG; } + +void ColorToning::setListener(ToolPanelListener *tpl) +{ + ToolPanel::setListener(tpl); + labgrid->setListener(tpl); +} + /* void ColorToning::neutralCurves_pressed () { disableListener(); @@ -400,6 +431,8 @@ void ColorToning::read (const ProcParams* pp, const ParamsEdited* pedited) clshape->setUnChanged (!pedited->colorToning.clcurve); cl2shape->setUnChanged (!pedited->colorToning.cl2curve); lumamode->set_inconsistent (!pedited->colorToning.lumamode); + + labgrid->setEdited(pedited->colorToning.labgridALow || pedited->colorToning.labgridBLow || pedited->colorToning.labgridAHigh || pedited->colorToning.labgridBHigh); } redlow->setValue (pp->colorToning.redlow); @@ -431,6 +464,8 @@ void ColorToning::read (const ProcParams* pp, const ParamsEdited* pedited) lastLumamode = pp->colorToning.lumamode; + labgrid->setParams(pp->colorToning.labgridALow, pp->colorToning.labgridBLow, pp->colorToning.labgridAHigh, pp->colorToning.labgridBHigh, false); + if (pedited && !pedited->colorToning.method) { method->set_active (5); } else if (pp->colorToning.method == "Lab") { @@ -443,6 +478,8 @@ void ColorToning::read (const ProcParams* pp, const ParamsEdited* pedited) method->set_active (3); } else if (pp->colorToning.method == "Splitlr") { method->set_active (4); + } else if (pp->colorToning.method == "LabGrid") { + method->set_active(5); } methodChanged(); @@ -495,6 +532,8 @@ void ColorToning::write (ProcParams* pp, ParamsEdited* pedited) pp->colorToning.saturatedOpacity = saturatedOpacity->getIntValue(); pp->colorToning.strength = strength->getIntValue(); + labgrid->getParams(pp->colorToning.labgridALow, pp->colorToning.labgridBLow, pp->colorToning.labgridAHigh, pp->colorToning.labgridBHigh); + if (pedited) { pedited->colorToning.redlow = redlow->getEditedState (); pedited->colorToning.greenlow = greenlow->getEditedState (); @@ -519,6 +558,8 @@ void ColorToning::write (ProcParams* pp, ParamsEdited* pedited) pedited->colorToning.hlColSat = hlColSat->getEditedState (); pedited->colorToning.shadowsColSat = shadowsColSat->getEditedState (); + + pedited->colorToning.labgridALow = pedited->colorToning.labgridBLow = pedited->colorToning.labgridAHigh = pedited->colorToning.labgridBHigh = labgrid->getEdited(); } if (method->get_active_row_number() == 0) { @@ -531,6 +572,8 @@ void ColorToning::write (ProcParams* pp, ParamsEdited* pedited) pp->colorToning.method = "Splitco"; } else if (method->get_active_row_number() == 4) { pp->colorToning.method = "Splitlr"; + } else if (method->get_active_row_number() == 5) { + pp->colorToning.method = "LabGrid"; } if (twocolor->get_active_row_number() == 0) { @@ -587,6 +630,7 @@ void ColorToning::setDefaults (const ProcParams* defParams, const ParamsEdited* hlColSat->setDefault (defParams->colorToning.hlColSat); shadowsColSat->setDefault (defParams->colorToning.shadowsColSat); strength->setDefault (defParams->colorToning.strength); + labgrid->setDefault(defParams->colorToning.labgridALow, defParams->colorToning.labgridBLow, defParams->colorToning.labgridAHigh, defParams->colorToning.labgridBHigh); if (pedited) { redlow->setDefaultEditedState (pedited->colorToning.redlow ? Edited : UnEdited); @@ -604,6 +648,7 @@ void ColorToning::setDefaults (const ProcParams* defParams, const ParamsEdited* hlColSat->setDefaultEditedState (pedited->colorToning.hlColSat ? Edited : UnEdited); shadowsColSat->setDefaultEditedState (pedited->colorToning.shadowsColSat ? Edited : UnEdited); strength->setDefaultEditedState (pedited->colorToning.strength ? Edited : UnEdited); + labgrid->setEdited((pedited->colorToning.labgridALow || pedited->colorToning.labgridBLow || pedited->colorToning.labgridAHigh || pedited->colorToning.labgridBHigh) ? Edited : UnEdited); } else { redlow->setDefaultEditedState (Irrelevant); greenlow->setDefaultEditedState (Irrelevant); @@ -620,6 +665,7 @@ void ColorToning::setDefaults (const ProcParams* defParams, const ParamsEdited* hlColSat->setDefaultEditedState (Irrelevant); shadowsColSat->setDefaultEditedState (Irrelevant); strength->setDefaultEditedState (Irrelevant); + labgrid->setEdited(Edited); } } @@ -782,6 +828,8 @@ void ColorToning::methodChanged () { if (!batchMode) { + labgridBox->hide(); + if (method->get_active_row_number() == 0) { // Lab colorSep->show(); colorCurveEditorG->show(); @@ -929,6 +977,26 @@ void ColorToning::methodChanged () chanMixerBox->hide(); neutrHBox->hide(); lumamode->show(); + } else if (method->get_active_row_number() == 5) { // Lab Grid + colorSep->hide(); + colorCurveEditorG->hide(); + twocolor->hide(); + opacityCurveEditorG->hide(); + clCurveEditorG->hide(); + cl2CurveEditorG->hide(); + hlColSat->hide(); + shadowsColSat->hide(); + balance->hide(); + p1Frame->hide(); + autosat->hide(); + satProtectionThreshold->hide(); + saturatedOpacity->hide(); + strength->hide(); + chanMixerBox->hide(); + neutrHBox->hide(); + lumamode->hide(); + + labgridBox->show(); } } diff --git a/rtgui/colortoning.h b/rtgui/colortoning.h index 347cfd126..588e6ee3b 100644 --- a/rtgui/colortoning.h +++ b/rtgui/colortoning.h @@ -12,6 +12,7 @@ #include "curveeditorgroup.h" #include "thresholdadjuster.h" #include "colorprovider.h" +#include "labgrid.h" class ColorToning final : public ToolParamBlock, @@ -49,6 +50,8 @@ public: void colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller* caller); + void setListener(ToolPanelListener *tpl); + private: //Gtk::HSeparator* satLimiterSep; Gtk::HSeparator* colorSep; @@ -101,6 +104,11 @@ private: bool lastLumamode; sigc::connection lumamodeConn; + rtengine::ProcEvent EvColorToningLabGridValue; + Gtk::Button *labgridReset; + LabGrid *labgrid; + Gtk::HBox *labgridBox; + IdleRegister idle_register; }; diff --git a/rtgui/labgrid.cc b/rtgui/labgrid.cc new file mode 100644 index 000000000..945073221 --- /dev/null +++ b/rtgui/labgrid.cc @@ -0,0 +1,328 @@ +/** -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2017 Alberto Griggio + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +// adapted from the "color correction" module of Darktable. Original copyright follows +/* + copyright (c) 2009--2010 johannes hanika. + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +*/ + +#include "labgrid.h" + +using rtengine::Color; + + +bool LabGrid::notifyListener() +{ + if (listener) { + listener->panelChanged(evt, Glib::ustring::compose(M("TP_COLORTONING_LABGRID_VALUES"), int(low_a), int(low_b), int(high_a), int(high_b))); + } + return false; +} + + +LabGrid::LabGrid(rtengine::ProcEvent evt): + Gtk::DrawingArea(), + evt(evt), litPoint(NONE), + low_a(0.f), high_a(0.f), low_b(0.f), high_b(0.f), + defaultLow_a(0.f), defaultHigh_a(0.f), defaultLow_b(0.f), defaultHigh_b(0.f), + listener(nullptr), + edited(false), + isDragged(false) +{ + set_can_focus(true); + add_events(Gdk::EXPOSURE_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK); +} + +void LabGrid::getParams(double &la, double &lb, double &ha, double &hb) const +{ + la = low_a; + ha = high_a; + lb = low_b; + hb = high_b; +} + + +void LabGrid::setParams(double la, double lb, double ha, double hb, bool notify) +{ + low_a = la; + low_b = lb; + high_a = ha; + high_b = hb; + queue_draw(); + if (notify) { + notifyListener(); + } +} + +void LabGrid::setDefault (double la, double lb, double ha, double hb) +{ + defaultLow_a = la; + defaultLow_b = lb; + defaultHigh_a = ha; + defaultHigh_b = hb; +} + + +void LabGrid::reset(bool toInitial) +{ + if (toInitial) { + setParams(defaultLow_a, defaultLow_b, defaultHigh_a, defaultHigh_b, true); + } else { + setParams(0., 0., 0., 0., true); + } +} + + +void LabGrid::setEdited(bool yes) +{ + edited = yes; +} + + +bool LabGrid::getEdited() const +{ + return edited; +} + + +void LabGrid::setListener(ToolPanelListener *l) +{ + listener = l; +} + + +void LabGrid::on_style_updated () +{ + setDirty(true); + queue_draw (); +} + + +bool LabGrid::on_draw(const ::Cairo::RefPtr &crf) +{ + Gtk::Allocation allocation = get_allocation(); + allocation.set_x(0); + allocation.set_y(0); + + // setDrawRectangle will allocate the backbuffer Surface + if (setDrawRectangle(Cairo::FORMAT_ARGB32, allocation)) { + setDirty(true); + } + + if (!isDirty() || !surfaceCreated()) { + return true; + } + + Glib::RefPtr style = get_style_context(); + Cairo::RefPtr cr = getContext(); + + if (isDirty()) { + int width = allocation.get_width(); + int height = allocation.get_height(); + + cr->set_line_cap(Cairo::LINE_CAP_SQUARE); + + // clear background + cr->set_source_rgba (0., 0., 0., 0.); + cr->set_operator (Cairo::OPERATOR_CLEAR); + cr->paint (); + cr->set_operator (Cairo::OPERATOR_OVER); + style->render_background(cr, 0, 0, width, height); + + // drawing the cells + cr->translate(inset, inset); + cr->set_antialias(Cairo::ANTIALIAS_NONE); + width -= 2 * inset; + height -= 2 * inset; + // flip y: + cr->translate(0, height); + cr->scale(1., -1.); + const int cells = 8; + float step = rtengine::ColorToningParams::LABGRID_CORR_MAX / float(cells/2); + for (int j = 0; j < cells; j++) { + for (int i = 0; i < cells; i++) { + float R, G, B; + float x, y, z; + int ii = i - cells/2; + int jj = j - cells/2; + float a = step * (ii + 0.5); + float b = step * (jj + 0.5); + Color::Lab2XYZ(25000.f, a, b, x, y, z); + Color::xyz2srgb(x, y, z, R, G, B); + cr->set_source_rgb(R / 65535.f, G / 65535.f, B / 65535.f); + cr->rectangle(width * i / float(cells), height * j / float(cells), width / float(cells) - 1, height / float(cells) - 1); + cr->fill(); + } + } + + // drawing the connection line + cr->set_antialias(Cairo::ANTIALIAS_DEFAULT); + float loa, hia, lob, hib; + loa = .5f * (width + width * low_a / rtengine::ColorToningParams::LABGRID_CORR_MAX); + hia = .5f * (width + width * high_a / rtengine::ColorToningParams::LABGRID_CORR_MAX); + lob = .5f * (height + height * low_b / rtengine::ColorToningParams::LABGRID_CORR_MAX); + hib = .5f * (height + height * high_b / rtengine::ColorToningParams::LABGRID_CORR_MAX); + cr->set_line_width(2.); + cr->set_source_rgb(0.6, 0.6, 0.6); + cr->move_to(loa, lob); + cr->line_to(hia, hib); + cr->stroke(); + + // drawing points + cr->set_source_rgb(0.1, 0.1, 0.1); + if (litPoint == LOW) { + cr->arc(loa, lob, 5, 0, 2. * rtengine::RT_PI); + } else { + cr->arc(loa, lob, 3, 0, 2. * rtengine::RT_PI); + } + cr->fill(); + + cr->set_source_rgb(0.9, 0.9, 0.9); + if (litPoint == HIGH) { + cr->arc(hia, hib, 5, 0, 2. * rtengine::RT_PI); + } else { + cr->arc(hia, hib, 3, 0, 2. * rtengine::RT_PI); + } + cr->fill(); + } + + copySurface(crf); + return false; +} + + +bool LabGrid::on_button_press_event(GdkEventButton *event) +{ + if (event->button == 1) { + if (event->type == GDK_2BUTTON_PRESS) { + switch (litPoint) { + case NONE: + low_a = low_b = high_a = high_b = 0.f; + break; + case LOW: + low_a = low_b = 0.f; + break; + case HIGH: + high_a = high_b = 0.f; + break; + } + edited = true; + notifyListener(); + queue_draw(); + } else if (event->type == GDK_BUTTON_PRESS && litPoint != NONE) { + isDragged = true; + } + return false; + } + return true; +} + + +bool LabGrid::on_button_release_event(GdkEventButton *event) +{ + if (event->button == 1) { + isDragged = false; + return false; + } + return true; +} + + +bool LabGrid::on_motion_notify_event(GdkEventMotion *event) +{ + if (isDragged && delayconn.connected()) { + delayconn.disconnect(); + } + + State oldLitPoint = litPoint; + + int width = get_allocated_width() - 2 * inset, height = get_allocated_height() - 2 * inset; + const float mouse_x = std::min(std::max(event->x - inset, 0.), double(width)); + const float mouse_y = std::min(std::max(height - 1 - event->y + inset, 0.), double(height)); + const float ma = (2.0 * mouse_x - width) / (float)width; + const float mb = (2.0 * mouse_y - height) / (float)height; + if (isDragged) { + if (litPoint == LOW) { + low_a = ma * rtengine::ColorToningParams::LABGRID_CORR_MAX; + low_b = mb * rtengine::ColorToningParams::LABGRID_CORR_MAX; + } else if (litPoint == HIGH) { + high_a = ma * rtengine::ColorToningParams::LABGRID_CORR_MAX; + high_b = mb * rtengine::ColorToningParams::LABGRID_CORR_MAX; + } + edited = true; + grab_focus(); + if (options.adjusterMinDelay == 0) { + notifyListener(); + } else { + delayconn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &LabGrid::notifyListener), options.adjusterMinDelay); + } + queue_draw(); + } else { + litPoint = NONE; + float la = low_a / rtengine::ColorToningParams::LABGRID_CORR_MAX; + float lb = low_b / rtengine::ColorToningParams::LABGRID_CORR_MAX; + float ha = high_a / rtengine::ColorToningParams::LABGRID_CORR_MAX; + float hb = high_b / rtengine::ColorToningParams::LABGRID_CORR_MAX; + const float thrs = 0.05f; + const float distlo = (la - ma) * (la - ma) + (lb - mb) * (lb - mb); + const float disthi = (ha - ma) * (ha - ma) + (hb - mb) * (hb - mb); + if (distlo < thrs * thrs && distlo < disthi) { + litPoint = LOW; + } else if (disthi < thrs * thrs && disthi <= distlo) { + litPoint = HIGH; + } + if ((oldLitPoint == NONE && litPoint != NONE) || (oldLitPoint != NONE && litPoint == NONE)) { + queue_draw(); + } + } + return true; +} + + +Gtk::SizeRequestMode LabGrid::get_request_mode_vfunc() const +{ + return Gtk::SIZE_REQUEST_HEIGHT_FOR_WIDTH; +} + + +void LabGrid::get_preferred_width_vfunc(int &minimum_width, int &natural_width) const +{ + minimum_width = 50; + natural_width = 150; // same as GRAPH_SIZE from mycurve.h +} + + +void LabGrid::get_preferred_height_for_width_vfunc(int width, int &minimum_height, int &natural_height) const +{ + minimum_height = natural_height = width; +} diff --git a/rtgui/labgrid.h b/rtgui/labgrid.h new file mode 100644 index 000000000..348ab2398 --- /dev/null +++ b/rtgui/labgrid.h @@ -0,0 +1,90 @@ +/** -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2017 Alberto Griggio + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +// adapted from the "color correction" module of Darktable. Original copyright follows +/* + copyright (c) 2009--2010 johannes hanika. + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +*/ + +#pragma once + +#include +#include "eventmapper.h" +#include "toolpanel.h" + + +class LabGrid: public Gtk::DrawingArea, public BackBuffer { +private: + rtengine::ProcEvent evt; + enum State { NONE, HIGH, LOW }; + State litPoint; + float low_a; + float high_a; + float low_b; + float high_b; + + float defaultLow_a; + float defaultHigh_a; + float defaultLow_b; + float defaultHigh_b; + + ToolPanelListener *listener; + bool edited; + bool isDragged; + sigc::connection delayconn; + static const int inset = 2; + + bool notifyListener(); + void getLitPoint(); + +public: + LabGrid(rtengine::ProcEvent evt); + + void getParams(double &la, double &lb, double &ha, double &hb) const; + void setParams(double la, double lb, double ha, double hb, bool notify); + void setDefault (double la, double lb, double ha, double hb); + void setEdited(bool yes); + bool getEdited() const; + void reset(bool toInitial); + void setListener(ToolPanelListener *l); + + bool on_draw(const ::Cairo::RefPtr &crf); + void on_style_updated (); + bool on_button_press_event(GdkEventButton *event); + bool on_button_release_event(GdkEventButton *event); + bool on_motion_notify_event(GdkEventMotion *event); + Gtk::SizeRequestMode get_request_mode_vfunc() const; + void get_preferred_width_vfunc(int &minimum_width, int &natural_width) const; + void get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const; +}; + diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 0c5156555..c0be121a1 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -134,6 +134,10 @@ void ParamsEdited::set(bool v) colorToning.greenhigh = v; colorToning.bluehigh = v; colorToning.lumamode = v; + colorToning.labgridALow = v; + colorToning.labgridBLow = v; + colorToning.labgridAHigh = v; + colorToning.labgridBHigh = v; sharpening.enabled = v; sharpening.radius = v; @@ -803,6 +807,10 @@ void ParamsEdited::initFrom(const std::vector& colorToning.greenhigh = colorToning.greenhigh && p.colorToning.greenhigh == other.colorToning.greenhigh; colorToning.bluehigh = colorToning.bluehigh && p.colorToning.bluehigh == other.colorToning.bluehigh; colorToning.lumamode = colorToning.lumamode && p.colorToning.lumamode == other.colorToning.lumamode; + colorToning.labgridALow = colorToning.labgridALow && p.colorToning.labgridALow == other.colorToning.labgridALow; + colorToning.labgridBLow = colorToning.labgridBLow && p.colorToning.labgridBLow == other.colorToning.labgridBLow; + colorToning.labgridAHigh = colorToning.labgridAHigh && p.colorToning.labgridAHigh == other.colorToning.labgridAHigh; + colorToning.labgridBHigh = colorToning.labgridBHigh && p.colorToning.labgridBHigh == other.colorToning.labgridBHigh; sharpenEdge.enabled = sharpenEdge.enabled && p.sharpenEdge.enabled == other.sharpenEdge.enabled; sharpenEdge.passes = sharpenEdge.passes && p.sharpenEdge.passes == other.sharpenEdge.passes; sharpenEdge.amount = sharpenEdge.amount && p.sharpenEdge.amount == other.sharpenEdge.amount; @@ -1767,6 +1775,19 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.colorToning.bluehigh = dontforceSet && options.baBehav[ADDSET_COLORTONING_SPLIT] ? toEdit.colorToning.bluehigh + mods.colorToning.bluehigh : mods.colorToning.bluehigh; } + if (colorToning.labgridALow) { + toEdit.colorToning.labgridALow = mods.colorToning.labgridALow; + } + if (colorToning.labgridBLow) { + toEdit.colorToning.labgridBLow = mods.colorToning.labgridBLow; + } + if (colorToning.labgridAHigh) { + toEdit.colorToning.labgridAHigh = mods.colorToning.labgridAHigh; + } + if (colorToning.labgridBHigh) { + toEdit.colorToning.labgridBHigh = mods.colorToning.labgridBHigh; + } + if (sharpenEdge.enabled) { toEdit.sharpenEdge.enabled = mods.sharpenEdge.enabled; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index fae60db62..07f90a90e 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -171,6 +171,10 @@ public: bool satlow; bool sathigh; bool lumamode; + bool labgridALow; + bool labgridBLow; + bool labgridAHigh; + bool labgridBHigh; }; class SharpenEdgeParamsEdited diff --git a/tools/build-rawtherapee b/tools/build-rawtherapee index 8c86ed54d..5c13df061 100755 --- a/tools/build-rawtherapee +++ b/tools/build-rawtherapee @@ -1,6 +1,6 @@ #!/usr/bin/env bash # By Morgan Hardwood -# Version 2017-12-25 +# Version 2018-01-06 # This script gets the latest source code for the given program and compiles it. # The name of the program, used for the folder names: @@ -22,11 +22,14 @@ exe="${prog}" exeRelativePath="" # The path to the repository: -repo="git@github.com:Beep6581/RawTherapee.git" +repo="https://github.com/Beep6581/RawTherapee.git" # No touching below this line, with the exception of the "Compile" section # ----------------------------------------------------------------------------- +# The name of the project's standard branch, typically "master": +master="dev" + buildOnly="false" buildType="release" @@ -35,8 +38,6 @@ exeRelativePath="${exeRelativePath/%\/}" # Append forward-slash to exeRelativePath only if it is not empty. exePath="${exeRelativePath:+${exeRelativePath}/}${exe}" -printf '%s\n' "" "Program name: ${prog}" "Build type: ${buildType}" "Build without updating: ${buildOnly}" "" - # Command-line arguments OPTIND=1 while getopts "bdh?-" opt; do @@ -59,16 +60,18 @@ done shift $((OPTIND-1)) [ "$1" = "--" ] && shift +printf '%s\n' "" "Program name: ${prog}" "Build type: ${buildType}" "Build without updating: ${buildOnly}" "" + # Clone if needed cloned="false" updates="false" if [[ ! -d "$HOME/programs/code-${prog}" ]]; then mkdir -p "$HOME/programs" || exit 1 git clone "$repo" "$HOME/programs/code-${prog}" || exit 1 - pushd "$HOME/programs/code-${prog}" || exit 1 + pushd "$HOME/programs/code-${prog}" 1>/dev/null || exit 1 cloned="true" else - pushd "$HOME/programs/code-${prog}" || exit 1 + pushd "$HOME/programs/code-${prog}" 1>/dev/null || exit 1 git fetch if [[ $(git rev-parse HEAD) != $(git rev-parse '@{u}') ]]; then updates="true" @@ -80,8 +83,20 @@ if [[ "$updates" = "true" && "$buildOnly" = "false" ]]; then git pull || exit 1 fi +# Find out which branch git is on +branch="$(git rev-parse --abbrev-ref HEAD)" + +# Set build and install folder names +if [[ $branch = $master && $buildType = release ]]; then + buildDir="$HOME/programs/code-${prog}/build" + installDir="$HOME/programs/${prog}" +else + buildDir="$HOME/programs/code-${prog}/build-${branch}-${buildType}" + installDir="$HOME/programs/${prog}-${branch}-${buildType}" +fi + existsExe="false" -if [[ -e "$HOME/programs/${prog}/${exePath}" ]]; then +if [[ -e "${installDir}/${exePath}" ]]; then existsExe="true" fi @@ -101,9 +116,9 @@ if [[ ! ( $cpuCount -ge 1 && $cpuCount -le 64 ) ]]; then fi # Prepare folders -rm -rf "$HOME/programs/${prog}" "$HOME/programs/code-${prog}/build" -mkdir -p "$HOME/programs/${prog}" "$HOME/programs/code-${prog}/build" || exit 1 -cd "$HOME/programs/code-${prog}/build" || exit 1 +rm -rf "${installDir}" +mkdir -p "${buildDir}" "${installDir}" || exit 1 +cd "${buildDir}" || exit 1 # ----------------------------------------------------------------------------- # Compile @@ -116,7 +131,7 @@ cmake \ -DCACHE_NAME_SUFFIX="5-dev" \ -DPROC_TARGET_NUMBER="2" \ -DBUILD_BUNDLE="ON" \ - -DBUNDLE_BASE_INSTALL_DIR="$HOME/programs/${prog}" \ + -DBUNDLE_BASE_INSTALL_DIR="${installDir}" \ -DOPTION_OMP="ON" \ -DWITH_LTO="OFF" \ -DWITH_PROF="OFF" \ @@ -127,6 +142,6 @@ cmake \ make --jobs="$cpuCount" install || exit 1 # Finished -printf '%s\n' "" "To run ${prog} type:" "~/programs/${prog}/${exePath}" "" +printf '%s\n' "" "To run ${prog} type:" "${installDir}/${exePath}" "" popd 1>/dev/null