diff --git a/rtdata/languages/default b/rtdata/languages/default index 9ce03ed4b..5c29117c3 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -684,10 +684,13 @@ TP_ICM_SAVEREFERENCE;Save reference image for profiling TP_ICM_WORKINGPROFILE;Working Profile TP_IMPULSEDENOISE_LABEL;Impulse Noise Reduction TP_IMPULSEDENOISE_THRESH;Impulse NR Threshold +TP_LABCURVE_AVOIDCOLORCLIP;Avoid color clipping TP_LABCURVE_BRIGHTNESS;Brightness TP_LABCURVE_CONTRAST;Contrast TP_LABCURVE_CURVEEDITOR;Luminance Curve +TP_LABCURVE_ENABLESATLIMITER;Enable saturation limiter TP_LABCURVE_LABEL;Lab Curves +TP_LABCURVE_SATLIMIT;Saturation limit TP_LABCURVE_SATURATION;Saturation TP_LENSGEOM_AUTOCROP;Auto Crop TP_LENSGEOM_FILL;Auto Fill diff --git a/rtengine/curves.cc b/rtengine/curves.cc index 7229e25cb..2073e33a6 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -301,104 +301,84 @@ void Curve::getVal (const std::vector& t, std::vector& res) { res[i] = getVal(t[i]); } -double CurveFactory::centercontrast (double x, double b, double m) { - if (b==0) - return x; - if (b>0) { - if (x>m) - return m + (1.0-m) * tanh (b*(x-m)/(1.0-m)) / tanh (b); - else - return m + m * tanh (b*(x-m)/m) / tanh (b); - } - else { - if (x>m) - return 2.0*x - m - (1.0-m) * tanh (b*(x-m)/(1.0-m)) / tanh (b); - else - return 2.0*x - m - m * tanh (b*(x-m)/m) / tanh (b); - } -} - - - - void CurveFactory::complexsgnCurve (double satclip, double satcompr, double saturation, double colormult, const std::vector& curvePoints, int* outCurve, int skip) { +void CurveFactory::complexsgnCurve (double saturation, const std::vector& curvePoints, float* outCurve, int skip) { + + //colormult = chroma_scale for Lab manipulations + + // check if contrast curve is needed + bool needsaturation = (saturation<-0.0001 || saturation>0.0001); + + // curve without contrast + double* dcurve = new double[65536]; + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + std::vector satcurvePoints; + satcurvePoints.push_back((double)((CurveType)NURBS)); + if (saturation>0) { + satcurvePoints.push_back(0); //black point. Value in [0 ; 1] range + satcurvePoints.push_back(0); //black point. Value in [0 ; 1] range - //colormult = chroma_scale for Lab manipulations + satcurvePoints.push_back(0.25+saturation/500.0); //toe point + satcurvePoints.push_back(0.25-saturation/500.0); //value at toe point - // check if contrast curve is needed - bool needsaturation = (saturation<-0.0001 || saturation>0.0001); + satcurvePoints.push_back(0.75-saturation/500.0); //shoulder point + satcurvePoints.push_back(0.75+saturation/500.0); //value at shoulder point - // curve without contrast - double* dcurve = new double[65536]; + satcurvePoints.push_back(1); // white point + satcurvePoints.push_back(1); // value at white point + } else { + satcurvePoints.push_back(0); + satcurvePoints.push_back(-(saturation/200.0)); - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - std::vector satcurvePoints; - satcurvePoints.push_back((double)((CurveType)NURBS)); - if (saturation>0) { - satcurvePoints.push_back(0); //black point. Value in [0 ; 1] range - satcurvePoints.push_back(0); //black point. Value in [0 ; 1] range - - satcurvePoints.push_back(0.25+saturation/500.0); //toe point - satcurvePoints.push_back(0.25-saturation/500.0); //value at toe point - - satcurvePoints.push_back(0.75-saturation/500.0); //shoulder point - satcurvePoints.push_back(0.75+saturation/500.0); //value at shoulder point - - satcurvePoints.push_back(1); // white point - satcurvePoints.push_back(1); // value at white point - } else { - satcurvePoints.push_back(0); - satcurvePoints.push_back(-0.5*(saturation/100.0)); - - satcurvePoints.push_back(1); - satcurvePoints.push_back(1+saturation/200.0); - } - Curve* satcurve = NULL; - satcurve = new Curve (satcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000, - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - // create a curve if needed - Curve* tcurve = NULL; - if (curvePoints.size()>0 && curvePoints[0]!=0) - tcurve = new Curve (curvePoints, CURVES_MIN_POLY_POINTS/skip); - - for (int i=0; i<=0xffff; i+= i<0xffff-skip ? skip : 1 ) { - - // change to [0,1] range - double val = (double)i / 65535.0; - - // apply default multiplier (that is >1 if highlight recovery is on) - val *= colormult; - - // apply saturation curve - if (needsaturation) - val = satcurve->getVal (val); - - // apply custom/parametric/NURBS curve, if any - if (tcurve) { - val = tcurve->getVal (val); - } - - // store result in a temporary array - dcurve[i] = CLIPD(val); - } - delete tcurve; - - // if skip>1, let apply linear interpolation in the skipped points of the curve - int prev = 0; - for (int i=1; i<=0xffff-skip; i++) { - if (i%skip==0) { - prev+=skip; - continue; - } - dcurve[i] = ( dcurve[prev] * (skip - i%skip) + dcurve[prev+skip] * (i%skip) ) / skip; - } - - for (int i=0; i<=0xffff; i++) - outCurve[i] = (int) (65535.0 * dcurve[i]); - delete [] dcurve; - delete satcurve; + satcurvePoints.push_back(1); + satcurvePoints.push_back(1+saturation/200.0); } + Curve* satcurve = NULL; + satcurve = new Curve (satcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000, + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + // create a curve if needed + Curve* tcurve = NULL; + if (curvePoints.size()>0 && curvePoints[0]!=0) + tcurve = new Curve (curvePoints, CURVES_MIN_POLY_POINTS/skip); + + for (int i=0; i<=0xffff; i+= i<0xffff-skip ? skip : 1 ) { + + // change to [0,1] range + double val = (double)i / 65535.0; + + // apply saturation curve + if (needsaturation) + val = satcurve->getVal (val); + + // apply custom/parametric/NURBS curve, if any + if (tcurve) { + val = tcurve->getVal (val); + } + + // store result in a temporary array + dcurve[i] = CLIPD(val); + } + delete tcurve; + + // if skip>1, let apply linear interpolation in the skipped points of the curve + int prev = 0; + for (int i=1; i<=0xffff-skip; i++) { + if (i%skip==0) { + prev+=skip; + continue; + } + dcurve[i] = ( dcurve[prev] * (skip - i%skip) + dcurve[prev+skip] * (i%skip) ) / skip; + } + + for (int i=0; i<=0xffff; i++) { + outCurve[i] = (65535.0 * dcurve[i]); + //if (i%1000==0) printf("satcurve[%d]= %f\n",i,outCurve[i]); + } + delete [] dcurve; + delete satcurve; +} //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -567,7 +547,6 @@ double CurveFactory::centercontrast (double x, double b, double m) { // apply contrast enhancement for (int i=0; i<=0xffff; i++) { - //double val = centercontrast (dcurve[i], contr_b, avg); dcurve[i] = contrastcurve->getVal (dcurve[i]); } delete contrastcurve; diff --git a/rtengine/curves.h b/rtengine/curves.h index d20219888..e35b9cd7d 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -136,8 +136,6 @@ class CurveFactory { static void init (); static void cleanup (); - - static inline double centercontrast (double x, double b, double m); // standard srgb gamma and its inverse static inline double gamma2 (double x) { @@ -159,7 +157,7 @@ class CurveFactory { public: // static void updateCurve3 (int* curve, int* ohistogram, const std::vector& cpoints, double defmul, double ecomp, int black, double hlcompr, double shcompr, double br, double contr, double gamma_, bool igamma, int skip=1); static void complexCurve (double ecomp, double black, double hlcompr, double hlcomprthresh, double shcompr, double br, double contr, double defmul, double gamma_, bool igamma, const std::vector& curvePoints, unsigned int* histogram, float* hlCurve, float* shCurve, int* outCurve, unsigned int* outBeforeCCurveHistogram, int skip=1); - static void complexsgnCurve (double satclip, double satcompr, double saturation, double colormult, const std::vector& curvePoints, int* outCurve, int skip=1); + static void complexsgnCurve (double saturation, const std::vector& curvePoints, float* outCurve, int skip=1); }; diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 44ebd575c..555aeed81 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -172,9 +172,8 @@ void Crop::update (int todo, bool internal) { // apply luminance operations if (todo & (M_LUMINANCE+M_COLOR)) { - parent->ipf.luminanceCurve (laboCrop, labnCrop, parent->lumacurve, 0, croph); - parent->ipf.chrominanceCurve (laboCrop, labnCrop, 0, parent->chroma_acurve, 0, croph); - parent->ipf.chrominanceCurve (laboCrop, labnCrop, 1, parent->chroma_bcurve, 0, croph); + parent->ipf.luminanceCurve (laboCrop, labnCrop, parent->lumacurve); + parent->ipf.chrominanceCurve (laboCrop, labnCrop, parent->chroma_acurve, parent->chroma_bcurve); parent->ipf.colorCurve (labnCrop, labnCrop); diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 68456d6fe..2f93c627b 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -41,8 +41,8 @@ ImProcCoordinator::ImProcCoordinator () tonecurve = new int[65536]; lumacurve = new int[65536]; - chroma_acurve = new int[65536]; - chroma_bcurve = new int[65536]; + chroma_acurve = new float[65536]; + chroma_bcurve = new float[65536]; vhist16 = new unsigned int[65536]; lhist16 = new unsigned int[65536]; @@ -228,19 +228,18 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { if (todo & M_LUMACURVE) { CurveFactory::complexCurve (0.0, 0.0, 0.0, 0.0, 0.0, params.labCurve.brightness, params.labCurve.contrast, 0.0, 0.0, false, \ params.labCurve.lcurve, lhist16, dummy1, dummy2, lumacurve, bcLhist, scale==1 ? 1 : 16); - CurveFactory::complexsgnCurve (0.0, 100.0, params.labCurve.saturation, 1.0, params.labCurve.acurve, chroma_acurve, scale==1 ? 1 : 16); - CurveFactory::complexsgnCurve (0.0, 100.0, params.labCurve.saturation, 1.0, params.labCurve.bcurve, chroma_bcurve, scale==1 ? 1 : 16); + CurveFactory::complexsgnCurve (params.labCurve.saturation, params.labCurve.acurve, chroma_acurve, scale==1 ? 1 : 16); + CurveFactory::complexsgnCurve (params.labCurve.saturation, params.labCurve.bcurve, chroma_bcurve, scale==1 ? 1 : 16); } if (todo & (M_LUMINANCE+M_COLOR) ) { progress ("Applying Luminance Curve...",100*readyphase/numofphases); - ipf.luminanceCurve (oprevl, nprevl, lumacurve, 0, pH); + ipf.luminanceCurve (oprevl, nprevl, lumacurve); readyphase++; progress ("Applying Color Boost...",100*readyphase/numofphases); - ipf.chrominanceCurve (oprevl, nprevl, 0, chroma_acurve, 0, pH); - ipf.chrominanceCurve (oprevl, nprevl, 1, chroma_bcurve, 0, pH); + ipf.chrominanceCurve (oprevl, nprevl, chroma_acurve, chroma_bcurve); ipf.colorCurve (nprevl, nprevl); readyphase++; diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 041783440..0bd5facaf 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -69,8 +69,8 @@ class ImProcCoordinator : public StagedImageProcessor { int *tonecurve; int *lumacurve; - int *chroma_acurve; - int *chroma_bcurve; + float *chroma_acurve; + float *chroma_bcurve; unsigned int *vhist16; unsigned int *lhist16; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index a0e98f2d6..7427eb466 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -249,6 +249,7 @@ void ImProcFunctions::firstAnalysis (Image16* original, const ProcParams* params histogram[i] += hist[j][i]; chroma_scale = 32768*32768 / (3*chroma_radius); + //printf ("chroma_radius= %d chroma_scale= %d\n",chroma_radius,chroma_scale); delete [] cr; for (int i=0; i0 ? (float)hltonecurve[r]/r : (float)hltonecurve[1]); - //float gtonefactor = (g>0 ? (float)hltonecurve[g]/g : (float)hltonecurve[1]); - //float btonefactor = (b>0 ? (float)hltonecurve[b]/b : (float)hltonecurve[1]); - //float tonefactor = (rtonefactor+gtonefactor+btonefactor)/3; - //float tonefactor = (0.299*rtonefactor+0.587*gtonefactor+0.114*btonefactor); - - //float tonefactor=(my_tonecurve[r]+my_tonecurve[g]+my_tonecurve[b])/3; + float tonefactor=(hltonecurve[r]+hltonecurve[g]+hltonecurve[b])/3; r = (r*tonefactor); @@ -434,30 +429,102 @@ void ImProcFunctions::rgbProc (Image16* working, LabImage* lab, float* hltonecur //delete [] my_tonecurve; } -void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, int* curve, int row_from, int row_to) { +void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, int* curve) { int W = lold->W; - //int H = lold->H; - for (int i=row_from; iH; + for (int i=0; iL[i][j] = curve[lold->L[i][j]]; } -void ImProcFunctions::chrominanceCurve (LabImage* lold, LabImage* lnew, int channel, int* curve, int row_from, int row_to) { +void ImProcFunctions::chrominanceCurve (LabImage* lold, LabImage* lnew, float* acurve, float* bcurve) { int W = lold->W; - //int H = lold->H; - if (channel==0) { - for (int i=row_from; ia[i][j] = curve[lold->a[i][j]+32768]-32768; - } - if (channel==1) { - for (int i=row_from; ib[i][j] = curve[lold->b[i][j]+32768]-32768; - } + int H = lold->H; + /*for (int i=0; ia[i][j] = acurve[lold->a[i][j]+32768]-32768; + lnew->b[i][j] = bcurve[lold->b[i][j]+32768]-32768; + }*/ + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + double* cmultiplier = new double [181021]; + + double c = (0.5+2*params->labCurve.saturation/500.0) / (0.5-2*params->labCurve.saturation/500.0); + + + if (params->labCurve.enable_saturationlimiter && c>1) { + // re-generate color multiplier lookup table + double d = params->labCurve.saturationlimit * chroma_scale / 3.0; + double alpha = 0.5; + double threshold1 = alpha * d; + double threshold2 = c*d*(alpha+1.0) - d; + for (int i=0; i<=181020; i++) { // lookup table stores multipliers with a 0.25 chrominance resolution + double chrominance = (double)i/4; + if (chrominance < threshold1) + cmultiplier[i] = c; + else if (chrominance < d) + cmultiplier[i] = (c / (2.0*d*(alpha-1.0)) * (chrominance-d)*(chrominance-d) + c*d/2.0 * (alpha+1.0) ) / chrominance; + else if (chrominance < threshold2) + cmultiplier[i] = (1.0 / (2.0*d*(c*(alpha+1.0)-2.0)) * (chrominance-d)*(chrominance-d) + c*d/2.0 * (alpha+1.0) ) / chrominance; + else + cmultiplier[i] = 1.0; + } + } + + +#pragma omp parallel for if (multiThread) + for (int i=0; ia[i][j]; + int ob = lold->b[i][j]; + + int atmp = (int)acurve[oa+32768]-32768; + int btmp = (int)bcurve[ob+32768]-32768; + + int chroma = (int)(4.0 * sqrt(SQR(oa) + SQR(ob))); + double wanted_c = c; + if (params->labCurve.enable_saturationlimiter && c>1) { + wanted_c = cmultiplier [MIN(chroma,181020)]; + } + + double real_c = wanted_c; + if (wanted_c >= 1.0 && params->labCurve.avoidclip) { + double cclip = 100000; + double cr = tightestroot ((double)lnew->L[i][j]/655.35, (double)(oa)/chroma_scale, (double)(ob)/chroma_scale, 3.079935, -1.5371515, -0.54278342); + double cg = tightestroot ((double)lnew->L[i][j]/655.35, (double)(oa)/chroma_scale, (double)(ob)/chroma_scale, -0.92123418, 1.87599, 0.04524418); + double cb = tightestroot ((double)lnew->L[i][j]/655.35, (double)(oa)/chroma_scale, (double)(ob)/chroma_scale, 0.052889682, -0.20404134, 1.15115166); + if (cr>1.0 && cr1.0 && cg1.0 && cb chroma) { + lnew->a[i][j] = CLIPTO(nna,-32000,32000); + lnew->b[i][j] = CLIPTO(nnb,-32000,32000); + } else { + lnew->a[i][j] = CLIPTO(atmp,-32000,32000); + lnew->b[i][j] = CLIPTO(btmp,-32000,32000); + } + } + + delete [] cmultiplier; + + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + } #include "cubic.cc" diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 734bf17bc..3c6ecbb17 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -82,8 +82,8 @@ class ImProcFunctions { void firstAnalysis (Image16* working, const ProcParams* params, unsigned int* vhist16, double gamma); void rgbProc (Image16* working, LabImage* lab, float* hltonecurve, float* shtonecurve, int* tonecurve, SHMap* shmap, /*float defmul,*/ int sat); - void luminanceCurve (LabImage* lold, LabImage* lnew, int* curve, int row_from, int row_to); - void chrominanceCurve (LabImage* lold, LabImage* lnew, int channel, int* curve, int row_from, int row_to); + void luminanceCurve (LabImage* lold, LabImage* lnew, int* curve); + void chrominanceCurve (LabImage* lold, LabImage* lnew, float* acurve, float* bcurve); void colorCurve (LabImage* lold, LabImage* lnew); void sharpening (LabImage* lab, unsigned short** buffer); void lumadenoise (LabImage* lab, int** buffer); diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 8bda34cdf..026db24da 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -130,8 +130,11 @@ enum ProcEvent { EvDefringeRadius=105, EvDefringeThreshold=106, EvHLComprThreshold=107, + EvLAvoidClip=108, + EvLSatLimiter=109, + EvLSatLimit=110, - NUMOFEVENTS=108 + NUMOFEVENTS=111 }; } #endif diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 41b86f6c9..d94bacdd7 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -62,6 +62,9 @@ void ProcParams::setDefaults () { labCurve.brightness = 0; labCurve.contrast = 0; labCurve.saturation = 0; + labCurve.avoidclip = false; + labCurve.enable_saturationlimiter = false; + labCurve.saturationlimit = 50; labCurve.lcurve.clear (); labCurve.acurve.clear (); labCurve.bcurve.clear (); @@ -253,6 +256,9 @@ int ProcParams::save (Glib::ustring fname) const { keyFile.set_integer ("Luminance Curve", "Brightness", labCurve.brightness); keyFile.set_integer ("Luminance Curve", "Contrast", labCurve.contrast); keyFile.set_integer ("Luminance Curve", "Saturation", labCurve.saturation); + keyFile.set_boolean ("Luminance Curve", "AvoidColorClipping", labCurve.avoidclip); + keyFile.set_boolean ("Luminance Curve", "SaturationLimiter", labCurve.enable_saturationlimiter); + keyFile.set_double ("Luminance Curve", "SaturationLimit", labCurve.saturationlimit); Glib::ArrayHandle lcurve = labCurve.lcurve; Glib::ArrayHandle acurve = labCurve.acurve; Glib::ArrayHandle bcurve = labCurve.bcurve; @@ -525,7 +531,10 @@ if (keyFile.has_group ("Luminance Curve")) { if (keyFile.has_key ("Luminance Curve", "Brightness")) labCurve.brightness = keyFile.get_integer ("Luminance Curve", "Brightness"); if (keyFile.has_key ("Luminance Curve", "Contrast")) labCurve.contrast = keyFile.get_integer ("Luminance Curve", "Contrast"); if (keyFile.has_key ("Luminance Curve", "Saturation")) labCurve.saturation = keyFile.get_integer ("Luminance Curve", "Saturation"); - if (version>200) + if (keyFile.has_key ("Luminance Curve", "AvoidColorClipping")) labCurve.avoidclip = keyFile.get_boolean ("Luminance Curve", "AvoidColorClipping"); + if (keyFile.has_key ("Luminance Curve", "SaturationLimiter")) labCurve.enable_saturationlimiter= keyFile.get_boolean ("Luminance Curve", "SaturationLimiter"); + if (keyFile.has_key ("Luminance Curve", "SaturationLimit")) labCurve.saturationlimit = keyFile.get_double ("Luminance Curve", "SaturationLimit"); + if (version>200) if (keyFile.has_key ("Luminance Curve", "LCurve")) labCurve.lcurve = keyFile.get_double_list ("Luminance Curve", "LCurve"); if (keyFile.has_key ("Luminance Curve", "aCurve")) labCurve.acurve = keyFile.get_double_list ("Luminance Curve", "aCurve"); if (keyFile.has_key ("Luminance Curve", "bCurve")) labCurve.bcurve = keyFile.get_double_list ("Luminance Curve", "bCurve"); @@ -862,6 +871,9 @@ bool ProcParams::operator== (const ProcParams& other) { && labCurve.brightness == other.labCurve.brightness && labCurve.contrast == other.labCurve.contrast && labCurve.saturation == other.labCurve.saturation + && labCurve.avoidclip == other.labCurve.avoidclip + && labCurve.enable_saturationlimiter == other.labCurve.enable_saturationlimiter + && labCurve.saturationlimit == other.labCurve.saturationlimit && sharpening.enabled == other.sharpening.enabled && sharpening.radius == other.sharpening.radius && sharpening.amount == other.sharpening.amount diff --git a/rtengine/procparams.h b/rtengine/procparams.h index e9c7770f4..f414ffa33 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -56,6 +56,9 @@ class LCurveParams { int brightness; int contrast; int saturation; + bool avoidclip; + bool enable_saturationlimiter; + double saturationlimit; }; /** diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 801bcdedc..23d86c553 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -128,5 +128,8 @@ DEFRINGE, // EvDefringeEnabled, DEFRINGE, // EvDefringeRadius, DEFRINGE, // EvDefringeThreshold, RGBCURVE, // EvHLComprThreshold, +LUMINANCECURVE, // EvCBAvoidClip, +LUMINANCECURVE, // EvCBSatLimiter, +LUMINANCECURVE, // EvCBSatLimit, }; diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 63f3ae304..14f5d56db 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -716,11 +716,10 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei // luminance processing CurveFactory::complexCurve (0.0, 0.0, 0.0, 0.0, 0.0, params.labCurve.brightness, params.labCurve.contrast, 0.0, 0.0, false, params.labCurve.lcurve, hist16, curve1, curve2, curve, NULL, 16); - ipf.luminanceCurve (labView, labView, curve, 0, fh); - CurveFactory::complexsgnCurve (0.0, 100.0, params.labCurve.saturation, 1.0, params.labCurve.acurve, curve, 16); - ipf.chrominanceCurve (labView, labView, 0, curve, 0, fh); - CurveFactory::complexsgnCurve (0.0, 100.0, params.labCurve.saturation, 1.0, params.labCurve.bcurve, curve, 16); - ipf.chrominanceCurve (labView, labView, 1, curve, 0, fh); + ipf.luminanceCurve (labView, labView, curve); + CurveFactory::complexsgnCurve (params.labCurve.saturation, params.labCurve.acurve, curve1, 16); + CurveFactory::complexsgnCurve (params.labCurve.saturation, params.labCurve.bcurve, curve2, 16); + ipf.chrominanceCurve (labView, labView, curve1, curve2); delete [] curve1; delete [] curve2; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 1c9c62a91..5454685ff 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -152,11 +152,10 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p // luminance processing CurveFactory::complexCurve (0.0, 0.0, 0.0, 0.0, 0.0, params.labCurve.brightness, params.labCurve.contrast, 0.0, 0.0, false, params.labCurve.lcurve, hist16, curve1, curve2, curve, NULL); - ipf.luminanceCurve (labView, labView, curve, 0, fh); - CurveFactory::complexsgnCurve (0.0, 100.0, params.labCurve.saturation, 1.0, params.labCurve.acurve, curve, 1); - ipf.chrominanceCurve (labView, labView, 0, curve, 0, fh); - CurveFactory::complexsgnCurve (0.0, 100.0, params.labCurve.saturation, 1.0, params.labCurve.bcurve, curve, 1); - ipf.chrominanceCurve (labView, labView, 1, curve, 0, fh); + ipf.luminanceCurve (labView, labView, curve); + CurveFactory::complexsgnCurve (params.labCurve.saturation, params.labCurve.acurve, curve1, 1); + CurveFactory::complexsgnCurve (params.labCurve.saturation, params.labCurve.bcurve, curve2, 1); + ipf.chrominanceCurve (labView, labView, curve1, curve2); ipf.impulsedenoise (labView); ipf.defringe (labView); diff --git a/rtgui/labcurve.cc b/rtgui/labcurve.cc index be30e66df..197e861eb 100644 --- a/rtgui/labcurve.cc +++ b/rtgui/labcurve.cc @@ -53,14 +53,31 @@ LCurve::LCurve () : ToolPanel(), brAdd(false), contrAdd(false), satAdd(false) { pack_start (*curveEditorG, Gtk::PACK_SHRINK, 4); - //curveEditorG->show(); - brightness->setAdjusterListener (this); contrast->setAdjusterListener (this); saturation->setAdjusterListener (this); - - //channel->signal_changed().connect( sigc::mem_fun(*this, &LCurve::channel) ); - + + + //%%%%%%%%%%%%%%%%%% + pack_start (*Gtk::manage (new Gtk::HSeparator())); + + avoidclip = Gtk::manage (new Gtk::CheckButton (M("TP_LABCURVE_AVOIDCOLORCLIP"))); + + pack_start (*avoidclip); + pack_start (*Gtk::manage (new Gtk::HSeparator())); + + enablelimiter = Gtk::manage (new Gtk::CheckButton (M("TP_LABCURVE_ENABLESATLIMITER"))); + pack_start (*enablelimiter); + + saturationlimiter = new Adjuster (M("TP_LABCURVE_SATLIMIT"), 0, 200, 0.1, 100); + saturationlimiter->show (); + saturationlimiter->reference (); + + //saturation->setAdjusterListener (this); + saturationlimiter->setAdjusterListener (this); + acconn = avoidclip->signal_toggled().connect( sigc::mem_fun(*this, &LCurve::avoidclip_toggled) ); + elconn = enablelimiter->signal_toggled().connect( sigc::mem_fun(*this, &LCurve::enablelimiter_toggled) ); + //%%%%%%%%%%%%%%%%%%% } @@ -76,6 +93,12 @@ void LCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { brightness->setEditedState (pedited->labCurve.brightness ? Edited : UnEdited); contrast->setEditedState (pedited->labCurve.contrast ? Edited : UnEdited); saturation->setEditedState (pedited->labCurve.saturation ? Edited : UnEdited); + + //%%%%%%%%%%%%%%%%%%%%%% + saturationlimiter->setEditedState (pedited->labCurve.saturationlimit ? Edited : UnEdited); + avoidclip->set_inconsistent (!pedited->labCurve.avoidclip); + enablelimiter->set_inconsistent (!pedited->labCurve.enable_saturationlimiter); + //%%%%%%%%%%%%%%%%%%%%%% lshape->setUnChanged (!pedited->labCurve.lcurve); ashape->setUnChanged (!pedited->labCurve.acurve); @@ -86,6 +109,23 @@ void LCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { brightness->setValue (pp->labCurve.brightness); contrast->setValue (pp->labCurve.contrast); saturation->setValue (pp->labCurve.saturation); + + //%%%%%%%%%%%%%%%%%%%%%% + saturationlimiter->setValue (pp->labCurve.saturationlimit); + acconn.block (true); + avoidclip->set_active (pp->labCurve.avoidclip); + acconn.block (false); + elconn.block (true); + enablelimiter->set_active (pp->labCurve.enable_saturationlimiter); + elconn.block (false); + + removeIfThere (this, saturationlimiter, false); + if (enablelimiter->get_active () || enablelimiter->get_inconsistent()) + pack_start (*saturationlimiter); + + lastACVal = pp->labCurve.avoidclip; + lastELVal = pp->labCurve.enable_saturationlimiter; + //%%%%%%%%%%%%%%%%%%%%%% lshape->setCurve (pp->labCurve.lcurve); ashape->setCurve (pp->labCurve.acurve); @@ -100,6 +140,12 @@ void LCurve::write (ProcParams* pp, ParamsEdited* pedited) { pp->labCurve.brightness = brightness->getValue (); pp->labCurve.contrast = (int)contrast->getValue (); pp->labCurve.saturation = (int)saturation->getValue (); + + //%%%%%%%%%%%%%%%%%%%%%% + pp->labCurve.avoidclip = avoidclip->get_active (); + pp->labCurve.enable_saturationlimiter = enablelimiter->get_active (); + pp->labCurve.saturationlimit = saturationlimiter->getValue (); + //%%%%%%%%%%%%%%%%%%%%%% pp->labCurve.lcurve = lshape->getCurve (); pp->labCurve.acurve = ashape->getCurve (); @@ -109,6 +155,12 @@ void LCurve::write (ProcParams* pp, ParamsEdited* pedited) { pedited->labCurve.brightness = brightness->getEditedState (); pedited->labCurve.contrast = contrast->getEditedState (); pedited->labCurve.saturation = saturation->getEditedState (); + + //%%%%%%%%%%%%%%%%%%%%%% + pedited->labCurve.avoidclip = !avoidclip->get_inconsistent(); + pedited->labCurve.enable_saturationlimiter = !enablelimiter->get_inconsistent(); + pedited->labCurve.saturationlimit = saturationlimiter->getEditedState (); + //%%%%%%%%%%%%%%%%%%%%%% pedited->labCurve.lcurve = !lshape->isUnChanged (); pedited->labCurve.acurve = !ashape->isUnChanged (); @@ -121,20 +173,77 @@ void LCurve::setDefaults (const ProcParams* defParams, const ParamsEdited* pedit brightness->setDefault (defParams->labCurve.brightness); contrast->setDefault (defParams->labCurve.contrast); saturation->setDefault (defParams->labCurve.saturation); + saturationlimiter->setDefault (defParams->labCurve.saturationlimit); if (pedited) { brightness->setDefaultEditedState (pedited->labCurve.brightness ? Edited : UnEdited); contrast->setDefaultEditedState (pedited->labCurve.contrast ? Edited : UnEdited); saturation->setDefaultEditedState (pedited->labCurve.saturation ? Edited : UnEdited); + saturationlimiter->setDefaultEditedState (pedited->labCurve.saturationlimit ? Edited : UnEdited); } else { brightness->setDefaultEditedState (Irrelevant); contrast->setDefaultEditedState (Irrelevant); saturation->setDefaultEditedState (Irrelevant); + saturationlimiter->setDefaultEditedState (Irrelevant); } } +//%%%%%%%%%%%%%%%%%%%%%% +//Clipping control changed +void LCurve::avoidclip_toggled () { + + if (batchMode) { + if (avoidclip->get_inconsistent()) { + avoidclip->set_inconsistent (false); + acconn.block (true); + avoidclip->set_active (false); + acconn.block (false); + } + else if (lastACVal) + avoidclip->set_inconsistent (true); + + lastACVal = avoidclip->get_active (); + } + + if (listener) { + if (avoidclip->get_active ()) + listener->panelChanged (EvLAvoidClip, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvLAvoidClip, M("GENERAL_DISABLED")); + } +} + +void LCurve::enablelimiter_toggled () { + + if (batchMode) { + if (enablelimiter->get_inconsistent()) { + enablelimiter->set_inconsistent (false); + elconn.block (true); + enablelimiter->set_active (false); + elconn.block (false); + } + else if (lastELVal) + enablelimiter->set_inconsistent (true); + + lastELVal = enablelimiter->get_active (); + } + + removeIfThere (this, saturationlimiter, false); + if (enablelimiter->get_active () || enablelimiter->get_inconsistent()) + pack_start (*saturationlimiter); + + if (listener) { + if (enablelimiter->get_active ()) + listener->panelChanged (EvLSatLimiter, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvLSatLimiter, M("GENERAL_DISABLED")); + } +} +//%%%%%%%%%%%%%%%%%%%%%% + + /* * Curve listener * @@ -170,6 +279,8 @@ void LCurve::adjusterChanged (Adjuster* a, double newval) { listener->panelChanged (EvLContrast, costr); else if (a==saturation) listener->panelChanged (EvLSaturation, costr); + else if (a==saturationlimiter) + listener->panelChanged (EvLSatLimiter, costr); } //attempt to hide unused channels @@ -198,6 +309,7 @@ void LCurve::setBatchMode (bool batchMode) { brightness->showEditedCB (); contrast->showEditedCB (); saturation->showEditedCB (); + saturationlimiter->showEditedCB (); curveEditorG->setBatchMode (batchMode); } @@ -210,6 +322,7 @@ void LCurve::setAdjusterBehavior (bool bradd, bool contradd, bool satadd) { contrast->setLimits (-100, 100, 1, 0); if ((!satAdd && satadd) || (satAdd && !satadd)) saturation->setLimits (-100, 100, 1, 0); + brAdd = bradd; contrAdd = contradd; diff --git a/rtgui/labcurve.h b/rtgui/labcurve.h index ce404f959..2f3579179 100644 --- a/rtgui/labcurve.h +++ b/rtgui/labcurve.h @@ -37,6 +37,15 @@ class LCurve : public Gtk::VBox, public AdjusterListener, public ToolPanel, publ CurveEditor* lshape; CurveEditor* ashape; CurveEditor* bshape; + + //%%%%%%%%%%%%%%%% + Gtk::CheckButton* avoidclip; + Gtk::CheckButton* enablelimiter; + Adjuster* saturationlimiter; + bool cbAdd; + sigc::connection acconn, elconn; + bool lastACVal, lastELVal; + //%%%%%%%%%%%%%%%% bool brAdd, contrAdd, satAdd; @@ -53,6 +62,8 @@ class LCurve : public Gtk::VBox, public AdjusterListener, public ToolPanel, publ void curveChanged (CurveEditor* ce); void adjusterChanged (Adjuster* a, double newval); + void avoidclip_toggled (); + void enablelimiter_toggled (); void updateCurveBackgroundHistogram (unsigned* hist); }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index c5719582d..ff920fd78 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -45,6 +45,9 @@ void ParamsEdited::set (bool v) { labCurve.brightness = v; labCurve.contrast = v; labCurve.saturation = v; + labCurve.avoidclip = v; + labCurve.enable_saturationlimiter = v; + labCurve.saturationlimit = v; sharpening.enabled = v; sharpening.radius = v; sharpening.amount = v; @@ -198,6 +201,9 @@ void ParamsEdited::initFrom (const std::vector labCurve.brightness = labCurve.brightness && p.labCurve.brightness == other.labCurve.brightness; labCurve.contrast = labCurve.contrast && p.labCurve.contrast == other.labCurve.contrast; labCurve.saturation = labCurve.saturation && p.labCurve.saturation == other.labCurve.saturation; + labCurve.avoidclip = labCurve.avoidclip && p.labCurve.avoidclip == other.labCurve.avoidclip; + labCurve.enable_saturationlimiter = labCurve.enable_saturationlimiter && p.labCurve.enable_saturationlimiter == other.labCurve.enable_saturationlimiter; + labCurve.saturationlimit = labCurve.saturationlimit && p.labCurve.saturationlimit == other.labCurve.saturationlimit; sharpening.enabled = sharpening.enabled && p.sharpening.enabled == other.sharpening.enabled; sharpening.radius = sharpening.radius && p.sharpening.radius == other.sharpening.radius; sharpening.amount = sharpening.amount && p.sharpening.amount == other.sharpening.amount; @@ -345,6 +351,9 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if (labCurve.brightness) toEdit.labCurve.brightness = options.baBehav[ADDSET_LC_BRIGHTNESS] ? toEdit.labCurve.brightness + mods.labCurve.brightness : mods.labCurve.brightness; if (labCurve.contrast) toEdit.labCurve.contrast = options.baBehav[ADDSET_LC_CONTRAST] ? toEdit.labCurve.contrast + mods.labCurve.contrast : mods.labCurve.contrast; if (labCurve.saturation) toEdit.labCurve.saturation = options.baBehav[ADDSET_LC_SATURATION] ? toEdit.labCurve.saturation + mods.labCurve.saturation : mods.labCurve.saturation; + if (labCurve.avoidclip) toEdit.labCurve.avoidclip = mods.labCurve.avoidclip; + if (labCurve.enable_saturationlimiter)toEdit.labCurve.enable_saturationlimiter = mods.labCurve.enable_saturationlimiter; + if (labCurve.saturationlimit) toEdit.labCurve.saturationlimit = mods.labCurve.saturationlimit; if (sharpening.enabled) toEdit.sharpening.enabled = mods.sharpening.enabled; if (sharpening.radius) toEdit.sharpening.radius = mods.sharpening.radius; if (sharpening.amount) toEdit.sharpening.amount = options.baBehav[ADDSET_SHARP_AMOUNT] ? toEdit.sharpening.amount + mods.sharpening.amount : mods.sharpening.amount; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 3778a7546..8004a90af 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -46,6 +46,9 @@ class LCurveParamsEdited { bool brightness; bool contrast; bool saturation; + bool avoidclip; + bool enable_saturationlimiter; + bool saturationlimit; bool lcurve; bool acurve; bool bcurve; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 18d8d987b..d09e284ac 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -69,17 +69,17 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { addPanel (colorPanel, chmixer, M("TP_CHMIXER_LABEL")); toolPanels.push_back (chmixer); addPanel (exposurePanel, shadowshighlights, M("TP_SHADOWSHLIGHTS_LABEL")); toolPanels.push_back (shadowshighlights); addPanel (detailsPanel, sharpening, M("TP_SHARPENING_LABEL")); toolPanels.push_back (sharpening); - addPanel (colorPanel, colorboost, M("TP_COLORBOOST_LABEL")); toolPanels.push_back (colorboost); - addPanel (colorPanel, colorshift, M("TP_COLORSHIFT_LABEL")); toolPanels.push_back (colorshift); + //addPanel (colorPanel, colorboost, M("TP_COLORBOOST_LABEL")); toolPanels.push_back (colorboost); + //addPanel (colorPanel, colorshift, M("TP_COLORSHIFT_LABEL")); toolPanels.push_back (colorshift); addPanel (colorPanel, hsvequalizer, M("TP_HSVEQUALIZER_LABEL")); toolPanels.push_back (hsvequalizer); addPanel (exposurePanel, lcurve, M("TP_LABCURVE_LABEL")); toolPanels.push_back (lcurve); addPanel (detailsPanel, impulsedenoise, M("TP_IMPULSEDENOISE_LABEL")); toolPanels.push_back (impulsedenoise); - addPanel (detailsPanel, lumadenoise, M("TP_LUMADENOISE_LABEL")); toolPanels.push_back (lumadenoise); - addPanel (detailsPanel, colordenoise, M("TP_COLORDENOISE_LABEL")); toolPanels.push_back (colordenoise); + //addPanel (detailsPanel, lumadenoise, M("TP_LUMADENOISE_LABEL")); toolPanels.push_back (lumadenoise); + //addPanel (detailsPanel, colordenoise, M("TP_COLORDENOISE_LABEL")); toolPanels.push_back (colordenoise); addPanel (detailsPanel, dirpyrdenoise, M("TP_DIRPYRDENOISE_LABEL")); toolPanels.push_back (dirpyrdenoise); addPanel (detailsPanel, defringe, M("TP_DEFRINGE_LABEL")); toolPanels.push_back (defringe); addPanel (detailsPanel, dirpyrequalizer, M("TP_DIRPYREQUALIZER_LABEL")); toolPanels.push_back (dirpyrequalizer); - addPanel (detailsPanel, equalizer, M("TP_EQUALIZER_LABEL")); toolPanels.push_back (equalizer); + //addPanel (detailsPanel, equalizer, M("TP_EQUALIZER_LABEL")); toolPanels.push_back (equalizer); addPanel (transformPanel, crop, M("TP_CROP_LABEL")); toolPanels.push_back (crop); addPanel (transformPanel, resize, M("TP_RESIZE_LABEL")); toolPanels.push_back (resize); addPanel (transformPanel, lensgeom, M("TP_LENSGEOM_LABEL")); toolPanels.push_back (lensgeom);