diff --git a/rtdata/languages/Deutsch b/rtdata/languages/Deutsch index 5ce927c7e..e78d51da5 100644 --- a/rtdata/languages/Deutsch +++ b/rtdata/languages/Deutsch @@ -231,7 +231,7 @@ HISTORY_MSG_7;Schwarz HISTORY_MSG_8;Belichtungskorrektur HISTORY_MSG_9;Lichter-Kompression HISTORY_MSG_10;Schatten-Kompression -HISTORY_MSG_11;Tonwertkurve +HISTORY_MSG_11;Tonwertkurve 1 HISTORY_MSG_12;Automatische Belichtung HISTORY_MSG_13;Belichtungsbeschneidung HISTORY_MSG_14;Luminanz Helligkeit @@ -261,9 +261,9 @@ HISTORY_MSG_37;Farbverstärkung HISTORY_MSG_38;Weißabgleich Methode HISTORY_MSG_39;Weißabgleich Farbtemp. HISTORY_MSG_40;Weißabgleich Farbton -HISTORY_MSG_41;Tonewertkurve Modus -HISTORY_MSG_42;Farbkorrektur "B" -HISTORY_MSG_43;Luminanz-Rauschfilter +HISTORY_MSG_41;Tonewertkurve Modus 1 +HISTORY_MSG_42;Tonwertkurve 2 +HISTORY_MSG_43;Tonewertkurve Modus 2 HISTORY_MSG_44;Luminanz-Rauschfilter Radius HISTORY_MSG_45;Luminanz-Rauschfilter Kantentoleranz HISTORY_MSG_46;Farb-Rauschfilter @@ -897,14 +897,17 @@ TP_EXPOSURE_COMPRHIGHLIGHTSTHRESHOLD;Lichter wiederherstellen\nSchwellenwert TP_EXPOSURE_COMPRHIGHLIGHTS;Lichter wiederherstellen\nStärke TP_EXPOSURE_COMPRSHADOWS;Schatten wiederherstellen TP_EXPOSURE_CONTRAST;Kontrast -TP_EXPOSURE_CURVEEDITOR;Tonwertkurve +TP_EXPOSURE_CURVEEDITOR1;Tonwertkurve 1 +TP_EXPOSURE_CURVEEDITOR2;Tonwertkurve 2 TP_EXPOSURE_EXPCOMP;Belichtungskorrektur TP_EXPOSURE_LABEL;Belichtung TP_EXPOSURE_SATURATION;Sättigung TP_EXPOSURE_TCMODE_FILMLIKE;Film-ähnliche -TP_EXPOSURE_TCMODE_LABEL;Tonewertkurve Modus +TP_EXPOSURE_TCMODE_LABEL1;Tonewertkurve Modus 1 +TP_EXPOSURE_TCMODE_LABEL2;Tonewertkurve Modus 2 +TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Weighted Standard TP_EXPOSURE_TCMODE_STANDARD;Standard -TP_EXPOSURE_TCMODE_VALBLENDING;Hellwert-Kanal +TP_EXPOSURE_TCMODE_SATANDVALBLENDING;Saturation and Value Blending TP_EXPO_AFTER;Nach Interpolation (vor RGB-Konvertierung) TP_FLATFIELD_AUTOSELECT;Automatische Auswahl TP_FLATFIELD_BLURRADIUS;Unschärferadius diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 8aa4773db..2aeb2d8f5 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -233,7 +233,7 @@ HISTORY_MSG_7;Noir HISTORY_MSG_8;Compensation d'exposition HISTORY_MSG_9;Compression des hautes lumières HISTORY_MSG_10;Compression des ombres -HISTORY_MSG_11;Courbe tonale +HISTORY_MSG_11;Courbe tonale 1 HISTORY_MSG_12;Exposition auto HISTORY_MSG_13;Rognage de l'exposition HISTORY_MSG_14;Luminance - Luminosité @@ -263,9 +263,9 @@ HISTORY_MSG_37;Exposition auto HISTORY_MSG_38;Méthode de balance des blancs HISTORY_MSG_39;Température de couleur HISTORY_MSG_40;Teinte de balance des blancs -HISTORY_MSG_41;Mode courbe tonale -HISTORY_MSG_42;Décalage couleur "B" -HISTORY_MSG_43;Débruitage de la Luminance +HISTORY_MSG_41;Mode courbe tonale 1 +HISTORY_MSG_42;Courbe tonale2 +HISTORY_MSG_43;Mode courbe tonale 2 HISTORY_MSG_44;Débruitage Lum. - Rayon HISTORY_MSG_45;Débruitage Lum. - Tolérance des bords HISTORY_MSG_46;Débruitage Chromatique @@ -928,14 +928,18 @@ TP_EXPOSURE_COMPRHIGHLIGHTSTHRESHOLD;Seuil de compression\ndes hautes lumières TP_EXPOSURE_COMPRHIGHLIGHTS;Compression hautes lumières TP_EXPOSURE_COMPRSHADOWS;Compression des ombres TP_EXPOSURE_CONTRAST;Contraste -TP_EXPOSURE_CURVEEDITOR;Courbe tonale +TP_EXPOSURE_CURVEEDITOR1;Courbe Tonale 1 +TP_EXPOSURE_CURVEEDITOR2;Courbe Tonale 2 +TP_EXPOSURE_CURVEEDITOR2_TOOLTIP;Référez-vous à la section suivante du manuel pour en savoir plus sur les manières d'obtenir les meilleurs résultats avec l'option de double courbe:\nThe Toolbox > Exposure Tab > Exposure Panel > Tone Curve TP_EXPOSURE_EXPCOMP;Compensation d'exposition TP_EXPOSURE_LABEL;Exposition TP_EXPOSURE_SATURATION;Saturation TP_EXPOSURE_TCMODE_FILMLIKE;Similaire Film -TP_EXPOSURE_TCMODE_LABEL;Mode +TP_EXPOSURE_TCMODE_LABEL1;Mode courbe 1 +TP_EXPOSURE_TCMODE_LABEL2;Mode courbe 2 +TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Standard Pondéré TP_EXPOSURE_TCMODE_STANDARD;Standard -TP_EXPOSURE_TCMODE_VALBLENDING;Canal Valeur +TP_EXPOSURE_TCMODE_SATANDVALBLENDING;Mixage Saturation et Valeur TP_EXPO_AFTER; Après l'interpolation (avant la conversion RVB) TP_FLATFIELD_AUTOSELECT;Sélection automatique TP_FLATFIELD_BLURRADIUS;Rayon de floutage diff --git a/rtdata/languages/default b/rtdata/languages/default index 390617b4c..75a7e5e31 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -233,7 +233,7 @@ HISTORY_MSG_7;Black HISTORY_MSG_8;Exposure Compensation HISTORY_MSG_9;Highlight Compression HISTORY_MSG_10;Shadow Compression -HISTORY_MSG_11;Tone Curve +HISTORY_MSG_11;Tone Curve 1 HISTORY_MSG_12;Auto Exposure HISTORY_MSG_13;Exposure Clipping HISTORY_MSG_14;Luminance Brightness @@ -263,9 +263,9 @@ HISTORY_MSG_37;Auto Exposure HISTORY_MSG_38;White Balance Method HISTORY_MSG_39;Color Temperature HISTORY_MSG_40;White Balance Tint -HISTORY_MSG_41;Tone Curve Mode -HISTORY_MSG_42;Color Shift "B" -HISTORY_MSG_43;Luminance Denoising +HISTORY_MSG_41;Tone Curve Mode 1 +HISTORY_MSG_42;Tone Curve 2 +HISTORY_MSG_43;Tone Curve Mode 2 HISTORY_MSG_44;Lum. Denoising Radius HISTORY_MSG_45;Lum. Denoising Edge Tolerance HISTORY_MSG_46;Color Denoising @@ -923,14 +923,18 @@ TP_EXPOSURE_COMPRHIGHLIGHTSTHRESHOLD;Highlight recovery threshold TP_EXPOSURE_COMPRHIGHLIGHTS;Highlight recovery amount TP_EXPOSURE_COMPRSHADOWS;Shadow recovery TP_EXPOSURE_CONTRAST;Contrast -TP_EXPOSURE_CURVEEDITOR;Tone Curve +TP_EXPOSURE_CURVEEDITOR1;Tone Curve 1 +TP_EXPOSURE_CURVEEDITOR2;Tone Curve 2 +TP_EXPOSURE_CURVEEDITOR2_TOOLTIP;Please refer to the following section of the manual to learn more on how to achieve the best results with the double curve option:\nThe Toolbox > Exposure Tab > Exposure Panel > Tone Curve TP_EXPOSURE_EXPCOMP;Exposure Compensation TP_EXPOSURE_LABEL;Exposure TP_EXPOSURE_SATURATION;Saturation TP_EXPOSURE_TCMODE_FILMLIKE;Film-like -TP_EXPOSURE_TCMODE_LABEL;Curve mode +TP_EXPOSURE_TCMODE_LABEL1;Curve mode 1 +TP_EXPOSURE_TCMODE_LABEL2;Curve mode 2 +TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Weighted Standard TP_EXPOSURE_TCMODE_STANDARD;Standard -TP_EXPOSURE_TCMODE_VALBLENDING;Value channel +TP_EXPOSURE_TCMODE_SATANDVALBLENDING;Saturation and Value Blending TP_EXPO_AFTER; After interpolation (before RGB conversion) TP_FLATFIELD_AUTOSELECT;Auto selection TP_FLATFIELD_BLURRADIUS;Blur Radius diff --git a/rtdata/profiles/BW-1.pp3 b/rtdata/profiles/BW-1.pp3 index 2cbe7629a..53cf95043 100644 --- a/rtdata/profiles/BW-1.pp3 +++ b/rtdata/profiles/BW-1.pp3 @@ -1,7 +1,7 @@ [Version] AppVersion=4.0.9 -Version=304 +Version=305 [General] Rank=0 @@ -21,6 +21,8 @@ HighlightComprThreshold=33 ShadowCompr=50 CurveMode=Standard Curve=1;0;0;0.04;0.03;0.17684498029510265;0.21732319394192093;0.70232558139534862;0.74883720930232545;1;1; +CurveMode2=Standard +Curve2=0; [Channel Mixer] Red=100;0;0; diff --git a/rtdata/profiles/BW-2.pp3 b/rtdata/profiles/BW-2.pp3 index 1c6b8bc65..b3504fe4a 100644 --- a/rtdata/profiles/BW-2.pp3 +++ b/rtdata/profiles/BW-2.pp3 @@ -1,7 +1,7 @@ [Version] AppVersion=4.0.9 -Version=304 +Version=305 [General] Rank=0 @@ -21,6 +21,8 @@ HighlightComprThreshold=33 ShadowCompr=50 CurveMode=Standard Curve=1;0;0;0.45754265471370759;0.57906737998843294;1;1; +CurveMode2=Standard +Curve2=0; [Channel Mixer] Red=100;0;0; diff --git a/rtdata/profiles/BW-3.pp3 b/rtdata/profiles/BW-3.pp3 index d531f7e49..163e6d558 100644 --- a/rtdata/profiles/BW-3.pp3 +++ b/rtdata/profiles/BW-3.pp3 @@ -1,7 +1,7 @@ [Version] AppVersion=4.0.9 -Version=304 +Version=305 [General] Rank=0 @@ -21,6 +21,8 @@ HighlightComprThreshold=33 ShadowCompr=50 CurveMode=Standard Curve=0; +CurveMode2=Standard +Curve2=0; [Channel Mixer] Red=100;0;0; diff --git a/rtdata/profiles/BW-4.pp3 b/rtdata/profiles/BW-4.pp3 index fe91696e7..03b394eb3 100644 --- a/rtdata/profiles/BW-4.pp3 +++ b/rtdata/profiles/BW-4.pp3 @@ -1,7 +1,7 @@ [Version] AppVersion=4.0.9 -Version=304 +Version=305 [General] Rank=0 @@ -21,6 +21,8 @@ HighlightComprThreshold=33 ShadowCompr=50 CurveMode=Standard Curve=0; +CurveMode2=Standard +Curve2=0; [Channel Mixer] Red=100;0;0; diff --git a/rtdata/profiles/Default-ISO-High.pp3 b/rtdata/profiles/Default-ISO-High.pp3 index 399b1566a..4d839002c 100644 --- a/rtdata/profiles/Default-ISO-High.pp3 +++ b/rtdata/profiles/Default-ISO-High.pp3 @@ -1,7 +1,7 @@ [Version] AppVersion=4.0.9 -Version=304 +Version=305 [General] Rank=0 @@ -21,6 +21,8 @@ HighlightComprThreshold=33 ShadowCompr=50 CurveMode=Standard Curve=0; +CurveMode2=Standard +Curve2=0; [Channel Mixer] Red=100;0;0; diff --git a/rtdata/profiles/Default-ISO-Medium.pp3 b/rtdata/profiles/Default-ISO-Medium.pp3 index 7d0474b37..56d4d9a57 100644 --- a/rtdata/profiles/Default-ISO-Medium.pp3 +++ b/rtdata/profiles/Default-ISO-Medium.pp3 @@ -1,7 +1,7 @@ [Version] AppVersion=4.0.9 -Version=304 +Version=305 [General] Rank=0 @@ -21,6 +21,8 @@ HighlightComprThreshold=33 ShadowCompr=50 CurveMode=Standard Curve=0; +CurveMode2=Standard +Curve2=0; [Channel Mixer] Red=100;0;0; diff --git a/rtdata/profiles/Default.pp3 b/rtdata/profiles/Default.pp3 index c29e3256b..84a29cb06 100644 --- a/rtdata/profiles/Default.pp3 +++ b/rtdata/profiles/Default.pp3 @@ -1,7 +1,7 @@ [Version] AppVersion=4.0.9 -Version=304 +Version=305 [General] Rank=0 @@ -21,6 +21,8 @@ HighlightComprThreshold=33 ShadowCompr=50 CurveMode=Standard Curve=0; +CurveMode2=Standard +Curve2=0; [Channel Mixer] Red=100;0;0; diff --git a/rtdata/profiles/Highkey-1.pp3 b/rtdata/profiles/Highkey-1.pp3 index d6b9ac28b..d90907f28 100644 --- a/rtdata/profiles/Highkey-1.pp3 +++ b/rtdata/profiles/Highkey-1.pp3 @@ -1,7 +1,7 @@ [Version] AppVersion=4.0.9 -Version=304 +Version=305 [General] Rank=0 @@ -21,6 +21,8 @@ HighlightComprThreshold=33 ShadowCompr=50 CurveMode=Standard Curve=2;0.105;0.25;0.75;15;60;30;-70; +CurveMode2=Standard +Curve2=0; [Channel Mixer] Red=100;0;0; diff --git a/rtdata/profiles/Natural-1.pp3 b/rtdata/profiles/Natural-1.pp3 index 153f5a6b3..27a1b37db 100644 --- a/rtdata/profiles/Natural-1.pp3 +++ b/rtdata/profiles/Natural-1.pp3 @@ -1,7 +1,7 @@ [Version] AppVersion=4.0.9 -Version=304 +Version=305 [General] Rank=0 @@ -21,6 +21,8 @@ HighlightComprThreshold=33 ShadowCompr=50 CurveMode=Standard Curve=1;0;0;0.04;0.03;0.17684498029510265;0.21732319394192093;0.70232558139534862;0.74883720930232545;1;1; +CurveMode2=Standard +Curve2=0; [Channel Mixer] Red=100;0;0; diff --git a/rtdata/profiles/Natural-2.pp3 b/rtdata/profiles/Natural-2.pp3 index 1f65f5f67..6e14e5f9b 100644 --- a/rtdata/profiles/Natural-2.pp3 +++ b/rtdata/profiles/Natural-2.pp3 @@ -1,7 +1,7 @@ [Version] AppVersion=4.0.9 -Version=304 +Version=305 [General] Rank=0 @@ -21,6 +21,8 @@ HighlightComprThreshold=33 ShadowCompr=50 CurveMode=Standard Curve=1;0;0;0.45754265471370759;0.57906737998843294;1;1; +CurveMode2=Standard +Curve2=0; [Channel Mixer] Red=100;0;0; diff --git a/rtdata/profiles/Neutral.pp3 b/rtdata/profiles/Neutral.pp3 index 758ca88a1..bf41369b5 100644 --- a/rtdata/profiles/Neutral.pp3 +++ b/rtdata/profiles/Neutral.pp3 @@ -1,7 +1,7 @@ [Version] AppVersion=4.0.9 -Version=304 +Version=305 [General] Rank=0 @@ -21,6 +21,8 @@ HighlightComprThreshold=0 ShadowCompr=50 CurveMode=Standard Curve=0; +CurveMode2=Standard +Curve2=0; [Channel Mixer] Red=100;0;0; diff --git a/rtdata/profiles/Punchy-1.pp3 b/rtdata/profiles/Punchy-1.pp3 index 5c4b9c235..2c52362ba 100644 --- a/rtdata/profiles/Punchy-1.pp3 +++ b/rtdata/profiles/Punchy-1.pp3 @@ -1,7 +1,7 @@ [Version] AppVersion=4.0.9 -Version=304 +Version=305 [General] Rank=0 @@ -21,6 +21,8 @@ HighlightComprThreshold=33 ShadowCompr=50 CurveMode=Standard Curve=0; +CurveMode2=Standard +Curve2=0; [Channel Mixer] Red=120;-10;-10; diff --git a/rtdata/profiles/Punchy-2.pp3 b/rtdata/profiles/Punchy-2.pp3 index c1eb8c263..ea7a18b9e 100644 --- a/rtdata/profiles/Punchy-2.pp3 +++ b/rtdata/profiles/Punchy-2.pp3 @@ -1,7 +1,7 @@ [Version] AppVersion=4.0.9 -Version=304 +Version=305 [General] Rank=0 @@ -21,6 +21,8 @@ HighlightComprThreshold=33 ShadowCompr=50 CurveMode=Standard Curve=0; +CurveMode2=Standard +Curve2=0; [Channel Mixer] Red=100;0;0; diff --git a/rtengine/LUT.h b/rtengine/LUT.h index ab938c968..09cdc856b 100644 --- a/rtengine/LUT.h +++ b/rtengine/LUT.h @@ -95,7 +95,8 @@ public: maxs=size-2; } - LUT(int s, T * source) { + LUT(int s, T * source, int flags = 0xfffffff) { + clip = flags; data = new T[s]; owner = 1; size = s; diff --git a/rtengine/curves.cc b/rtengine/curves.cc index faaa3cc0c..4c42146c5 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -41,7 +41,7 @@ namespace rtengine { x = 0; y = 0; ypp = 0; - hashSize = 1000; // has to be initiallised to the maximum value + hashSize = 1000; // has to be initialized to the maximum value } void Curve::AddPolygons () @@ -293,10 +293,15 @@ namespace rtengine { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, double hlcomprthresh, - double shcompr, double br, double contr, double gamma_, bool igamma_, int curveMode, - const std::vector& curvePoints, LUTu & histogram, LUTu & histogramCropped, + double shcompr, double br, double contr, double gamma_, bool igamma_, + ToneCurveParams::eTCModeId curveMode, const std::vector& curvePoints, + ToneCurveParams::eTCModeId curveMode2, const std::vector& curvePoints2, + LUTu & histogram, LUTu & histogramCropped, LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, - LUTu & outBeforeCCurveHistogram, NonStandardToneCurve & outNSToneCurve, int skip) { + LUTu & outBeforeCCurveHistogram, + ToneCurve & customToneCurve1, + ToneCurve & customToneCurve2, + int skip) { //double def_mul = pow (2.0, defmul); @@ -324,7 +329,7 @@ namespace rtengine { LUTf dcurve(0x10000); // check if inverse gamma is needed at the end - bool needigamma = igamma_ && gamma_>0; + bool needigamma = igamma_ && gamma_>1.; // clear array that stores histogram valid before applying the custom curve outBeforeCCurveHistogram.clear(); @@ -405,7 +410,7 @@ namespace rtengine { val = (double)i / 65535.0; // gamma correction - if (gamma_>1) + if (gamma_>1.) val = gamma (val, gamma_, start, slope, mul, add); // apply brightness curve @@ -470,11 +475,32 @@ namespace rtengine { } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - // create a curve if needed + + // create second curve if needed bool histNeeded = false; DiagonalCurve* tcurve = NULL; - outNSToneCurve.Reset(); + customToneCurve2.Reset(); + + if (!curvePoints2.empty() && curvePoints2[0]>DCT_Linear && curvePoints2[0]isIdentity()) { + delete tcurve; + tcurve = NULL; + } + else + customToneCurve2.Set(tcurve); + delete tcurve; + tcurve = NULL; + } + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + // create first curve if needed + customToneCurve1.Reset(); if (!curvePoints.empty() && curvePoints[0]>DCT_Linear && curvePoints[0]getVal ((float)i/65536.0f); outCurve[i] = (65536.0f * val); } - } - else { - // Skip the slow getval method if no curve is used (or an identity curve) - for (int i=0; i<65536; i++) { - outCurve[i] = i; - } - } - - if (tcurve) delete tcurve; + } + // let the LUTf empty for identity curves + else { + outCurve.reset(); + } } @@ -746,14 +771,14 @@ namespace rtengine { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void NonStandardToneCurve::Reset() { +void ToneCurve::Reset() { lutToneCurve.reset(); } // Fill a LUT with X/Y, ranged 0xffff -void NonStandardToneCurve::Set(Curve *pCurve) { - lutToneCurve(0xffff); - for (int i=0;i<0xffff;i++) lutToneCurve[i] = pCurve->getVal(i/(double)0xffff) * 0xffff; +void ToneCurve::Set(Curve *pCurve) { + lutToneCurve(65536); + for (int i=0;i<65536;i++) lutToneCurve[i] = pCurve->getVal(i/(double)65535) * 65535; } } diff --git a/rtengine/curves.h b/rtengine/curves.h index 316d6d514..44e9eb4ee 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -39,7 +39,7 @@ using namespace std; namespace rtengine { - class NonStandardToneCurve; + class ToneCurve; class CurveFactory { @@ -178,8 +178,8 @@ class CurveFactory { public: static void complexCurve (double ecomp, double black, double hlcompr, double hlcomprthresh, double shcompr, double br, double contr, - double gamma_, bool igamma_, int curveMode, const std::vector& curvePoints, LUTu & histogram, LUTu & histogramCropped, - LUTf & hlCurve, LUTf & shCurve,LUTf & outCurve, LUTu & outBeforeCCurveHistogram, NonStandardToneCurve & outNSToneCurve, int skip=1); + double gamma_, bool igamma_, ToneCurveParams::eTCModeId curveMode, const std::vector& curvePoints, ToneCurveParams::eTCModeId curveMode2, const std::vector& curvePoints2, LUTu & histogram, LUTu & histogramCropped, + LUTf & hlCurve, LUTf & shCurve,LUTf & outCurve, LUTu & outBeforeCCurveHistogram, ToneCurve & outToneCurve, ToneCurve & outToneCurve2, int skip=1); static void complexsgnCurve ( 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& cclurvePoints, LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, LUTf & lhskCurve, int skip=1); static void complexLCurve (double br, double contr, const std::vector& curvePoints, LUTu & histogram, LUTu & histogramCropped, @@ -272,18 +272,23 @@ class FlatCurve : public Curve { bool isIdentity () const { return kind==FCT_Empty; }; }; -class NonStandardToneCurve { +class ToneCurve { public: LUTf lutToneCurve; // 0xffff range - virtual ~NonStandardToneCurve() {}; + virtual ~ToneCurve() {}; void Reset(); void Set(Curve *pCurve); operator bool (void) const { return lutToneCurve; } }; -class AdobeToneCurve : public NonStandardToneCurve { +class StandardToneCurve : public ToneCurve { + public: + void Apply(float& r, float& g, float& b) const; +}; + +class AdobeToneCurve : public ToneCurve { private: void RGBTone(float& r, float& g, float& b) const; // helper for tone curve @@ -291,7 +296,12 @@ class AdobeToneCurve : public NonStandardToneCurve { void Apply(float& r, float& g, float& b) const; }; -class ValueBlendingToneCurve : public NonStandardToneCurve { +class SatAndValueBlendingToneCurve : public ToneCurve { + public: + void Apply(float& r, float& g, float& b) const; +}; + +class WeightedStdToneCurve : public ToneCurve { private: float Triangle(float refX, float refY, float X2) const; public: @@ -299,6 +309,16 @@ class ValueBlendingToneCurve : public NonStandardToneCurve { }; +// Standard tone curve +inline void StandardToneCurve::Apply (float& r, float& g, float& b) const { + + assert (lutToneCurve); + + r = lutToneCurve[r]; + g = lutToneCurve[g]; + b = lutToneCurve[b]; +} + // Tone curve according to Adobe's reference implementation // values in 0xffff space // inlined to make sure there will be no cache flush when used @@ -332,13 +352,12 @@ inline void AdobeToneCurve::RGBTone (float& r, float& g, float& b) const { g = b + ((r - b) * (gold - bold) / (rold - bold)); } - -inline float ValueBlendingToneCurve::Triangle(float a, float a1, float b) const { +inline float WeightedStdToneCurve::Triangle(float a, float a1, float b) const { if (a != b) { float b1; float a2 = a1 - a; if (b < a) { b1 = b + a2 * b / a ; } - else { b1 = b + a2 * (1.f-b) / (1.-a); } + else { b1 = b + a2 * (65535.f-b) / (65535.f-a); } return b1; } return a1; @@ -346,19 +365,56 @@ inline float ValueBlendingToneCurve::Triangle(float a, float a1, float b) const // Tone curve modifying the value channel only, preserving hue and saturation // values in 0xffff space -inline void ValueBlendingToneCurve::Apply (float& r, float& g, float& b) const { +inline void WeightedStdToneCurve::Apply (float& r, float& g, float& b) const { assert (lutToneCurve); - float h, s, v, h2, s2, v2; + float r1 = lutToneCurve[r]; + float g1 = Triangle(r, r1, g); + float b1 = Triangle(r, r1, b); + + float g2 = lutToneCurve[g]; + float r2 = Triangle(g, g2, r); + float b2 = Triangle(g, g2, b); + + float b3 = lutToneCurve[b]; + float r3 = Triangle(b, b3, r); + float g3 = Triangle(b, b3, g); + + r = LIM((r1*0.50f + r2*0.25f + r3*0.25f), 0.f, 65535.f); + g = LIM((g1*0.25f + g2*0.50f + g3*0.25f), 0.f, 65535.f); + b = LIM((b1*0.25f + b2*0.25f + b3*0.50f), 0.f, 65535.f); +} + +// Tone curve modifying the value channel only, preserving hue and saturation +// values in 0xffff space +inline void SatAndValueBlendingToneCurve::Apply (float& r, float& g, float& b) const { + + assert (lutToneCurve); + + float h, s, v; + float lum = (r+g+b)/3.f; + //float lum = Color::rgbLuminance(r, g, b); + float newLum = lutToneCurve[lum]; + if (newLum == lum) + return; + bool increase = newLum > lum; + Color::rgb2hsv(r, g, b, h, s, v); - r = lutToneCurve[r]; - g = lutToneCurve[g]; - b = lutToneCurve[b]; - Color::rgb2hsv(r, g, b, h2, s2, v2); - - Color::hsv2rgb(h, s, v2, r, g, b); + if (increase) { + // Linearly targeting Value = 1 and Saturation = 0 + float coef = (newLum-lum)/(65535.f-lum); + float dV = (1.f-v)*coef; + s *= 1.f-coef; + Color::hsv2rgb(h, s, v+dV, r, g, b); + } + else { + // Linearly targeting Value = 0 + float coef = (lum-newLum)/lum ; + float dV = v*coef; + Color::hsv2rgb(h, s, v-dV, r, g, b); + } } } diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index cf1391594..8fdb42f22 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -150,7 +150,7 @@ void Crop::update (int todo) { if (todo & M_RGBCURVE) parent->ipf.rgbProc (baseCrop, laboCrop, parent->hltonecurve, parent->shtonecurve, parent->tonecurve, cshmap, - params.toneCurve.saturation, parent->rCurve, parent->gCurve, parent->bCurve, parent->nonStandardCurve ); + params.toneCurve.saturation, parent->rCurve, parent->gCurve, parent->bCurve, parent->customToneCurve1, parent->customToneCurve2 ); /*xref=000;yref=000; if (colortest && cropw>115 && croph>115) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 8b18650cc..4550c35fc 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -28,40 +28,42 @@ namespace rtengine { extern const Settings* settings; ImProcCoordinator::ImProcCoordinator () - : workimg(NULL), awbComputed(false), ipf(¶ms, true), scale(10), highDetailPreprocessComputed(false), highDetailRawComputed(false), allocated(false), - pW(-1), pH(-1), plistener(NULL), - imageListener(NULL), aeListener(NULL), hListener(NULL), resultValid(false), - changeSinceLast(0), updaterRunning(false), destroying(false) { + : workimg(NULL), awbComputed(false), ipf(¶ms, true), scale(10), highDetailPreprocessComputed(false), + highDetailRawComputed(false), allocated(false), - hltonecurve(65536,0); - shtonecurve(65536,2);//clip above - tonecurve(65536,0);//,1); + hltonecurve(65536,0), + shtonecurve(65536,2),//clip above + tonecurve(65536,0),//,1); - lumacurve(65536,0); - chroma_acurve(65536,0); - chroma_bcurve(65536,0); - satcurve(65536,0); - lhskcurve(65536,0); + lumacurve(65536,0), + chroma_acurve(65536,0), + chroma_bcurve(65536,0), + satcurve(65536,0), + lhskcurve(65536,0), - vhist16(65536); - lhist16(65536); lhist16Cropped(65536); - histCropped(65536); + vhist16(65536), + lhist16(65536), lhist16Cropped(65536), + histCropped(65536), - histRed(256); histRedRaw(256); - histGreen(256); histGreenRaw(256); - histBlue(256); histBlueRaw(256); - histLuma(256); - histToneCurve(256); - histLCurve(256); - bcabhist(256); - - rCurve(65536,0); - rcurvehist(256); rcurvehistCropped(256); rbeforehist(256); - gCurve(65536,0); - gcurvehist(256); gcurvehistCropped(256); gbeforehist(256); - bCurve(65536,0); - bcurvehist(256); bcurvehistCropped(256); bbeforehist(256); -} + histRed(256), histRedRaw(256), + histGreen(256), histGreenRaw(256), + histBlue(256), histBlueRaw(256), + histLuma(256), + histToneCurve(256), + histLCurve(256), + bcabhist(256), + + rCurve(), + gCurve(), + bCurve(), + rcurvehist(256), rcurvehistCropped(256), rbeforehist(256), + gcurvehist(256), gcurvehistCropped(256), gbeforehist(256), + bcurvehist(256), bcurvehistCropped(256), bbeforehist(256), + + pW(-1), pH(-1), + plistener(NULL), imageListener(NULL), aeListener(NULL), hListener(NULL), + resultValid(false), changeSinceLast(0), updaterRunning(false), destroying(false) + {} void ImProcCoordinator::assign (ImageSource* imgsrc) { this->imgsrc = imgsrc; @@ -72,7 +74,7 @@ ImProcCoordinator::~ImProcCoordinator () { destroying = true; updaterThreadStart.lock (); if (updaterRunning && thread) - thread->join (); + thread->join (); mProcessing.lock(); mProcessing.unlock(); freeAll (); @@ -275,11 +277,13 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { if (hListener) oprevi->calcCroppedHistogram(params, scale, histCropped); // complexCurve also calculated pre-curves histogram dependend on crop + ipf.g = imgsrc->getGamma(); + ipf.iGamma = true; CurveFactory::complexCurve (params.toneCurve.expcomp, params.toneCurve.black/65535.0, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, - imgsrc->getGamma(), true, params.toneCurve.curveMode, params.toneCurve.curve, - vhist16, histCropped, hltonecurve, shtonecurve, tonecurve, histToneCurve, nonStandardCurve, scale==1 ? 1 : 1); + ipf.g, !ipf.iGamma, params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, + 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); @@ -288,7 +292,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { // if it's just crop we just need the histogram, no image updates if ( todo!=CROP ) { ipf.rgbProc (oprevi, oprevl, hltonecurve, shtonecurve, tonecurve, shmap, params.toneCurve.saturation, - rCurve, gCurve, bCurve, nonStandardCurve, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh); + rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh); } // compute L channel histogram @@ -377,7 +381,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { // process crop, if needed for (size_t i=0; ihasListener () && cropCall != crops[i] ) - crops[i]->update (todo); // may call outselves + crops[i]->update (todo); // may call ourselves progress ("Conversion to RGB...",100*readyphase/numofphases); if (todo!=CROP) { diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index fe3887221..172c52c87 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -76,22 +76,25 @@ class ImProcCoordinator : public StagedImageProcessor { LUTf satcurve; LUTf lhskcurve; - LUTf rCurve; - LUTf gCurve; - LUTf bCurve; - - NonStandardToneCurve nonStandardCurve; - - LUTu rcurvehist, rcurvehistCropped, rbeforehist; - LUTu gcurvehist, gcurvehistCropped, gbeforehist; - LUTu bcurvehist, bcurvehistCropped, bbeforehist; - LUTu vhist16; LUTu lhist16,lhist16Cropped; LUTu histCropped; - LUTu histRed, histGreen, histBlue, histLuma, histToneCurve, histLCurve, bcabhist; - LUTu histRedRaw, histGreenRaw, histBlueRaw; + LUTu histRed, histRedRaw; + LUTu histGreen, histGreenRaw; + LUTu histBlue, histBlueRaw; + LUTu histLuma, histToneCurve, histLCurve, bcabhist; + + LUTf rCurve; + LUTf gCurve; + LUTf bCurve; + + ToneCurve customToneCurve1; + ToneCurve customToneCurve2; + + LUTu rcurvehist, rcurvehistCropped, rbeforehist; + LUTu gcurvehist, gcurvehistCropped, gbeforehist; + LUTu bcurvehist, bcurvehistCropped, bbeforehist; int fw, fh, tr, fullw, fullh; int pW, pH; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index fbb4cd01a..52d757560 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -189,14 +189,18 @@ void ImProcFunctions::firstAnalysis (Imagefloat* original, const ProcParams* par } void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, - SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, const NonStandardToneCurve & nonStandardCurve ) { - rgbProc (working, lab, hltonecurve, shtonecurve, tonecurve, shmap, sat, rCurve, gCurve, bCurve, nonStandardCurve, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh); + SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, + const ToneCurve & customToneCurve1,const ToneCurve & customToneCurve2 ) { + rgbProc (working, lab, hltonecurve, shtonecurve, tonecurve, shmap, sat, rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2, params->toneCurve.expcomp, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh); } // Process RGB image and convert to LAB space void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, - SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, const NonStandardToneCurve & nonStandardCurve, - double expcomp, int hlcompr, int hlcomprthresh) { + SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, const ToneCurve & customToneCurve1, + const ToneCurve & customToneCurve2, double expcomp, int hlcompr, int hlcomprthresh) { + + LUTf iGammaLUTf; + Imagefloat *tmpImage = working->copy(); int h_th, s_th; if (shmap) { @@ -212,17 +216,17 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone double toxyz[3][3] = { { - ( wprof[0][0] / Color::D50x), - ( wprof[0][1] / Color::D50x), - ( wprof[0][2] / Color::D50x) + ( wprof[0][0] / Color::D50x), + ( wprof[0][1] / Color::D50x), + ( wprof[0][2] / Color::D50x) },{ - ( wprof[1][0] ), - ( wprof[1][1] ), - ( wprof[1][2] ) + ( wprof[1][0]), + ( wprof[1][1]), + ( wprof[1][2]) },{ - ( wprof[2][0] / Color::D50z), - ( wprof[2][1] / Color::D50z), - ( wprof[2][2] / Color::D50z) + ( wprof[2][0] / Color::D50z), + ( wprof[2][1] / Color::D50z), + ( wprof[2][2] / Color::D50z) } }; @@ -262,7 +266,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone // extracting datas from 'params' to avoid cache flush (to be confirmed) ToneCurveParams::eTCModeId curveMode = params->toneCurve.curveMode; - bool hasNonStandardToneCurve = bool(nonStandardCurve); + ToneCurveParams::eTCModeId curveMode2 = params->toneCurve.curveMode2; + bool hasToneCurve1 = bool(customToneCurve1); + bool hasToneCurve2 = bool(customToneCurve2); float chMixRR = float(params->chmixer.red[0]); float chMixRG = float(params->chmixer.red[1]); @@ -277,28 +283,59 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone int shHighlights = params->sh.highlights; int shShadows = params->sh.shadows; -#pragma omp parallel for if (multiThread) - for (int i=0; i 1.) { + iGammaLUTf(65535); + for (int i=0; i<65536; i++) { + iGammaLUTf[i] = float(CurveFactory::igamma (double(i)/65535., g, start, slope, mul, add)*65535.); + } + } - float r = working->r[i][j]; - float g = working->g[i][j]; - float b = working->b[i][j]; - - //if (i==100 & j==100) printf("rgbProc input R= %f G= %f B= %f \n",r,g,b); +#ifdef _OPENMP +#pragma omp parallel if (multiThread) +{ +#endif + + if (mixchannels) { +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; ir[i][j]; + float g = tmpImage->g[i][j]; + float b = tmpImage->b[i][j]; + + //if (i==100 & j==100) printf("rgbProc input R= %f G= %f B= %f \n",r,g,b); - if (mixchannels) { float rmix = (r*chMixRR + g*chMixRG + b*chMixRB) / 100.f; float gmix = (r*chMixGR + g*chMixGG + b*chMixGB) / 100.f; float bmix = (r*chMixBR + g*chMixBG + b*chMixBB) / 100.f; - - r = rmix; - g = gmix; - b = bmix; - } - if (processSH || processLCE) { + tmpImage->r[i][j] = rmix; + tmpImage->g[i][j] = gmix; + tmpImage->b[i][j] = bmix; + } + } + } + + if (processSH || processLCE) { +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; ir[i][j]; + float g = tmpImage->g[i][j]; + float b = tmpImage->b[i][j]; + double mapval = 1.0 + shmap->map[i][j]; double factor = 1.0; @@ -310,16 +347,28 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone } if (processLCE) { double sub = lceamount*(mapval-factor*(r*lumimul[0] + g*lumimul[1] + b*lumimul[2])); - r = factor*r-sub; - g = factor*g-sub; - b = factor*b-sub; + tmpImage->r[i][j] = factor*r-sub; + tmpImage->g[i][j] = factor*g-sub; + tmpImage->b[i][j] = factor*b-sub; } else { - r = factor*r; - g = factor*g; - b = factor*b; + tmpImage->r[i][j] = factor*r; + tmpImage->g[i][j] = factor*g; + tmpImage->b[i][j] = factor*b; } } + } + } + +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; ir[i][j]; + float g = tmpImage->g[i][j]; + float b = tmpImage->b[i][j]; //TODO: proper treatment of out-of-gamut colors //float tonefactor = hltonecurve[(0.299f*r+0.587f*g+0.114f*b)]; @@ -327,49 +376,200 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone (gr[i][j] = (r*tonefactor); + tmpImage->g[i][j] = (g*tonefactor); + tmpImage->b[i][j] = (b*tonefactor); + } + } + +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; ir[i][j]; + float g = tmpImage->g[i][j]; + float b = tmpImage->b[i][j]; //shadow tone curve float Y = (0.299f*r + 0.587f*g + 0.114f*b); - tonefactor = shtonecurve[Y]; - r *= tonefactor; - g *= tonefactor; - b *= tonefactor; + float tonefactor = shtonecurve[Y]; + tmpImage->r[i][j] *= tonefactor; + tmpImage->g[i][j] *= tonefactor; + tmpImage->b[i][j] *= tonefactor; + } + } - //brightness/contrast, + user tone curve if curveMode==TC_MODE_STD - r = tonecurve[r]; - g = tonecurve[g]; - b = tonecurve[b]; +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; ir[i][j] = tonecurve[ tmpImage->r[i][j] ]; + tmpImage->g[i][j] = tonecurve[ tmpImage->g[i][j] ]; + tmpImage->b[i][j] = tonecurve[ tmpImage->b[i][j] ]; + } + } - // Nothing to do, since the user's tone curve has been integrated into the global 'tonecurve' - }*/ - if (curveMode==ToneCurveParams::TC_MODE_FILMLIKE){ // Adobe like - const AdobeToneCurve& userToneCurve = static_cast(nonStandardCurve); - userToneCurve.Apply(r,g,b); - } - else if (curveMode==ToneCurveParams::TC_MODE_VALBLENDING){ // apply the curve on the value channel - - const ValueBlendingToneCurve& userToneCurve = static_cast(nonStandardCurve); - userToneCurve.Apply(r,g,b); + if (hasToneCurve1) { + if (curveMode==ToneCurveParams::TC_MODE_STD){ // Standard +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; i(customToneCurve1); + userToneCurve.Apply(tmpImage->r[i][j], tmpImage->g[i][j], tmpImage->b[i][j]); } } + } + else if (curveMode==ToneCurveParams::TC_MODE_FILMLIKE){ // Adobe like +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; i(customToneCurve1); + userToneCurve.Apply(tmpImage->r[i][j], tmpImage->g[i][j], tmpImage->b[i][j]); + } + } + } + else if (curveMode==ToneCurveParams::TC_MODE_SATANDVALBLENDING){ // apply the curve on the saturation and value channels +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; i(customToneCurve1); + userToneCurve.Apply(tmpImage->r[i][j], tmpImage->g[i][j], tmpImage->b[i][j]); + } + } + } + else if (curveMode==ToneCurveParams::TC_MODE_WEIGHTEDSTD){ // apply the curve to the rgb channels, weighted +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; i(customToneCurve1); + userToneCurve.Apply(tmpImage->r[i][j], tmpImage->g[i][j], tmpImage->b[i][j]); + } + } + } + } - // individual R, G and B tone curves - r = rCurve[r]; - g = gCurve[g]; - b = bCurve[b]; + if (hasToneCurve2) { + if (curveMode2==ToneCurveParams::TC_MODE_STD){ // Standard +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; i(customToneCurve2); + userToneCurve.Apply(tmpImage->r[i][j], tmpImage->g[i][j], tmpImage->b[i][j]); + } + } + } + else if (curveMode2==ToneCurveParams::TC_MODE_FILMLIKE){ // Adobe like +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; i(customToneCurve2); + userToneCurve.Apply(tmpImage->r[i][j], tmpImage->g[i][j], tmpImage->b[i][j]); + } + } + } + else if (curveMode2==ToneCurveParams::TC_MODE_SATANDVALBLENDING){ // apply the curve on the saturation and value channels +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; i(customToneCurve2); + userToneCurve.Apply(tmpImage->r[i][j], tmpImage->g[i][j], tmpImage->b[i][j]); + } + } + } + else if (curveMode2==ToneCurveParams::TC_MODE_WEIGHTEDSTD){ // apply the curve to the rgb channels, weighted +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; i(customToneCurve2); + userToneCurve.Apply(tmpImage->r[i][j], tmpImage->g[i][j], tmpImage->b[i][j]); + } + } + } + } + + if (iGammaLUTf) { +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; ir[i][j] = iGammaLUTf[ tmpImage->r[i][j] ]; + tmpImage->g[i][j] = iGammaLUTf[ tmpImage->g[i][j] ]; + tmpImage->b[i][j] = iGammaLUTf[ tmpImage->b[i][j] ]; + } + } + } + + if (rCurve) { +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; ir[i][j] = rCurve[ tmpImage->r[i][j] ]; + } + } + } + + if (gCurve) { +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; ig[i][j] = gCurve[ tmpImage->g[i][j] ]; + } + } + } + + if (bCurve) { +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; ib[i][j] = bCurve[ tmpImage->b[i][j] ]; + } + } + } - //if (r<0 || g<0 || b<0) { - // printf("negative values row=%d col=%d r=%f g=%f b=%f \n", i,j,r,g,b); - //} + if (sat!=0 || hCurveEnabled || sCurveEnabled || vCurveEnabled) { +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; ir[i][j]; + float g = tmpImage->g[i][j]; + float b = tmpImage->b[i][j]; - if (sat!=0 || hCurveEnabled || sCurveEnabled || vCurveEnabled) { float h,s,v; Color::rgb2hsv(r,g,b,h,s,v); if (sat > 0.5f) { @@ -414,9 +614,20 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone } } - Color::hsv2rgb(h,s,v,r,g,b); + Color::hsv2rgb(h, s, v, tmpImage->r[i][j], tmpImage->g[i][j], tmpImage->b[i][j]); } - + } + } + +#ifdef _OPENMP +#pragma omp for schedule(dynamic, 5) +#endif + for (int i=0; ir[i][j]; + float g = tmpImage->g[i][j]; + float b = tmpImage->b[i][j]; + float x = toxyz[0][0] * r + toxyz[0][1] * g + toxyz[0][2] * b; float y = toxyz[1][0] * r + toxyz[1][1] * g + toxyz[1][2] * b; float z = toxyz[2][0] * r + toxyz[2][1] * g + toxyz[2][2] * b; @@ -449,12 +660,17 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltone } } - +#ifdef _OPENMP +} +#endif + + delete tmpImage; + if (hCurveEnabled) delete hCurve; if (sCurveEnabled) delete sCurve; if (vCurveEnabled) delete vCurve; delete [] cossq; - } +} void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, LUTf & curve) { diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index e31f4a3b1..d81643af1 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -46,7 +46,6 @@ class ImProcFunctions { const ProcParams* params; double scale; bool multiThread; - float g; void calcVignettingParams(int oW, int oH, const VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul); @@ -68,6 +67,9 @@ class ImProcFunctions { public: + bool iGamma; // true if inverse gamma has to be applied in rgbProc + double g; + static LUTf cachef; double lumimul[3]; @@ -76,7 +78,7 @@ class ImProcFunctions { static void cleanupCache (); ImProcFunctions (const ProcParams* iparams, bool imultiThread=true) - : monitorTransform(NULL), params(iparams), scale(1), multiThread(imultiThread) {} + : monitorTransform(NULL), params(iparams), scale(1), multiThread(imultiThread), iGamma(true), g(0.0) {} ~ImProcFunctions (); void setScale (double iscale); @@ -85,9 +87,9 @@ class ImProcFunctions { void firstAnalysis (Imagefloat* working, const ProcParams* params, LUTu & vhist16, double gamma); void rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, - SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, const NonStandardToneCurve & nonStandardCurve); + SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2); void rgbProc (Imagefloat* working, LabImage* lab, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, - SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, const NonStandardToneCurve & nonStandardCurve, + SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, double expcomp, int hlcompr, int hlcomprthresh); void luminanceCurve (LabImage* lold, LabImage* lnew, LUTf &curve); diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index 46600dbc2..f71c8e3be 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -424,7 +424,7 @@ void ImProcFunctions::MLsharpen (LabImage* lab) { // has waived all copyright and related or neighboring rights to this work. // This code is licensed under CC0 v1.0, see license information at // http://creativecommons.org/publicdomain/zero/1.0/ -// addition from JD : pyramid + ponderated contrast with matrix 5x5 +// addition from JD : pyramid + pondered contrast with matrix 5x5 void ImProcFunctions::MLmicrocontrast(LabImage* lab) { if (params->sharpenMicro.enabled==false) return; diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 6e9fb1311..931d45bd4 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -32,7 +32,7 @@ enum ProcEvent { EvExpComp=7, EvHLCompr=8, EvSHCompr=9, - EvToneCurve=10, + EvToneCurve1=10, EvAutoExp=11, EvClip=12, EvLBrightness=13, @@ -62,9 +62,9 @@ enum ProcEvent { EvWBMethod=37, EvWBTemp=38, EvWBGreen=39, - EvToneCurveMode=40, - EvCShiftB=41, // obsolete - EvLDNEnabled=42, // obsolete + EvToneCurveMode1=40, + EvToneCurve2=41, + EvToneCurveMode2=42, EvLDNRadius=43, // obsolete EvLDNEdgeTolerance=44, // obsolete EvCDNEnabled=45, // obsolete diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 49cc8255a..de3b0abb1 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -138,7 +138,10 @@ void ProcParams::setDefaults () { toneCurve.shcompr = 50; toneCurve.curve.clear (); toneCurve.curve.push_back(DCT_Linear); + toneCurve.curve2.clear (); + toneCurve.curve2.push_back(DCT_Linear); toneCurve.curveMode = ToneCurveParams::TC_MODE_STD; + toneCurve.curveMode2 = ToneCurveParams::TC_MODE_STD; labCurve.brightness = 0; labCurve.contrast = 0; @@ -402,16 +405,41 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, ParamsEdited* p case (ToneCurveParams::TC_MODE_FILMLIKE): method = "FilmLike"; break; - case (ToneCurveParams::TC_MODE_VALBLENDING): - method = "ValueBlending"; + case (ToneCurveParams::TC_MODE_SATANDVALBLENDING): + method = "SatAndValueBlending"; + break; + case (ToneCurveParams::TC_MODE_WEIGHTEDSTD): + method = "WeightedStd"; 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; + } + 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 channel mixer if (!pedited || pedited->chmixer.red[0] || pedited->chmixer.red[1] || pedited->chmixer.red[2]) { @@ -805,13 +833,24 @@ if (keyFile.has_group ("Exposure")) { if (toneCurve.shcompr > 100) toneCurve.shcompr = 100; // older pp3 files can have values above 100. if (keyFile.has_key ("Exposure", "CurveMode")) { Glib::ustring sMode = keyFile.get_string ("Exposure", "CurveMode"); - if (sMode == "Standard") toneCurve.curveMode = ToneCurveParams::TC_MODE_STD; - else if (sMode == "FilmLike") toneCurve.curveMode = ToneCurveParams::TC_MODE_FILMLIKE; - else if (sMode == "ValueBlending") toneCurve.curveMode = ToneCurveParams::TC_MODE_VALBLENDING; + if (sMode == "Standard") toneCurve.curveMode = ToneCurveParams::TC_MODE_STD; + else if (sMode == "FilmLike") toneCurve.curveMode = ToneCurveParams::TC_MODE_FILMLIKE; + else if (sMode == "SatAndValueBlending") toneCurve.curveMode = ToneCurveParams::TC_MODE_SATANDVALBLENDING; + else if (sMode == "WeightedStd") toneCurve.curveMode = ToneCurveParams::TC_MODE_WEIGHTEDSTD; if (pedited) pedited->toneCurve.curveMode = true; } - if (ppVersion>200) + if (keyFile.has_key ("Exposure", "CurveMode2")) { + Glib::ustring sMode = keyFile.get_string ("Exposure", "CurveMode2"); + if (sMode == "Standard") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_STD; + else if (sMode == "FilmLike") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_FILMLIKE; + else if (sMode == "SatAndValueBlending") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_SATANDVALBLENDING; + else if (sMode == "WeightedStd") toneCurve.curveMode2 = ToneCurveParams::TC_MODE_WEIGHTEDSTD; + if (pedited) pedited->toneCurve.curveMode2 = true; + } + if (ppVersion>200) { if (keyFile.has_key ("Exposure", "Curve")) { toneCurve.curve = keyFile.get_double_list ("Exposure", "Curve"); if (pedited) pedited->toneCurve.curve = true; } + if (keyFile.has_key ("Exposure", "Curve2")) { toneCurve.curve2 = keyFile.get_double_list ("Exposure", "Curve2"); if (pedited) pedited->toneCurve.curve2 = true; } + } } // load channel mixer curve @@ -1252,6 +1291,7 @@ bool ProcParams::operator== (const ProcParams& other) { return toneCurve.curve == other.toneCurve.curve + && toneCurve.curve2 == other.toneCurve.curve2 && toneCurve.brightness == other.toneCurve.brightness && toneCurve.black == other.toneCurve.black && toneCurve.contrast == other.toneCurve.contrast @@ -1263,6 +1303,7 @@ bool ProcParams::operator== (const ProcParams& other) { && toneCurve.clip == other.toneCurve.clip && toneCurve.expcomp == other.toneCurve.expcomp && toneCurve.curveMode == other.toneCurve.curveMode + && toneCurve.curveMode2 == other.toneCurve.curveMode2 && labCurve.lcurve == other.labCurve.lcurve && labCurve.acurve == other.labCurve.acurve && labCurve.bcurve == other.labCurve.bcurve diff --git a/rtengine/procparams.h b/rtengine/procparams.h index ba7462d1e..09de24b3c 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -182,16 +182,19 @@ class ToneCurveParams { public: enum eTCModeId { - TC_MODE_STD, // Standard modes, the curve is applied on all component individually - TC_MODE_FILMLIKE, // Film-like mode, as defined in Adobe's reference code - TC_MODE_VALBLENDING // Modify the Value channel only + TC_MODE_STD, // Standard modes, the curve is applied on all component individually + TC_MODE_FILMLIKE, // Film-like mode, as defined in Adobe's reference code + TC_MODE_SATANDVALBLENDING, // Modify the Saturation and Value channel + TC_MODE_WEIGHTEDSTD // Weighted standard mode }; bool autoexp; double clip; double expcomp; std::vector curve; + std::vector curve2; eTCModeId curveMode; + eTCModeId curveMode2; int brightness; int black; int contrast; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 656c3f1a2..2fc494523 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -30,7 +30,7 @@ RGBCURVE, // EvBlack, RGBCURVE, // EvExpComp, RGBCURVE, // EvHLCompr, RGBCURVE, // EvSHCompr, -RGBCURVE, // EvToneCurve, +RGBCURVE, // EvToneCurve1, AUTOEXP, // EvAutoExp, AUTOEXP, // EvClip, LUMINANCECURVE, // EvLBrightness, @@ -60,9 +60,9 @@ M_VOID, // EvFixedExp WHITEBALANCE, // EvWBMethod, WHITEBALANCE, // EvWBTemp, WHITEBALANCE, // EvWBGreen, -RGBCURVE, // EvToneCurveMode -0, // EvCShiftB: obsolete -0, // EvLDNEnabled: obsolete, +RGBCURVE, // EvToneCurveMode1, +RGBCURVE, // EvToneCurve2, +RGBCURVE, // EvToneCurveMode2, 0, // EvLDNRadius: obsolete, 0, // EvLDNEdgeTolerance: obsolete, 0, // EvCDNEnabled:obsolete, diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 92295088d..7275066d8 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -742,11 +742,15 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei LUTu dummy; - NonStandardToneCurve nonStandardCurve; + ToneCurve customToneCurve1, customToneCurve2; - CurveFactory::complexCurve (expcomp, black/65535.0, hlcompr, hlcomprthresh, - params.toneCurve.shcompr, bright, contr, gamma, true, params.toneCurve.curveMode, - params.toneCurve.curve, hist16, dummy, curve1, curve2, curve, dummy, nonStandardCurve, 16); + ipf.g = gamma; + ipf.iGamma = true; + CurveFactory::complexCurve (expcomp, black/65535.0, hlcompr, hlcomprthresh, + params.toneCurve.shcompr, bright, contr, ipf.g, !ipf.iGamma, + params.toneCurve.curveMode, params.toneCurve.curve, + params.toneCurve.curveMode2, params.toneCurve.curve2, + hist16, dummy, curve1, curve2, curve, dummy, customToneCurve1, customToneCurve2, 16); CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, 16); CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, 16); @@ -754,7 +758,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei LabImage* labView = new LabImage (fw,fh); - ipf.rgbProc (baseImg, labView, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, nonStandardCurve, expcomp, hlcompr, hlcomprthresh); + ipf.rgbProc (baseImg, labView, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2, expcomp, hlcompr, hlcomprthresh); if (shmap) delete shmap; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 2e728b437..359a818db 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -168,17 +168,19 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p LUTf bCurve (65536,0); LUTu dummy; - NonStandardToneCurve nonStandardCurve; + ToneCurve customToneCurve1, customToneCurve2; - CurveFactory::complexCurve (expcomp, black/65535.0, hlcompr, hlcomprthresh, params.toneCurve.shcompr, bright, contr, imgsrc->getGamma(), true, - params.toneCurve.curveMode, params.toneCurve.curve, - hist16, dummy, curve1, curve2, curve, dummy, nonStandardCurve); + ipf.g = imgsrc->getGamma(); + ipf.iGamma = true; + CurveFactory::complexCurve (expcomp, black/65535.0, hlcompr, hlcomprthresh, params.toneCurve.shcompr, bright, contr, ipf.g, !ipf.iGamma, + params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, + 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); - ipf.rgbProc (baseImg, labView, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, nonStandardCurve, expcomp, hlcompr, hlcomprthresh); + ipf.rgbProc (baseImg, labView, curve1, curve2, curve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2, expcomp, hlcompr, hlcomprthresh); // Freeing baseImg because not used anymore delete baseImg; diff --git a/rtgui/curveeditor.cc b/rtgui/curveeditor.cc index c44e9b958..05ba0dd2c 100644 --- a/rtgui/curveeditor.cc +++ b/rtgui/curveeditor.cc @@ -135,18 +135,19 @@ CurveEditor::CurveEditor (Glib::ustring text, CurveEditorGroup* ceGroup, CurveEd bottomBarCP = NULL; leftBarCP = NULL; curveCP = NULL; + relatedWidget = NULL; group = ceGroup; subGroup = ceSubGroup; - if (group && text.size()) - curveType = new PopUpToggleButton(text + ":"); - else - curveType = new PopUpToggleButton(); + if (group && text.size()) + curveType = new PopUpToggleButton(text + ":"); + else + curveType = new PopUpToggleButton(); - curveType->set_tooltip_text(M("CURVEEDITOR_TYPE")); - // TODO: Does this signal have to be blocked when on curve type change ? - curveType->signal_toggled().connect ( sigc::mem_fun(*this, &CurveEditor::curveTypeToggled) ); + curveType->set_tooltip_text(M("CURVEEDITOR_TYPE")); + // TODO: Does this signal have to be blocked when on curve type change ? + curveType->signal_toggled().connect ( sigc::mem_fun(*this, &CurveEditor::curveTypeToggled) ); typeconn = curveType->signal_changed().connect (sigc::mem_fun(*this, &CurveEditor::typeSelectionChanged) ); } diff --git a/rtgui/curveeditor.h b/rtgui/curveeditor.h index b7d2adc9b..6167fa8ec 100644 --- a/rtgui/curveeditor.h +++ b/rtgui/curveeditor.h @@ -60,6 +60,7 @@ class CurveEditor { CurveEditorGroup* group; CurveEditorSubGroup* subGroup; + Gtk::Widget* relatedWidget; std::vector tempCurve; sigc::connection typeconn; diff --git a/rtgui/curveeditorgroup.cc b/rtgui/curveeditorgroup.cc index 530df00f8..b03676cbe 100644 --- a/rtgui/curveeditorgroup.cc +++ b/rtgui/curveeditorgroup.cc @@ -56,24 +56,45 @@ void CurveEditorGroup::hideCurrentCurve() { /* * Add a new curve to the curves list * - * The "periodic" parameter is only used by flat curve editors + * Parameters: + * cType: enum saying which kind of curve type has to be created + * curveLabel: Name of the curve that will be inserted in the toggle button, before the image. + * If empty, no text will prepend the image + * relatedWidget: pointer to a widget (or NULL) that will be inserted next to the curve's toggle button. + * if a smart pointer created by Gtk::manage is passed in, the widget will be deleted by the destructor, + * otherwise it'll have to be delete it manually + * periodic: for FlatCurve only, ask the curve to be periodic (default: True) + * */ -CurveEditor* CurveEditorGroup::addCurve(CurveType cType, Glib::ustring curveLabel, bool periodic) { +CurveEditor* CurveEditorGroup::addCurve(CurveType cType, Glib::ustring curveLabel, Gtk::Widget *relatedWidget, bool periodic) { switch (cType) { case (CT_Diagonal): + { if (!diagonalSubGroup) { diagonalSubGroup = new DiagonalCurveEditorSubGroup(this, curveDir); } - return (static_cast(diagonalSubGroup->addCurve(curveLabel))); + // We add it to the curve editor list + DiagonalCurveEditor* newCE = diagonalSubGroup->addCurve(curveLabel); + newCE->relatedWidget = relatedWidget; + curveEditors.push_back(newCE); + return (newCE); + } case (CT_Flat): + { if (!flatSubGroup) { flatSubGroup = new FlatCurveEditorSubGroup(this, curveDir); } - return (static_cast(flatSubGroup->addCurve(curveLabel, periodic))); + // We add it to the curve editor list + FlatCurveEditor* newCE = flatSubGroup->addCurve(curveLabel, periodic); + newCE->relatedWidget = relatedWidget; + curveEditors.push_back(newCE); + return (newCE); + } default: return (static_cast(NULL)); break; } + return NULL; // to avoid complains from Gcc } /* @@ -99,9 +120,15 @@ void CurveEditorGroup::newLine() { } int j = numberOfPackedCurve; - for (int i = (int)(curveEditors.size())-1; i >= j; i--) - { - headerBox->pack_end (*curveEditors[i]->curveType->buttonGroup, Gtk::PACK_EXPAND_WIDGET, 2); + bool hasRelatedWidget = false; + for (int i = (int)(curveEditors.size())-1; i >= j; i--) { + if (curveEditors[i]->relatedWidget != NULL) + hasRelatedWidget = true; + } + for (int i = (int)(curveEditors.size())-1; i >= j; i--) { + if (curveEditors[i]->relatedWidget != NULL) + headerBox->pack_end (*curveEditors[i]->relatedWidget, Gtk::PACK_EXPAND_WIDGET, 2); + headerBox->pack_end (*curveEditors[i]->curveType->buttonGroup, hasRelatedWidget ? Gtk::PACK_SHRINK : Gtk::PACK_EXPAND_WIDGET, 2); numberOfPackedCurve++; } @@ -259,6 +286,13 @@ void CurveEditorGroup::curveResetPressed () { } } +/* + * Set the tooltip text of the label of the curve group + */ +void CurveEditorGroup::setTooltip( Glib::ustring ttip) { + curveGroupLabel->set_tooltip_text( ttip ); +} + void CurveEditorGroup::setBatchMode (bool batchMode) { for (std::vector::iterator i = curveEditors.begin(); i != curveEditors.end(); ++i) { (*i)->curveType->addEntry("curveType-unchanged.png", M("GENERAL_UNCHANGED")); diff --git a/rtgui/curveeditorgroup.h b/rtgui/curveeditorgroup.h index b34b092ae..76c5d484d 100644 --- a/rtgui/curveeditorgroup.h +++ b/rtgui/curveeditorgroup.h @@ -75,9 +75,10 @@ public: void setBatchMode (bool batchMode); void setCurveExternal (CurveEditor* ce, const std::vector& c); void setCurveListener (CurveListener* l) { cl = l; } + void setTooltip (Glib::ustring ttip); CurveEditor* getDisplayedCurve () { return displayedCurve; } //void on_realize (); - CurveEditor* addCurve(CurveType cType, Glib::ustring curveLabel, bool periodic = true); + CurveEditor* addCurve(CurveType cType, Glib::ustring curveLabel, Gtk::Widget *relatedWidget=NULL, bool periodic=true); protected: //void curveTypeToggled (); diff --git a/rtgui/diagonalcurveeditorsubgroup.cc b/rtgui/diagonalcurveeditorsubgroup.cc index 90f8d9a3c..05676d566 100644 --- a/rtgui/diagonalcurveeditorsubgroup.cc +++ b/rtgui/diagonalcurveeditorsubgroup.cc @@ -232,9 +232,6 @@ DiagonalCurveEditor* DiagonalCurveEditorSubGroup::addCurve(Glib::ustring curveLa storeCurveValues(newCE, getCurveFromGUI(DCT_Spline)); storeCurveValues(newCE, getCurveFromGUI(DCT_Parametric)); storeCurveValues(newCE, getCurveFromGUI(DCT_NURBS)); - - // We add it to the curve editor list - parent->curveEditors.push_back(newCE); return newCE; } diff --git a/rtgui/flatcurveeditorsubgroup.cc b/rtgui/flatcurveeditorsubgroup.cc index e2e9ca8ac..b262d29e4 100644 --- a/rtgui/flatcurveeditorsubgroup.cc +++ b/rtgui/flatcurveeditorsubgroup.cc @@ -77,9 +77,6 @@ FlatCurveEditor* FlatCurveEditorSubGroup::addCurve(Glib::ustring curveLabel, boo // Initialization of the new curve storeCurveValues(newCE, getCurveFromGUI(FCT_MinMaxCPoints)); - - // We add it to the curve editor list - parent->curveEditors.push_back(newCE); return newCE; } diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 6e7390054..fca23965c 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -33,7 +33,9 @@ void ParamsEdited::set (bool v) { general.intrash = v; toneCurve.curve = v; + toneCurve.curve2 = v; toneCurve.curveMode = v; + toneCurve.curveMode2 = v; toneCurve.brightness = v; toneCurve.black = v; toneCurve.contrast = v; @@ -233,7 +235,9 @@ void ParamsEdited::initFrom (const std::vector for (size_t i=1; i bottomMilestones; bottomMilestones.push_back( GradientMilestone(0., 0., 0., 0.) ); bottomMilestones.push_back( GradientMilestone(1., 1., 1., 1.) ); @@ -86,35 +88,55 @@ ToneCurve::ToneCurve () : Gtk::VBox(), FoldableToolPanel(this) { saturation = Gtk::manage (new Adjuster (M("TP_EXPOSURE_SATURATION"), -100, 100, 1, 0)); pack_start (*saturation); -//----------- Curve ------------------------------ +//----------- Curve 1 ------------------------------ pack_start (*Gtk::manage (new Gtk::HSeparator())); - curveEditorG = new CurveEditorGroup (options.lastToneCurvesDir, M("TP_EXPOSURE_CURVEEDITOR")); + toneCurveMode = Gtk::manage (new MyComboBoxText ()); + toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_STANDARD")); + toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_FILMLIKE")); + toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_SATANDVALBLENDING")); + toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_WEIGHTEDSTD")); + toneCurveMode->set_active (0); + toneCurveMode->set_tooltip_text(M("TP_EXPOSURE_TCMODE_LABEL1")); + + curveEditorG = new CurveEditorGroup (options.lastToneCurvesDir, M("TP_EXPOSURE_CURVEEDITOR1")); curveEditorG->setCurveListener (this); - shape = static_cast(curveEditorG->addCurve(CT_Diagonal, "")); + shape = static_cast(curveEditorG->addCurve(CT_Diagonal, "", toneCurveMode)); shape->setBottomBarBgGradient(bottomMilestones); shape->setLeftBarBgGradient(bottomMilestones); - // This will add the reset button at the end of the curveType buttons curveEditorG->curveListComplete(); - pack_start (*curveEditorG, Gtk::PACK_SHRINK, 4); + pack_start( *curveEditorG, Gtk::PACK_SHRINK, 2); - Gtk::HBox* hb1 = Gtk::manage (new Gtk::HBox ()); - hb1->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_EXPOSURE_TCMODE_LABEL") +": ")),Gtk::PACK_SHRINK, 4); - toneCurveMode = Gtk::manage (new MyComboBoxText ()); - toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_STANDARD")); - toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_FILMLIKE")); - toneCurveMode->append_text (M("TP_EXPOSURE_TCMODE_VALBLENDING")); - toneCurveMode->set_active (0); - hb1->pack_end (*toneCurveMode, Gtk::PACK_EXPAND_WIDGET, 4); + tcmodeconn = toneCurveMode->signal_changed().connect( sigc::mem_fun(*this, &ToneCurve::curveMode1Changed), true ); - pack_start( *hb1, Gtk::PACK_SHRINK, 2); +//----------- Curve 2 ------------------------------ - tcmodeconn = toneCurveMode->signal_changed().connect( sigc::mem_fun(*this, &ToneCurve::curveModeChanged), true ); - //curveEditorG->show(); + toneCurveMode2 = Gtk::manage (new MyComboBoxText ()); + toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_STANDARD")); + toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_FILMLIKE")); + toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_SATANDVALBLENDING")); + toneCurveMode2->append_text (M("TP_EXPOSURE_TCMODE_WEIGHTEDSTD")); + toneCurveMode2->set_active (0); + toneCurveMode2->set_tooltip_text(M("TP_EXPOSURE_TCMODE_LABEL2")); + + curveEditorG2 = new CurveEditorGroup (options.lastToneCurvesDir, M("TP_EXPOSURE_CURVEEDITOR2")); + curveEditorG2->setCurveListener (this); + + shape2 = static_cast(curveEditorG2->addCurve(CT_Diagonal, "", toneCurveMode2)); + shape2->setBottomBarBgGradient(bottomMilestones); + shape2->setLeftBarBgGradient(bottomMilestones); + + // This will add the reset button at the end of the curveType buttons + curveEditorG2->curveListComplete(); + curveEditorG2->setTooltip(M("TP_EXPOSURE_CURVEEDITOR2_TOOLTIP")); + + pack_start( *curveEditorG2, Gtk::PACK_SHRINK, 2); + + tcmode2conn = toneCurveMode2->signal_changed().connect( sigc::mem_fun(*this, &ToneCurve::curveMode2Changed), true ); // --------- Set Up Listeners ------------- expcomp->setAdjusterListener (this); @@ -127,11 +149,17 @@ ToneCurve::ToneCurve () : Gtk::VBox(), FoldableToolPanel(this) { saturation->setAdjusterListener (this); } +ToneCurve::~ToneCurve () { + delete curveEditorG; + delete curveEditorG2; +} + void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { disableListener (); tcmodeconn.block(true); + tcmode2conn.block(true); autoconn.block (true); autolevels->set_active (pp->toneCurve.autoexp); @@ -148,8 +176,10 @@ void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { contrast->setValue (pp->toneCurve.contrast); saturation->setValue (pp->toneCurve.saturation); shape->setCurve (pp->toneCurve.curve); + shape2->setCurve (pp->toneCurve.curve2); toneCurveMode->set_active(pp->toneCurve.curveMode); + toneCurveMode2->set_active(pp->toneCurve.curveMode2); if (pedited) { expcomp->setEditedState (pedited->toneCurve.expcomp ? Edited : UnEdited); @@ -163,12 +193,17 @@ void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { autolevels->set_inconsistent (!pedited->toneCurve.autoexp); clipDirty = pedited->toneCurve.clip; shape->setUnChanged (!pedited->toneCurve.curve); + shape2->setUnChanged (!pedited->toneCurve.curve2); if (!pedited->toneCurve.curveMode) { - toneCurveMode->set_active(3); + toneCurveMode->set_active(4); + } + if (!pedited->toneCurve.curveMode2) { + toneCurveMode2->set_active(4); } } autoconn.block (false); + tcmode2conn.block(false); tcmodeconn.block(false); enableListener (); @@ -176,6 +211,7 @@ void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { void ToneCurve::autoOpenCurve () { shape->openIfNonlinear(); + shape2->openIfNonlinear(); } void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited) { @@ -191,26 +227,36 @@ void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited) { pp->toneCurve.contrast = (int)contrast->getValue (); pp->toneCurve.saturation = (int)saturation->getValue (); pp->toneCurve.curve = shape->getCurve (); + pp->toneCurve.curve2 = shape2->getCurve (); int tcMode = toneCurveMode->get_active_row_number(); if (tcMode == 0) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_STD; - if (tcMode == 1) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_FILMLIKE; - else if (tcMode == 2) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_VALBLENDING; + else if (tcMode == 1) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_FILMLIKE; + else if (tcMode == 2) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_SATANDVALBLENDING; + else if (tcMode == 3) pp->toneCurve.curveMode = ToneCurveParams::TC_MODE_WEIGHTEDSTD; + + tcMode = toneCurveMode2->get_active_row_number(); + if (tcMode == 0) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_STD; + else if (tcMode == 1) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_FILMLIKE; + else if (tcMode == 2) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_SATANDVALBLENDING; + else if (tcMode == 3) pp->toneCurve.curveMode2 = ToneCurveParams::TC_MODE_WEIGHTEDSTD; if (pedited) { - pedited->toneCurve.expcomp = expcomp->getEditedState (); - pedited->toneCurve.black = black->getEditedState (); - pedited->toneCurve.hlcompr = hlcompr->getEditedState (); + pedited->toneCurve.expcomp = expcomp->getEditedState (); + pedited->toneCurve.black = black->getEditedState (); + pedited->toneCurve.hlcompr = hlcompr->getEditedState (); pedited->toneCurve.hlcomprthresh = hlcomprthresh->getEditedState (); - pedited->toneCurve.shcompr = shcompr->getEditedState (); + pedited->toneCurve.shcompr = shcompr->getEditedState (); pedited->toneCurve.brightness = brightness->getEditedState (); - pedited->toneCurve.contrast = contrast->getEditedState (); + pedited->toneCurve.contrast = contrast->getEditedState (); pedited->toneCurve.saturation = saturation->getEditedState (); - pedited->toneCurve.autoexp = !autolevels->get_inconsistent(); - pedited->toneCurve.clip = clipDirty; - pedited->toneCurve.curve = !shape->isUnChanged (); - pedited->toneCurve.curveMode = toneCurveMode->get_active_row_number() != 3; + pedited->toneCurve.autoexp = !autolevels->get_inconsistent(); + pedited->toneCurve.clip = clipDirty; + pedited->toneCurve.curve = !shape->isUnChanged (); + pedited->toneCurve.curve2 = !shape2->isUnChanged (); + pedited->toneCurve.curveMode = toneCurveMode->get_active_row_number() != 4; + pedited->toneCurve.curveMode2 = toneCurveMode2->get_active_row_number() != 4; } } @@ -247,18 +293,33 @@ void ToneCurve::setDefaults (const ProcParams* defParams, const ParamsEdited* pe } } -void ToneCurve::curveChanged () { +void ToneCurve::curveChanged (CurveEditor* ce) { - if (listener) listener->panelChanged (EvToneCurve, M("HISTORY_CUSTOMCURVE")); + if (listener) { + if (ce == shape) + listener->panelChanged (EvToneCurve1, M("HISTORY_CUSTOMCURVE")); + else if (ce == shape2) + listener->panelChanged (EvToneCurve2, M("HISTORY_CUSTOMCURVE")); + } } -void ToneCurve::curveModeChanged () { +void ToneCurve::curveMode1Changed () { //if (listener) listener->panelChanged (EvToneCurveMode, toneCurveMode->get_active_text()); - if (listener) Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::curveModeChanged_)); + if (listener) Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::curveMode1Changed_)); } -bool ToneCurve::curveModeChanged_ () { - if (listener) listener->panelChanged (EvToneCurveMode, toneCurveMode->get_active_text()); +bool ToneCurve::curveMode1Changed_ () { + if (listener) listener->panelChanged (EvToneCurveMode1, toneCurveMode->get_active_text()); + return false; +} + +void ToneCurve::curveMode2Changed () { + //if (listener) listener->panelChanged (EvToneCurveMode, toneCurveMode->get_active_text()); + if (listener) Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::curveMode2Changed_)); +} + +bool ToneCurve::curveMode2Changed_ () { + if (listener) listener->panelChanged (EvToneCurveMode2, toneCurveMode2->get_active_text()); return false; } diff --git a/rtgui/tonecurve.h b/rtgui/tonecurve.h index 3a35b68c9..bd0e8649a 100644 --- a/rtgui/tonecurve.h +++ b/rtgui/tonecurve.h @@ -41,19 +41,22 @@ class ToneCurve : public Gtk::VBox, public AdjusterListener, public FoldableTool Adjuster* hlcomprthresh; Adjuster* shcompr; Adjuster* contrast; - Adjuster* saturation; - MyComboBoxText* toneCurveMode; + Adjuster* saturation; + MyComboBoxText* toneCurveMode; + MyComboBoxText* toneCurveMode2; bool clipDirty, lastAuto; - sigc::connection autoconn, neutralconn, tcmodeconn; + sigc::connection autoconn, neutralconn, tcmodeconn, tcmode2conn; CurveEditorGroup* curveEditorG; + CurveEditorGroup* curveEditorG2; DiagonalCurveEditor* shape; + DiagonalCurveEditor* shape2; // used temporarily in eventing double nextExpcomp; - int nextBrightness; - int nextContrast; + int nextBrightness; + int nextContrast; int nextBlack; int nextHlcompr; int nextHlcomprthresh; @@ -61,6 +64,7 @@ class ToneCurve : public Gtk::VBox, public AdjusterListener, public FoldableTool public: ToneCurve (); + ~ToneCurve (); void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); @@ -80,9 +84,11 @@ class ToneCurve : public Gtk::VBox, public AdjusterListener, public FoldableTool void autoExpChanged (double expcomp, int bright, int contr, int black, int hlcompr, int hlcomprthresh); bool autoExpComputed_ (); void enableAll (); - void curveChanged (); - void curveModeChanged (); - bool curveModeChanged_ (); + void curveChanged (CurveEditor* ce); + void curveMode1Changed (); + bool curveMode1Changed_ (); + void curveMode2Changed (); + bool curveMode2Changed_ (); void expandCurve (bool isExpanded); bool isCurveExpanded (); void updateCurveBackgroundHistogram (LUTu & histToneCurve, LUTu & histLCurve, LUTu & histRed, LUTu & histGreen, LUTu & histBlue, LUTu & histLuma);