From 71b74bbfd28521d1cc1d770ec61d649316655bfd Mon Sep 17 00:00:00 2001 From: ghorvath Date: Fri, 16 Apr 2010 08:44:41 +0000 Subject: [PATCH] New curve editor, first batch (parametric curves, overlaid histogram in curve area) --- CMakeLists.txt | 2 +- rtengine/curves.cc | 708 +++++++++++--------------------- rtengine/curves.h | 101 ++--- rtengine/dcraw.cc | 2 +- rtengine/imagesource.h | 2 +- rtengine/improccoordinator.cc | 8 +- rtengine/improccoordinator.h | 6 +- rtengine/improcfun.cc | 12 +- rtengine/improcfun.h | 6 +- rtengine/init.cc | 2 +- rtengine/procparams.cc | 25 +- rtengine/procparams.h | 37 +- rtengine/rawimagesource.cc | 2 +- rtengine/rawimagesource.h | 2 +- rtengine/rtengine.h | 2 +- rtengine/rtthumbnail.cc | 15 +- rtengine/rtthumbnail.h | 2 +- rtengine/simpleprocess.cc | 9 +- rtengine/stdimagesource.cc | 2 +- rtengine/stdimagesource.h | 2 +- rtgui/CMakeLists.txt | 2 +- rtgui/addsetids.h | 28 ++ rtgui/batchtoolpanelcoord.cc | 66 +-- rtgui/curveeditor.cc | 305 +++++++++++--- rtgui/curveeditor.h | 46 ++- rtgui/curvelistener.h | 28 ++ rtgui/editorpanel.cc | 7 +- rtgui/editorpanel.h | 6 +- rtgui/histogrampanel.cc | 1 + rtgui/histogrampanel.h | 3 +- rtgui/imagearea.cc | 2 +- rtgui/lcurve.cc | 105 ++--- rtgui/lcurve.h | 16 +- rtgui/mycurve.cc | 731 ++++++++++++++++++---------------- rtgui/mycurve.h | 33 +- rtgui/options.cc | 5 +- rtgui/paramsedited.cc | 92 ++--- rtgui/paramsedited.h | 17 +- rtgui/preferences.cc | 68 ++-- rtgui/preferences.h | 5 +- rtgui/shcselector.cc | 166 ++++++++ rtgui/shcselector.h | 61 +++ rtgui/tonecurve.cc | 43 +- rtgui/tonecurve.h | 16 +- rtgui/toolpanelcoord.cc | 19 +- rtgui/toolpanelcoord.h | 9 +- 46 files changed, 1579 insertions(+), 1248 deletions(-) create mode 100644 rtgui/addsetids.h create mode 100644 rtgui/curvelistener.h create mode 100644 rtgui/shcselector.cc create mode 100644 rtgui/shcselector.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ed2103208..e771de2a7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 2.6) -option (WITH_RAWZOR "Build with Rawzor support" ON) +option (WITH_RAWZOR "Build with Rawzor support" OFF) add_subdirectory (rtexif) add_subdirectory (rtengine) diff --git a/rtengine/curves.cc b/rtengine/curves.cc index aff9e5192..7e53b23ab 100755 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -24,264 +24,154 @@ #include #include +#undef CLIPD +#define CLIPD(a) ((a)>0.0?((a)<1.0?(a):1.0):0.0) + + namespace rtengine { -Curve::Curve (const char* iname, const char* descr) : islinear(false), isempty(false) { +Curve::Curve (const std::vector& p) : x(NULL), y(NULL), ypp(NULL) { - ypp = NULL; - name = iname; - char* buffer = new char[strlen(descr)+1]; - strcpy (buffer, descr); - char* token = strtok (buffer, ",; \t\n"); - std::vector xv; - std::vector yv; - while (token) { - double xd = atof (token); - token = strtok (NULL, ",; \t\n"); - if (token) { - double yd = atof (token); - xv.push_back (xd); - yv.push_back (yd); + if (p.size()<3) { + kind = 0; } - token = strtok (NULL, ",; \t\n"); - } - N = xv.size (); - x = new double[N]; - y = new double[N]; - for (int i=0; i& p) { - - x = NULL; - y = NULL; - ypp = NULL; - name = "custom"; - isempty = true; - N = p.size()/2; - if (N<2) - return; - int ix = 0; - islinear = p[ix++]<0; - x = new double[N]; - y = new double[N]; - for (int i=0; i= 0; --k) - ypp[k] = ypp[k] * ypp[k + 1] + u[k]; + ypp[N - 1] = 0.0; + for (int k = N - 2; k >= 0; --k) + ypp[k] = ypp[k] * ypp[k + 1] + u[k]; - delete [] u; - + delete [] u; } double Curve::getVal (double t) { -// -// Determine the interval [ T(I), T(I+1) ] that contains TVAL. -// Values below T[0] or above T[N-1] use extrapolation. -// - if (isempty) - return t; - if (t>x[N-1]) - return y[N-1]; - else if (t 1){ - int k = (k_hi + k_lo) / 2; - if (x[k] > t) - k_hi = k; - else - k_lo = k; - } - - double h = x[k_hi] - x[k_lo]; - if (islinear) - return y[k_lo] + (t - x[k_lo]) * ( y[k_hi] - y[k_lo] ) / h; - else { - double a = (x[k_hi] - t) / h; - double b = (t - x[k_lo]) / h; - return a*y[k_lo] + b*y[k_hi] + ((a*a*a - a)*ypp[k_lo] + (b*b*b - b)*ypp[k_hi]) * (h*h)/6.0; - } - -/* - if (t>x[N-1]) - return y[N-1]; - else if (tx[N-1]) + return y[N-1]; + else if (t 1){ + int k = (k_hi + k_lo) / 2; + if (x[k] > t) + k_hi = k; + else + k_lo = k; + } + + double h = x[k_hi] - x[k_lo]; + if (kind==-1) + return y[k_lo] + (t - x[k_lo]) * ( y[k_hi] - y[k_lo] ) / h; + else if (kind==1) { + double a = (x[k_hi] - t) / h; + double b = (t - x[k_lo]) / h; + double r = a*y[k_lo] + b*y[k_hi] + ((a*a*a - a)*ypp[k_lo] + (b*b*b - b)*ypp[k_hi]) * (h*h)/6.0; + if (r < 0.0) return 0.0; + if (r > 1.0) return 1.0; + return r; + } + else + return t; + } } -Glib::ustring Curve::getName () { +void Curve::getVal (const std::vector& t, std::vector& res) { + +// TODO!!!! can be made much faster!!! Binary search of getVal(double) at each point can be avoided - return name; + res.resize (t.size()); + for (int i=0; i CurveFactory::curves; - -/*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*(m-x)/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*(m-x)/m) / tanh (b); - } -} -*/ - double CurveFactory::centercontrast (double x, double b, double m) { if (b==0) @@ -299,103 +189,7 @@ double CurveFactory::centercontrast (double x, double b, double m) { return 2.0*x - m - m * tanh (b*(x-m)/m) / tanh (b); } } - - - -double CurveFactory::contrast (double x, double a) { - - if (a==0) - return x; - else if (a>0) { - double s = (1.0+exp(-0.5*a)) / (1.0+exp(-(x-0.5)*a)) * (exp(0.5*a)-exp(-(x-0.5)*a)) / (exp(0.5*a)-exp(-0.5*a)); - return s; - } - else { - double s = (1.0+exp(-0.5*a)) / (1.0+exp(-(x-0.5)*a)) * (exp(0.5*a)-exp(-(x-0.5)*a)) / (exp(0.5*a)-exp(-0.5*a)); - return 2*x - s; - } -} - -double CurveFactory::brightness (double x, double a, double bd1, double bd2) { - - if (a==1) - return x; - else if (a<1) - return a*x; - else { - if (x < 1.0/a-bd1) - return a*x; - else if (x > 1.0/a+bd2) - return 1; - else { - double d = bd1+bd2; - double s = - (-a*d*(1.0+a*(bd2-x))*(1.0+a*(bd2-x))*(-1.0+a*(bd1+x))-(2.0+a*(bd1+3.0*bd2-2.0*x))*(-1.0+a*(bd1+x))*(-1.0+a*(bd1+x)) + (-1.0+a*bd1)*(1.0+a*(bd2-x))*(1.0+a*(bd2-x))*(-2.0+a*(3.0*bd1+bd2+2.0*x))) / (a*a*a*d*d*d); - return s; - } - } -} - -double CurveFactory::softClip (double x, double d1, double d2, double a, double b, double c, double d) { - - if (x<1.0-d1) - return x; - else if (x>1.0+d2) - return 1.0; - else - return a*x*x*x + b*x*x + c*x + d; -} - -double CurveFactory::dlower (const double b, const double m, const double c) { - - return b / (tanh(b) * 2.0 * m); -} - -double CurveFactory::dupper (const double b, const double m, const double c) { - - return b / (tanh(b) * 2.0 * (c-m)); -} - -double CurveFactory::solve_lower (double m, double c, double deriv) { - - double b_u = 2.0*m*deriv; - double b_l = 0.0; - - double b; - while (b_u-b_l > 0.0000001) { - b = (b_u+b_l) / 2.0; - if (dlower(b,m,c) 0.0000001) { - b = (b_u+b_l) / 2.0; - if (dupper(b,m,c)& points, double defmul, double ecomp, int black, double hlcompr, double shcompr, double br, double contr, double gamma_, bool igamma, int skip) { double def_mul = pow (2.0, defmul); @@ -418,6 +212,11 @@ void CurveFactory::updateCurve3 (int* curve, int* ohistogram, const std::vector< bool needcontrast = contr>0.00001 || contr<-0.00001; bool needigamma = !needcontrast && igamma && gamma_>0; + // create a curve if needed + Curve* tcurve = NULL; + if (points.size()>0 && points[0]!=0) + tcurve = new Curve (points); + for (int i=0; i<=0xffff; i+= i<0xffff-skip ? skip : 1 ) { double val = (double)i / 65535.0; @@ -428,8 +227,8 @@ void CurveFactory::updateCurve3 (int* curve, int* ohistogram, const std::vector< val = basecurve (val, a, b, D, hlcompr/100.0, shcompr/100.0); val = brightness (val, br/100.0); -// if (tcurve) -// val = tcurve->getVal (val); + if (tcurve) + val = tcurve->getVal (val); if (needigamma) val = igamma2 (val); @@ -440,6 +239,7 @@ void CurveFactory::updateCurve3 (int* curve, int* ohistogram, const std::vector< val = 0.0; dcurve[i] = val; } + delete tcurve; /* if (igamma) { FILE* f = fopen ("curve.txt","wt"); @@ -451,7 +251,7 @@ if (igamma) { fclose (f); } */ - +/* int prev = 0; for (int i=1; i<=0xffff-skip; i++) { if (i%skip==0) { @@ -492,148 +292,128 @@ if (igamma) { for (int i=0; i<=0xffff; i++) curve[i] = (int) (65535.0 * dcurve[i]); delete [] dcurve; -} +}*/ -void CurveFactory::updateCurve2 (int* curve, int* ohistogram, const std::vector& points, double ecomp, double br, int black, double hlcompr, double shcompr, double contr, double gamma_, bool igamma, int skip) { +void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, double shcompr, double br, double contr, double defmul, double gamma_, bool igamma, const std::vector& curvePoints, unsigned int* histogram, int* outCurve, unsigned int* outBeforeCCurveHistogram, int skip) { - double ec_mul = pow (2, ecomp); - double bl = black / 65535.0; - double hi = pow (2.0,-br) + bl; + double def_mul = pow (2.0, defmul); - // compute parameters of the gamma curve - double start = exp(gamma_*log( -0.099 / ((1.0/gamma_-1.0)*1.099 ))); - double slope = 1.099 * pow (start, 1.0/gamma_-1) - 0.099/start; - double mul = 1.099; - double add = 0.099; + // compute parameters of the gamma curve + double start = exp(gamma_*log( -0.099 / ((1.0/gamma_-1.0)*1.099 ))); + double slope = 1.099 * pow (start, 1.0/gamma_-1) - 0.099/start; + double mul = 1.099; + double add = 0.099; - // compute parameters of the "levels" curve - shcompr /= 100.0; - hlcompr /= 100.0; - double correction = hlcompr<0.85 ? 1.0 : hlcompr+0.15; - correction = 1.0; - double d = pow (2.0,br); - double m = 0.5 / d + bl; - double c = (gamma_>0 ? gamma (ec_mul, gamma_, start, slope, mul, add) : ec_mul) * correction; -// double c = (gamma_>0 ? gamma (ec_mul, gamma_, start, slope, mul, add) : gamma2(ec_mul)) * correction; + // theoretical maximum of the curve + double D = gamma_>0 ? gamma (def_mul, gamma_, start, slope, mul, add) : def_mul; - double b_upper = solve_upper (m, c, d); - double b_lower = solve_lower (m, c, d); + // a: slope of the curve, black: starting point at the x axis + double a = pow (2.0, ecomp); - // generate curve without contrast (in double) - -// Curve* tcurve = curves[type]; - Curve* tcurve = new Curve (points); - if (tcurve->isEmpty()) { - delete tcurve; - tcurve = NULL; - } - - double* dcurve = new double[65536]; + // curve without contrast + double* dcurve = new double[65536]; - double bltanh = tanh (b_lower); - double butanh = tanh (b_upper); - - if (d * (c - bl) < 1) - hlcompr = 0; + // check if contrast curve is needed + bool needcontrast = contr>0.00001 || contr<-0.00001; + + // check if inverse gamma is needed at the end + bool needigamma = !needcontrast && igamma && gamma_>0; - bool needcontrast = contr>0.00001 || contr<-0.00001; - bool needigamma = !needcontrast && igamma && gamma_>0; + // create a curve if needed + Curve* tcurve = NULL; + if (curvePoints.size()>0 && curvePoints[0]!=0) + tcurve = new Curve (curvePoints); - for (int i=0; i<=0xffff; i+= i<0xffff-skip ? skip : 1 ) { - double val = (double)i / 65535.0; - val *= ec_mul; - if (gamma_>0) - val = gamma (val, gamma_, start, slope, mul, add); - -// double sval = levels (val, b_lower, b_upper, m, c); -// Acceleration: - double sval; - if (val <= m) { - double ttag = 2.0 / (1.0 + exp (-2.0*b_lower*(val-m)/m)) - 1.0; -// sval = (1.0 + tanh (b_lower*(val-m)/m) / bltanh) / 2.0; - sval = (1.0 + ttag / bltanh) / 2.0; - } - else { - double ttag = 2.0 / (1.0 + exp (-2.0*b_upper*(val-m)/(c-m))) - 1.0; -// sval = (1.0 + tanh (b_upper*(val-m)/(c-m)) / butanh) / 2.0; - sval = (1.0 + ttag / butanh) / 2.0; - } + // clear array that stores histogram valid before applying the custom curve + if (outBeforeCCurveHistogram) + memset (outBeforeCCurveHistogram, 0, 256*sizeof(int)); + + for (int i=0; i<=0xffff; i+= i<0xffff-skip ? skip : 1 ) { + + // change to [0,1] rage + double val = (double)i / 65535.0; + + // apply default multiplier (that is >1 if highlight recovery is on) + val *= def_mul; - if (valhi) - val = (1.0 - hlcompr) + hlcompr * sval; - else if (valgetVal (val); + // gamma correction + if (gamma_>0) + val = gamma (val, gamma_, start, slope, mul, add); + + // apply base curve, thus, exposure compensation and black point with shadow and highlight protection + val = basecurve (val, a, black, D, hlcompr/100.0, shcompr/100.0); - if (needigamma) - val = igamma2 (val); + // apply brightness curve + val = brightness (val, br/100.0); + + // apply custom/parametric curve, if any + if (tcurve) { + if (outBeforeCCurveHistogram) { + double hval = val; +// if (needigamma) +// hval = igamma2 (hval); + int hi = (int)(255.0*CLIPD(hval)); + outBeforeCCurveHistogram[hi]+=histogram[i] ; + } + val = tcurve->getVal (val); + } - if (val>1.0) - val = 1.0; - else if (val<0.0) - val = 0.0; - dcurve[i] = val; - } + // if inverse gamma is needed, do it (standard sRGB inverse gamma is applied) + if (needigamma) + val = igamma2 (val); -int prev = 0; -for (int i=1; i<=0xffff-skip; i++) { - if (i%skip==0) { - prev+=skip; - continue; + // store result in a temporary array + dcurve[i] = CLIPD(val); } - dcurve[i] = ( dcurve[prev] * (skip - i%skip) + dcurve[prev+skip] * (i%skip) ) / skip; -} - - if (needcontrast) { - // compute mean luminance of the image with the curve applied - int sum = 0; - double avg = 0; - for (int i=0; i<=0xffff; i++) { - avg += dcurve[i] * ohistogram[i]; - sum += ohistogram[i]; + 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; } - avg /= sum; - // compute contrast parameter - double contr_b = contr / 20; - if (contr_b>=0 && contr_b < 0.00001) - contr_b = 0.00001; - else if (contr_b<0 && contr_b > -0.00001) - contr_b = -0.00001; + if (needcontrast) { + // compute mean luminance of the image with the curve applied + int sum = 0; + double avg = 0; + for (int i=0; i<=0xffff; i++) { + avg += dcurve[i] * histogram[i]; + sum += histogram[i]; + } + avg /= sum; - // apply contrast enhancement - for (int i=0; i<=0xffff; i++) { - double val = centercontrast (dcurve[i], contr_b, avg); - if (igamma && gamma_>0) - val = igamma2 (val); - if (val>1.0) val = 1.0; - if (val<0.0) val = 0.0; - curve[i] = (int) (65535.0 * val); + // compute contrast parameter + double contr_b = contr / 20; + if (contr_b>=0 && contr_b < 0.00001) + contr_b = 0.00001; + else if (contr_b<0 && contr_b > -0.00001) + contr_b = -0.00001; + + // apply contrast enhancement + for (int i=0; i<=0xffff; i++) { + double val = centercontrast (dcurve[i], contr_b, avg); + if (igamma && gamma_>0) + val = igamma2 (val); + outCurve[i] = (int) (65535.0 * CLIPD(val)); + } } - } - else - for (int i=0; i<=0xffff; i++) - curve[i] = (int) (65535.0 * dcurve[i]); -//if (igamma) { -// FILE* f = fopen ("curve.txt","wt"); -// for (int i=0; i<65536; i++) -// fprintf (f, "%d\t%d\n", i, curve[i]); -// fclose (f); -//} - + else + for (int i=0; i<=0xffff; i++) + outCurve[i] = (int) (65535.0 * dcurve[i]); delete [] dcurve; } + int CurveFactory::gammatab [65536]; int CurveFactory::igammatab_srgb [65536]; int CurveFactory::gammatab_srgb [65536]; -void CurveFactory::loadCurves (Glib::ustring fname) { +void CurveFactory::init () { for (int i=0; i<65536; i++) gammatab_srgb[i] = (int)(65535 * gamma2 (i/65535.0)); @@ -641,38 +421,12 @@ void CurveFactory::loadCurves (Glib::ustring fname) { igammatab_srgb[i] = (int)(65535 * igamma2 (i/65535.0)); for (int i=0; i<65536; i++) gammatab[i] = (int)(65535 * pow (i/65535.0, 0.454545)); - - FILE* f = g_fopen (fname.c_str(), "rt"); - if (!f) - return; - - setlocale (LC_ALL, "C"); - - char* buffer = new char[1024]; - while (buffer = fgets(buffer, 1024, f)) { - int es = 0; - int llen = strlen(buffer); - for (es = 0; esgetName()] = c; - } - } - delete buffer; - - setlocale (LC_ALL, ""); + +/* FILE* f = fopen ("c.txt", "wt"); + for (int i=0; i<256; i++) + fprintf (f, "%g %g\n", i/255.0, clower (i/255.0, 2.0, 1.0)); + fclose (f);*/ } -std::vector CurveFactory::curveNames () { - - std::vector ret; - - int ix = 0; - for (std::map::iterator i = curves.begin(); i!=curves.end(); i++) - ret.push_back (i->second->getName()); - - return ret; -} } diff --git a/rtengine/curves.h b/rtengine/curves.h index a8e82c8d7..39b61bb1f 100755 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -26,46 +26,25 @@ namespace rtengine { -class Curve { - - protected: - int N; - double* x; - double* y; - double* ypp; - Glib::ustring name; - bool islinear; - bool isempty; - - protected: - void d3_np_fs (double a[], double b[]); - void spline_cubic_set (); - - public: - - Curve (const char* iname, int iN, double ix[], double iy[]); - Curve (const char* iname, const char* descr); - Curve (const std::vector& points); - ~Curve (); - - double getVal (double x); - Glib::ustring getName (); - bool isEmpty () { return isempty; } -}; - class CurveFactory { + friend class Curve; + protected: - static std::map curves; - static int gammatab[65536]; + // look-up tables for the standard srgb gamma and its inverse (filled by init()) static int igammatab_srgb[65536]; static int gammatab_srgb[65536]; + // look-up tables for the simple exponential gamma + static int gammatab[65536]; + + // functions calculating the parameters of the contrast curve based on the desired slope at the center static double solve_upper (double m, double c, double deriv); static double solve_lower (double m, double c, double deriv); static double dupper (const double b, const double m, const double c); static double dlower (const double b, const double m, const double c); + // basic convex function between (0,0) and (1,1). m1 and m2 controls the slope at the start and end point static inline double basel (double x, double m1, double m2) { if (x==0.0) return 0.0; @@ -74,9 +53,11 @@ class CurveFactory { double lx = log(x); return m2*x + (1.0-m2)*(2.0 - exp(k*lx))*exp(l*lx); } + // basic concave function between (0,0) and (1,1). m1 and m2 controls the slope at the start and end point static inline double baseu (double x, double m1, double m2) { return 1.0 - basel(1.0-x, m1, m2); } + // convex curve between (0,0) and (1,1) with slope m at (0,0). hr controls the highlight recovery static inline double cupper (double x, double m, double hr) { if (hr>1.0) return baseu (x, m, 2.0*(hr-1.0)/m); @@ -86,10 +67,12 @@ class CurveFactory { if (x1), hr,sr: highlight,shadow recovery + static inline double basecurve (double x, double a, double b, double D, double hr, double sr) { double m = b+0.5/a& cpoints, double ecomp, double br, int black, double hlcompr, double shcompr, double contr, double gamma_, bool igamma, int skip=1); - 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 std::vector curveNames (); +// 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 shcompr, double br, double contr, double defmul, double gamma_, bool igamma, const std::vector& curvePoints, unsigned int* histogram, int* outCurve, unsigned int* outBeforeCCurveHistogram, int skip=1); + +}; + +class Curve { + + protected: + int N; + double* x; + double* y; + double* ypp; + int kind; // = -1: linear interp., 0: empty, 1: spline interp., 2: parametric + + protected: + void spline_cubic_set (); + static inline double p00 (double x, double prot) { return CurveFactory::clower (x, 2.0, prot); } + static inline double p11 (double x, double prot) { return CurveFactory::cupper (x, 2.0, prot); } + static inline double p01 (double x, double prot) { return x<=0.5 ? CurveFactory::clower (x*2, 2.0, prot)/2.0 : 0.5 + CurveFactory::cupper ((x-0.5)*2, 2.0, prot)/2.0; } + static inline double p10 (double x, double prot) { return x<=0.5 ? CurveFactory::cupper (x*2, 2.0, prot)/2.0 : 0.5 + CurveFactory::clower ((x-0.5)*2, 2.0, prot)/2.0; } + static inline double pfull (double x, double prot, double sh, double hl) { return (1-sh)*(1-hl)*p00(x,prot) + sh*hl*p11(x,prot) + (1-sh)*hl*p01(x,prot) + sh*(1-hl)*p10(x,prot); } + + public: + + Curve (const std::vector& points); + ~Curve (); + + double getVal (double x); + void getVal (const std::vector& t, std::vector& res); }; }; diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 305749325..71e3166ec 100755 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -9258,7 +9258,7 @@ t4.set (); // generate histogram for auto exposure tpp->aeHistCompression = 3; - tpp->aeHistogram = new int[65536>>tpp->aeHistCompression]; + tpp->aeHistogram = new unsigned int[65536>>tpp->aeHistCompression]; memset (tpp->aeHistogram, 0, (65536>>tpp->aeHistCompression)*sizeof(int)); int radd = 4; int gadd = 2; diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 98d75f02c..a44746112 100755 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -83,7 +83,7 @@ class ImageSource : public InitialImage { void increaseRef () { references++; } void decreaseRef () { references--; if (!references) delete this; } - virtual int getAEHistogram (int* histogram, int& histcompr) {return 0;} + virtual int getAEHistogram (unsigned int* histogram, int& histcompr) {return 0;} // functions inherited from the InitialImage interface virtual Glib::ustring getFileName () { return fileName; } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index cecddac21..48e70ac66 100755 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -154,7 +154,7 @@ void ImProcCoordinator::updatePreviewImage (int todo) { if (todo & M_AUTOEXP) { if (params.toneCurve.autoexp) { - int aehist[65536]; int aehistcompr; + unsigned int aehist[65536]; int aehistcompr; imgsrc->getAEHistogram (aehist, aehistcompr); ipf.getAutoExp (aehist, aehistcompr, imgsrc->getDefGain(), params.toneCurve.clip, params.toneCurve.expcomp, params.toneCurve.black); if (aeListener) @@ -163,7 +163,7 @@ void ImProcCoordinator::updatePreviewImage (int todo) { } progress ("Exposure curve & CIELAB conversion...",100*readyphase/numofphases); if (todo & M_RGBCURVE) { - CurveFactory::updateCurve3 (tonecurve, vhist16, params.toneCurve.curve, imgsrc->getDefGain(), params.toneCurve.expcomp, params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, imgsrc->getGamma(), true); + CurveFactory::complexCurve (params.toneCurve.expcomp, params.toneCurve.black/65535.0, params.toneCurve.hlcompr, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, imgsrc->getDefGain(), imgsrc->getGamma(), true, params.toneCurve.curve, vhist16, tonecurve, bcrgbhist, scale==1 ? 1 : 1); ipf.rgbProc (oprevi, oprevl, ¶ms, tonecurve, shmap); // recompute luminance histogram @@ -177,7 +177,7 @@ void ImProcCoordinator::updatePreviewImage (int todo) { readyphase++; if (todo & M_LUMACURVE) { - CurveFactory::updateCurve2 (lumacurve, lhist16, params.lumaCurve.curve, 0, params.lumaCurve.brightness, params.lumaCurve.black, params.lumaCurve.hlcompr, params.lumaCurve.shcompr, params.lumaCurve.contrast, 0.0, false); + CurveFactory::complexCurve (0.0, 0.0, 0.0, 0.0, params.lumaCurve.brightness, params.lumaCurve.contrast, 0.0, 0.0, false, params.lumaCurve.curve, lhist16, lumacurve, bcLhist, scale==1 ? 1 : 16); } if (todo & M_LUMINANCE) { @@ -246,7 +246,7 @@ void ImProcCoordinator::updatePreviewImage (int todo) { hy2 = MIN(pH,MAX(0,(params.crop.y+params.crop.h) / scale)); } updateHistograms (hx1, hy1, hx2, hy2); - hListener->histogramChanged (rhist, ghist, bhist, Lhist); + hListener->histogramChanged (rhist, ghist, bhist, Lhist, bcrgbhist, bcLhist); } t9.set (); diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 8f2c85dd7..1324bf5a2 100755 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -64,10 +64,10 @@ class ImProcCoordinator : public StagedImageProcessor { int tonecurve [65536]; int lumacurve [65536]; - int vhist16[65536]; - int lhist16[65536]; + unsigned int vhist16[65536]; + unsigned int lhist16[65536]; - unsigned int rhist[256], ghist[256], bhist[256], Lhist[256]; + unsigned int rhist[256], ghist[256], bhist[256], Lhist[256], bcrgbhist[256], bcLhist[256]; int fw, fh, tr, fullw, fullh; int pW, pH; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 902763076..15f6fd736 100755 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -187,7 +187,7 @@ void ImProcFunctions::release () { monitorTransform = NULL; } -void ImProcFunctions::firstAnalysis_ (Image16* original, Glib::ustring wprofile, int* histogram, int* chroma_radius, int row_from, int row_to) { +void ImProcFunctions::firstAnalysis_ (Image16* original, Glib::ustring wprofile, unsigned int* histogram, int* chroma_radius, int row_from, int row_to) { TMatrix wprof = iccStore.workingSpaceMatrix (wprofile); int toxyz[3][3]; @@ -242,11 +242,11 @@ void ImProcFunctions::firstAnalysis_ (Image16* original, Glib::ustring wprofile, *chroma_radius = cradius; } -void ImProcFunctions::firstAnalysis (Image16* original, const ProcParams* params, int* histogram, double gamma) { +void ImProcFunctions::firstAnalysis (Image16* original, const ProcParams* params, unsigned int* histogram, double gamma) { int cr1, cr2; - int* hist1 = new int[65536]; memset (hist1, 0, 65536*sizeof(int)); - int* hist2 = new int[65536]; memset (hist2, 0, 65536*sizeof(int)); + unsigned int* hist1 = new unsigned int[65536]; memset (hist1, 0, 65536*sizeof(int)); + unsigned int* hist2 = new unsigned int[65536]; memset (hist2, 0, 65536*sizeof(int)); int H = original->height; @@ -366,8 +366,6 @@ void ImProcFunctions::rgbProc_ (Image16* working, LabImage* lab, const ProcParam b = CLIP((int)(factor*b-sub)); } else { - if (i==100 && j==3500) - printf ("r=%d, %d, fact=%g, mapval=%d, %d\n", r, (int)(factor*r), factor, mapval, shmap->map[i][j]); r = CLIP((int)(factor*r)); g = CLIP((int)(factor*g)); b = CLIP((int)(factor*b)); @@ -2020,7 +2018,7 @@ void ImProcFunctions::resize_ (Image16* src, Image16* dst, ResizeParams params, } } -void ImProcFunctions::getAutoExp (int* histogram, int histcompr, double expcomp, double clip, double& br, int& bl) { +void ImProcFunctions::getAutoExp (unsigned int* histogram, int histcompr, double expcomp, double clip, double& br, int& bl) { double sum = 0; for (int i=0; i<65536>>histcompr; i++) diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 405fe9704..1ed8dfbf6 100755 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -60,7 +60,7 @@ class ImProcFunctions { void lab2rgb_ (LabImage* lab, Image8* image, int row_from, int row_to); void colorCurve_ (LabImage* lold, LabImage* lnew, const ProcParams* params, int row_from, int row_to, double* cmultiplier); void sharpenHaloCtrl (LabImage* lab, const ProcParams* params, unsigned short** blurmap, unsigned short** base, int W, int row_from, int row_to); - void firstAnalysis_ (Image16* original, Glib::ustring wprofile, int* histogram, int* chroma_radius, int row_from, int row_to); + void firstAnalysis_ (Image16* original, Glib::ustring wprofile, unsigned int* histogram, int* chroma_radius, int row_from, int row_to); void resize_ (Image16* src, Image16* dst, ResizeParams params, int row_from, int row_to); void damping_ (float** aI, unsigned short** aO, float damping, int W, int rowfrom, int rowto); @@ -86,7 +86,7 @@ class ImProcFunctions { void release (); - void firstAnalysis (Image16* working, const ProcParams* params, int* vhist16, double gamma); + void firstAnalysis (Image16* working, const ProcParams* params, unsigned int* vhist16, double gamma); void rgbProc (Image16* working, LabImage* lab, const ProcParams* params, int* tonecurve, SHMap* shmap); void luminanceCurve (LabImage* lold, LabImage* lnew, int* curve, int row_from, int row_to); @@ -107,7 +107,7 @@ class ImProcFunctions { Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile); Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, Glib::ustring profile); - static void getAutoExp (int* histogram, int histcompr, double expcomp, double clip, double& br, int& bl); + static void getAutoExp (unsigned int* histogram, int histcompr, double expcomp, double clip, double& br, int& bl); }; }; #endif diff --git a/rtengine/init.cc b/rtengine/init.cc index 02111b00f..7f6c94a6e 100755 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -33,7 +33,7 @@ int init (const Settings* s) { settings = s; iccStore.parseDir (s->iccDirectory); - CurveFactory::loadCurves (""); + CurveFactory::init (); ImProcFunctions::initCache (); delete dcrMutex; dcrMutex = new Glib::Mutex; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 30bdebb21..8ec976384 100755 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -28,7 +28,6 @@ namespace procparams { ProcParams::ProcParams () { setDefaults (); - } ProcParams* ProcParams::create () { @@ -55,9 +54,6 @@ void ProcParams::setDefaults () { lumaCurve.brightness = 0; lumaCurve.contrast = 0; - lumaCurve.black = 0; - lumaCurve.hlcompr = 0; - lumaCurve.shcompr = 0; lumaCurve.curve.clear (); sharpening.enabled = true; @@ -170,7 +166,7 @@ int ProcParams::save (Glib::ustring fname) const { keyFile.set_boolean ("Exposure", "Auto", toneCurve.autoexp); keyFile.set_double ("Exposure", "Clip", toneCurve.clip); keyFile.set_double ("Exposure", "Compensation", toneCurve.expcomp); - keyFile.set_double ("Exposure", "Brightness", toneCurve.brightness); + keyFile.set_integer ("Exposure", "Brightness", toneCurve.brightness); keyFile.set_integer ("Exposure", "Contrast", toneCurve.contrast); keyFile.set_integer ("Exposure", "Black", toneCurve.black); keyFile.set_integer ("Exposure", "HighlightCompr", toneCurve.hlcompr); @@ -187,11 +183,8 @@ int ProcParams::save (Glib::ustring fname) const { keyFile.set_integer_list("Channel Mixer", "Blue", bmix); // save luma curve - keyFile.set_double ("Luminance Curve", "Brightness", lumaCurve.brightness); + keyFile.set_integer ("Luminance Curve", "Brightness", lumaCurve.brightness); keyFile.set_integer ("Luminance Curve", "Contrast", lumaCurve.contrast); - keyFile.set_integer ("Luminance Curve", "Black", lumaCurve.black); - keyFile.set_integer ("Luminance Curve", "HighlightCompr", lumaCurve.hlcompr); - keyFile.set_integer ("Luminance Curve", "ShadowCompr", lumaCurve.shcompr); Glib::ArrayHandle lcurve = lumaCurve.curve; keyFile.set_double_list("Luminance Curve", "Curve", lcurve); @@ -346,7 +339,7 @@ if (keyFile.has_group ("Exposure")) { if (keyFile.has_key ("Exposure", "Auto")) toneCurve.autoexp = keyFile.get_boolean ("Exposure", "Auto"); if (keyFile.has_key ("Exposure", "Clip")) toneCurve.clip = keyFile.get_double ("Exposure", "Clip"); if (keyFile.has_key ("Exposure", "Compensation")) toneCurve.expcomp = keyFile.get_double ("Exposure", "Compensation"); - if (keyFile.has_key ("Exposure", "Brightness")) toneCurve.brightness = keyFile.get_double ("Exposure", "Brightness"); + if (keyFile.has_key ("Exposure", "Brightness")) toneCurve.brightness = keyFile.get_integer ("Exposure", "Brightness"); if (keyFile.has_key ("Exposure", "Contrast")) toneCurve.contrast = keyFile.get_integer ("Exposure", "Contrast"); if (keyFile.has_key ("Exposure", "Black")) toneCurve.black = keyFile.get_integer ("Exposure", "Black"); if (keyFile.has_key ("Exposure", "HighlightCompr")) toneCurve.hlcompr = keyFile.get_integer ("Exposure", "HighlightCompr"); @@ -369,13 +362,10 @@ if (keyFile.has_group ("Channel Mixer")) { // load luma curve if (keyFile.has_group ("Luminance Curve")) { - if (keyFile.has_key ("Luminance Curve", "Brightness")) lumaCurve.brightness = keyFile.get_double ("Luminance Curve", "Brightness"); - if (keyFile.has_key ("Luminance Curve", "Contrast")) lumaCurve.contrast = keyFile.get_integer ("Luminance Curve", "Contrast"); - if (keyFile.has_key ("Luminance Curve", "Black")) lumaCurve.black = keyFile.get_integer ("Luminance Curve", "Black"); - if (keyFile.has_key ("Luminance Curve", "HighlightCompr")) lumaCurve.hlcompr = keyFile.get_integer ("Luminance Curve", "HighlightCompr"); - if (keyFile.has_key ("Luminance Curve", "ShadowCompr")) lumaCurve.shcompr = keyFile.get_integer ("Luminance Curve", "ShadowCompr"); + if (keyFile.has_key ("Luminance Curve", "Brightness")) lumaCurve.brightness = keyFile.get_integer ("Luminance Curve", "Brightness"); + if (keyFile.has_key ("Luminance Curve", "Contrast")) lumaCurve.contrast = keyFile.get_integer ("Luminance Curve", "Contrast"); if (version>200) - if (keyFile.has_key ("Luminance Curve", "Curve")) lumaCurve.curve = keyFile.get_double_list ("Luminance Curve", "Curve"); + if (keyFile.has_key ("Luminance Curve", "Curve")) lumaCurve.curve = keyFile.get_double_list ("Luminance Curve", "Curve"); } // load sharpening @@ -569,10 +559,7 @@ bool ProcParams::operator== (const ProcParams& other) { && toneCurve.expcomp == other.toneCurve.expcomp && lumaCurve.curve == other.lumaCurve.curve && lumaCurve.brightness == other.lumaCurve.brightness - && lumaCurve.black == other.lumaCurve.black && lumaCurve.contrast == other.lumaCurve.contrast - && lumaCurve.shcompr == other.lumaCurve.shcompr - && lumaCurve.hlcompr == other.lumaCurve.hlcompr && 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 307865eb9..31449afbf 100755 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -26,28 +26,31 @@ namespace rtengine { namespace procparams { /** - * Common parameters of the tone curve and the luminance curve + * Parameters of the tone curve */ -class CurveParams { - - public: - std::vector curve; - double brightness; - int black; - int contrast; - int shcompr; - int hlcompr; -}; - -/** - * Additional parameters of the tone curve (auto exposure related parameters) - */ -class ToneCurveParams : public CurveParams { +class ToneCurveParams { public: bool autoexp; double clip; double expcomp; + std::vector curve; + int brightness; + int black; + int contrast; + int shcompr; + int hlcompr; +}; + +/** + * Parameters of the luminance curve + */ +class LCurveParams { + + public: + std::vector curve; + int brightness; + int contrast; }; /** @@ -287,7 +290,7 @@ class ProcParams { public: ToneCurveParams toneCurve; ///< Tone curve parameters - CurveParams lumaCurve; ///< CIELAB luminance curve parameters + LCurveParams lumaCurve; ///< CIELAB luminance curve parameters SharpeningParams sharpening; ///< Sharpening parameters ColorBoostParams colorBoost; ///< Color boost parameters WBParams wb; ///< White balance parameters diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 2c6929401..18d8829d0 100755 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1925,7 +1925,7 @@ void RawImageSource::hlRecovery (std::string method, unsigned short* red, unsign HLRecovery_ColorPropagation (red, green, blue, i, sx1, width, skip); } -int RawImageSource::getAEHistogram (int* histogram, int& histcompr) { +int RawImageSource::getAEHistogram (unsigned int* histogram, int& histcompr) { histcompr = 3; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 8922b1248..1329baa08 100755 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -112,7 +112,7 @@ class RawImageSource : public ImageSource { ImageData* getImageData () { return idata; } void setProgressListener (ProgressListener* pl) { plistener = pl; } - int getAEHistogram (int* histogram, int& histcompr); + int getAEHistogram (unsigned int* histogram, int& histcompr); static void colorSpaceConversion (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], double& defgain); static void inverse33 (double (*coeff)[3], double (*icoeff)[3]); diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 18709b419..42e078036 100755 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -201,7 +201,7 @@ namespace rtengine { * @param greenh is the array of size 256 containing the histogram of the green channel * @param blueh is the array of size 256 containing the histogram of the blue channel * @param lumah is the array of size 256 containing the histogram of the luminance channel */ - virtual void histogramChanged (unsigned int* redh, unsigned int* greenh, unsigned int* blueh, unsigned int* lumah) {} + virtual void histogramChanged (unsigned int* redh, unsigned int* greenh, unsigned int* blueh, unsigned int* lumah, unsigned int* bcrgbhist, unsigned int* bcLhist) {} }; /** This listener is used when the auto exposure has been recomputed (e.g. when the clipping ratio changed). */ diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index aef52b88c..15e85c415 100755 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -100,7 +100,7 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, // histogram computation tpp->aeHistCompression = 3; - tpp->aeHistogram = new int[65536>>tpp->aeHistCompression]; + tpp->aeHistogram = new unsigned int[65536>>tpp->aeHistCompression]; memset (tpp->aeHistogram, 0, (65536>>tpp->aeHistCompression)*sizeof(int)); int ix = 0; for (int i=0; iheight*img->width; i++) { @@ -197,7 +197,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei logDefGain = 0.0; rmi = 1024.0 * rm * defGain / mul_lum; gmi = 1024.0 * gm * defGain / mul_lum; - bmi = 1024.0 * bm * defGain / mul_lum; + bmi = 1024.0 * bm * defGain / mul_lum; } else { rmi = 1024.0 * rm / mul_lum; @@ -213,7 +213,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei else rwidth = thumbImg->width * rheight / thumbImg->height; - Image16* baseImg = thumbImg->resize (rwidth, rheight, interp); + Image16* baseImg = thumbImg->resize (rwidth, rheight, interp); if (params.coarse.rotate) { Image16* tmp = baseImg->rotate (params.coarse.rotate); @@ -268,7 +268,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei int fh = baseImg->height; ImProcFunctions ipf; - int* hist16 = new int [65536]; + unsigned int* hist16 = new unsigned int [65536]; ipf.firstAnalysis (baseImg, ¶ms, hist16, isRaw ? 2.2 : 0.0); // perform transform @@ -316,7 +316,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei ipf.getAutoExp (aeHistogram, aeHistCompression, logDefGain, params.toneCurve.clip, br, bl); int* curve = new int [65536]; - CurveFactory::updateCurve3 (curve, hist16, params.toneCurve.curve, logDefGain, br, bl, params.toneCurve.hlcompr, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, isRaw ? 2.2 : 0, true); + CurveFactory::complexCurve (br, bl/65535.0, params.toneCurve.hlcompr, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, logDefGain, isRaw ? 2.2 : 0, true, params.toneCurve.curve, hist16, curve, NULL, 16); LabImage* labView = new LabImage (baseImg); ipf.rgbProc (baseImg, labView, ¶ms, curve, shmap); @@ -331,7 +331,8 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei hist16[labView->L[i][j]]++; // luminance processing - CurveFactory::updateCurve2 (curve, hist16, params.lumaCurve.curve, 0, params.lumaCurve.brightness, params.lumaCurve.black, params.lumaCurve.hlcompr, params.lumaCurve.shcompr, params.lumaCurve.contrast, 0.0, false); + CurveFactory::complexCurve (0.0, 0.0, 0.0, 0.0, params.lumaCurve.brightness, params.lumaCurve.contrast, 0.0, 0.0, false, params.lumaCurve.curve, hist16, curve, NULL, 16); + ipf.luminanceCurve (labView, labView, curve, 0, fh); delete [] curve; @@ -866,7 +867,7 @@ bool Thumbnail::readAEHistogram (const Glib::ustring& fname) { if (!f) aeHistogram = NULL; else { - aeHistogram = new int[65536>>aeHistCompression]; + aeHistogram = new unsigned int[65536>>aeHistCompression]; fread (aeHistogram, 1, (65536>>aeHistCompression)*sizeof(int), f); fclose (f); return true; diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index dfad657e4..f45e4c691 100755 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -46,7 +46,7 @@ namespace rtengine { double camwbBlue; double autowbTemp; double autowbGreen; - int* aeHistogram; + unsigned int* aeHistogram; int aeHistCompression; int embProfileLength; unsigned char* embProfileData; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 3f008c870..5edef48a0 100755 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -88,7 +88,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p pl->setProgress (0.25); // perform first analysis - int* hist16 = new int[65536]; + unsigned int* hist16 = new unsigned int[65536]; ipf.firstAnalysis (baseImg, ¶ms, hist16, imgsrc->getGamma()); // perform transform @@ -126,13 +126,14 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p int bl = params.toneCurve.black; if (params.toneCurve.autoexp) { - int aehist[65536]; int aehistcompr; + unsigned int aehist[65536]; int aehistcompr; imgsrc->getAEHistogram (aehist, aehistcompr); ipf.getAutoExp (aehist, aehistcompr, imgsrc->getDefGain(), params.toneCurve.clip, br, bl); } int* curve = new int [65536]; - CurveFactory::updateCurve3 (curve, hist16, params.toneCurve.curve, imgsrc->getDefGain(), br, bl, params.toneCurve.hlcompr, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, imgsrc->getGamma(), true); + + CurveFactory::complexCurve (br, bl/65535.0, params.toneCurve.hlcompr, params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, imgsrc->getDefGain(), imgsrc->getGamma(), true, params.toneCurve.curve, hist16, curve, NULL); LabImage* labView = new LabImage (baseImg); ipf.rgbProc (baseImg, labView, ¶ms, curve, shmap); @@ -150,7 +151,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p hist16[labView->L[i][j]]++; // luminance processing - CurveFactory::updateCurve2 (curve, hist16, params.lumaCurve.curve, 0, params.lumaCurve.brightness, params.lumaCurve.black, params.lumaCurve.hlcompr, params.lumaCurve.shcompr, params.lumaCurve.contrast, 0.0, false); + CurveFactory::complexCurve (0.0, 0.0, 0.0, 0.0, params.lumaCurve.brightness, params.lumaCurve.contrast, 0.0, 0.0, false, params.lumaCurve.curve, hist16, curve, NULL); ipf.luminanceCurve (labView, labView, curve, 0, fh); ipf.lumadenoise (labView, ¶ms, 1, buffer); ipf.sharpening (labView, ¶ms, 1, (unsigned short**)buffer); diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index 101b7013e..5b25b6ec4 100755 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -443,7 +443,7 @@ void StdImageSource::hlRecovery (unsigned short* red, unsigned short* green, uns rtengine::hlRecovery (red, green, blue, img->height, img->width, i, sx1, sx2, skip, needhr, hrmap); } */ -int StdImageSource::getAEHistogram (int* histogram, int& histcompr) { +int StdImageSource::getAEHistogram (unsigned int* histogram, int& histcompr) { histcompr = 3; diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 488597d76..ef0c626f5 100755 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -49,7 +49,7 @@ class StdImageSource : public ImageSource { ColorTemp getAutoWB (); ColorTemp getSpotWB (std::vector red, std::vector green, std::vector& blue, int tran); - int getAEHistogram (int* histogram, int& histcompr); + int getAEHistogram (unsigned int* histogram, int& histcompr); double getDefGain () { return 0.0; } double getGamma () { return 0.0; } diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 0af03e287..2417dc8b7 100755 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -12,7 +12,7 @@ SET (BASESOURCEFILES batchtoolpanelcoord.cc paramsedited.cc cropwindow.cc previewhandler.cc previewwindow.cc navigator.cc indclippedpanel.cc filterpanel.cc cursormanager.cc rtwindow.cc renamedlg.cc recentbrowser.cc placesbrowser.cc filepanel.cc editorpanel.cc batchqueuepanel.cc ilabel.cc thumbbrowserbase.cc adjuster.cc filebrowserentry.cc filebrowser.cc filethumbnailbuttonset.cc - cachemanager.cc cacheimagedata.cc + cachemanager.cc cacheimagedata.cc shcselector.cc clipboard.cc thumbimageupdater.cc bqentryupdater.cc coarsepanel.cc cacorrection.cc colorshift.cc hlrec.cc chmixer.cc colorboost.cc resize.cc icmpanel.cc crop.cc shadowshighlights.cc diff --git a/rtgui/addsetids.h b/rtgui/addsetids.h new file mode 100644 index 000000000..05be8f225 --- /dev/null +++ b/rtgui/addsetids.h @@ -0,0 +1,28 @@ +#ifndef _ADDSETIDS_ +#define _ADDSETIDS_ + +#define ADDSET_TC_EXPCOMP 0 +#define ADDSET_TC_BRIGHTNESS 1 +#define ADDSET_TC_BLACKLEVEL 2 +#define ADDSET_TC_CONTRAST 3 +#define ADDSET_SH_HIGHLIGHTS 4 +#define ADDSET_SH_SHADOWS 5 +#define ADDSET_SH_LOCALCONTRAST 6 +#define ADDSET_LC_BRIGHTNESS 7 +#define ADDSET_LC_CONTRAST 8 +#define ADDSET_SHARP_AMOUNT 9 +#define ADDSET_LD_EDGETOLERANCE 10 +#define ADDSET_WB_TEMPERATURE 11 +#define ADDSET_WB_GREEN 12 +#define ADDSET_CBOOST_AMOUNT 13 +#define ADDSET_CS_BLUEYELLOW 14 +#define ADDSET_CS_GREENMAGENTA 15 +#define ADDSET_ROTATE_DEGREE 16 +#define ADDSET_DIST_AMOUNT 17 +#define ADDSET_CA_BLUE 18 +#define ADDSET_CA_RED 19 +#define ADDSET_VIGN_AMOUNT 20 + +#define ADDSET_PARAM_NUM 21 + +#endif diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index 72bbea093..fb8d306dd 100755 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -21,6 +21,7 @@ #include #include #include +#include using namespace rtengine::procparams; @@ -119,43 +120,47 @@ void BatchToolPanelCoordinator::initSession () { pparams = selected[0]->getProcParams (); coarse->initBatchBehavior (); - curve->setAdjusterBehavior (options.baBehav[0], options.baBehav[1], options.baBehav[2], options.baBehav[3]); - whitebalance->setAdjusterBehavior (options.baBehav[12], options.baBehav[13]); - vignetting->setAdjusterBehavior (options.baBehav[21]); - rotate->setAdjusterBehavior (options.baBehav[17]); - distortion->setAdjusterBehavior (options.baBehav[18]); - cacorrection->setAdjusterBehavior (options.baBehav[19], options.baBehav[20]); - colorshift->setAdjusterBehavior (options.baBehav[15], options.baBehav[16]); - colorboost->setAdjusterBehavior (options.baBehav[14]); - lumadenoise->setAdjusterBehavior (options.baBehav[11]); - sharpening->setAdjusterBehavior (options.baBehav[10]); - shadowshighlights->setAdjusterBehavior (options.baBehav[4], options.baBehav[5], options.baBehav[6]); + curve->setAdjusterBehavior (options.baBehav[ADDSET_TC_EXPCOMP], options.baBehav[ADDSET_TC_BRIGHTNESS], options.baBehav[ADDSET_TC_BLACKLEVEL], options.baBehav[ADDSET_TC_CONTRAST]); + lcurve->setAdjusterBehavior (options.baBehav[ADDSET_LC_BRIGHTNESS], options.baBehav[ADDSET_LC_CONTRAST]); + whitebalance->setAdjusterBehavior (options.baBehav[ADDSET_WB_TEMPERATURE], options.baBehav[ADDSET_WB_GREEN]); + vignetting->setAdjusterBehavior (options.baBehav[ADDSET_VIGN_AMOUNT]); + rotate->setAdjusterBehavior (options.baBehav[ADDSET_ROTATE_DEGREE]); + distortion->setAdjusterBehavior (options.baBehav[ADDSET_DIST_AMOUNT]); + cacorrection->setAdjusterBehavior (options.baBehav[ADDSET_CA_RED], options.baBehav[ADDSET_CA_BLUE]); + colorshift->setAdjusterBehavior (options.baBehav[ADDSET_CS_BLUEYELLOW], options.baBehav[ADDSET_CS_GREENMAGENTA]); + colorboost->setAdjusterBehavior (options.baBehav[ADDSET_CBOOST_AMOUNT]); + lumadenoise->setAdjusterBehavior (options.baBehav[ADDSET_LD_EDGETOLERANCE]); + sharpening->setAdjusterBehavior (options.baBehav[ADDSET_SHARP_AMOUNT]); + shadowshighlights->setAdjusterBehavior (options.baBehav[ADDSET_SH_HIGHLIGHTS], options.baBehav[ADDSET_SH_SHADOWS], options.baBehav[ADDSET_SH_LOCALCONTRAST]); - if (options.baBehav[0]) pparams.toneCurve.expcomp = 0; - if (options.baBehav[1]) pparams.toneCurve.brightness = 0; - if (options.baBehav[2]) pparams.toneCurve.black = 0; - if (options.baBehav[3]) pparams.toneCurve.contrast = 0; + if (options.baBehav[ADDSET_TC_EXPCOMP]) pparams.toneCurve.expcomp = 0; + if (options.baBehav[ADDSET_TC_BRIGHTNESS]) pparams.toneCurve.brightness = 0; + if (options.baBehav[ADDSET_TC_BLACKLEVEL]) pparams.toneCurve.black = 0; + if (options.baBehav[ADDSET_TC_CONTRAST]) pparams.toneCurve.contrast = 0; - if (options.baBehav[4]) pparams.sh.highlights = 0; - if (options.baBehav[5]) pparams.sh.shadows = 0; - if (options.baBehav[6]) pparams.sh.localcontrast = 0; + if (options.baBehav[ADDSET_SH_HIGHLIGHTS]) pparams.sh.highlights = 0; + if (options.baBehav[ADDSET_SH_SHADOWS]) pparams.sh.shadows = 0; + if (options.baBehav[ADDSET_SH_LOCALCONTRAST]) pparams.sh.localcontrast = 0; + + if (options.baBehav[ADDSET_LC_BRIGHTNESS]) pparams.lumaCurve.brightness = 0; + if (options.baBehav[ADDSET_LC_CONTRAST]) pparams.lumaCurve.contrast = 0; - if (options.baBehav[10]) pparams.sharpening.amount = 0; - if (options.baBehav[11]) pparams.lumaDenoise.edgetolerance = 0; + if (options.baBehav[ADDSET_SHARP_AMOUNT]) pparams.sharpening.amount = 0; + if (options.baBehav[ADDSET_LD_EDGETOLERANCE]) pparams.lumaDenoise.edgetolerance = 0; - if (options.baBehav[12]) pparams.wb.temperature = 0; - if (options.baBehav[13]) pparams.wb.green = 0; + if (options.baBehav[ADDSET_WB_TEMPERATURE]) pparams.wb.temperature = 0; + if (options.baBehav[ADDSET_WB_GREEN]) pparams.wb.green = 0; - if (options.baBehav[14]) pparams.colorBoost.amount = 0; + if (options.baBehav[ADDSET_CBOOST_AMOUNT]) pparams.colorBoost.amount = 0; - if (options.baBehav[15]) pparams.colorShift.a = 0; - if (options.baBehav[16]) pparams.colorShift.b = 0; + if (options.baBehav[ADDSET_CS_BLUEYELLOW]) pparams.colorShift.a = 0; + if (options.baBehav[ADDSET_CS_GREENMAGENTA]) pparams.colorShift.b = 0; - if (options.baBehav[17]) pparams.rotate.degree = 0; - if (options.baBehav[18]) pparams.distortion.amount = 0; - if (options.baBehav[19]) pparams.cacorrection.red = 0; - if (options.baBehav[20]) pparams.cacorrection.blue = 0; - if (options.baBehav[21]) pparams.vignetting.amount = 0; + if (options.baBehav[ADDSET_ROTATE_DEGREE]) pparams.rotate.degree = 0; + if (options.baBehav[ADDSET_DIST_AMOUNT]) pparams.distortion.amount = 0; + if (options.baBehav[ADDSET_CA_RED]) pparams.cacorrection.red = 0; + if (options.baBehav[ADDSET_CA_BLUE]) pparams.cacorrection.blue = 0; + if (options.baBehav[ADDSET_VIGN_AMOUNT]) pparams.vignetting.amount = 0; for (int i=0; isetDefaults (&pparams, &pparamsEdited); @@ -260,7 +265,6 @@ CropGUIListener* BatchToolPanelCoordinator::startCropEditing (Thumbnail* thm) { if (thm) { int w, h; thm->getFinalSize (thm->getProcParams (), w, h); - printf ("final=%d %d\n", w, h); crop->setDimensions (w, h); } return crop; diff --git a/rtgui/curveeditor.cc b/rtgui/curveeditor.cc index 713321fe6..d629caa08 100755 --- a/rtgui/curveeditor.cc +++ b/rtgui/curveeditor.cc @@ -19,55 +19,125 @@ #include #include #include +#include #include -CurveEditor::CurveEditor () { +CurveEditor::CurveEditor () : cl(NULL), activeParamControl(-1), realized(false), curveTypeIx(-1) { - curve = Gtk::manage (new MyCurve ()); + Gtk::HBox* tsbox = Gtk::manage (new Gtk::HBox ()); + Gtk::Label* tslab = Gtk::manage (new Gtk::Label ("Type:")); + curveType = Gtk::manage (new Gtk::ComboBoxText ()); + + tsbox->pack_start (*tslab, Gtk::PACK_SHRINK, 8); + tsbox->pack_start (*curveType); + + pack_start (*tsbox); + + curveType->append_text ("Linear"); + curveType->append_text ("Parametric"); + curveType->append_text ("Custom"); + curveType->set_active (0); + + // custom curve + customCurveBox = new Gtk::VBox (); + customCurve = Gtk::manage (new MyCurve ()); Gtk::AspectFrame* af = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false)); - af->add (*curve); - curve->set_size_request (-1, 200); - pack_start (*af, Gtk::PACK_EXPAND_WIDGET); + af->add (*customCurve); + customCurve->set_size_request (-1, 200); + customCurve->setType (Spline); + customCurveBox->pack_start (*af, Gtk::PACK_EXPAND_WIDGET); Gtk::HBox* bbox = Gtk::manage (new Gtk::HBox ()); - - linear = Gtk::manage (new Gtk::Button (M("CURVEEDITOR_LINEAR"))); save = Gtk::manage (new Gtk::Button ()); - Gtk::Image* saveImg = Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON)); - saveImg->show (); - save->add (*saveImg); + save->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON))); load = Gtk::manage (new Gtk::Button ()); - Gtk::Image* loadImg = Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON)); - loadImg->show (); - load->add (*loadImg); + load->add (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-open"), Gtk::ICON_SIZE_BUTTON))); - bbox->pack_start (*linear); - bbox->pack_end (*save, Gtk::PACK_SHRINK, 4); - bbox->pack_end (*load, Gtk::PACK_SHRINK, 4); + bbox->pack_end (*save, Gtk::PACK_EXPAND_WIDGET, 4); + bbox->pack_end (*load, Gtk::PACK_EXPAND_WIDGET, 4); - pack_end (*bbox, Gtk::PACK_SHRINK, 2); - show_all (); + customCurveBox->pack_end (*bbox, Gtk::PACK_SHRINK, 2); + customCurveBox->show_all (); - linear->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditor::linearPressed) ); save->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditor::savePressed) ); load->signal_clicked().connect( sigc::mem_fun(*this, &CurveEditor::loadPressed) ); - - linear->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLINEAR")); save->set_tooltip_text (M("CURVEEDITOR_TOOLTIPSAVE")); load->set_tooltip_text (M("CURVEEDITOR_TOOLTIPLOAD")); + + // parametric curve + paramCurveBox = new Gtk::VBox (); + paramCurve = Gtk::manage (new MyCurve ()); + Gtk::Table* ctab = Gtk::manage (new Gtk::Table (2,1)); + Gtk::AspectFrame* afp = Gtk::manage (new Gtk::AspectFrame ("",Gtk::ALIGN_CENTER,Gtk::ALIGN_CENTER,1,false)); + afp->add (*paramCurve); + paramCurve->set_size_request (200, 200); + paramCurve->setType (Parametric); + shcSelector = Gtk::manage (new SHCSelector ()); + shcSelector->set_size_request (200, 20); + + ctab->attach (*afp, 0, 1, 0, 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + ctab->attach (*shcSelector, 0, 1, 1, 2, Gtk::FILL, Gtk::SHRINK, 2, 2); + + Gtk::HBox* tmpb = Gtk::manage (new Gtk::HBox ()); + tmpb->pack_start (*ctab, true, false); + + paramCurveBox->pack_start (*tmpb, true, true); + + highlights = Gtk::manage (new Adjuster ("Highlights", -100, 100, 1, 0)); + lights = Gtk::manage (new Adjuster ("Lights", -100, 100, 1, 0)); + darks = Gtk::manage (new Adjuster ("Darks", -100, 100, 1, 0)); + shadows = Gtk::manage (new Adjuster ("Shadows", -100, 100, 1, 0)); + + Gtk::EventBox* evhighlights = Gtk::manage (new Gtk::EventBox ()); + Gtk::EventBox* evlights = Gtk::manage (new Gtk::EventBox ()); + Gtk::EventBox* evdarks = Gtk::manage (new Gtk::EventBox ()); + Gtk::EventBox* evshadows = Gtk::manage (new Gtk::EventBox ()); + + evhighlights->add (*highlights); + evlights->add (*lights); + evdarks->add (*darks); + evshadows->add (*shadows); + + paramCurveBox->pack_start (*Gtk::manage (new Gtk::HSeparator ())); + paramCurveBox->pack_start (*evhighlights); + paramCurveBox->pack_start (*evlights); + paramCurveBox->pack_start (*evdarks); + paramCurveBox->pack_start (*evshadows); + paramCurveBox->show_all (); + + customCurveBox->reference (); + paramCurveBox->reference (); + + customCurve->setCurveListener (this); + paramCurve->setCurveListener (this); + shcSelector->setSHCListener (this); + + highlights->setAdjusterListener (this); + lights->setAdjusterListener (this); + darks->setAdjusterListener (this); + shadows->setAdjusterListener (this); + + evhighlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + evlights->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + evdarks->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + evshadows->set_events(Gdk::ENTER_NOTIFY_MASK | Gdk::LEAVE_NOTIFY_MASK); + typeconn = curveType->signal_changed().connect (sigc::mem_fun(*this, &CurveEditor::typeSelectionChanged) ); + evhighlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterEntered), 4)); + evlights->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterEntered), 5)); + evdarks->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterEntered), 6)); + evshadows->signal_enter_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterEntered), 7)); + evhighlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterLeft), 4)); + evlights->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterLeft), 5)); + evdarks->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterLeft), 6)); + evshadows->signal_leave_notify_event().connect (sigc::bind(sigc::mem_fun(*this, &CurveEditor::adjusterLeft), 7)); + + show_all (); } -void CurveEditor::linearPressed () { +CurveEditor::~CurveEditor () { - std::vector lcurve (5); - lcurve[0] = 1.0; - lcurve[1] = 0.0; - lcurve[2] = 0.0; - lcurve[3] = 1.0; - lcurve[4] = 1.0; - curve->setPoints (lcurve); - curve->queue_draw (); - curve->notifyListener (); + delete customCurveBox; + delete paramCurveBox; } void CurveEditor::savePressed () { @@ -99,18 +169,7 @@ void CurveEditor::savePressed () { std::string fname = dialog.get_filename(); - bool hasext = true; - int dotpos = fname.find_last_of ('.'); - if (dotpos==Glib::ustring::npos) - hasext = false; - int dirpos1 = fname.find_last_of ('/'); - if (dirpos1!=Glib::ustring::npos || dirpos1>dotpos) - hasext = false; - int dirpos2 = fname.find_last_of ('\\'); - if (dirpos2!=Glib::ustring::npos || dirpos2>dotpos) - hasext = false; - - if (!hasext) + if (getExtension (fname)!="rtc") fname = fname + ".rtc"; if (Glib::file_test (fname, Glib::FILE_TEST_EXISTS)) { @@ -122,7 +181,7 @@ void CurveEditor::savePressed () { } std::ofstream f (fname.c_str()); - std::vector p = curve->getPoints (); + std::vector p = customCurve->getPoints (); int ix = 0; if (p[ix++]<0) f << "Linear\n"; @@ -170,25 +229,165 @@ void CurveEditor::loadPressed () { if (f) p.push_back (x); } - curve->setPoints (p); - curve->queue_draw (); - curve->notifyListener (); + customCurve->setPoints (p); + customCurve->queue_draw (); + customCurve->notifyListener (); } } } +void CurveEditor::on_realize () { + + Gtk::VBox::on_realize(); + realized = true; + setCurve (tmpCurve); +} + void CurveEditor::setCurve (const std::vector& c) { - if (c.size()>4) { - curve->setPoints (c); - curve->queue_draw (); + tmpCurve = c; + + if (realized && curveType->get_active_row_number()<3) { // if it is not realized or "unchanged" is selected, just store the curve (prev line) and do not change gui + + typeconn.block(true); + if (c.size()==0 || c[0]==0) { + curveType->set_active (0); + curveTypeIx = 0; + } + else if (c[0]==1) { + curveType->set_active (2); + curveTypeIx = 2; + customCurve->setPoints (c); + } + else if (c[0]==2) { + curveType->set_active (1); + curveTypeIx = 1; + paramCurve->setPoints (c); + shcSelector->setPositions (c[1], c[2], c[3]); + highlights->setValue (c[4]); + lights->setValue (c[5]); + darks->setValue (c[6]); + shadows->setValue (c[7]); + } + removeIfThere (this, customCurveBox, false); + removeIfThere (this, paramCurveBox, false); + + if (curveType->get_active_row_number()==1) + pack_start (*paramCurveBox); + else if (curveType->get_active_row_number()==2) + pack_start (*customCurveBox); + + typeconn.block(false); } - else - linearPressed (); } std::vector CurveEditor::getCurve () { - return curve->getPoints (); + if (!realized || curveType->get_active_row_number()==3) + return tmpCurve; + + if (curveTypeIx<=0) { + std::vector lcurve (1); + lcurve[0] = 0.0; + return lcurve; + } + else if (curveTypeIx==1) { + std::vector lcurve (8); + lcurve[0] = 2.0; + shcSelector->getPositions (lcurve[1], lcurve[2], lcurve[3]); + lcurve[4] = highlights->getValue (); + lcurve[5] = lights->getValue (); + lcurve[6] = darks->getValue (); + lcurve[7] = shadows->getValue (); + return lcurve; + } + else if (curveTypeIx==2) + return customCurve->getPoints (); } +void CurveEditor::typeSelectionChanged () { + + removeIfThere (this, customCurveBox, false); + removeIfThere (this, paramCurveBox, false); + + if (curveType->get_active_row_number()==1) + pack_start (*paramCurveBox); + else if (curveType->get_active_row_number()==2) + pack_start (*customCurveBox); + + if (curveType->get_active_row_number()<3) + curveTypeIx = curveType->get_active_row_number(); + + curveChanged (); +} + +void CurveEditor::curveChanged () { + + if (cl) + cl->curveChanged (); +} + +void CurveEditor::shcChanged () { + + paramCurve->setPoints (getCurve()); + if (cl) + cl->curveChanged (); +} + +void CurveEditor::adjusterChanged (Adjuster* a, double newval) { + + paramCurve->setPoints (getCurve()); + if (cl) + cl->curveChanged (); +} + +bool CurveEditor::adjusterEntered (GdkEventCrossing* ev, int ac) { + + if (ev->detail != GDK_NOTIFY_INFERIOR) { + activeParamControl = ac; + paramCurve->setActiveParam (activeParamControl); + } + return true; +} + +bool CurveEditor::adjusterLeft (GdkEventCrossing* ev, int ac) { + + if (ev->detail != GDK_NOTIFY_INFERIOR) { + activeParamControl = -1; + paramCurve->setActiveParam (activeParamControl); + } + return true; +} + +void CurveEditor::setBatchMode (bool batchMode) { + + curveType->append_text ("(Unchanged)"); +} + +bool CurveEditor::isUnChanged () { + + return curveType->get_active_row_number()==3; +} + +void CurveEditor::setUnChanged (bool uc) { + + if (uc) { + typeconn.block(true); + removeIfThere (this, customCurveBox, false); + removeIfThere (this, paramCurveBox, false); + curveType->set_active (3); + typeconn.block(false); + } + else { + typeconn.block(true); + curveType->set_active (-1); // hack: if it remains 3 (unchanged), then setcurve does not switch selection in the combo + setCurve (getCurve ()); + typeconn.block(false); + } +} + +void CurveEditor::updateBackgroundHistogram (unsigned int* hist) { + + paramCurve->updateBackgroundHistogram (hist); + customCurve->updateBackgroundHistogram (hist); +} diff --git a/rtgui/curveeditor.h b/rtgui/curveeditor.h index 834fd4950..35fd715e8 100755 --- a/rtgui/curveeditor.h +++ b/rtgui/curveeditor.h @@ -21,22 +21,58 @@ #include #include +#include +#include -class CurveEditor : public Gtk::VBox { +class CurveEditor : public Gtk::VBox, public CurveListener, public SHCListener, public AdjusterListener { - MyCurve* curve; - Gtk::Button* linear; + Gtk::ComboBoxText* curveType; + Gtk::VBox* paramCurveBox; + Gtk::VBox* customCurveBox; + + MyCurve* customCurve; + MyCurve* paramCurve; + SHCSelector* shcSelector; + + Adjuster* highlights; + Adjuster* lights; + Adjuster* darks; + Adjuster* shadows; + Gtk::Button* save; Gtk::Button* load; + + CurveListener* cl; + + bool realized; + std::vector tmpCurve; + int curveTypeIx; + + int activeParamControl; + + sigc::connection typeconn; public: + CurveEditor (); - void setCurveListener (CurveListener* cl) { curve->setCurveListener (cl); } - void linearPressed (); + virtual ~CurveEditor (); + void setBatchMode (bool batchMode); + bool isUnChanged (); + void setUnChanged (bool uc); + + void on_realize (); + void setCurveListener (CurveListener* l) { cl = l; } void savePressed (); void loadPressed (); + void typeSelectionChanged (); void setCurve (const std::vector& c); std::vector getCurve (); + void curveChanged (); + void shcChanged (); + void adjusterChanged (Adjuster* a, double newval); + bool adjusterEntered (GdkEventCrossing* ev, int ac); + bool adjusterLeft (GdkEventCrossing* ev, int ac); + void updateBackgroundHistogram (unsigned int* hist); }; diff --git a/rtgui/curvelistener.h b/rtgui/curvelistener.h new file mode 100644 index 000000000..87102db6b --- /dev/null +++ b/rtgui/curvelistener.h @@ -0,0 +1,28 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _CURVELISTENER_ +#define _CURVELISTENER_ + +class CurveListener { + + public: + virtual void curveChanged () {} +}; + +#endif diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 44816e4c1..7e5b26075 100755 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -285,7 +285,7 @@ void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) { ipc->setPreviewImageListener (previewHandler); ipc->setPreviewScale (10); tpc->initImage (ipc, tmb->getType()==FT_Raw); - ipc->setHistogramListener (histogramPanel); + ipc->setHistogramListener (this); // iarea->fitZoom (); // tell to the editorPanel that the next image has to be fitted to the screen iarea->imageArea->setPreviewHandler (previewHandler); @@ -799,3 +799,8 @@ void EditorPanel::beforeAfterToggled () { } } +void EditorPanel::histogramChanged (unsigned int* rh, unsigned int* gh, unsigned int* bh, unsigned int* lh, unsigned int* bcrgb, unsigned int* bcl) { + + histogramPanel->histogramChanged (rh, gh, bh, lh); + tpc->updateCurveBackgroundHistogram (bcrgb, bcl); +} diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index e8c3e01a9..e55c64bc7 100755 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -44,7 +44,8 @@ class EditorPanel : public Gtk::VBox, public PParamsChangeListener, public rtengine::ProgressListener, public ThumbnailListener, - public HistoryBeforeLineListener { + public HistoryBeforeLineListener, + public rtengine::HistogramListener { protected: Gtk::Label *progressLabel; @@ -121,6 +122,9 @@ class EditorPanel : public Gtk::VBox, // HistoryBeforeLineListener void historyBeforeLineChanged (const rtengine::procparams::ProcParams& params); + // HistogramListener + void histogramChanged (unsigned int* rh, unsigned int* gh, unsigned int* bh, unsigned int* lh, unsigned int* bcrgb, unsigned int* bcl); + // event handlers void info_toggled (); void hideHistoryActivated (); diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index c319d043f..4f22b571a 100755 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -18,6 +18,7 @@ */ #include #include +#include HistogramPanel::HistogramPanel () { diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 04296ebf1..d50ed2838 100755 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -21,7 +21,6 @@ #include #include -#include class HistogramArea; struct HistogramAreaIdleHelper { @@ -74,7 +73,7 @@ class HistogramArea : public Gtk::DrawingArea { void styleChanged (const Glib::RefPtr& style); }; -class HistogramPanel : public Gtk::HBox, public rtengine::HistogramListener { +class HistogramPanel : public Gtk::HBox { protected: diff --git a/rtgui/imagearea.cc b/rtgui/imagearea.cc index 8fbeeeda6..572a2b701 100755 --- a/rtgui/imagearea.cc +++ b/rtgui/imagearea.cc @@ -51,7 +51,7 @@ void ImageArea::on_realize() { Gtk::DrawingArea::on_realize(); - add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK); + add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::POINTER_MOTION_HINT_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK); Cairo::FontOptions cfo; cfo.set_antialias (Cairo::ANTIALIAS_SUBPIXEL); diff --git a/rtgui/lcurve.cc b/rtgui/lcurve.cc index a0836a562..b40f37e8e 100755 --- a/rtgui/lcurve.cc +++ b/rtgui/lcurve.cc @@ -22,29 +22,17 @@ using namespace rtengine; using namespace rtengine::procparams; -LCurve::LCurve () : ToolPanel() { +LCurve::LCurve () : ToolPanel(), brAdd(false), contrAdd(false) { Gtk::HBox* abox = Gtk::manage (new Gtk::HBox ()); abox->set_border_width (2); - brightness = Gtk::manage (new Adjuster (M("TP_LUMACURVE_BRIGHTNESS"), -2, 2, 0.01, 0)); - hlcompr = Gtk::manage (new Adjuster (M("TP_LUMACURVE_COMPRHIGHLIGHTS"), 0, 100, 1, 0)); - black = Gtk::manage (new Adjuster (M("TP_LUMACURVE_BLACKLEVEL"), 0, 32768, 1, 0)); - shcompr = Gtk::manage (new Adjuster (M("TP_LUMACURVE_COMPRSHADOWS"), 0, 100, 1, 0)); - contrast = Gtk::manage (new Adjuster (M("TP_LUMACURVE_CONTRAST"), -50, 50, 1, 0)); + brightness = Gtk::manage (new Adjuster (M("TP_LUMACURVE_BRIGHTNESS"), -100, 100, 0.01, 0)); + contrast = Gtk::manage (new Adjuster (M("TP_LUMACURVE_CONTRAST"), -100, 100, 1, 0)); pack_start (*brightness); brightness->show (); - pack_start (*hlcompr); - hlcompr->show (); - - pack_start (*black); - black->show (); - - pack_start (*shcompr); - shcompr->show (); - pack_start (*contrast); contrast->show (); @@ -56,51 +44,55 @@ LCurve::LCurve () : ToolPanel() { shape->show (); shape->setCurveListener (this); - curvexp = Gtk::manage (new Gtk::Expander (M("TP_LUMACURVE_CURVEEDITOR"))); - curvexp->show (); - curvexp->add (*shape); - - pack_start (*curvexp, Gtk::PACK_SHRINK, 4); + pack_start (*shape, Gtk::PACK_SHRINK, 4); brightness->setAdjusterListener (this); - hlcompr->setAdjusterListener (this); - black->setAdjusterListener (this); - shcompr->setAdjusterListener (this); contrast->setAdjusterListener (this); } -void LCurve::read (const ProcParams* pp) { +void LCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { disableListener (); - brightness->setValue (pp->lumaCurve.brightness); - black->setValue (pp->lumaCurve.black); - hlcompr->setValue (pp->lumaCurve.hlcompr); - shcompr->setValue (pp->lumaCurve.shcompr); + if (pedited) { + brightness->setEditedState (pedited->lumaCurve.brightness ? Edited : UnEdited); + contrast->setEditedState (pedited->lumaCurve.contrast ? Edited : UnEdited); + shape->setUnChanged (!pedited->lumaCurve.curve); + } + brightness->setValue (pp->lumaCurve.brightness); contrast->setValue (pp->lumaCurve.contrast); shape->setCurve (pp->lumaCurve.curve); enableListener (); } -void LCurve::write (ProcParams* pp) { +void LCurve::write (ProcParams* pp, ParamsEdited* pedited) { pp->lumaCurve.brightness = brightness->getValue (); - pp->lumaCurve.black = (int)black->getValue (); - pp->lumaCurve.hlcompr = (int)hlcompr->getValue (); - pp->lumaCurve.shcompr = (int)shcompr->getValue (); pp->lumaCurve.contrast = (int)contrast->getValue (); pp->lumaCurve.curve = shape->getCurve (); + + if (pedited) { + pedited->lumaCurve.brightness = brightness->getEditedState (); + pedited->lumaCurve.contrast = contrast->getEditedState (); + pedited->lumaCurve.curve = !shape->isUnChanged (); + } } -void LCurve::setDefaults (const ProcParams* defParams) { +void LCurve::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { brightness->setDefault (defParams->lumaCurve.brightness); - black->setDefault (defParams->lumaCurve.black); - hlcompr->setDefault (defParams->lumaCurve.hlcompr); - shcompr->setDefault (defParams->lumaCurve.shcompr); contrast->setDefault (defParams->lumaCurve.contrast); + + if (pedited) { + brightness->setDefaultEditedState (pedited->lumaCurve.brightness ? Edited : UnEdited); + contrast->setDefaultEditedState (pedited->lumaCurve.contrast ? Edited : UnEdited); + } + else { + brightness->setDefaultEditedState (Irrelevant); + contrast->setDefaultEditedState (Irrelevant); + } } void LCurve::curveChanged () { @@ -122,22 +114,31 @@ void LCurve::adjusterChanged (Adjuster* a, double newval) { if (a==brightness) listener->panelChanged (EvLBrightness, costr); - else if (a==black) - listener->panelChanged (EvLBlack, costr); else if (a==contrast) listener->panelChanged (EvLContrast, costr); - else if (a==hlcompr) - listener->panelChanged (EvLHLCompr, costr); - else if (a==shcompr) - listener->panelChanged (EvLSHCompr, costr); } -void LCurve::expandCurve (bool isExpanded) { - - curvexp->set_expanded (isExpanded); -} - -bool LCurve::isCurveExpanded () { - - return curvexp->get_expanded (); -} - + +void LCurve::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + brightness->showEditedCB (); + contrast->showEditedCB (); + + shape->setBatchMode (batchMode); +} + +void LCurve::setAdjusterBehavior (bool bradd, bool contradd) { + + if (!brAdd && bradd || brAdd && !bradd) + brightness->setLimits (-100, 100, 1, 0); + if (!contrAdd && contradd || contrAdd && !contradd) + contrast->setLimits (-100, 100, 1, 0); + + brAdd = bradd; + contrAdd = contradd; +} + +void LCurve::updateCurveBackgroundHistogram (unsigned* hist) { + + shape->updateBackgroundHistogram (hist); +} diff --git a/rtgui/lcurve.h b/rtgui/lcurve.h index 88aaf0e4c..b8d1bd4c2 100755 --- a/rtgui/lcurve.h +++ b/rtgui/lcurve.h @@ -29,25 +29,23 @@ class LCurve : public Gtk::VBox, public AdjusterListener, public ToolPanel, publ protected: Adjuster* brightness; - Adjuster* black; Adjuster* contrast; - Adjuster* hlcompr; - Adjuster* shcompr; CurveEditor* shape; - Gtk::Expander* curvexp; + bool brAdd, contrAdd; public: LCurve (); - void read (const rtengine::procparams::ProcParams* pp); - void write (rtengine::procparams::ProcParams* pp); - void setDefaults (const rtengine::procparams::ProcParams* defParams); + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + void setAdjusterBehavior (bool bradd, bool contradd); void curveChanged (); void adjusterChanged (Adjuster* a, double newval); - void expandCurve (bool isExpanded); - bool isCurveExpanded (); + void updateCurveBackgroundHistogram (unsigned* hist); }; #endif diff --git a/rtgui/mycurve.cc b/rtgui/mycurve.cc index 913a398f6..6fcd5808b 100755 --- a/rtgui/mycurve.cc +++ b/rtgui/mycurve.cc @@ -17,11 +17,13 @@ * along with RawTherapee. If not, see . */ #include +#include +#include #define RADIUS 3 /* radius of the control points */ #define MIN_DISTANCE 8 /* min distance between control points */ -MyCurve::MyCurve () : listener(NULL) { +MyCurve::MyCurve () : listener(NULL), activeParam(-1), bghistvalid(false) { cursor_type = Gdk::TOP_LEFT_ARROW; curve.type = Spline; @@ -36,373 +38,340 @@ MyCurve::MyCurve () : listener(NULL) { curve.x.push_back(1); curve.y.push_back(1); curve.type = Spline; + + mcih = new MyCurveIdleHelper; + mcih->myCurve = this; + mcih->destroyed = false; + mcih->pending = 0; } -void MyCurve::spline_solve (int n, double x[], double y[], double y2[]) { - - double* u = new double[n-1]; - - y2[0] = u[0] = 0.0; /* set lower boundary condition to "natural" */ - - for (int i = 1; i < n - 1; ++i) - { - double sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]); - double p = sig * y2[i - 1] + 2.0; - y2[i] = (sig - 1.0) / p; - u[i] = ((y[i + 1] - y[i]) - / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1])); - u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p; - } - - y2[n - 1] = 0.0; - for (int k = n - 2; k >= 0; --k) - y2[k] = y2[k] * y2[k + 1] + u[k]; - - delete [] u; +MyCurve::~MyCurve () { + + if (mcih->pending) + mcih->destroyed = true; + else + delete mcih; } -double MyCurve::spline_eval (int n, double x[], double y[], double y2[], double val) { - - if (val>x[n-1]) - return y[n-1]; - else if (val 1){ - int k = (k_hi + k_lo) / 2; - if (x[k] > val) - k_hi = k; - else - k_lo = k; - } - - double h = x[k_hi] - x[k_lo]; - double a = (x[k_hi] - val) / h; - double b = (val - x[k_lo]) / h; - return a*y[k_lo] + b*y[k_hi] + ((a*a*a - a)*y2[k_lo] + (b*b*b - b)*y2[k_hi]) * (h*h)/6.0; -} - - std::vector MyCurve::get_vector (int veclen) { - std::vector vector; + std::vector vector; + vector.resize (veclen); - int num = curve.x.size(); + if (curve.type != Parametric) { + // count active points: + double prev =- 1.0; + int active = 0; + int firstact = -1; + for (int i = 0; i < curve.x.size(); ++i) + if (curve.x[i] > prev) { + if (firstact < 0) + firstact = i; + prev = curve.x[i]; + ++active; + } + // handle degenerate case: + if (active < 2) { + double ry; + if (active > 0) + ry = curve.y[firstact]; + else + ry = 0.0; + if (ry < 0.0) ry = 0.0; + if (ry > 1.0) ry = 1.0; + for (int x = 0; x < veclen; ++x) + vector[x] = ry; + return vector; + } + } - /* count active points: */ - double prev =- 1.0; - int active = 0; - int firstact = -1; - for (int i = 0; i < num; ++i) - if (curve.x[i] > prev) { - if (firstact < 0) - firstact = i; - prev = curve.x[i]; - ++active; - } - /* handle degenerate case: */ - if (active < 2) { - double ry; - if (active > 0) - ry = curve.y[firstact]; - else - ry = 0.0; - if (ry < 0.0) ry = 0.0; - if (ry > 1.0) ry = 1.0; - for (int x = 0; x < veclen; ++x) - vector.push_back(ry); - return vector; - } - - if (curve.type==Spline) { - - double* mem = new double [3*active]; - double* xv = mem; - double* yv = mem + active; - double* y2v = mem + 2*active; - - prev = -1.0; - int dst = 0; - for (int i = 0; i < num; ++i) { - if (curve.x[i] > prev) { - prev = curve.x[i]; - xv[dst] = curve.x[i]; - yv[dst] = curve.y[i]; - dst++; - } - } - spline_solve (active, xv, yv, y2v); - - double dx = 1.0 / (veclen - 1); - double rx = 0.0; - for (int x = 0; x < veclen; ++x, rx += dx) { - double ry = spline_eval (active, xv, yv, y2v, rx); - if (ry < 0.0) ry = 0; - if (ry > 1.0) ry = 1.0; - vector.push_back (ry); - } - delete [] mem; - } - else if (curve.type==Linear) { - double dx = 1.0 / (veclen - 1); - double rx = 0; - double ry = 0; - double dy = 0.0; - int i = firstact; - for (int x = 0; x < veclen; ++x, rx += dx) { - if (rx >= curve.x[i]) { - if (rx > curve.x[i]) - ry = 0.0; - dy = 0.0; - int next = i + 1; - while (next < num && curve.x[next] <= curve.x[i]) - ++next; - if (next < num) { - double delta_x = curve.x[next] - curve.x[i]; - dy = (curve.y[next] - curve.y[i]) / delta_x; - dy *= dx; - ry = curve.y[i]; - i = next; - } - } - if (rxcurve.x[num-1]) - vector.push_back (curve.y[num-1]); - else - vector.push_back (ry); - ry += dy; - } - } - return vector; + // calculate remaining points + std::vector curveDescr = getPoints (); + rtengine::Curve* rtcurve = new rtengine::Curve (curveDescr); + std::vector t; + t.resize (veclen); + for (int i = 0; i < veclen; i++) + t[i] = (double) i / (veclen - 1.0); + rtcurve->getVal (t, vector); + delete rtcurve; + return vector; } void MyCurve::interpolate (int width, int height) { - this->height = height; - point.clear (); - std::vector vector = get_vector (width); - this->height = height; - for (int i = 0; i < width; ++i) { - Gdk::Point p (RADIUS + i, RADIUS + height - (int)((height-1) * vector[i] + 0.5)); - point.push_back (p); - } -} + this->height = height; + point.resize (width); + std::vector vector = get_vector (width); + this->height = height; + for (int i = 0; i < width; ++i) + point[i] = Gdk::Point (RADIUS + i, RADIUS + height - (int)((height-1) * vector[i] + 0.5)); + upoint.clear (); + lpoint.clear (); + if (curve.type==Parametric && activeParam>0) { + double tmp = curve.x[activeParam-1]; + if (activeParam>=4) { + upoint.resize(width); + lpoint.resize(width); + curve.x[activeParam-1] = 100; + vector = get_vector (width); + for (int i = 0; i < width; ++i) + upoint[i] = Gdk::Point (RADIUS + i, RADIUS + height - (int)((height-1) * vector[i] + 0.5)); + curve.x[activeParam-1] = -100; + vector = get_vector (width); + for (int i = 0; i < width; ++i) + lpoint[i] = Gdk::Point (RADIUS + i, RADIUS + height - (int)((height-1) * vector[i] + 0.5)); + curve.x[activeParam-1] = tmp; + } + } +} void MyCurve::draw (int width, int height) { - if (!pixmap) - return; + if (!pixmap) + return; - if (this->height != height || point.size() != width) - interpolate (width, height); + // re-calculate curve if dimensions changed + if (this->height != height || point.size() != width) + interpolate (width, height); - Gtk::StateType state = Gtk::STATE_NORMAL; - if (!is_sensitive()) - state = Gtk::STATE_INSENSITIVE; + + Gtk::StateType state = Gtk::STATE_NORMAL; + if (!is_sensitive()) + state = Gtk::STATE_INSENSITIVE; - Glib::RefPtr style = get_style (); + Glib::RefPtr style = get_style (); + Cairo::RefPtr cr = pixmap->create_cairo_context(); - Cairo::RefPtr cr = pixmap->create_cairo_context(); + // bounding rectangle + Gdk::Color c = style->get_bg (state); + cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); + cr->rectangle (0, 0, width + RADIUS*2, height + RADIUS*2); + cr->fill (); - /* clear the pixmap: */ -// gtk_paint_flat_box (style->gobj(), pixmap->gobj(), GTK_STATE_NORMAL, GTK_SHADOW_NONE, -// NULL, (GtkWidget*)gobj(), "curve_bg", 0, 0, , height + RADIUS * 2); + // histogram in the background + if (bghistvalid) { + // find heighest bin + int histheight = 0; + for (int i=0; i<256; i++) + if (bghist[i]>histheight) + histheight = bghist[i]; + // draw histogram + cr->set_line_width (1.0); + double stepSize = (width-1) / 256.0; + cr->move_to (0, height-1); + cr->set_source_rgb (0.75, 0.75, 0.75); + for (int i=0; i<256; i++) { + double val = bghist[i] * (double)(height-2) / histheight; + if (val>height-1) + val = height-1; + if (i>0) + cr->line_to (i*stepSize, height-1-val); + } + cr->line_to (width-1, height-1); + cr->fill (); + } -// pixmap->draw_rectangle (style->get_bg_gc (state), false, 0, 0, width + RADIUS*2 - 1, height + RADIUS*2 - 1); + // draw the grid lines: + cr->set_line_width (1.0); + c = style->get_dark (state); + cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); + cr->set_antialias (Cairo::ANTIALIAS_NONE); + for (int i = 0; i < 5; i++) { + cr->move_to (RADIUS, i * height / 4 + RADIUS); + cr->line_to (width + RADIUS, i * height / 4 + RADIUS); + cr->move_to (i * width / 4 + RADIUS, RADIUS); + cr->line_to (i * width / 4 + RADIUS, height + RADIUS); + } + cr->stroke (); + + // draw f(x)=x line + cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); + std::valarray ds (1); + ds[0] = 4; + cr->set_dash (ds, 0); + cr->move_to (RADIUS, height + RADIUS); + cr->line_to (width + RADIUS, RADIUS); + cr->stroke (); + cr->unset_dash (); - Gdk::Color c = style->get_bg (state); - cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); - cr->rectangle (0, 0, width + RADIUS*2, height + RADIUS*2); - cr->fill (); + cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + cr->set_line_width (1.0); - /* draw the grid lines: (XXX make more meaningful) */ - cr->set_line_width (1.0); - c = style->get_dark (state); - cr->set_source_rgb (c.get_red_p(), c.get_green_p(), c.get_blue_p()); - cr->set_antialias (Cairo::ANTIALIAS_NONE); - for (int i = 0; i < 5; i++) { - - cr->move_to (RADIUS, i * height / 4 + RADIUS); - cr->line_to (width + RADIUS, i * height / 4 + RADIUS); - cr->move_to (i * width / 4 + RADIUS, RADIUS); - cr->line_to (i * width / 4 + RADIUS, height + RADIUS); -// pixmap->draw_line (style->get_dark_gc (state), RADIUS, i * height / 4 + RADIUS, width + RADIUS, i * height / 4 + RADIUS); -// pixmap->draw_line (style->get_dark_gc (state), i * width / 4 + RADIUS, RADIUS, i * width / 4 + RADIUS, height + RADIUS); - } - cr->stroke (); + // draw upper and lower bounds + if (curve.type==Parametric && activeParam>0 && lpoint.size()>1 && upoint.size()>1) { + cr->set_source_rgba (0.0, 0.0, 0.0, 0.15); + cr->move_to (upoint[0].get_x(), upoint[0].get_y()); + for (int i=1; iline_to (upoint[i].get_x(), upoint[i].get_y()); + cr->line_to (lpoint[lpoint.size()-1].get_x(), lpoint[lpoint.size()-1].get_y()); + for (int i=lpoint.size()-2; i>=0; i--) + cr->line_to (lpoint[i].get_x(), lpoint[i].get_y()); + cr->line_to (upoint[0].get_x(), upoint[0].get_y()); + cr->fill (); + } - cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); - cr->set_line_width (1.0); - cr->set_source_rgb (0.0, 0.0, 0.0); - cr->move_to (point[0].get_x(), point[0].get_y()); - for (int i=1; iline_to (point[i].get_x(), point[i].get_y()); - cr->stroke (); + // draw curve + cr->set_source_rgb (0.0, 0.0, 0.0); + cr->move_to (point[0].get_x(), point[0].get_y()); + for (int i=1; iline_to (point[i].get_x(), point[i].get_y()); + cr->stroke (); - for (int i = 0; i < curve.x.size(); ++i) { + // draw bullets + if (curve.type!=Parametric) + for (int i = 0; i < curve.x.size(); ++i) { + double x = ((width-1) * curve.x[i] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, width); + double y = height - ((height-1) * curve.y[i] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, height); - double x = ((width-1) * curve.x[i] + 0.5)+RADIUS; // project (curve.x[i], 0, 1, width); - double y = height - ((height-1) * curve.y[i] + 0.5)+RADIUS; // project (curve.y[i], 0, 1, height); + cr->arc (x, y, RADIUS, 0, 2*M_PI); + cr->fill (); + } - /* draw a bullet: */ - cr->arc (x, y, RADIUS, 0, 2*M_PI); - cr->fill (); - } - - get_window()->draw_drawable (style->get_fg_gc (state), pixmap, 0, 0, 0, 0, width + RADIUS * 2, height + RADIUS * 2); + get_window()->draw_drawable (style->get_fg_gc (state), pixmap, 0, 0, 0, 0, width + RADIUS * 2, height + RADIUS * 2); } bool MyCurve::handleEvents (GdkEvent* event) { - Gdk::CursorType new_type = cursor_type; - int src, dst; - GdkEventMotion *mevent; - std::vector::iterator itx, ity; + Gdk::CursorType new_type = cursor_type; + int src, dst; + GdkEventMotion *mevent; + std::vector::iterator itx, ity; - bool retval = false; + bool retval = false; - int width = get_allocation().get_width() - RADIUS * 2; - int height = get_allocation().get_height() - RADIUS * 2; + int width = get_allocation().get_width() - RADIUS * 2; + int height = get_allocation().get_height() - RADIUS * 2; - if ((width < 0) || (height < 0)) - return false; + if ((width < 0) || (height < 0)) + return false; - /* get the pointer position */ - int tx, ty; - Gdk::ModifierType gm; - get_window()->get_pointer (tx, ty, gm); - int x = CLAMP ((tx - RADIUS), 0, width-1); - int y = CLAMP ((ty - RADIUS), 0, height-1); + /* get the pointer position */ + int tx, ty; + Gdk::ModifierType gm; + get_window()->get_pointer (tx, ty, gm); + int x = CLAMP ((tx - RADIUS), 0, width-1); + int y = CLAMP ((ty - RADIUS), 0, height-1); - unsigned int distance = ~0U; - int num = curve.x.size(); - int closest_point = 0; - for (int i = 0; i < num; ++i) { - int cx = (int)((width-1) * curve.x[i] + 0.5); //project (c->ctlpoint[i][0], min_x, c->max_x, width); - if ((unsigned int) abs (x - cx) < distance) { - distance = abs (x - cx); - closest_point = i; - } - } - - switch (event->type) { - case Gdk::CONFIGURE: - if (pixmap) - pixmap.clear (); - /* fall through */ - - case Gdk::EXPOSE: - if (!pixmap) { - pixmap = Gdk::Pixmap::create (get_window(), get_allocation().get_width(), get_allocation().get_height()); - interpolate (width, height); - } - draw (width, height); - - break; - - case Gdk::BUTTON_PRESS: - add_modal_grab (); - new_type = Gdk::PLUS; - switch (curve.type) { - case Linear: - case Spline: - if (distance > MIN_DISTANCE) { - /* insert a new control point */ - if (num > 0) { - int cx = (int)((width-1)*curve.x[closest_point]+0.5); - if (x > cx) - ++closest_point; - } - itx = curve.x.begin(); - ity = curve.y.begin(); - for (int i=0; i= 0.0) { - curve.x[dst] = curve.x[src]; - curve.y[dst] = curve.y[src]; - ++dst; - ++itx; - ++ity; - } - } - if (dst < src) { - curve.x.erase (itx, curve.x.end()); - curve.y.erase (ity, curve.y.end()); - if (curve.x.size() <= 0) { - curve.x.push_back (0); - curve.y.push_back (0); - interpolate (width, height); - draw (width, height); - } - } - new_type = Gdk::FLEUR; - grab_point = -1; - retval = true; - notifyListener (); - break; - - case Gdk::MOTION_NOTIFY: - mevent = (GdkEventMotion *) event; - - switch (curve.type) { - case Linear: - case Spline: - if (grab_point == -1) { - /* if no point is grabbed... */ - if (distance <= MIN_DISTANCE) - new_type = Gdk::FLEUR; - else - new_type = Gdk::PLUS; - } - else { - /* drag the grabbed point */ - new_type = Gdk::FLEUR; - int leftbound = -MIN_DISTANCE; - if (grab_point > 0) - leftbound = (int)((width-1)*curve.x[grab_point-1]+0.5); + unsigned int distance = ~0U; + int num = curve.x.size(); + int closest_point = 0; - int rightbound = width + RADIUS * 2 + MIN_DISTANCE; - if (grab_point + 1 < num) - rightbound = (int)((width-1)*curve.x[grab_point+1]+0.5); + if (curve.type!=Parametric) { + for (int i = 0; i < num; ++i) { + int cx = (int)((width-1) * curve.x[i] + 0.5); //project (c->ctlpoint[i][0], min_x, c->max_x, width); + if ((unsigned int) abs (x - cx) < distance) { + distance = abs (x - cx); + closest_point = i; + } + } + } - if (tx <= leftbound || tx >= rightbound || ty > height + RADIUS * 2 + MIN_DISTANCE || ty < -MIN_DISTANCE) - curve.x[grab_point] = -1.0; - else { - curve.x[grab_point] = (double) x / (width-1); - curve.y[grab_point] = (double) (height-y) / (height-1); - } - interpolate (width, height); - draw (width, height); - notifyListener (); - } - break; - } + switch (event->type) { + case Gdk::CONFIGURE: + if (pixmap) + pixmap.clear (); + + case Gdk::EXPOSE: + if (!pixmap) { + pixmap = Gdk::Pixmap::create (get_window(), get_allocation().get_width(), get_allocation().get_height()); + interpolate (width, height); + } + draw (width, height); + break; + + case Gdk::BUTTON_PRESS: + if (curve.type!=Parametric) { + add_modal_grab (); + new_type = Gdk::PLUS; + if (distance > MIN_DISTANCE) { + /* insert a new control point */ + if (num > 0) { + int cx = (int)((width-1)*curve.x[closest_point]+0.5); + if (x > cx) + ++closest_point; + } + itx = curve.x.begin(); + ity = curve.y.begin(); + for (int i=0; i= 0.0) { + curve.x[dst] = curve.x[src]; + curve.y[dst] = curve.y[src]; + ++dst; + ++itx; + ++ity; + } + if (dst < src) { + curve.x.erase (itx, curve.x.end()); + curve.y.erase (ity, curve.y.end()); + if (curve.x.size() <= 0) { + curve.x.push_back (0); + curve.y.push_back (0); + interpolate (width, height); + draw (width, height); + } + } + new_type = Gdk::FLEUR; + grab_point = -1; + retval = true; + notifyListener (); + } + break; + + case Gdk::MOTION_NOTIFY: + mevent = (GdkEventMotion *) event; + if (curve.type == Linear || curve.type == Spline) { + if (grab_point == -1) { + /* if no point is grabbed... */ + if (distance <= MIN_DISTANCE) + new_type = Gdk::FLEUR; + else + new_type = Gdk::PLUS; + } + else { + /* drag the grabbed point */ + new_type = Gdk::FLEUR; + int leftbound = -MIN_DISTANCE; + if (grab_point > 0) + leftbound = (int)((width-1)*curve.x[grab_point-1]+0.5); + + int rightbound = width + RADIUS * 2 + MIN_DISTANCE; + if (grab_point + 1 < num) + rightbound = (int)((width-1)*curve.x[grab_point+1]+0.5); + + if (tx <= leftbound || tx >= rightbound || ty > height + RADIUS * 2 + MIN_DISTANCE || ty < -MIN_DISTANCE) + curve.x[grab_point] = -1.0; + else { + curve.x[grab_point] = (double) x / (width-1); + curve.y[grab_point] = (double) (height-y) / (height-1); + } + interpolate (width, height); + draw (width, height); + notifyListener (); + } + } if (new_type != cursor_type) { cursor_type = new_type; @@ -410,49 +379,63 @@ bool MyCurve::handleEvents (GdkEvent* event) { get_window ()->set_cursor (*cursor); delete cursor; } - retval = true; break; default: break; } - return retval; - } std::vector MyCurve::getPoints () { std::vector result; - if (curve.type==Linear) - result.push_back (-1.0); - else - result.push_back (+1.0); - for (int i=0; i=0) { + if (curve.type==Parametric) { + result.push_back (+2.0); + for (int i=0; i=0) { + result.push_back (curve.x[i]); + result.push_back (curve.y[i]); + } + } return result; } void MyCurve::setPoints (const std::vector& p) { int ix = 0; - if (p[ix++]>0) - curve.type = Spline; - else - curve.type = Linear; - - curve.x.clear (); - curve.y.clear (); - for (int i=0; icurveChanged (); } + +void MyCurve::setActiveParam (int ac) { + + activeParam = ac; + pixmap.clear (); + queue_draw (); +} + +int mchistupdate (void* data) { + + gdk_threads_enter (); + + MyCurveIdleHelper* mcih = (MyCurveIdleHelper*)data; + + if (mcih->destroyed) { + if (mcih->pending == 1) + delete mcih; + else + mcih->pending--; + gdk_threads_leave (); + return 0; + } + + mcih->myCurve->pixmap.clear (); + mcih->myCurve->queue_draw (); + + mcih->pending--; + gdk_threads_leave (); + return 0; +} + +void MyCurve::updateBackgroundHistogram (unsigned int* hist) { + + if (hist!=NULL) { + memcpy (bghist, hist, 256*sizeof(unsigned int)); + bghistvalid = true; + } + else + bghistvalid = false; + + mcih->pending++; + g_idle_add (mchistupdate, mcih); + +} + diff --git a/rtgui/mycurve.h b/rtgui/mycurve.h index 13f0d85a0..168c70ec3 100755 --- a/rtgui/mycurve.h +++ b/rtgui/mycurve.h @@ -21,24 +21,29 @@ #include #include +#include -class CurveListener { - - public: - virtual void curveChanged () {} -}; - -enum CurveType {Linear, Spline}; +enum CurveType {Linear, Spline, Parametric}; class CurveDescr { public: CurveType type; - std::vector x, y; + std::vector x, y; // in case of parametric curves the curve parameters are stored in vector x. In other cases these vectors store the coordinates of the bullets. +}; + +class MyCurve; +struct MyCurveIdleHelper { + MyCurve* myCurve; + bool destroyed; + int pending; }; class MyCurve : public Gtk::DrawingArea { + friend int mchistupdate (void* data); + + protected: CurveListener* listener; CurveDescr curve; Gdk::CursorType cursor_type; @@ -47,16 +52,20 @@ class MyCurve : public Gtk::DrawingArea { int grab_point; int last; std::vector point; + std::vector upoint; + std::vector lpoint; + int activeParam; + unsigned int bghist[256]; + bool bghistvalid; + MyCurveIdleHelper* mcih; - protected: void draw (int width, int height); void interpolate (int width, int height); std::vector get_vector (int veclen); - double spline_eval (int n, double x[], double y[], double y2[], double val); - void spline_solve (int n, double x[], double y[], double y2[]); public: MyCurve (); + ~MyCurve (); void setCurveListener (CurveListener* cl) { listener = cl; } std::vector getPoints (); @@ -64,6 +73,8 @@ class MyCurve : public Gtk::DrawingArea { void setType (CurveType t); bool handleEvents (GdkEvent* event); void notifyListener (); + void setActiveParam (int ac); + void updateBackgroundHistogram (unsigned int* hist); }; #endif diff --git a/rtgui/options.cc b/rtgui/options.cc index 928b59bab..a70ba3f58 100755 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -22,6 +22,7 @@ #include #include #include +#include Options options; Glib::ustring versionString = "v3.0 alpha 1"; @@ -107,8 +108,8 @@ void Options::setDefaults () { thumbnailZoomRatios.push_back (1.0); overlayedFileNames = true; - int babehav[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}; - baBehav = std::vector (babehav, babehav+22); + int babehav[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0}; + baBehav = std::vector (babehav, babehav+ADDSET_PARAM_NUM); rtSettings.dualThreadEnabled = true; rtSettings.demosaicMethod = "eahd"; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index d23a8045e..d8175bd01 100755 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -19,6 +19,7 @@ #include #include #include +#include ParamsEdited::ParamsEdited () { @@ -38,10 +39,7 @@ void ParamsEdited::set (bool v) { toneCurve.expcomp = v; lumaCurve.curve = v; lumaCurve.brightness = v; - lumaCurve.black = v; lumaCurve.contrast = v; - lumaCurve.shcompr = v; - lumaCurve.hlcompr = v; sharpening.enabled = v; sharpening.radius = v; sharpening.amount = v; @@ -145,10 +143,7 @@ void ParamsEdited::initFrom (const std::vector toneCurve.expcomp = toneCurve.expcomp && p.toneCurve.expcomp == other.toneCurve.expcomp; lumaCurve.curve = lumaCurve.curve && p.lumaCurve.curve == other.lumaCurve.curve; lumaCurve.brightness = lumaCurve.brightness && p.lumaCurve.brightness == other.lumaCurve.brightness; - lumaCurve.black = lumaCurve.black && p.lumaCurve.black == other.lumaCurve.black; lumaCurve.contrast = lumaCurve.contrast && p.lumaCurve.contrast == other.lumaCurve.contrast; - lumaCurve.shcompr = lumaCurve.shcompr && p.lumaCurve.shcompr == other.lumaCurve.shcompr; - lumaCurve.hlcompr = lumaCurve.hlcompr && p.lumaCurve.hlcompr == other.lumaCurve.hlcompr; 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; @@ -233,55 +228,52 @@ void ParamsEdited::initFrom (const std::vector void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rtengine::procparams::ProcParams& mods) { if (toneCurve.curve) toEdit.toneCurve.curve = mods.toneCurve.curve; - if (toneCurve.brightness) toEdit.toneCurve.brightness = options.baBehav[1] ? toEdit.toneCurve.brightness + mods.toneCurve.brightness : mods.toneCurve.brightness; - if (toneCurve.black) toEdit.toneCurve.black = options.baBehav[2] ? toEdit.toneCurve.black + mods.toneCurve.black : mods.toneCurve.black; - if (toneCurve.contrast) toEdit.toneCurve.contrast = options.baBehav[3] ? toEdit.toneCurve.contrast + mods.toneCurve.contrast : mods.toneCurve.contrast; + if (toneCurve.brightness) toEdit.toneCurve.brightness = options.baBehav[ADDSET_TC_BRIGHTNESS] ? toEdit.toneCurve.brightness + mods.toneCurve.brightness : mods.toneCurve.brightness; + if (toneCurve.black) toEdit.toneCurve.black = options.baBehav[ADDSET_TC_BLACKLEVEL] ? toEdit.toneCurve.black + mods.toneCurve.black : mods.toneCurve.black; + if (toneCurve.contrast) toEdit.toneCurve.contrast = options.baBehav[ADDSET_TC_CONTRAST] ? toEdit.toneCurve.contrast + mods.toneCurve.contrast : mods.toneCurve.contrast; if (toneCurve.shcompr) toEdit.toneCurve.shcompr = mods.toneCurve.shcompr; if (toneCurve.hlcompr) toEdit.toneCurve.hlcompr = mods.toneCurve.hlcompr; if (toneCurve.autoexp) toEdit.toneCurve.autoexp = mods.toneCurve.autoexp; if (toneCurve.clip) toEdit.toneCurve.clip = mods.toneCurve.clip; - if (toneCurve.expcomp) toEdit.toneCurve.expcomp = options.baBehav[0] ? toEdit.toneCurve.expcomp + mods.toneCurve.expcomp : mods.toneCurve.expcomp; + if (toneCurve.expcomp) toEdit.toneCurve.expcomp = options.baBehav[ADDSET_TC_EXPCOMP] ? toEdit.toneCurve.expcomp + mods.toneCurve.expcomp : mods.toneCurve.expcomp; if (lumaCurve.curve) toEdit.lumaCurve.curve = mods.lumaCurve.curve; - if (lumaCurve.brightness) toEdit.lumaCurve.brightness = mods.lumaCurve.brightness; - if (lumaCurve.black) toEdit.lumaCurve.black = mods.lumaCurve.black; - if (lumaCurve.contrast) toEdit.lumaCurve.contrast = mods.lumaCurve.contrast; - if (lumaCurve.shcompr) toEdit.lumaCurve.shcompr = mods.lumaCurve.shcompr; - if (lumaCurve.hlcompr) toEdit.lumaCurve.hlcompr = mods.lumaCurve.hlcompr; - 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[10] ? toEdit.sharpening.amount + mods.sharpening.amount : mods.sharpening.amount; - if (sharpening.threshold) toEdit.sharpening.threshold = mods.sharpening.threshold; - if (sharpening.edgesonly) toEdit.sharpening.edgesonly = mods.sharpening.edgesonly; - if (sharpening.edges_radius) toEdit.sharpening.edges_radius = mods.sharpening.edges_radius; - if (sharpening.edges_tolerance) toEdit.sharpening.edges_tolerance = mods.sharpening.edges_tolerance; - if (sharpening.halocontrol) toEdit.sharpening.halocontrol = mods.sharpening.halocontrol; - if (sharpening.halocontrol_amount) toEdit.sharpening.halocontrol_amount = mods.sharpening.halocontrol_amount; - if (sharpening.method) toEdit.sharpening.method = mods.sharpening.method; - if (sharpening.deconvamount) toEdit.sharpening.deconvamount = options.baBehav[10] ? toEdit.sharpening.deconvamount + mods.sharpening.deconvamount : mods.sharpening.deconvamount; - if (sharpening.deconvradius) toEdit.sharpening.deconvradius = mods.sharpening.deconvradius; - if (sharpening.deconviter) toEdit.sharpening.deconviter = mods.sharpening.deconviter; - if (sharpening.deconvdamping) toEdit.sharpening.deconvdamping = mods.sharpening.deconvdamping; - if (colorBoost.amount) toEdit.colorBoost.amount = options.baBehav[14] ? toEdit.colorBoost.amount + mods.colorBoost.amount : mods.colorBoost.amount; - if (colorBoost.avoidclip) toEdit.colorBoost.avoidclip = mods.colorBoost.avoidclip; - if (colorBoost.enable_saturationlimiter) toEdit.colorBoost.enable_saturationlimiter = mods.colorBoost.enable_saturationlimiter; - if (colorBoost.saturationlimit) toEdit.colorBoost.saturationlimit = mods.colorBoost.saturationlimit; - if (wb.method) toEdit.wb.method = mods.wb.method; - if (wb.green) toEdit.wb.green = options.baBehav[13] ? toEdit.wb.green + mods.wb.green : mods.wb.green; - if (wb.temperature) toEdit.wb.temperature = options.baBehav[12] ? toEdit.wb.temperature + mods.wb.temperature : mods.wb.temperature; - if (colorShift.a) toEdit.colorShift.a = options.baBehav[15] ? toEdit.colorShift.a + mods.colorShift.a : mods.colorShift.a; - if (colorShift.b) toEdit.colorShift.b = options.baBehav[16] ? toEdit.colorShift.b + mods.colorShift.b : mods.colorShift.b; - if (lumaDenoise.enabled) toEdit.lumaDenoise.enabled = mods.lumaDenoise.enabled; - if (lumaDenoise.radius) toEdit.lumaDenoise.radius = mods.lumaDenoise.radius; - if (lumaDenoise.edgetolerance) toEdit.lumaDenoise.edgetolerance = options.baBehav[11] ? toEdit.lumaDenoise.edgetolerance + mods.lumaDenoise.edgetolerance : mods.lumaDenoise.edgetolerance; - if (colorDenoise.enabled) toEdit.colorDenoise.enabled = mods.colorDenoise.enabled; - if (colorDenoise.amount) toEdit.colorDenoise.amount = mods.colorDenoise.amount; + if (lumaCurve.brightness) toEdit.lumaCurve.brightness = options.baBehav[ADDSET_LC_BRIGHTNESS] ? toEdit.lumaCurve.brightness + mods.lumaCurve.brightness : mods.lumaCurve.brightness; + if (lumaCurve.contrast) toEdit.lumaCurve.contrast = options.baBehav[ADDSET_LC_CONTRAST] ? toEdit.lumaCurve.contrast + mods.lumaCurve.contrast : mods.lumaCurve.contrast; + 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; + if (sharpening.threshold) toEdit.sharpening.threshold = mods.sharpening.threshold; + if (sharpening.edgesonly) toEdit.sharpening.edgesonly = mods.sharpening.edgesonly; + if (sharpening.edges_radius) toEdit.sharpening.edges_radius = mods.sharpening.edges_radius; + if (sharpening.edges_tolerance) toEdit.sharpening.edges_tolerance = mods.sharpening.edges_tolerance; + if (sharpening.halocontrol) toEdit.sharpening.halocontrol = mods.sharpening.halocontrol; + if (sharpening.halocontrol_amount) toEdit.sharpening.halocontrol_amount = mods.sharpening.halocontrol_amount; + if (sharpening.method) toEdit.sharpening.method = mods.sharpening.method; + if (sharpening.deconvamount) toEdit.sharpening.deconvamount = options.baBehav[ADDSET_SHARP_AMOUNT] ? toEdit.sharpening.deconvamount + mods.sharpening.deconvamount : mods.sharpening.deconvamount; + if (sharpening.deconvradius) toEdit.sharpening.deconvradius = mods.sharpening.deconvradius; + if (sharpening.deconviter) toEdit.sharpening.deconviter = mods.sharpening.deconviter; + if (sharpening.deconvdamping) toEdit.sharpening.deconvdamping = mods.sharpening.deconvdamping; + if (colorBoost.amount) toEdit.colorBoost.amount = options.baBehav[ADDSET_CBOOST_AMOUNT] ? toEdit.colorBoost.amount + mods.colorBoost.amount : mods.colorBoost.amount; + if (colorBoost.avoidclip) toEdit.colorBoost.avoidclip = mods.colorBoost.avoidclip; + if (colorBoost.enable_saturationlimiter)toEdit.colorBoost.enable_saturationlimiter = mods.colorBoost.enable_saturationlimiter; + if (colorBoost.saturationlimit) toEdit.colorBoost.saturationlimit = mods.colorBoost.saturationlimit; + if (wb.method) toEdit.wb.method = mods.wb.method; + if (wb.green) toEdit.wb.green = options.baBehav[ADDSET_WB_GREEN] ? toEdit.wb.green + mods.wb.green : mods.wb.green; + if (wb.temperature) toEdit.wb.temperature = options.baBehav[ADDSET_WB_TEMPERATURE] ? toEdit.wb.temperature + mods.wb.temperature : mods.wb.temperature; + if (colorShift.a) toEdit.colorShift.a = options.baBehav[ADDSET_CS_BLUEYELLOW] ? toEdit.colorShift.a + mods.colorShift.a : mods.colorShift.a; + if (colorShift.b) toEdit.colorShift.b = options.baBehav[ADDSET_CS_GREENMAGENTA] ? toEdit.colorShift.b + mods.colorShift.b : mods.colorShift.b; + if (lumaDenoise.enabled) toEdit.lumaDenoise.enabled = mods.lumaDenoise.enabled; + if (lumaDenoise.radius) toEdit.lumaDenoise.radius = mods.lumaDenoise.radius; + if (lumaDenoise.edgetolerance) toEdit.lumaDenoise.edgetolerance = options.baBehav[ADDSET_LD_EDGETOLERANCE] ? toEdit.lumaDenoise.edgetolerance + mods.lumaDenoise.edgetolerance : mods.lumaDenoise.edgetolerance; + if (colorDenoise.enabled) toEdit.colorDenoise.enabled = mods.colorDenoise.enabled; + if (colorDenoise.amount) toEdit.colorDenoise.amount = mods.colorDenoise.amount; if (sh.enabled) toEdit.sh.enabled = mods.sh.enabled; if (sh.hq) toEdit.sh.hq = mods.sh.hq; - if (sh.highlights) toEdit.sh.highlights = options.baBehav[4] ? toEdit.sh.highlights + mods.sh.highlights : mods.sh.highlights; + if (sh.highlights) toEdit.sh.highlights = options.baBehav[ADDSET_SH_HIGHLIGHTS] ? toEdit.sh.highlights + mods.sh.highlights : mods.sh.highlights; if (sh.htonalwidth) toEdit.sh.htonalwidth = mods.sh.htonalwidth; - if (sh.shadows) toEdit.sh.shadows = options.baBehav[5] ? toEdit.sh.shadows + mods.sh.shadows : mods.sh.shadows; + if (sh.shadows) toEdit.sh.shadows = options.baBehav[ADDSET_SH_SHADOWS] ? toEdit.sh.shadows + mods.sh.shadows : mods.sh.shadows; if (sh.stonalwidth) toEdit.sh.stonalwidth = mods.sh.stonalwidth; - if (sh.localcontrast) toEdit.sh.localcontrast = options.baBehav[6] ? toEdit.sh.localcontrast + mods.sh.localcontrast : mods.sh.localcontrast; + if (sh.localcontrast) toEdit.sh.localcontrast = options.baBehav[ADDSET_SH_LOCALCONTRAST] ? toEdit.sh.localcontrast + mods.sh.localcontrast : mods.sh.localcontrast; if (sh.radius) toEdit.sh.radius = mods.sh.radius; if (crop.enabled) toEdit.crop.enabled = mods.crop.enabled; if (crop.x) toEdit.crop.x = mods.crop.x; @@ -297,10 +289,10 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if (coarse.vflip) toEdit.coarse.vflip = mods.coarse.vflip ? !toEdit.coarse.vflip : toEdit.coarse.vflip; if (rotate.degree) toEdit.rotate.degree = options.baBehav[17] ? toEdit.rotate.degree + mods.rotate.degree : mods.rotate.degree; if (rotate.fill) toEdit.rotate.fill = mods.rotate.fill; - if (distortion.amount) toEdit.distortion.amount = options.baBehav[18] ? toEdit.distortion.amount + mods.distortion.amount : mods.distortion.amount; - if (cacorrection.red) toEdit.cacorrection.red = options.baBehav[19] ? toEdit.cacorrection.red + mods.cacorrection.red : mods.cacorrection.red; - if (cacorrection.blue) toEdit.cacorrection.blue = options.baBehav[20] ? toEdit.cacorrection.blue + mods.cacorrection.blue : mods.cacorrection.blue; - if (vignetting.amount) toEdit.vignetting.amount = options.baBehav[21] ? toEdit.vignetting.amount + mods.vignetting.amount : mods.vignetting.amount; + if (distortion.amount) toEdit.distortion.amount = options.baBehav[ADDSET_DIST_AMOUNT] ? toEdit.distortion.amount + mods.distortion.amount : mods.distortion.amount; + if (cacorrection.red) toEdit.cacorrection.red = options.baBehav[ADDSET_CA_RED] ? toEdit.cacorrection.red + mods.cacorrection.red : mods.cacorrection.red; + if (cacorrection.blue) toEdit.cacorrection.blue = options.baBehav[ADDSET_CA_BLUE] ? toEdit.cacorrection.blue + mods.cacorrection.blue : mods.cacorrection.blue; + if (vignetting.amount) toEdit.vignetting.amount = options.baBehav[ADDSET_VIGN_AMOUNT] ? toEdit.vignetting.amount + mods.vignetting.amount : mods.vignetting.amount; if (vignetting.radius) toEdit.vignetting.radius = mods.vignetting.radius; if (chmixer.red[0]) toEdit.chmixer.red[0] = mods.chmixer.red[0]; if (chmixer.red[1]) toEdit.chmixer.red[1] = mods.chmixer.red[1]; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index fb85a01c0..f1640dea5 100755 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -24,7 +24,7 @@ #include #include -class CurveParamsEdited { +class ToneCurveParamsEdited { public: bool curve; @@ -33,16 +33,19 @@ class CurveParamsEdited { bool contrast; bool shcompr; bool hlcompr; -}; - -class ToneCurveParamsEdited : public CurveParamsEdited { - - public: bool autoexp; bool clip; bool expcomp; }; +class LCurveParamsEdited { + + public: + bool brightness; + bool contrast; + bool curve; +}; + class SharpeningParamsEdited { public: @@ -217,7 +220,7 @@ class ParamsEdited { public: ToneCurveParamsEdited toneCurve; - CurveParamsEdited lumaCurve; + LCurveParamsEdited lumaCurve; SharpeningParamsEdited sharpening; ColorBoostParamsEdited colorBoost; WBParamsEdited wb; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index b61f80e9b..2f20f52f5 100755 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -21,6 +21,7 @@ #include #include #include +#include extern Options options; extern Glib::ustring argv0; @@ -126,74 +127,74 @@ Gtk::Widget* Preferences::getBatchProcPanel () { mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_EXPOSURE_LABEL")); - appendBehavList (mi, M("TP_EXPOSURE_EXPCOMP"), false); - appendBehavList (mi, M("TP_EXPOSURE_BRIGHTNESS"), false); - appendBehavList (mi, M("TP_EXPOSURE_BLACKLEVEL"), false); - appendBehavList (mi, M("TP_EXPOSURE_CONTRAST"), false); + appendBehavList (mi, M("TP_EXPOSURE_EXPCOMP"), ADDSET_TC_EXPCOMP, false); + appendBehavList (mi, M("TP_EXPOSURE_BRIGHTNESS"), ADDSET_TC_BRIGHTNESS, false); + appendBehavList (mi, M("TP_EXPOSURE_BLACKLEVEL"), ADDSET_TC_BLACKLEVEL, false); + appendBehavList (mi, M("TP_EXPOSURE_CONTRAST"), ADDSET_TC_CONTRAST, false); mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_SHADOWSHLIGHTS_LABEL")); - appendBehavList (mi, M("TP_SHADOWSHLIGHTS_HIGHLIGHTS"), false); - appendBehavList (mi, M("TP_SHADOWSHLIGHTS_SHADOWS"), false); - appendBehavList (mi, M("TP_SHADOWSHLIGHTS_LOCALCONTR"), false); + appendBehavList (mi, M("TP_SHADOWSHLIGHTS_HIGHLIGHTS"), ADDSET_SH_HIGHLIGHTS, false); + appendBehavList (mi, M("TP_SHADOWSHLIGHTS_SHADOWS"), ADDSET_SH_SHADOWS, false); + appendBehavList (mi, M("TP_SHADOWSHLIGHTS_LOCALCONTR"), ADDSET_SH_LOCALCONTRAST, false); mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_LUMACURVE_LABEL")); - appendBehavList (mi, M("TP_LUMACURVE_BRIGHTNESS"), false); - appendBehavList (mi, M("TP_LUMACURVE_BLACKLEVEL"), false); - appendBehavList (mi, M("TP_LUMACURVE_CONTRAST"), false); + appendBehavList (mi, M("TP_LUMACURVE_BRIGHTNESS"), ADDSET_LC_BRIGHTNESS, false); + appendBehavList (mi, M("TP_LUMACURVE_CONTRAST"), ADDSET_LC_CONTRAST, false); mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_SHARPENING_LABEL")); - appendBehavList (mi, M("TP_SHARPENING_AMOUNT"), false); + appendBehavList (mi, M("TP_SHARPENING_AMOUNT"), ADDSET_SHARP_AMOUNT, false); mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_LUMADENOISE_LABEL")); - appendBehavList (mi, M("TP_LUMADENOISE_EDGETOLERANCE"), true); + appendBehavList (mi, M("TP_LUMADENOISE_EDGETOLERANCE"), ADDSET_LD_EDGETOLERANCE, true); mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_WBALANCE_LABEL")); - appendBehavList (mi, M("TP_WBALANCE_TEMPERATURE"), true); - appendBehavList (mi, M("TP_WBALANCE_GREEN"), true); + appendBehavList (mi, M("TP_WBALANCE_TEMPERATURE"), ADDSET_WB_TEMPERATURE, true); + appendBehavList (mi, M("TP_WBALANCE_GREEN"), ADDSET_WB_GREEN, true); mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_COLORBOOST_LABEL")); - appendBehavList (mi, M("TP_COLORBOOST_AMOUNT"), false); + appendBehavList (mi, M("TP_COLORBOOST_AMOUNT"), ADDSET_CBOOST_AMOUNT, false); mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_COLORSHIFT_LABEL")); - appendBehavList (mi, M("TP_COLORSHIFT_BLUEYELLOW"), false); - appendBehavList (mi, M("TP_COLORSHIFT_GREENMAGENTA"), false); + appendBehavList (mi, M("TP_COLORSHIFT_BLUEYELLOW"), ADDSET_CS_BLUEYELLOW, false); + appendBehavList (mi, M("TP_COLORSHIFT_GREENMAGENTA"), ADDSET_CS_GREENMAGENTA, false); mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_ROTATE_LABEL")); - appendBehavList (mi, M("TP_ROTATE_DEGREE"), false); + appendBehavList (mi, M("TP_ROTATE_DEGREE"), ADDSET_ROTATE_DEGREE, false); mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_DISTORTION_LABEL")); - appendBehavList (mi, M("TP_DISTORTION_AMOUNT"), false); + appendBehavList (mi, M("TP_DISTORTION_AMOUNT"), ADDSET_DIST_AMOUNT, false); mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_CACORRECTION_LABEL")); - appendBehavList (mi, M("TP_CACORRECTION_BLUE"), true); - appendBehavList (mi, M("TP_CACORRECTION_RED"), true); + appendBehavList (mi, M("TP_CACORRECTION_BLUE"), ADDSET_CA_BLUE, true); + appendBehavList (mi, M("TP_CACORRECTION_RED"), ADDSET_CA_RED, true); mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_VIGNETTING_LABEL")); - appendBehavList (mi, M("TP_VIGNETTING_AMOUNT"), false); + appendBehavList (mi, M("TP_VIGNETTING_AMOUNT"), ADDSET_VIGN_AMOUNT, false); behTreeView->expand_all (); return mvbpp; } -void Preferences::appendBehavList (Gtk::TreeModel::iterator& parent, Glib::ustring label, bool set) { +void Preferences::appendBehavList (Gtk::TreeModel::iterator& parent, Glib::ustring label, int id, bool set) { Gtk::TreeModel::iterator ci = behModel->append (parent->children()); ci->set_value (behavColumns.label, label); ci->set_value (behavColumns.visible, true); ci->set_value (behavColumns.badd, !set); ci->set_value (behavColumns.bset, set); + ci->set_value (behavColumns.addsetid, id); } void Preferences::behAddRadioToggled (const Glib::ustring& path) { @@ -703,10 +704,10 @@ void Preferences::storePreferences () { moptions.paramsLoadLocation = (PPLoadLocation)loadParamsPreference->get_active_row_number (); int i = 0; - moptions.baBehav.clear (); + moptions.baBehav.resize (ADDSET_PARAM_NUM); for (Gtk::TreeIter sections=behModel->children().begin(); sections!=behModel->children().end(); sections++) for (Gtk::TreeIter adjs=sections->children().begin(); adjs!=sections->children().end(); adjs++) - moptions.baBehav.push_back (adjs->get_value (behavColumns.badd)); + moptions.baBehav[adjs->get_value (behavColumns.addsetid)] = adjs->get_value (behavColumns.badd); } void Preferences::fillPreferences () { @@ -784,13 +785,16 @@ void Preferences::fillPreferences () { addc.block (true); setc.block (true); - int i = 0; - for (Gtk::TreeIter sections=behModel->children().begin(); sections!=behModel->children().end(); sections++) - for (Gtk::TreeIter adjs=sections->children().begin(); adjs!=sections->children().end(); adjs++) - if (moptions.baBehav.size()>i) { - adjs->set_value (behavColumns.badd, moptions.baBehav[i]==1); - adjs->set_value (behavColumns.bset, moptions.baBehav[i++]!=1); - } + if (moptions.baBehav.size() == ADDSET_PARAM_NUM) { + for (int i=0; ichildren().begin(); sections!=behModel->children().end(); sections++) + for (Gtk::TreeIter adjs=sections->children().begin(); adjs!=sections->children().end(); adjs++) + if (adjs->get_value (behavColumns.addsetid) == i) { + adjs->set_value (behavColumns.badd, moptions.baBehav[i]==1); + adjs->set_value (behavColumns.bset, moptions.baBehav[i]!=1); + break; + } + } addc.block (false); setc.block (false); diff --git a/rtgui/preferences.h b/rtgui/preferences.h index f27b1fcd5..d741f74e2 100755 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -42,7 +42,8 @@ class Preferences : public Gtk::Dialog { Gtk::TreeModelColumn badd; Gtk::TreeModelColumn bset; Gtk::TreeModelColumn visible; - BehavColumns() { add(label); add(badd); add(bset); add(visible);} + Gtk::TreeModelColumn addsetid; + BehavColumns() { add(label); add(badd); add(bset); add(visible); add(addsetid); } }; Glib::RefPtr behModel; BehavColumns behavColumns; @@ -108,7 +109,7 @@ class Preferences : public Gtk::Dialog { void themeChanged (); - void appendBehavList (Gtk::TreeModel::iterator& parent, Glib::ustring label, bool set); + void appendBehavList (Gtk::TreeModel::iterator& parent, Glib::ustring label, int id, bool set); Gtk::Widget* getProcParamsPanel (); Gtk::Widget* getColorManagementPanel (); diff --git a/rtgui/shcselector.cc b/rtgui/shcselector.cc new file mode 100644 index 000000000..0b699e052 --- /dev/null +++ b/rtgui/shcselector.cc @@ -0,0 +1,166 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include +#include + +SHCSelector::SHCSelector() : movingPosition(-1), cl(NULL) { + + positions[0] = 0.25; + positions[1] = 0.5; + positions[2] = 0.75; +} + +void SHCSelector::setPositions (double spos, double cpos, double hpos) { + + positions[0] = spos; + positions[1] = cpos; + positions[2] = hpos; + + queue_draw (); +} + +void SHCSelector::getPositions (double& spos, double& cpos, double& hpos) { + + spos = positions[0]; + cpos = positions[1]; + hpos = positions[2]; +} + +void SHCSelector::on_realize() { + + Gtk::DrawingArea::on_realize(); + + add_events(Gdk::EXPOSURE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); +} + +bool SHCSelector::on_expose_event(GdkEventExpose* event) { + + Cairo::RefPtr cr = get_window()->create_cairo_context(); + + int w = get_width (); + int h = get_height (); + + wslider = h *2.0 / 5.0; + + Gdk::Color bgc = get_style()->get_bg (Gtk::STATE_NORMAL); + Gdk::Color fgc = get_style()->get_text (Gtk::STATE_NORMAL); + + // clear bg + cr->set_source_rgb (bgc.get_red_p(), bgc.get_green_p(), bgc.get_blue_p()); + cr->rectangle (0, 0, w, h); + cr->fill(); + + // draw gradient background + Cairo::RefPtr< Cairo::LinearGradient > bggradient = Cairo::LinearGradient::create (0, 0, w, 0); + bggradient->add_color_stop_rgb (0, 0, 0, 0); + bggradient->add_color_stop_rgb (1, 1, 1, 1); + + cr->set_line_width (1.0); + cr->set_source (bggradient); + cr->rectangle (0.5, h*2.0/7.0 + 0.5, w-0.5, h*3.0/7.0-0.5); + cr->fill_preserve(); + cr->set_source_rgb (fgc.get_red_p(), fgc.get_green_p(), fgc.get_blue_p()); + cr->stroke (); + + // draw sliders + cr->set_line_width (1.0); + for (int i=0; i<3; i++) { + cr->move_to (w*positions[i]-wslider/2+0.5, h-0.5); + cr->line_to (w*positions[i]-wslider/2+0.5, wslider/2 + 0.5); + cr->line_to (w*positions[i], 0.5); + cr->line_to (w*positions[i]+wslider/2-0.5, wslider/2 + 0.5); + cr->line_to (w*positions[i]+wslider/2-0.5, h-0.5); + cr->line_to (w*positions[i]-wslider/2+0.5, h-0.5); + cr->set_source_rgb (bgc.get_red_p(), bgc.get_green_p(), bgc.get_blue_p()); + cr->fill_preserve (); + cr->set_source_rgb (fgc.get_red_p(), fgc.get_green_p(), fgc.get_blue_p()); + cr->stroke (); + } + + // draw text for the slider that is being moved + Glib::RefPtr context = get_pango_context () ; + cr->set_line_width (0.5); + if (movingPosition >= 0) { + int i = movingPosition; + Glib::RefPtr layout = create_pango_layout(Glib::ustring::format(std::setprecision(2), positions[i])); + cr->move_to (w*positions[i]+wslider/2-0.5, 0); + cr->set_source_rgb (bgc.get_red_p(), bgc.get_green_p(), bgc.get_blue_p()); + layout->add_to_cairo_context (cr); + cr->fill_preserve (); + cr->stroke (); + cr->move_to (w*positions[i]+wslider/2+0.5, 1); + layout->add_to_cairo_context (cr); + cr->fill_preserve (); + cr->stroke (); + cr->set_source_rgb (fgc.get_red_p(), fgc.get_green_p(), fgc.get_blue_p()); + cr->move_to (w*positions[i]+wslider/2, 0.5); + layout->add_to_cairo_context (cr); + cr->fill_preserve (); + cr->stroke (); + } +} + +bool SHCSelector::on_button_press_event (GdkEventButton* event) { + + // check if a slider is under the cursor + int w = get_width (); + movingPosition = -1; + for (int i=0; i<3; i++) + if (event->x > w*positions[i]-wslider/2 && event->x < w*positions[i]+wslider/2) { + movingPosition = i; + tmpX = event->x; + tmpPos = positions[i]; + break; + } + queue_draw (); +} + +bool SHCSelector::on_button_release_event (GdkEventButton* event) { + + if (movingPosition >= 0) { + movingPosition = -1; + queue_draw (); + } +} + +bool SHCSelector::on_motion_notify_event (GdkEventMotion* event) { + + if (movingPosition >= 0) { + int w = get_width (); + positions[movingPosition] = tmpPos + (event->x - tmpX) / w; + if (positions[movingPosition] < 0) + positions[movingPosition] = 0.0; + else if (movingPosition > 0 && positions[movingPosition] < positions[movingPosition-1]+wslider/w) + positions[movingPosition] = positions[movingPosition-1]+wslider/w; + if (positions[movingPosition] > 1.0) + positions[movingPosition] = 1.0; + else if (movingPosition <3 && positions[movingPosition] > positions[movingPosition+1]-wslider/w) + positions[movingPosition] = positions[movingPosition+1]-wslider/w; + + if (cl) + cl->shcChanged (); + queue_draw (); + } +} + +void SHCSelector::styleChanged (const Glib::RefPtr& style) { + + queue_draw (); +} diff --git a/rtgui/shcselector.h b/rtgui/shcselector.h new file mode 100644 index 000000000..3199e4ae9 --- /dev/null +++ b/rtgui/shcselector.h @@ -0,0 +1,61 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef _SHCSELECTOR_ +#define _SHCSELECTOR_ + +#include + +class SHCListener { + public: + virtual void shcChanged () {} +}; + +class SHCSelector : public Gtk::DrawingArea { + + protected: + + Glib::RefPtr gc_; + Glib::RefPtr backBuffer; + + int movingPosition; + double tmpX, tmpPos; + + double positions[3]; + double wslider; + + SHCListener* cl; + + public: + + SHCSelector(); + + void setSHCListener (SHCListener* l) { cl = l;; } + + void setPositions (double spos, double cpos, double hpos); + void getPositions (double& spos, double& cpos, double& hpos); + void on_realize(); + bool on_expose_event(GdkEventExpose* event); + bool on_button_press_event (GdkEventButton* event); + bool on_button_release_event (GdkEventButton* event); + bool on_motion_notify_event (GdkEventMotion* event); + void styleChanged (const Glib::RefPtr& style); +}; + +#endif + diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index b56c0c332..4f3f80110 100755 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -49,7 +49,7 @@ ToneCurve::ToneCurve () : ToolPanel(), expAdd(false), blackAdd(false), brAdd(fal pack_start (*Gtk::manage (new Gtk::HSeparator())); //----------- Exposure Compensation ------------------------ - expcomp = new Adjuster (M("TP_EXPOSURE_EXPCOMP"), -5, 5, 0.01, 0); + expcomp = Gtk::manage (new Adjuster (M("TP_EXPOSURE_EXPCOMP"), -5, 5, 0.01, 0)); pack_start (*expcomp); hlcompr = Gtk::manage (new Adjuster (M("TP_EXPOSURE_COMPRHIGHLIGHTS"), 0, 150, 1, 0)); pack_start (*hlcompr); @@ -68,7 +68,7 @@ ToneCurve::ToneCurve () : ToolPanel(), expAdd(false), blackAdd(false), brAdd(fal contrast = Gtk::manage (new Adjuster (M("TP_EXPOSURE_CONTRAST"), -100, 100, 1, 0)); pack_start (*contrast); -/* + //----------- Curve ------------------------------ pack_start (*Gtk::manage (new Gtk::HSeparator())); @@ -78,7 +78,7 @@ ToneCurve::ToneCurve () : ToolPanel(), expAdd(false), blackAdd(false), brAdd(fal curvexp->add (*shape); pack_start (*curvexp, Gtk::PACK_SHRINK, 4); -*/ + // --------- Set Up Listeners ------------- expcomp->setAdjusterListener (this); brightness->setAdjusterListener (this); @@ -88,11 +88,6 @@ ToneCurve::ToneCurve () : ToolPanel(), expAdd(false), blackAdd(false), brAdd(fal contrast->setAdjusterListener (this); } -ToneCurve::~ToneCurve () { - - delete expcomp; -} - void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { disableListener (); @@ -106,6 +101,7 @@ void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { contrast->setEditedState (pedited->toneCurve.contrast ? Edited : UnEdited); autolevels->set_inconsistent (!pedited->toneCurve.autoexp); clipDirty = pedited->toneCurve.clip; + shape->setUnChanged (!pedited->toneCurve.curve); } autoconn.block (true); @@ -120,7 +116,7 @@ void ToneCurve::read (const ProcParams* pp, const ParamsEdited* pedited) { shcompr->setValue (pp->toneCurve.shcompr); brightness->setValue (pp->toneCurve.brightness); contrast->setValue (pp->toneCurve.contrast); -// shape->setCurve (pp->toneCurve.curve); + shape->setCurve (pp->toneCurve.curve); enableListener (); } @@ -135,7 +131,7 @@ void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited) { pp->toneCurve.shcompr = (int)shcompr->getValue (); pp->toneCurve.brightness = (int)brightness->getValue (); pp->toneCurve.contrast = (int)contrast->getValue (); -// pp->toneCurve.curve = shape->getCurve (); + pp->toneCurve.curve = shape->getCurve (); if (pedited) { pedited->toneCurve.expcomp = expcomp->getEditedState (); @@ -144,8 +140,9 @@ void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited) { pedited->toneCurve.shcompr = shcompr->getEditedState (); pedited->toneCurve.brightness = brightness->getEditedState (); pedited->toneCurve.contrast = contrast->getEditedState (); - pedited->toneCurve.autoexp = !autolevels->get_inconsistent(); - pedited->toneCurve.clip = clipDirty; + pedited->toneCurve.autoexp = !autolevels->get_inconsistent(); + pedited->toneCurve.clip = clipDirty; + pedited->toneCurve.curve = !shape->isUnChanged (); } } @@ -176,13 +173,13 @@ void ToneCurve::setDefaults (const ProcParams* defParams, const ParamsEdited* pe } } -/*void ToneCurve::curveChanged () { +void ToneCurve::curveChanged () { if (listener) { listener->panelChanged (EvToneCurve, M("HISTORY_CUSTOMCURVE")); } } -*/ + void ToneCurve::adjusterChanged (Adjuster* a, double newval) { if (autolevels->get_active() && (a==expcomp || a==black || a==hlcompr || a==shcompr)) { @@ -270,7 +267,7 @@ void ToneCurve::waitForAutoExp () { hlcompr->setEnabled (false); shcompr->setEnabled (false); contrast->setEnabled (false); -// shape->set_sensitive (false); + shape->set_sensitive (false); } int aexpcomputed (void* data) { @@ -287,7 +284,6 @@ void ToneCurve::autoExpChanged (double br, int bl) { nextBr = br; g_idle_add (aexpcomputed, this); - // Glib::signal_idle().connect (sigc::mem_fun(*this, &ToneCurve::autoExpComputed_)); } @@ -300,7 +296,7 @@ void ToneCurve::enableAll () { hlcompr->setEnabled (true); shcompr->setEnabled (true); contrast->setEnabled (true); -// shape->set_sensitive (true); + shape->set_sensitive (true); } bool ToneCurve::autoExpComputed_ () { @@ -314,7 +310,6 @@ bool ToneCurve::autoExpComputed_ () { return false; } -/* void ToneCurve::expandCurve (bool isExpanded) { curvexp->set_expanded (isExpanded); @@ -324,7 +319,7 @@ bool ToneCurve::isCurveExpanded () { return curvexp->get_expanded (); } -*/ + void ToneCurve::setBatchMode (bool batchMode) { @@ -340,6 +335,8 @@ void ToneCurve::setBatchMode (bool batchMode) { shcompr->showEditedCB (); brightness->showEditedCB (); contrast->showEditedCB (); + + shape->setBatchMode (batchMode); } void ToneCurve::setAdjusterBehavior (bool expadd, bool bradd, bool blackadd, bool contradd) { @@ -351,9 +348,9 @@ void ToneCurve::setAdjusterBehavior (bool expadd, bool bradd, bool blackadd, boo else if (blackAdd && !blackadd) black->setLimits (0, 32768, 1, 0); if (!brAdd && bradd || brAdd && !bradd) - brightness->setLimits (-100, 100, 0.01, 0); + brightness->setLimits (-100, 100, 1, 0); if (!contrAdd && contradd || contrAdd && !contradd) - contrast->setLimits (-100, 100, 0.01, 0); + contrast->setLimits (-100, 100, 1, 0); expAdd = expadd; blackAdd = blackadd; @@ -361,3 +358,7 @@ void ToneCurve::setAdjusterBehavior (bool expadd, bool bradd, bool blackadd, boo contrAdd = contradd; } +void ToneCurve::updateCurveBackgroundHistogram (unsigned* hist) { + + shape->updateBackgroundHistogram (hist); +} diff --git a/rtgui/tonecurve.h b/rtgui/tonecurve.h index 822964f00..4f4ad5256 100755 --- a/rtgui/tonecurve.h +++ b/rtgui/tonecurve.h @@ -22,10 +22,10 @@ #include #include #include -//#include -//#include +#include +#include -class ToneCurve : public Gtk::VBox, public AdjusterListener, public ToolPanel, public rtengine::AutoExpListener/*, public CurveListener */{ +class ToneCurve : public Gtk::VBox, public AdjusterListener, public ToolPanel, public rtengine::AutoExpListener, public CurveListener { protected: Gtk::HBox* abox; @@ -39,15 +39,14 @@ class ToneCurve : public Gtk::VBox, public AdjusterListener, public ToolPanel, p Adjuster* contrast; bool expAdd, blackAdd, brAdd, contrAdd, clipDirty, lastAuto; sigc::connection autoconn; -// CurveEditor* shape; -// Gtk::Expander* curvexp; + CurveEditor* shape; + Gtk::Expander* curvexp; double nextBr; int nextBl; public: ToneCurve (); - virtual ~ToneCurve (); void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); @@ -63,9 +62,10 @@ class ToneCurve : public Gtk::VBox, public AdjusterListener, public ToolPanel, p void autoExpChanged (double br, int bl); bool autoExpComputed_ (); void enableAll (); -/* void curveChanged (); + void curveChanged (); void expandCurve (bool isExpanded); - bool isCurveExpanded ();*/ + bool isCurveExpanded (); + void updateCurveBackgroundHistogram (unsigned* hist); }; #endif diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 6b9db38b0..642a2df6c 100755 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -36,7 +36,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { lumadenoise = Gtk::manage (new LumaDenoise ()); colordenoise = Gtk::manage (new ColorDenoise ()); sharpening = Gtk::manage (new Sharpening ()); -// lcurve = Gtk::manage (new LCurve ()); + lcurve = Gtk::manage (new LCurve ()); colorboost = Gtk::manage (new ColorBoost ()); colorshift = Gtk::manage (new ColorShift ()); distortion = Gtk::manage (new Distortion ()); @@ -60,7 +60,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { 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 (exposurePanel, lcurve, M("TP_LUMACURVE_LABEL")); toolPanels.push_back (lcurve);*/ + addPanel (exposurePanel, lcurve, M("TP_LUMACURVE_LABEL")); toolPanels.push_back (lcurve); addPanel (detailsPanel, lumadenoise, M("TP_LUMADENOISE_LABEL")); toolPanels.push_back (lumadenoise); addPanel (detailsPanel, colordenoise, M("TP_COLORDENOISE_LABEL")); toolPanels.push_back (colordenoise); addPanel (transformPanel, crop, M("TP_CROP_LABEL")); toolPanels.push_back (crop); @@ -249,26 +249,23 @@ void ToolPanelCoordinator::closeImage () { void ToolPanelCoordinator::readOptions () { crop->readOptions (); -/* for (int i=0; iset_expanded (options.tpOpen[i]); - if (options.crvOpen.size()>1) { + if (options.crvOpen.size()>1) curve->expandCurve (options.crvOpen[0]); - lcurve->expandCurve (options.crvOpen[1]); - }*/ } void ToolPanelCoordinator::writeOptions () { crop->writeOptions (); -/* options.tpOpen.clear (); + options.tpOpen.clear (); for (int i=0; iget_expanded ()); options.crvOpen.clear (); options.crvOpen.push_back (curve->isCurveExpanded()); - options.crvOpen.push_back (lcurve->isCurveExpanded());*/ } @@ -353,3 +350,9 @@ int ToolPanelCoordinator::getSpotWBRectSize () { return whitebalance->getSize (); } + +void ToolPanelCoordinator::updateCurveBackgroundHistogram (unsigned* histrgb, unsigned* histl) { + + curve->updateCurveBackgroundHistogram (histrgb); + lcurve->updateCurveBackgroundHistogram (histl); +} diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 778ea4945..eb19edd59 100755 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -34,7 +34,7 @@ #include #include #include -//#include +#include #include #include #include @@ -54,7 +54,7 @@ class ImageEditorCoordinator; class ToolPanelCoordinator : public ToolPanelListener, public ProfileChangeListener, public WBProvider, - public RotateListener , + public RotateListener, public SpotWBListener, public CropPanelListener, public ICMPanelListener, @@ -79,7 +79,7 @@ class ToolPanelCoordinator : public ToolPanelListener, LumaDenoise* lumadenoise; ColorDenoise* colordenoise; Sharpening* sharpening; -// LCurve* lcurve; + LCurve* lcurve; std::vector paramcListeners; @@ -109,7 +109,8 @@ class ToolPanelCoordinator : public ToolPanelListener, ToolPanelCoordinator (); ~ToolPanelCoordinator (); - bool getChangedState () { return hasChanged; } + bool getChangedState () { return hasChanged; } + void updateCurveBackgroundHistogram (unsigned* histrgb, unsigned* histl); // multiple listeners can be added that are notified on changes (typical: profile panel and the history) void addPParamsChangeListener (PParamsChangeListener* pp) { paramcListeners.push_back (pp); }