From 540fa3e0057c8f4cf4ab55693792eb8dd79e2fcf Mon Sep 17 00:00:00 2001 From: torger Date: Thu, 7 Nov 2013 08:00:42 +0100 Subject: [PATCH] Issue 2001: added vignette filter tool --- rtdata/languages/default | 14 +- rtengine/colorclip.h | 27 +++ rtengine/cubic.cc | 70 -------- rtengine/cubint.cc | 73 -------- rtengine/cubintch.cc | 62 ------- rtengine/dcrop.cc | 5 +- rtengine/improccoordinator.cc | 16 +- rtengine/improcfun.h | 110 +++++++++++- rtengine/iptransform.cc | 311 +++++++++++++++++++++++++--------- rtengine/procevents.h | 4 +- rtengine/procparams.cc | 22 +++ rtengine/procparams.h | 13 ++ rtengine/refreshmap.cc | 4 +- rtengine/refreshmap.h | 5 +- rtengine/rtthumbnail.cc | 6 +- rtengine/simpleprocess.cc | 2 +- rtgui/CMakeLists.txt | 2 +- rtgui/addsetids.h | 5 +- rtgui/batchtoolpanelcoord.cc | 5 + rtgui/options.cc | 7 +- rtgui/paramsedited.cc | 16 +- rtgui/paramsedited.h | 10 ++ rtgui/partialpastedlg.cc | 7 + rtgui/partialpastedlg.h | 3 +- rtgui/ppversion.h | 23 ++- rtgui/preferences.cc | 6 + rtgui/toolpanelcoord.cc | 2 + rtgui/toolpanelcoord.h | 2 + 28 files changed, 512 insertions(+), 320 deletions(-) delete mode 100644 rtengine/cubic.cc delete mode 100644 rtengine/cubint.cc delete mode 100644 rtengine/cubintch.cc diff --git a/rtdata/languages/default b/rtdata/languages/default index 1ca699bf6..7c989d960 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -443,8 +443,10 @@ HISTORY_MSG_205;CAM02 hot/bad pixels HISTORY_MSG_206;CAT02 - Adapt scene auto HISTORY_MSG_207;Defringing Hue curve HISTORY_MSG_208;Blue/Red Equalizer -HISTORY_MSG_210;Gradient Filter -HISTORY_MSG_211;Gradient Filter +HISTORY_MSG_210;Graduated Filter +HISTORY_MSG_211;Graduated Filter +HISTORY_MSG_212;Vignette Filter +HISTORY_MSG_213;Vignette Filter HISTORY_NEWSNAPSHOTAS;As... HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s @@ -659,6 +661,7 @@ PARTIALPASTE_LENSPROFILE;Lens correction profile PARTIALPASTE_LUMADENOISE;Luminance noise reduction PARTIALPASTE_LUMINANCEGROUP;Luminance related settings PARTIALPASTE_METAICMGROUP;Metadata/Color Management Settings +PARTIALPASTE_PCVIGNETTE;Vignette Filter PARTIALPASTE_PERSPECTIVE;Perspective PARTIALPASTE_PREPROCESS_GREENEQUIL;Green equilibration PARTIALPASTE_PREPROCESS_HOTDEADPIXFILT;Apply hot/dead pixel filter @@ -1199,6 +1202,13 @@ TP_LUMADENOISE_LABEL;Luminance Noise Reduction TP_LUMADENOISE_RADIUS;Radius TP_NEUTRAL;Neutral TP_NEUTRAL_TIP;Reset exposure sliders to neutral values.\nApplies to the same controls that Auto Levels applies to, regardless of whether you used Auto Levels or not +TP_PCVIGNETTE_FEATHER;Feather +TP_PCVIGNETTE_FEATHER_TOOLTIP;Feathering: 0=corners only, 50=halfway to center, 100=to center +TP_PCVIGNETTE_LABEL;Vignette Filter +TP_PCVIGNETTE_ROUNDNESS;Roundness +TP_PCVIGNETTE_ROUNDNESS_TOOLTIP;Roundness: 0=rectangle, 50=fitted ellipse, 100=circle +TP_PCVIGNETTE_STRENGTH;Strength +TP_PCVIGNETTE_STRENGTH_TOOLTIP;Filter strength in stops (reached in corners) TP_PERSPECTIVE_HORIZONTAL;Horizontal TP_PERSPECTIVE_LABEL;Perspective TP_PERSPECTIVE_VERTICAL;Vertical diff --git a/rtengine/colorclip.h b/rtengine/colorclip.h index b81c35bc3..0526af83d 100644 --- a/rtengine/colorclip.h +++ b/rtengine/colorclip.h @@ -90,6 +90,30 @@ inline double tightestroot (double L, double a, double b, double r1, double r2, /******************************************************************************* * FindCubicRoots + * -------------- + * + * Copyright (C) 1997-2001 Ken Turkowski. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * ------------------------------------------------------------------------ * * Solve: * coeff[3] * x^3 + coeff[2] * x^2 + coeff[1] * x + coeff[0] = 0 @@ -97,6 +121,7 @@ inline double tightestroot (double L, double a, double b, double r1, double r2, * returns: * 3 - 3 real roots * 1 - 1 real root (2 complex conjugate) + * *******************************************************************************/ /*long @@ -111,6 +136,7 @@ FindCubicRoots(const FLOAT coeff[4], FLOAT x[3]) double_t Qcubed = Q * Q * Q; double_t d = Qcubed - R * R; + // Three real roots if (d >= 0) { double_t theta = acos(R / sqrt(Qcubed)); double_t sqrtQ = sqrt(Q); @@ -120,6 +146,7 @@ FindCubicRoots(const FLOAT coeff[4], FLOAT x[3]) return (3); } + // One real root else { double_t e = pow(sqrt(-d) + fabs(R), 1. / 3.); if (R > 0) diff --git a/rtengine/cubic.cc b/rtengine/cubic.cc deleted file mode 100644 index 3354f3c9d..000000000 --- a/rtengine/cubic.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright (C) 1997-2001 Ken Turkowski. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include - - -#define FLOAT float -#define double_t double - -/******************************************************************************* - * FindCubicRoots - * - * Solve: - * coeff[3] * x^3 + coeff[2] * x^2 + coeff[1] * x + coeff[0] = 0 - * - * returns: - * 3 - 3 real roots - * 1 - 1 real root (2 complex conjugate) - *******************************************************************************/ - -long -FindCubicRoots(const FLOAT coeff[4], FLOAT x[3]) -{ - FLOAT a1 = coeff[2] / coeff[3]; - FLOAT a2 = coeff[1] / coeff[3]; - FLOAT a3 = coeff[0] / coeff[3]; - - double_t Q = (a1 * a1 - 3 * a2) / 9; - double_t R = (2 * a1 * a1 * a1 - 9 * a1 * a2 + 27 * a3) / 54; - double_t Qcubed = Q * Q * Q; - double_t d = Qcubed - R * R; - - /* Three real roots */ - if (d >= 0) { - double_t theta = acos(R / sqrt(Qcubed)); - double_t sqrtQ = sqrt(Q); - x[0] = -2 * sqrtQ * cos( theta / 3) - a1 / 3; - x[1] = -2 * sqrtQ * cos((theta + 2 * 3.14159265) / 3) - a1 / 3; - x[2] = -2 * sqrtQ * cos((theta + 4 * 3.14159265) / 3) - a1 / 3; - return (3); - } - - /* One real root */ - else { - double_t e = pow(sqrt(-d) + fabs(R), 1. / 3.); - if (R > 0) - e = -e; - x[0] = (e + Q / e) - a1 / 3.; - return (1); - } -} diff --git a/rtengine/cubint.cc b/rtengine/cubint.cc deleted file mode 100644 index a658999dd..000000000 --- a/rtengine/cubint.cc +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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 . - */ - -inline void interpolateTransformCubic (Imagefloat* src, int xs, int ys, double Dx, double Dy, float *r, float *g, float *b, double mul) { - const double A=-0.85; - - double w[4]; - - { - double t1, t2; - t1 = -A*(Dx-1.0)*Dx; - t2 = (3.0-2.0*Dx)*Dx*Dx; - w[3] = t1*Dx; - w[2] = t1*(Dx-1.0) + t2; - w[1] = -t1*Dx + 1.0 - t2; - w[0] = -t1*(Dx-1.0); - } - - double rd, gd, bd; - double yr[4], yg[4], yb[4]; - - for (int k=ys, kx=0; kr(k,i) * w[ix]; - gd += src->g(k,i) * w[ix]; - bd += src->b(k,i) * w[ix]; - } - yr[kx] = rd; yg[kx] = gd; yb[kx] = bd; - } - - - { - double t1, t2; - - t1 = -A*(Dy-1.0)*Dy; - t2 = (3.0-2.0*Dy)*Dy*Dy; - w[3] = t1*Dy; - w[2] = t1*(Dy-1.0) + t2; - w[1] = -t1*Dy + 1.0 - t2; - w[0] = -t1*(Dy-1.0); - } - - rd = gd = bd = 0.0; - for (int i=0; i<4; i++) { - rd += yr[i] * w[i]; - gd += yg[i] * w[i]; - bd += yb[i] * w[i]; - } - - *r = rd * mul; - *g = gd * mul; - *b = bd * mul; - -// if (xs==100 && ys==100) -// printf ("r=%g, g=%g\n", *r, *g); -} diff --git a/rtengine/cubintch.cc b/rtengine/cubintch.cc deleted file mode 100644 index 7bc55e089..000000000 --- a/rtengine/cubintch.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 . - */ - -inline void interpolateTransformChannelsCubic (float** src, int xs, int ys, double Dx, double Dy, float *r, double mul) { - const double A=-0.85; - - double w[4]; - - { - double t1, t2; - t1 = -A*(Dx-1.0)*Dx; - t2 = (3.0-2.0*Dx)*Dx*Dx; - w[3] = t1*Dx; - w[2] = t1*(Dx-1.0) + t2; - w[1] = -t1*Dx + 1.0 - t2; - w[0] = -t1*(Dx-1.0); - } - - double rd; - double yr[4]; - - for (int k=ys, kx=0; kparams; + // No need to update todo here, since it has already been changed in ImprocCoordinator::updatePreviewImage, + // and Crop::update ask to do ALL anyway + // give possibility to the listener to modify crop window (as the full image dimensions are already known at this point) int wx, wy, ww, wh, ws; bool overrideWindow = false; @@ -129,7 +132,7 @@ void Crop::update (int todo) { transCrop = new Imagefloat (cropw, croph); if ((todo & M_TRANSFORM) && needstransform) - parent->ipf.transform (baseCrop, transCrop, cropx/skip, cropy/skip, trafx/skip, trafy/skip, SKIPS(parent->fw,skip), SKIPS(parent->fh,skip), + parent->ipf.transform (baseCrop, transCrop, cropx/skip, cropy/skip, trafx/skip, trafy/skip, SKIPS(parent->fw,skip), SKIPS(parent->fh,skip), parent->getFullWidth(), parent->getFullHeight(), parent->imgsrc->getMetaData()->getFocalLen(), parent->imgsrc->getMetaData()->getFocalLen35mm(), parent->imgsrc->getMetaData()->getFocusDist(), parent->imgsrc->getRotateDegree(), false); if (transCrop) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index f39dedad2..3dfe943d0 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -112,6 +112,9 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { int numofphases = 14; int readyphase = 0; + if (todo==CROP && ipf.needsPCVignetting()) + todo |= TRANSFORM; // Change about Crop does affect TRANSFORM + // Tells to the ImProcFunctions' tools what is the preview scale, which may lead to some simplifications ipf.setScale (scale); @@ -238,8 +241,8 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { readyphase++; progress ("Rotate / Distortion...",100*readyphase/numofphases); - bool needstransform = ipf.needsTransform(); // Remove transformation if unneeded + bool needstransform = ipf.needsTransform(); if (!needstransform && orig_prev!=oprevi) { delete oprevi; oprevi = orig_prev; @@ -247,7 +250,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { if (needstransform && orig_prev==oprevi) oprevi = new Imagefloat (pW, pH); if ((todo & M_TRANSFORM) && needstransform) - ipf.transform (orig_prev, oprevi, 0, 0, 0, 0, pW, pH, imgsrc->getMetaData()->getFocalLen(), + ipf.transform (orig_prev, oprevi, 0, 0, 0, 0, pW, pH, fw, fh, imgsrc->getMetaData()->getFocalLen(), imgsrc->getMetaData()->getFocalLen35mm(), imgsrc->getMetaData()->getFocusDist(), imgsrc->getRotateDegree(), false); readyphase++; @@ -274,7 +277,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { } progress ("Exposure curve & CIELAB conversion...",100*readyphase/numofphases); - if ((todo & M_RGBCURVE) || todo==CROP) { + if ((todo & M_RGBCURVE) || (todo & M_CROP)) { if (hListener) oprevi->calcCroppedHistogram(params, scale, histCropped); // complexCurve also calculated pre-curves histogram dependend on crop @@ -291,7 +294,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, scale==1 ? 1 : 1); // if it's just crop we just need the histogram, no image updates - if ( todo!=CROP ) { + if ( todo!=MINUPDATE ) { ipf.rgbProc (oprevi, oprevl, hltonecurve, shtonecurve, tonecurve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, customToneCurve1, customToneCurve2, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh); } @@ -316,7 +319,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { butili=false; ccutili=false; cclutili=false; - if ((todo & M_LUMACURVE) || todo==CROP) { + if ((todo & M_LUMACURVE) || (todo & M_CROP)) { CurveFactory::complexLCurve (params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, lhist16, lhist16Cropped, lumacurve, histLCurve, scale==1 ? 1 : 16, utili); } @@ -329,7 +332,6 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { nprevl->CopyFrom(oprevl); progress ("Applying Color Boost...",100*readyphase/numofphases); - int poscc; ipf.chromiLuminanceCurve (pW,nprevl, nprevl, chroma_acurve, chroma_bcurve, satcurve,lhskcurve, lumacurve, utili, autili, butili, ccutili,cclutili, histCCurve); ipf.vibrance(nprevl); @@ -465,7 +467,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { crops[i]->update (todo); // may call ourselves progress ("Conversion to RGB...",100*readyphase/numofphases); - if (todo!=CROP) { + if (todo!=CROP && todo!=MINUPDATE) { MyMutex::MyLock prevImgLock(previmg->getMutex()); try { diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index d9125549b..bc1ad32e2 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -51,9 +51,9 @@ class ImProcFunctions { void calcVignettingParams(int oW, int oH, const VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul); - void transformPreview (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap); - void transformLuminanceOnly (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH); - void transformHighQuality (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap, bool fullImage); + void transformPreview (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap); + void transformLuminanceOnly (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH, int fW, int fH); + void transformHighQuality (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap, bool fullImage); void sharpenHaloCtrl (LabImage* lab, float** blurmap, float** base, int W, int H); void sharpenHaloCtrlcam (CieImage* ncie, float** blurmap, float** base, int W, int H); @@ -67,7 +67,106 @@ class ImProcFunctions { bool needsGradient (); bool needsVignetting (); bool needsLCP (); - // static cmsUInt8Number* Mempro = NULL; + // static cmsUInt8Number* Mempro = NULL; + + inline void interpolateTransformCubic (Imagefloat* src, int xs, int ys, double Dx, double Dy, float *r, float *g, float *b, double mul) { + const double A=-0.85; + + double w[4]; + + { + double t1, t2; + t1 = -A*(Dx-1.0)*Dx; + t2 = (3.0-2.0*Dx)*Dx*Dx; + w[3] = t1*Dx; + w[2] = t1*(Dx-1.0) + t2; + w[1] = -t1*Dx + 1.0 - t2; + w[0] = -t1*(Dx-1.0); + } + + double rd, gd, bd; + double yr[4], yg[4], yb[4]; + + for (int k=ys, kx=0; kr(k,i) * w[ix]; + gd += src->g(k,i) * w[ix]; + bd += src->b(k,i) * w[ix]; + } + yr[kx] = rd; yg[kx] = gd; yb[kx] = bd; + } + + + { + double t1, t2; + + t1 = -A*(Dy-1.0)*Dy; + t2 = (3.0-2.0*Dy)*Dy*Dy; + w[3] = t1*Dy; + w[2] = t1*(Dy-1.0) + t2; + w[1] = -t1*Dy + 1.0 - t2; + w[0] = -t1*(Dy-1.0); + } + + rd = gd = bd = 0.0; + for (int i=0; i<4; i++) { + rd += yr[i] * w[i]; + gd += yg[i] * w[i]; + bd += yb[i] * w[i]; + } + + *r = rd * mul; + *g = gd * mul; + *b = bd * mul; + + // if (xs==100 && ys==100) + // printf ("r=%g, g=%g\n", *r, *g); + } + + inline void interpolateTransformChannelsCubic (float** src, int xs, int ys, double Dx, double Dy, float *r, double mul) { + const double A=-0.85; + + double w[4]; + + { + double t1, t2; + t1 = -A*(Dx-1.0)*Dx; + t2 = (3.0-2.0*Dx)*Dx*Dx; + w[3] = t1*Dx; + w[2] = t1*(Dx-1.0) + t2; + w[1] = -t1*Dx + 1.0 - t2; + w[0] = -t1*(Dx-1.0); + } + + double rd; + double yr[4]; + + for (int k=ys, kx=0; kwidth, original->height, params->coarse, rawRotationDeg); } - if (!(needsCA() || needsDistortion() || needsRotation() || needsPerspective() || needsLCP()) && (needsVignetting() || needsGradient())) - transformLuminanceOnly (original, transformed, cx, cy, oW, oH); - else if (!needsCA() && scale!=1) - transformPreview (original, transformed, cx, cy, sx, sy, oW, oH, pLCPMap); - else - transformHighQuality (original, transformed, cx, cy, sx, sy, oW, oH, pLCPMap, fullImage); + if (!(needsCA() || needsDistortion() || needsRotation() || needsPerspective() || needsLCP()) && (needsVignetting() || needsPCVignetting() || needsGradient())) + transformLuminanceOnly (original, transformed, cx, cy, oW, oH, fW, fH); + else if (!needsCA() && scale!=1) + transformPreview (original, transformed, cx, cy, sx, sy, oW, oH, fW, fH, pLCPMap); + else + transformHighQuality (original, transformed, cx, cy, sx, sy, oW, oH, fW, fH, pLCPMap, fullImage); if (pLCPMap) delete pLCPMap; } @@ -246,7 +246,6 @@ struct grad_params { float ta, yc, xc; float ys, ys_inv; float scale, botmul, topmul; - float gamma; float top_edge_0; int h; }; @@ -322,7 +321,6 @@ static void calcGradientParams(int oW, int oH, const GradientParams& gradient, s gp.ys_inv = 0; gp.ys = 0; } - gp.gamma = 1.5; // tested to be "visually pleasing" } static float calcGradientFactor(const struct grad_params& gp, int x, int y) { @@ -338,10 +336,11 @@ static float calcGradientFactor(const struct grad_params& gp, int x, int y) { if (gp.bright_top) { val = 1.0 - val; } - val = 2 * val - 1.0; // adjust range to -1 to 1 - val = 0.5 * (3 * val - powf(val, 3)); // s-curve - val = 0.5 * (1.0 + val); // adjust range back to 0 to 1 - val = powf(val, gp.gamma); // apply gamma + if (gp.scale < 1.0) { + val = pow(sin(val*M_PI/2), 3); + } else { + val = 1.0 - pow(cos(val*M_PI/2), 3); + } return gp.scale + val * (1.0 - gp.scale); } } else { @@ -354,33 +353,168 @@ static float calcGradientFactor(const struct grad_params& gp, int x, int y) { return gp.botmul; } else { float val = ((float)(gy - top_edge) * gp.ys_inv); + if (gp.bright_top) { val = 1.0 - val; } - val = 2 * val - 1.0; - val = 0.5 * (3 * val - powf(val, 3)); - val = 0.5 * (1.0 + val); - val = powf(val, gp.gamma); + if (gp.scale < 1.0) { + val = pow(sin(val*M_PI/2), 3); + } else { + val = 1.0 - pow(cos(val*M_PI/2), 3); + } return gp.scale + val * (1.0 - gp.scale); } } } -// Transform vignetting only -void ImProcFunctions::transformLuminanceOnly (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH) { +struct pcv_params { + float oe_a, oe_b, oe1_a, oe1_b, oe2_a, oe2_b; + float ie_mul, ie1_mul, ie2_mul; + float sepmix, feather; + int w, h, x1, x2, y1, y2; + int sep; + bool is_super_ellipse_mode, is_portrait; + float scale; + float fadeout_mul; +}; +static void calcPCVignetteParams(int fW, int fH, int oW, int oH, const PCVignetteParams& pcvignette, const CropParams &crop, struct pcv_params& pcv) { + + // ellipse formula: (x/a)^2 + (y/b)^2 = 1 + double roundness = pcvignette.roundness / 100.0; + pcv.feather = pcvignette.feather / 100.0; + if (crop.enabled) { + pcv.w = (crop.w * oW) / fW; + pcv.h = (crop.h * oH) / fH; + pcv.x1 = (crop.x * oW) / fW; + pcv.y1 = (crop.y * oH) / fH; + pcv.x2 = pcv.x1+pcv.w; + pcv.y2 = pcv.y1+pcv.h; + } else { + pcv.x1 = 0, pcv.y1 = 0; + pcv.x2 = oW, pcv.y2 = oH; + pcv.w = oW; + pcv.h = oH; + } + pcv.fadeout_mul = 1.0 / (0.05 * sqrtf(oW*oW+oH*oH)); + float short_side = (pcv.w < pcv.h) ? pcv.w : pcv.h; + float long_side = (pcv.w > pcv.h) ? pcv.w : pcv.h; + + pcv.sep = 2; + pcv.sepmix = 0; + pcv.oe_a = sqrt(2.0)*long_side*0.5; + pcv.oe_b = pcv.oe_a * short_side / long_side; + pcv.ie_mul = 1.0 / sqrt(2.0); + pcv.is_super_ellipse_mode = false; + pcv.is_portrait = (pcv.w < pcv.h); + if (roundness < 0.5) { + // make super-ellipse of higher and higher degree + pcv.is_super_ellipse_mode = true; + float sepf = 2 + 4*powf(1.0 - 2*roundness, 1.3); // gamma 1.3 used to balance the effect in the 0.0...0.5 roundness range + pcv.sep = ((int)sepf) & ~0x1; + pcv.sepmix = (sepf - pcv.sep) * 0.5; // 0.0 to 1.0 + pcv.oe1_a = powf(2.0, 1.0/pcv.sep)*long_side*0.5; + pcv.oe1_b = pcv.oe1_a * short_side / long_side; + pcv.ie1_mul = 1.0 / powf(2.0, 1.0/pcv.sep); + pcv.oe2_a = powf(2.0, 1.0/(pcv.sep+2))*long_side*0.5; + pcv.oe2_b = pcv.oe2_a * short_side / long_side; + pcv.ie2_mul = 1.0 / powf(2.0, 1.0/(pcv.sep+2)); + } + if (roundness > 0.5) { + // scale from fitted ellipse towards circle + float rad = sqrtf(pcv.w*pcv.w+pcv.h*pcv.h) / 2.0; + float diff_a = rad - pcv.oe_a; + float diff_b = rad - pcv.oe_b; + pcv.oe_a = pcv.oe_a + diff_a * 2*(roundness - 0.5); + pcv.oe_b = pcv.oe_b + diff_b * 2*(roundness - 0.5); + } + pcv.scale = powf(2, -pcvignette.strength); + if (pcvignette.strength >= 6.0) { + pcv.scale = 0.0; + } +} + +static float calcPCVignetteFactor(const struct pcv_params& pcv, int x, int y) { + + float fo = 1.0; + if (x < pcv.x1 || x > pcv.x2 || y < pcv.y1 || y > pcv.y2) { + /* + The initial plan was to have 1.0 directly outside the crop box (ie no fading), but due to + rounding/trunction here and there I didn't succeed matching up exactly on the pixel with + the crop box. To hide that mismatch I made a fade. + */ + int dist_x = (x < pcv.x1) ? pcv.x1 - x : x - pcv.x2; + int dist_y = (y < pcv.y1) ? pcv.y1 - y : y - pcv.y2; + if (dist_x < 0) dist_x = 0; + if (dist_y < 0) dist_y = 0; + fo = sqrtf(dist_x*dist_x+dist_y*dist_y) * pcv.fadeout_mul; + if (fo >= 1.0) { + return 1.0; + } + } + float val, a, b; + if (pcv.is_portrait) { + a = fabs((y-pcv.y1)-pcv.h*0.5); + b = fabs((x-pcv.x1)-pcv.w*0.5); + } else { + a = fabs((x-pcv.x1)-pcv.w*0.5); + b = fabs((y-pcv.y1)-pcv.h*0.5); + } + float angle = atan2f(b, a); + float dist = sqrtf(a*a+b*b); + float dist_oe, dist_ie; + if (pcv.is_super_ellipse_mode) { + float dist_oe1 = pcv.oe1_a*pcv.oe1_b / powf(powf(pcv.oe1_b*cosf(angle), pcv.sep) + powf(pcv.oe1_a*sinf(angle), pcv.sep), 1.0/pcv.sep); + float dist_oe2 = pcv.oe2_a*pcv.oe2_b / powf(powf(pcv.oe2_b*cosf(angle), pcv.sep+2) + powf(pcv.oe2_a*sinf(angle), pcv.sep+2), 1.0/(pcv.sep+2)); + float dist_ie1 = pcv.ie1_mul * dist_oe1 * (1.0 - pcv.feather); + float dist_ie2 = pcv.ie2_mul * dist_oe2 * (1.0 - pcv.feather); + dist_oe = dist_oe1 * (1.0 - pcv.sepmix) + dist_oe2 * pcv.sepmix; + dist_ie = dist_ie1 * (1.0 - pcv.sepmix) + dist_ie2 * pcv.sepmix; + } else { + dist_oe = pcv.oe_a*pcv.oe_b / sqrtf(pcv.oe_b*cosf(angle)*pcv.oe_b*cosf(angle) + pcv.oe_a*sinf(angle)*pcv.oe_a*sinf(angle)); + dist_ie = pcv.ie_mul * dist_oe * (1.0 - pcv.feather); + } + if (dist <= dist_ie) { + return 1.0; + } + + if (dist >= dist_oe) { + val = pcv.scale; + } else { + val = (dist - dist_ie) / (dist_oe - dist_ie); + if (pcv.scale < 1.0) { + val = pow(cos(val*M_PI/2), 4); + } else { + val = 1 - pow(sin(val*M_PI/2), 4); + } + val = pcv.scale + val * (1.0 - pcv.scale); + } + if (fo < 1.0) { + val = 1.0 * fo + val * (1.0 - fo); + } + return val; +} + +void ImProcFunctions::transformLuminanceOnly (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH, int fW, int fH) { const bool applyVignetting = needsVignetting(); const bool applyGradient = needsGradient(); + const bool applyPCVignetting = needsPCVignetting(); double vig_w2, vig_h2, maxRadius, v, b, mul; if (applyVignetting) { calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); } - struct grad_params gp; - if (applyGradient) { - calcGradientParams(oW, oH, params->gradient, gp); - } + struct grad_params gp; + if (applyGradient) { + calcGradientParams(oW, oH, params->gradient, gp); + } + + struct pcv_params pcv; + if (applyPCVignetting) { + //fprintf(stderr, "%d %d | %d %d | %d %d | %d %d [%d %d]\n", fW, fH, oW, oH, transformed->width, transformed->height, cx, cy, params->crop.w, params->crop.h); + calcPCVignetteParams(fW, fH, oW, oH, params->pcvignette, params->crop, pcv); + } #pragma omp parallel for if (multiThread) for (int y=0; yheight; y++) { @@ -394,7 +528,10 @@ void ImProcFunctions::transformLuminanceOnly (Imagefloat* original, Imagefloat* } if (applyGradient) { factor *= calcGradientFactor(gp, cx+x, cy+y); - } + } + if (applyPCVignetting) { + factor *= calcPCVignetteFactor(pcv, cx+x, cy+y); + } transformed->r(y,x) = original->r(y,x) * factor; transformed->g(y,x) = original->g(y,x) * factor; transformed->b(y,x) = original->b(y,x) * factor; @@ -403,10 +540,7 @@ void ImProcFunctions::transformLuminanceOnly (Imagefloat* original, Imagefloat* } // Transform WITH scaling (opt.) and CA, cubic interpolation -#include "cubintch.cc" -#include "cubint.cc" - -void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, +void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap, bool fullImage) { double w2 = (double) oW / 2.0 - 0.5; @@ -415,10 +549,14 @@ void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* tr double vig_w2,vig_h2,maxRadius,v,b,mul; calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); - struct grad_params gp; - if (needsGradient()) { + struct grad_params gp; + if (needsGradient()) { calcGradientParams(oW, oH, params->gradient, gp); } + struct pcv_params pcv; + if (needsPCVignetting()) { + calcPCVignetteParams(fW, fH, oW, oH, params->pcvignette, params->crop, pcv); + } float** chOrig[3]; chOrig[0] = original->r.ptrs; @@ -504,13 +642,13 @@ void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* tr } double r2; - if (needsVignetting()) { - double vig_Dx = vig_x_d * cost - vig_y_d * sint; - double vig_Dy = vig_x_d * sint + vig_y_d * cost; + if (needsVignetting()) { + double vig_Dx = vig_x_d * cost - vig_y_d * sint; + double vig_Dy = vig_x_d * sint + vig_y_d * cost; r2=sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy); } - for (int c=0; c < (enableCA ? 3 : 1); c++) { + for (int c=0; c < (enableCA ? 3 : 1); c++) { double Dx = Dxc * (s + chDist[c]); double Dy = Dyc * (s + chDist[c]); @@ -520,22 +658,25 @@ void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* tr // LCP CA if (enableLCPCA) pLCPMap->correctCA(Dx,Dy,c); - // Extract integer and fractions of source screen coordinates - int xc = (int)Dx; Dx -= (double)xc; xc -= sx; - int yc = (int)Dy; Dy -= (double)yc; yc -= sy; + // Extract integer and fractions of source screen coordinates + int xc = (int)Dx; Dx -= (double)xc; xc -= sx; + int yc = (int)Dy; Dy -= (double)yc; yc -= sy; - // Convert only valid pixels - if (yc>=0 && ycheight && xc>=0 && xcwidth) { + // Convert only valid pixels + if (yc>=0 && ycheight && xc>=0 && xcwidth) { - // multiplier for vignetting correction - double vignmul = 1.0; - if (needsVignetting()) - vignmul /= std::max(v + mul * tanh (b*(maxRadius-s*r2) / maxRadius), 0.001); - if (needsGradient()) { - vignmul *= calcGradientFactor(gp, cx+x, cy+y); - } + // multiplier for vignetting correction + double vignmul = 1.0; + if (needsVignetting()) + vignmul /= std::max(v + mul * tanh (b*(maxRadius-s*r2) / maxRadius), 0.001); + if (needsGradient()) { + vignmul *= calcGradientFactor(gp, cx+x, cy+y); + } + if (needsPCVignetting()) { + vignmul *= calcPCVignetteFactor(pcv, cx+x, cy+y); + } - if (yc > 0 && yc < original->height-2 && xc > 0 && xc < original->width-2) { + if (yc > 0 && yc < original->height-2 && xc > 0 && xc < original->width-2) { // all interpolation pixels inside image if (enableCA) interpolateTransformChannelsCubic (chOrig[c], xc-1, yc-1, Dx, Dy, &(chTrans[c][y][x]), vignmul); @@ -543,37 +684,37 @@ void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* tr interpolateTransformCubic (original, xc-1, yc-1, Dx, Dy, &(transformed->r(y,x)), &(transformed->g(y,x)), &(transformed->b(y,x)), vignmul); } else { // edge pixels - int y1 = LIM(yc, 0, original->height-1); - int y2 = LIM(yc+1, 0, original->height-1); - int x1 = LIM(xc, 0, original->width-1); - int x2 = LIM(xc+1, 0, original->width-1); + int y1 = LIM(yc, 0, original->height-1); + int y2 = LIM(yc+1, 0, original->height-1); + int x1 = LIM(xc, 0, original->width-1); + int x2 = LIM(xc+1, 0, original->width-1); - if (enableCA) { - chTrans[c][y][x] = vignmul * (chOrig[c][y1][x1]*(1.0-Dx)*(1.0-Dy) + chOrig[c][y1][x2]*Dx*(1.0-Dy) + chOrig[c][y2][x1]*(1.0-Dx)*Dy + chOrig[c][y2][x2]*Dx*Dy); - } else { - transformed->r(y,x) = vignmul*(original->r(y1,x1)*(1.0-Dx)*(1.0-Dy) + original->r(y1,x2)*Dx*(1.0-Dy) + original->r(y2,x1)*(1.0-Dx)*Dy + original->r(y2,x2)*Dx*Dy); - transformed->g(y,x) = vignmul*(original->g(y1,x1)*(1.0-Dx)*(1.0-Dy) + original->g(y1,x2)*Dx*(1.0-Dy) + original->g(y2,x1)*(1.0-Dx)*Dy + original->g(y2,x2)*Dx*Dy); - transformed->b(y,x) = vignmul*(original->b(y1,x1)*(1.0-Dx)*(1.0-Dy) + original->b(y1,x2)*Dx*(1.0-Dy) + original->b(y2,x1)*(1.0-Dx)*Dy + original->b(y2,x2)*Dx*Dy); - } - } + if (enableCA) { + chTrans[c][y][x] = vignmul * (chOrig[c][y1][x1]*(1.0-Dx)*(1.0-Dy) + chOrig[c][y1][x2]*Dx*(1.0-Dy) + chOrig[c][y2][x1]*(1.0-Dx)*Dy + chOrig[c][y2][x2]*Dx*Dy); + } else { + transformed->r(y,x) = vignmul*(original->r(y1,x1)*(1.0-Dx)*(1.0-Dy) + original->r(y1,x2)*Dx*(1.0-Dy) + original->r(y2,x1)*(1.0-Dx)*Dy + original->r(y2,x2)*Dx*Dy); + transformed->g(y,x) = vignmul*(original->g(y1,x1)*(1.0-Dx)*(1.0-Dy) + original->g(y1,x2)*Dx*(1.0-Dy) + original->g(y2,x1)*(1.0-Dx)*Dy + original->g(y2,x2)*Dx*Dy); + transformed->b(y,x) = vignmul*(original->b(y1,x1)*(1.0-Dx)*(1.0-Dy) + original->b(y1,x2)*Dx*(1.0-Dy) + original->b(y2,x1)*(1.0-Dx)*Dy + original->b(y2,x2)*Dx*Dy); } - else { - if (enableCA) { - // not valid (source pixel x,y not inside source image, etc.) - chTrans[c][y][x] = 0; - } else { - transformed->r(y,x) = 0; - transformed->g(y,x) = 0; - transformed->b(y,x) = 0; - } - } - } + } + } + else { + if (enableCA) { + // not valid (source pixel x,y not inside source image, etc.) + chTrans[c][y][x] = 0; + } else { + transformed->r(y,x) = 0; + transformed->g(y,x) = 0; + transformed->b(y,x) = 0; + } + } + } } } } // Transform WITH scaling, WITHOUT CA, simple (and fast) interpolation. Used for preview -void ImProcFunctions::transformPreview (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap) { +void ImProcFunctions::transformPreview (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap) { double w2 = (double) oW / 2.0 - 0.5; double h2 = (double) oH / 2.0 - 0.5; @@ -581,10 +722,14 @@ void ImProcFunctions::transformPreview (Imagefloat* original, Imagefloat* transf double vig_w2, vig_h2, maxRadius, v, b, mul; calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); - struct grad_params gp; - if (needsGradient()) { - calcGradientParams(oW, oH, params->gradient, gp); - } + struct grad_params gp; + if (needsGradient()) { + calcGradientParams(oW, oH, params->gradient, gp); + } + struct pcv_params pcv; + if (needsPCVignetting()) { + calcPCVignetteParams(fW, fH, oW, oH, params->pcvignette, params->crop, pcv); + } // auxiliary variables for distortion correction bool needsDist = needsDistortion(); // for performance @@ -665,11 +810,13 @@ void ImProcFunctions::transformPreview (Imagefloat* original, Imagefloat* transf if (yc>=0 && ycheight && xc>=0 && xcwidth) { // multiplier for vignetting correction - double vignmul = 1.0; + double vignmul = 1.0; if (needsVignetting()) - vignmul /= std::max(v + mul * tanh (b*(maxRadius-s*r2) / maxRadius), 0.001); - if (needsGradient()) - vignmul *= calcGradientFactor(gp, cx+x, cy+y); + vignmul /= std::max(v + mul * tanh (b*(maxRadius-s*r2) / maxRadius), 0.001); + if (needsGradient()) + vignmul *= calcGradientFactor(gp, cx+x, cy+y); + if (needsPCVignetting()) + vignmul *= calcPCVignetteFactor(pcv, cx+x, cy+y); if (yc < original->height-1 && xc < original->width-1) { // all interpolation pixels inside image @@ -739,6 +886,10 @@ bool ImProcFunctions::needsGradient () { return params->gradient.enabled && fabs(params->gradient.strength) > 1e-15; } +bool ImProcFunctions::needsPCVignetting () { + return params->pcvignette.enabled && fabs(params->pcvignette.strength) > 1e-15; +} + bool ImProcFunctions::needsVignetting () { return params->vignetting.amount; } @@ -748,7 +899,7 @@ bool ImProcFunctions::needsLCP () { } bool ImProcFunctions::needsTransform () { - return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsGradient () || needsVignetting () || needsLCP(); + return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsGradient () || needsPCVignetting () || needsVignetting () || needsLCP(); } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index bb3d02ace..2bf679fda 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -234,7 +234,9 @@ enum ProcEvent { EvWBequalbo=208, EvGradient=209, EvGradientEnabled=210, - NUMOFEVENTS=211 + EvPCVignette=211, + EvPCVignetteEnabled=212, + NUMOFEVENTS=213 }; } #endif diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index e1ae6ff34..03c8c1faa 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -338,6 +338,11 @@ void ProcParams::setDefaults () { gradient.centerX = 0; gradient.centerY = 0; + pcvignette.enabled = false; + pcvignette.strength = 0; + pcvignette.feather = 50; + pcvignette.roundness = 50; + cacorrection.red = 0; cacorrection.blue = 0; @@ -838,6 +843,12 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol if (!pedited || pedited->gradient.centerX) keyFile.set_integer ("Gradient", "CenterX", gradient.centerX); if (!pedited || pedited->gradient.centerY) keyFile.set_integer ("Gradient", "CenterY", gradient.centerY); + // save post-crop vignette + if (!pedited || pedited->pcvignette.enabled) keyFile.set_boolean ("PCVignette", "Enabled", pcvignette.enabled); + if (!pedited || pedited->pcvignette.strength) keyFile.set_double ("PCVignette", "Strength", pcvignette.strength); + if (!pedited || pedited->pcvignette.feather) keyFile.set_integer ("PCVignette", "Feather", pcvignette.feather); + if (!pedited || pedited->pcvignette.roundness) keyFile.set_integer ("PCVignette", "Roundness", pcvignette.roundness); + // save C/A correction if (!pedited || pedited->cacorrection.red) keyFile.set_double ("CACorrection", "Red", cacorrection.red); if (!pedited || pedited->cacorrection.blue) keyFile.set_double ("CACorrection", "Blue", cacorrection.blue); @@ -1393,6 +1404,13 @@ if (keyFile.has_group ("Gradient")) { if (keyFile.has_key ("Gradient", "CenterY")) { gradient.centerY = keyFile.get_integer ("Gradient", "CenterY"); if (pedited) pedited->gradient.centerY = true; } } +if (keyFile.has_group ("PCVignette")) { + if (keyFile.has_key ("PCVignette", "Enabled")) { pcvignette.enabled = keyFile.get_boolean ("PCVignette", "Enabled"); if (pedited) pedited->pcvignette.enabled = true; } + if (keyFile.has_key ("PCVignette", "Strength")) { pcvignette.strength = keyFile.get_double ("PCVignette", "Strength");if (pedited) pedited->pcvignette.strength = true; } + if (keyFile.has_key ("PCVignette", "Feather")) { pcvignette.feather = keyFile.get_integer ("PCVignette", "Feather"); if (pedited) pedited->pcvignette.feather = true; } + if (keyFile.has_key ("PCVignette", "Roundness")) { pcvignette.roundness = keyFile.get_integer ("PCVignette", "Roundness"); if (pedited) pedited->pcvignette.roundness = true; } +} + // load c/a correction if (keyFile.has_group ("CACorrection")) { if (keyFile.has_key ("CACorrection", "Red")) { cacorrection.red = keyFile.get_double ("CACorrection", "Red"); if (pedited) pedited->cacorrection.red = true; } @@ -1734,6 +1752,10 @@ bool ProcParams::operator== (const ProcParams& other) { && gradient.strength == other.gradient.strength && gradient.centerX == other.gradient.centerX && gradient.centerY == other.gradient.centerY + && pcvignette.enabled == other.pcvignette.enabled + && pcvignette.strength == other.pcvignette.strength + && pcvignette.feather == other.pcvignette.feather + && pcvignette.roundness == other.pcvignette.roundness && cacorrection.red == other.cacorrection.red && cacorrection.blue == other.cacorrection.blue && vignetting.amount == other.vignetting.amount diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 627cd25c7..2e490c74d 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -590,6 +590,18 @@ class GradientParams { int centerY; }; +/** + * Parameters of the post-crop vignette filter + */ +class PCVignetteParams { + + public: + bool enabled; + double strength; + int feather; + int roundness; +}; + /** * Parameters of the vignetting correction */ @@ -786,6 +798,7 @@ class ProcParams { LensProfParams lensProf; ///< Lens correction profile parameters PerspectiveParams perspective; ///< Perspective correction parameters GradientParams gradient; ///< Gradient filter parameters + PCVignetteParams pcvignette; ///< Post-crop vignette filter parameters CACorrParams cacorrection; ///< Lens c/a correction parameters VignettingParams vignetting; ///< Lens vignetting correction parameters ChannelMixerParams chmixer; ///< Channel mixer parameters diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index b132796e7..278d44c2f 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -230,7 +230,9 @@ DEFRINGE, // EvPFCurve, WHITEBALANCE, // EvWBequal, WHITEBALANCE, // EvWBequalbo, TRANSFORM, // EvGradient -TRANSFORM // EvGradientEnabled +TRANSFORM, // EvGradientEnabled +TRANSFORM, // EvPCVignette +TRANSFORM // EvPCVignetteEnabled //LUMINANCECURVE // EvCATsharpcie diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h index 00bdabada..ba914e77d 100644 --- a/rtengine/refreshmap.h +++ b/rtengine/refreshmap.h @@ -24,12 +24,14 @@ // Use M_VOID is you wish to update the proc params without updating the preview at all ! #define M_VOID (1<<15) // Use M_MINUPDATE if you you wish to update the preview without modifying the image (think about it like a "refreshPreview") +// Must NOT be used with other event (i.e. will be used for MINUPDATE only) #define M_MINUPDATE (1<<14) // Force high quality #define M_HIGHQUAL (1<<13) // Elementary functions that can be done to // the preview image when an event occurs +#define M_CROP (1<<11) #define M_PREPROC (1<<10) #define M_RAW (1<<9) #define M_INIT (1<<8) @@ -59,13 +61,14 @@ #define DARKFRAME (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define FLATFIELD (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define DIRPYRDENOISE (M_COLOR|M_LUMINANCE) -#define CROP M_MINUPDATE +#define CROP M_CROP #define RESIZE M_VOID #define EXIF M_VOID #define IPTC M_VOID #define DIRPYREQUALIZER (M_COLOR|M_LUMINANCE) #define OUTPUTPROFIL (M_COLOR|M_LUMINANCE) #define GAMMA (M_COLOR|M_LUMINANCE) +#define MINUPDATE M_MINUPDATE #define NONE 0 #define ALLNORAW (M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 24d81e1b0..91013fa92 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -682,7 +682,11 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei // perform transform if (ipf.needsTransform()) { Imagefloat* trImg = new Imagefloat (fw, fh); - ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, focalLen, focalLen35mm, focusDist, 0, true); // Raw rotate degree not detectable here + int origFW; + int origFH; + double tscale; + getDimensions(origFW, origFH, tscale); + ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, origFW*tscale+0.5, origFH*tscale+0.5, focalLen, focalLen35mm, focusDist, 0, true); // Raw rotate degree not detectable here delete baseImg; baseImg = trImg; } diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 1c71bf629..dd5125250 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -136,7 +136,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p // perform transform (excepted resizing) if (ipf.needsTransform()) { Imagefloat* trImg = new Imagefloat (fw, fh); - ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, imgsrc->getMetaData()->getFocalLen(), imgsrc->getMetaData()->getFocalLen35mm(), + ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, fw, fh, imgsrc->getMetaData()->getFocalLen(), imgsrc->getMetaData()->getFocalLen35mm(), imgsrc->getMetaData()->getFocusDist(), imgsrc->getRotateDegree(), true); delete baseImg; baseImg = trImg; diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 55d3372a5..459c52a9b 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -10,7 +10,7 @@ set (BASESOURCEFILES impulsedenoise.cc dirpyrdenoise.cc epd.cc exifpanel.cc toolpanel.cc lensprofile.cc sharpening.cc vibrance.cc rgbcurves.cc - whitebalance.cc vignetting.cc gradient.cc rotate.cc distortion.cc + whitebalance.cc vignetting.cc gradient.cc pcvignette.cc rotate.cc distortion.cc crophandler.cc dirbrowser.cc curveeditor.cc curveeditorgroup.cc diagonalcurveeditorsubgroup.cc flatcurveeditorsubgroup.cc filecatalog.cc extprog.cc diff --git a/rtgui/addsetids.h b/rtgui/addsetids.h index 37ad71d1c..5a35f176f 100644 --- a/rtgui/addsetids.h +++ b/rtgui/addsetids.h @@ -70,8 +70,11 @@ #define ADDSET_GRADIENT_FEATHER 62 #define ADDSET_GRADIENT_STRENGTH 63 #define ADDSET_GRADIENT_CENTER 64 +#define ADDSET_PCVIGNETTE_STRENGTH 65 +#define ADDSET_PCVIGNETTE_FEATHER 66 +#define ADDSET_PCVIGNETTE_ROUNDNESS 67 // When adding items, make sure to update ADDSET_PARAM_NUM -#define ADDSET_PARAM_NUM 65 // THIS IS USED AS A DELIMITER!! +#define ADDSET_PARAM_NUM 68 // THIS IS USED AS A DELIMITER!! #endif diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index 7319baddb..a505e8af1 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -134,6 +134,7 @@ void BatchToolPanelCoordinator::initSession () { distortion->setAdjusterBehavior (false); perspective->setAdjusterBehavior (false); gradient->setAdjusterBehavior (false, false, false, false); + pcvignette->setAdjusterBehavior (false, false, false); cacorrection->setAdjusterBehavior (false); sharpening->setAdjusterBehavior (false); sharpenEdge->setAdjusterBehavior (false, false); @@ -162,6 +163,7 @@ void BatchToolPanelCoordinator::initSession () { distortion->setAdjusterBehavior (options.baBehav[ADDSET_DIST_AMOUNT]); perspective->setAdjusterBehavior (options.baBehav[ADDSET_PERSPECTIVE]); gradient->setAdjusterBehavior (options.baBehav[ADDSET_GRADIENT_DEGREE], options.baBehav[ADDSET_GRADIENT_FEATHER], options.baBehav[ADDSET_GRADIENT_STRENGTH], options.baBehav[ADDSET_GRADIENT_CENTER]); + pcvignette->setAdjusterBehavior (options.baBehav[ADDSET_PCVIGNETTE_STRENGTH], options.baBehav[ADDSET_PCVIGNETTE_FEATHER], options.baBehav[ADDSET_PCVIGNETTE_ROUNDNESS]); cacorrection->setAdjusterBehavior (options.baBehav[ADDSET_CA]); sharpening->setAdjusterBehavior (options.baBehav[ADDSET_SHARP_AMOUNT]); sharpenEdge->setAdjusterBehavior (options.baBehav[ADDSET_SHARPENEDGE_AMOUNT],options.baBehav[ADDSET_SHARPENEDGE_PASS]); @@ -238,6 +240,9 @@ void BatchToolPanelCoordinator::initSession () { if (options.baBehav[ADDSET_GRADIENT_STRENGTH]) pparams.gradient.strength = 0; if (options.baBehav[ADDSET_GRADIENT_CENTER]) pparams.gradient.centerX = 0; if (options.baBehav[ADDSET_GRADIENT_CENTER]) pparams.gradient.centerY = 0; + if (options.baBehav[ADDSET_PCVIGNETTE_STRENGTH]) pparams.pcvignette.strength = 0; + if (options.baBehav[ADDSET_PCVIGNETTE_FEATHER]) pparams.pcvignette.feather = 0; + if (options.baBehav[ADDSET_PCVIGNETTE_ROUNDNESS]) pparams.pcvignette.roundness = 0; if (options.baBehav[ADDSET_CA]) pparams.cacorrection.red = 0; if (options.baBehav[ADDSET_CA]) pparams.cacorrection.blue = 0; if (options.baBehav[ADDSET_VIGN_AMOUNT]) pparams.vignetting.amount = 0; diff --git a/rtgui/options.cc b/rtgui/options.cc index 0dd0a2de4..60932f54b 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -452,10 +452,13 @@ void Options::setDefaults () { 0, // ADDSET_CAT_CHROMA 0, // ADDSET_CAT_CONTRAST 0, // ADDSET_WB_EQUAL - 0, // ADDSET_GRADIENT_AMOUNT - 0, // ADDSET_GRADIENT_RADIUS + 0, // ADDSET_GRADIENT_DEGREE + 0, // ADDSET_GRADIENT_FEATHER 0, // ADDSET_GRADIENT_STRENGTH 0, // ADDSET_GRADIENT_CENTER + 0, // ADDSET_PCVIGNETTE_STRENGTH + 0, // ADDSET_PCVIGNETTE_FEATHER + 0, // ADDSET_PCVIGNETTE_ROUNDNESS }; baBehav = std::vector (babehav, babehav+ADDSET_PARAM_NUM); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 62f5b27b8..e2c8353b2 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -196,6 +196,10 @@ void ParamsEdited::set (bool v) { gradient.strength = v; gradient.centerX = v; gradient.centerY = v; + pcvignette.enabled = v; + pcvignette.strength = v; + pcvignette.feather = v; + pcvignette.roundness = v; cacorrection.red = v; cacorrection.blue = v; vignetting.amount = v; @@ -450,6 +454,10 @@ void ParamsEdited::initFrom (const std::vector gradient.strength = gradient.strength && p.gradient.strength == other.gradient.strength; gradient.centerX = gradient.centerX && p.gradient.centerX == other.gradient.centerX; gradient.centerY = gradient.centerY && p.gradient.centerY == other.gradient.centerY; + pcvignette.enabled = pcvignette.enabled && p.pcvignette.enabled == other.pcvignette.enabled; + pcvignette.strength = pcvignette.strength && p.pcvignette.strength == other.pcvignette.strength; + pcvignette.feather = pcvignette.feather && p.pcvignette.feather == other.pcvignette.feather; + pcvignette.roundness = pcvignette.roundness && p.pcvignette.roundness == other.pcvignette.roundness; cacorrection.red = cacorrection.red && p.cacorrection.red == other.cacorrection.red; cacorrection.blue = cacorrection.blue && p.cacorrection.blue == other.cacorrection.blue; vignetting.amount = vignetting.amount && p.vignetting.amount == other.vignetting.amount; @@ -705,12 +713,16 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if (perspective.horizontal) toEdit.perspective.horizontal = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.horizontal + mods.perspective.horizontal : mods.perspective.horizontal; if (perspective.vertical) toEdit.perspective.vertical = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.vertical + mods.perspective.vertical : mods.perspective.vertical; - if (gradient.enabled) toEdit.gradient.enabled = mods.gradient.enabled; - if (gradient.degree) toEdit.gradient.degree = dontforceSet && options.baBehav[ADDSET_GRADIENT_DEGREE] ? toEdit.gradient.degree + mods.gradient.degree : mods.gradient.degree; + if (gradient.enabled) toEdit.gradient.enabled = mods.gradient.enabled; + if (gradient.degree) toEdit.gradient.degree = dontforceSet && options.baBehav[ADDSET_GRADIENT_DEGREE] ? toEdit.gradient.degree + mods.gradient.degree : mods.gradient.degree; if (gradient.feather) toEdit.gradient.feather = mods.gradient.feather; if (gradient.strength) toEdit.gradient.strength = mods.gradient.strength; if (gradient.centerX) toEdit.gradient.centerX = mods.gradient.centerX; if (gradient.centerY) toEdit.gradient.centerY = mods.gradient.centerY; + if (pcvignette.enabled) toEdit.pcvignette.enabled = mods.pcvignette.enabled; + if (pcvignette.strength) toEdit.pcvignette.strength = mods.pcvignette.strength; + if (pcvignette.feather) toEdit.pcvignette.feather = mods.pcvignette.feather; + if (pcvignette.roundness) toEdit.pcvignette.roundness = mods.pcvignette.roundness; if (cacorrection.red) toEdit.cacorrection.red = dontforceSet && options.baBehav[ADDSET_CA] ? toEdit.cacorrection.red + mods.cacorrection.red : mods.cacorrection.red; if (cacorrection.blue) toEdit.cacorrection.blue = dontforceSet && options.baBehav[ADDSET_CA] ? toEdit.cacorrection.blue + mods.cacorrection.blue : mods.cacorrection.blue; if (vignetting.amount) toEdit.vignetting.amount = dontforceSet && options.baBehav[ADDSET_VIGN_AMOUNT] ? toEdit.vignetting.amount + mods.vignetting.amount : mods.vignetting.amount; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index d9b7bca78..94f20a41b 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -324,6 +324,15 @@ class GradientParamsEdited { bool centerY; }; +class PCVignetteParamsEdited { + + public: + bool enabled; + bool strength; + bool feather; + bool roundness; +}; + class VignettingParamsEdited { public: @@ -462,6 +471,7 @@ class ParamsEdited { LensProfParamsEdited lensProf; PerspectiveParamsEdited perspective; GradientParamsEdited gradient; + PCVignetteParamsEdited pcvignette; CACorrParamsEdited cacorrection; VignettingParamsEdited vignetting; ChannelMixerParamsEdited chmixer; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index cf66e73be..ff3a0b1df 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -49,6 +49,7 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) { hlrec = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_HLRECONSTRUCTION"))); sh = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_SHADOWSHIGHLIGHTS"))); epd = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EPD"))); + pcvignette = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_PCVIGNETTE"))); gradient = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_GRADIENT"))); labcurve = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_LABCURVE"))); colorappearance= Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_COLORAPP"))); @@ -127,6 +128,7 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) { vboxes[0]->pack_start (*hlrec, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*sh, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*epd, Gtk::PACK_SHRINK, 2); + vboxes[0]->pack_start (*pcvignette, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*gradient, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*labcurve, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*colorappearance, Gtk::PACK_SHRINK, 2); @@ -248,6 +250,7 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) { hlrecConn = hlrec->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); shConn = sh->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); epdConn = epd->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); + pcvignetteConn = pcvignette->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); gradientConn = gradient->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); labcurveConn = labcurve->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); colorappearanceConn=colorappearance->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); @@ -430,6 +433,7 @@ void PartialPasteDlg::basicToggled () { hlrecConn.block (true); shConn.block (true); epdConn.block(true); + pcvignetteConn.block (true); gradientConn.block (true); labcurveConn.block (true); colorappearanceConn.block (true); @@ -441,6 +445,7 @@ void PartialPasteDlg::basicToggled () { hlrec->set_active (basic->get_active ()); sh->set_active (basic->get_active ()); epd->set_active (basic->get_active ()); + pcvignette->set_active (basic->get_active ()); gradient->set_active (basic->get_active ()); labcurve->set_active (basic->get_active ()); colorappearance->set_active (basic->get_active ()); @@ -450,6 +455,7 @@ void PartialPasteDlg::basicToggled () { hlrecConn.block (false); shConn.block (false); epdConn.block (false); + pcvignetteConn.block (false); gradientConn.block (false); labcurveConn.block (false); colorappearanceConn.block (false); @@ -604,6 +610,7 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param if (!hlrec->get_active ()) filterPE.hlrecovery = falsePE.hlrecovery; if (!sh->get_active ()) filterPE.sh = falsePE.sh; if (!epd->get_active ()) filterPE.edgePreservingDecompositionUI = falsePE.edgePreservingDecompositionUI; + if (!pcvignette->get_active ()) filterPE.pcvignette = falsePE.pcvignette; if (!gradient->get_active ()) filterPE.gradient = falsePE.gradient; if (!labcurve->get_active ()) filterPE.labCurve = falsePE.labCurve; if (!colorappearance->get_active ()) filterPE.colorappearance= falsePE.colorappearance; diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index d100ec881..b56094076 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -43,6 +43,7 @@ class PartialPasteDlg : public Gtk::Dialog { Gtk::CheckButton* hlrec; Gtk::CheckButton* sh; Gtk::CheckButton* epd; + Gtk::CheckButton* pcvignette; Gtk::CheckButton* gradient; Gtk::CheckButton* labcurve; Gtk::CheckButton* colorappearance; @@ -110,7 +111,7 @@ class PartialPasteDlg : public Gtk::Dialog { sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaicmConn, rawConn; - sigc::connection wbConn, exposureConn, hlrecConn, shConn, gradientConn, labcurveConn, colorappearanceConn; + sigc::connection wbConn, exposureConn, hlrecConn, shConn, pcvignetteConn, gradientConn, labcurveConn, colorappearanceConn; sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, waveqConn, defringeConn, epdConn, dirpyreqConn; sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn; sigc::connection distortionConn, cacorrConn, vignettingConn, lcpConn; diff --git a/rtgui/ppversion.h b/rtgui/ppversion.h index 3b3c9cd06..4797eb9ea 100644 --- a/rtgui/ppversion.h +++ b/rtgui/ppversion.h @@ -2,16 +2,23 @@ #define _PPVERSION_ // This number have to be incremented whenever the PP3 file format is modified -#define PPVERSION 310 +#define PPVERSION 311 #define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified -/* Log of version changes - * 307 2013-03-16 - * [Perspective] Horizontal and Vertical changed from int to double - * added [Directional Pyramid Denoising] Method, Redchro, Bluechro - * added [RGB Curves] LumaMode - * 310 2013-09-16 - * Defringing /Threshold - changed calculation, issue 1801 +/* + Log of version changes + + 311 2013-11-07 + [Gradient] new tool (gradient/graduated filter + [PCVignette] new tool (vignette filter) + + 310 2013-09-16 + Defringing /Threshold - changed calculation, issue 1801 + + 307 2013-03-16 + [Perspective] Horizontal and Vertical changed from int to double + added [Directional Pyramid Denoising] Method, Redchro, Bluechro + added [RGB Curves] LumaMode */ #endif diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index f368d6ac9..3c2da4f78 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -255,6 +255,12 @@ Gtk::Widget* Preferences::getBatchProcPanel () { appendBehavList (mi, M("TP_GRADIENT_STRENGTH"), ADDSET_GRADIENT_STRENGTH, false); appendBehavList (mi, M("TP_GRADIENT_CENTER_X")+", "+M("TP_GRADIENT_CENTER_Y"), ADDSET_GRADIENT_CENTER, false); + mi = behModel->append (); + mi->set_value (behavColumns.label, M("TP_PCVIGNETTE_LABEL")); + appendBehavList (mi, M("TP_PCVIGNETTE_STRENGTH"), ADDSET_PCVIGNETTE_STRENGTH, false); + appendBehavList (mi, M("TP_PCVIGNETTE_FEATHER"), ADDSET_PCVIGNETTE_FEATHER, false); + appendBehavList (mi, M("TP_PCVIGNETTE_ROUNDNESS"), ADDSET_PCVIGNETTE_ROUNDNESS, false); + mi = behModel->append (); mi->set_value (behavColumns.label, M("TP_CACORRECTION_LABEL")); appendBehavList (mi, M("TP_CACORRECTION_BLUE")+", "+M("TP_CACORRECTION_RED"), ADDSET_CA, true); diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 5604bcc56..eea01dd70 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -60,6 +60,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { whitebalance = Gtk::manage (new WhiteBalance ()); vignetting = Gtk::manage (new Vignetting ()); gradient = Gtk::manage (new Gradient ()); + pcvignette = Gtk::manage (new PCVignette ()); perspective = Gtk::manage (new PerspCorrection ()); cacorrection = Gtk::manage (new CACorrection ()); hlrecovery = Gtk::manage (new HLRecovery ()); @@ -90,6 +91,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { addPanel (colorPanel, hsvequalizer, M("TP_HSVEQUALIZER_LABEL")); toolPanels.push_back (hsvequalizer); addPanel (colorPanel, rgbcurves, M("TP_RGBCURVES_LABEL")); toolPanels.push_back (rgbcurves); addPanel (exposurePanel, edgePreservingDecompositionUI, M("TP_EPD_LABEL")); toolPanels.push_back (edgePreservingDecompositionUI); + addPanel (exposurePanel, pcvignette, M("TP_PCVIGNETTE_LABEL")); toolPanels.push_back (pcvignette); addPanel (exposurePanel, gradient, M("TP_GRADIENT_LABEL")); toolPanels.push_back (gradient); addPanel (exposurePanel, lcurve, M("TP_LABCURVE_LABEL")); toolPanels.push_back (lcurve); // addPanel (exposurePanel, edgePreservingDecompositionUI, M("TP_EPD_LABEL")); toolPanels.push_back (edgePreservingDecompositionUI); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index a46e53721..1c9b71434 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -52,6 +52,7 @@ #include "rotate.h" #include "vignetting.h" #include "gradient.h" +#include "pcvignette.h" #include "toolbar.h" #include "lensgeom.h" #include "lensgeomlistener.h" @@ -88,6 +89,7 @@ class ToolPanelCoordinator : public ToolPanelListener, WhiteBalance* whitebalance; Vignetting* vignetting; Gradient* gradient; + PCVignette* pcvignette; LensGeometry* lensgeom; LensProfilePanel* lensProf; Rotate* rotate;