From 56dafcf8c195eceb548d0b45cd41ee2aeada7af4 Mon Sep 17 00:00:00 2001 From: Hombre Date: Sat, 23 Apr 2016 00:43:48 +0200 Subject: [PATCH 001/135] Spot Removal tool It is not working yet, but the GUI is (almost) done. See issue #2239. --- rtdata/images/Dark/actions/spot-active.png | Bin 0 -> 330 bytes rtdata/images/Dark/actions/spot-normal.png | Bin 0 -> 397 bytes rtdata/images/Dark/actions/spot-prelight.png | Bin 0 -> 322 bytes rtdata/images/Light/actions/spot-active.png | Bin 0 -> 330 bytes rtdata/images/Light/actions/spot-normal.png | Bin 0 -> 397 bytes rtdata/images/Light/actions/spot-prelight.png | Bin 0 -> 322 bytes rtdata/languages/Francais | 6 +- rtdata/languages/default | 6 +- rtengine/CMakeLists.txt | 2 +- rtengine/alpha.cc | 75 ++ rtengine/alpha.h | 77 ++ rtengine/dcrop.cc | 61 +- rtengine/dcrop.h | 1 + rtengine/iimage.h | 53 ++ rtengine/image16.cc | 16 +- rtengine/image16.h | 3 +- rtengine/image8.cc | 2 +- rtengine/image8.h | 2 +- rtengine/imagedimensions.cc | 2 +- rtengine/imagedimensions.h | 60 +- rtengine/imagefloat.cc | 16 +- rtengine/imagefloat.h | 3 +- rtengine/imageio.h | 2 +- rtengine/imagesource.h | 2 +- rtengine/improccoordinator.cc | 56 +- rtengine/improccoordinator.h | 2 + rtengine/improcfun.h | 3 + rtengine/procevents.h | 3 +- rtengine/procparams.cc | 65 +- rtengine/procparams.h | 50 ++ rtengine/rawimagesource.cc | 2 +- rtengine/rawimagesource.h | 2 +- rtengine/refreshmap.cc | 19 +- rtengine/refreshmap.h | 40 +- rtengine/simpleprocess.cc | 4 + rtengine/spot.cc | 370 ++++++++++ rtengine/stdimagesource.cc | 2 +- rtengine/stdimagesource.h | 2 +- rtgui/CMakeLists.txt | 2 +- rtgui/paramsedited.cc | 14 + rtgui/paramsedited.h | 8 + rtgui/spot.cc | 690 ++++++++++++++++++ rtgui/spot.h | 101 +++ rtgui/thumbimageupdater.cc | 4 +- rtgui/toolpanelcoord.cc | 3 + rtgui/toolpanelcoord.h | 2 + tools/source_icons/scalable/spot-active.file | 1 + tools/source_icons/scalable/spot-active.svg | 81 ++ tools/source_icons/scalable/spot-normal.file | 1 + tools/source_icons/scalable/spot-normal.svg | 70 ++ .../source_icons/scalable/spot-prelight.file | 1 + tools/source_icons/scalable/spot-prelight.svg | 74 ++ 52 files changed, 1955 insertions(+), 106 deletions(-) create mode 100644 rtdata/images/Dark/actions/spot-active.png create mode 100644 rtdata/images/Dark/actions/spot-normal.png create mode 100644 rtdata/images/Dark/actions/spot-prelight.png create mode 100644 rtdata/images/Light/actions/spot-active.png create mode 100644 rtdata/images/Light/actions/spot-normal.png create mode 100644 rtdata/images/Light/actions/spot-prelight.png create mode 100644 rtengine/alpha.cc create mode 100644 rtengine/alpha.h create mode 100644 rtengine/spot.cc create mode 100644 rtgui/spot.cc create mode 100644 rtgui/spot.h create mode 100644 tools/source_icons/scalable/spot-active.file create mode 100644 tools/source_icons/scalable/spot-active.svg create mode 100644 tools/source_icons/scalable/spot-normal.file create mode 100644 tools/source_icons/scalable/spot-normal.svg create mode 100644 tools/source_icons/scalable/spot-prelight.file create mode 100644 tools/source_icons/scalable/spot-prelight.svg diff --git a/rtdata/images/Dark/actions/spot-active.png b/rtdata/images/Dark/actions/spot-active.png new file mode 100644 index 0000000000000000000000000000000000000000..56bd35f477f0c8dd54944e913feba472c6dffcd3 GIT binary patch literal 330 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&kmSQK*5Dp-y;YjHK@;M7UB8wRq z_$5J@am9+;)<8kY64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1T!d%8G= zXiS_sVI$We1A#Vs?}>bTyCe#Xf;MUG_{lQqotXT_cf7Hm8NOLQlAHACNy6@o)~d@N z|9_YLe|OELS@l|y!uqAP`>uSgG-61(b}KgXOre$oM2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4UJd?&7I?d*?GOH2cTId+?aw?X59h&POBO zMBkm^U{XCf+~?lj@_T3QoIJJY!m)(Sl1XiaB5xK=OAXw!^=D+V!HpcFn8$LKaUX^D z2(BwQ!Yg-bk%t10k&SX(iQDW9fXN)5SZG>g6bqL2L% z^=rBxO_qi%l@HNent3`!c9!CuhZlNe9|h0Y)>nK$*Cz3{)NZTf0Mp|K#r!L6LW^&U zzp(6$D`-iZGhgvP=T0ky#S#0H>)ZD8_g#4NqN3As+N&1ZL&sA#1-V!L&wd{Hh2?uk p=y!$E-lFH{zvNzcu>bx~?r>$%*9+IT{09adgQu&X%Q~loCII#VsOSIy literal 0 HcmV?d00001 diff --git a/rtdata/images/Dark/actions/spot-prelight.png b/rtdata/images/Dark/actions/spot-prelight.png new file mode 100644 index 0000000000000000000000000000000000000000..cb9e555bd57a120ea0c4e10dd6559ab06b31766b GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&kmSQK*5Dp-y;YjHK@;M7UB8wRq z_$5J@am9+;)<8kY64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1U{d%8G= zXiQu>VIx_{dC9j-C+I3D|Xj;Jk_>J-xMWxuuiunq6jeg2W=DoeZ z(WngYGT N;OXk;vd$@?2>{bTyCe#Xf;MUG_{lQqotXT_cf7Hm8NOLQlAHACNy6@o)~d@N z|9_YLe|OELS@l|y!uqAP`>uSgG-61(b}KgXOre$oM2?p zUk71ECym(^Ktah8*NBqf{Irtt#G+J&^73-M%)IR4UJd?&7I?d*?GOH2cTId+?aw?X59h&POBO zMBkm^U{XCf+~?lj@_T3QoIJJY!m)(Sl1XiaB5xK=OAXw!^=D+V!HpcFn8$LKaUX^D z2(BwQ!Yg-bk%t10k&SX(iQDW9fXN)5SZG>g6bqL2L% z^=rBxO_qi%l@HNent3`!c9!CuhZlNe9|h0Y)>nK$*Cz3{)NZTf0Mp|K#r!L6LW^&U zzp(6$D`-iZGhgvP=T0ky#S#0H>)ZD8_g#4NqN3As+N&1ZL&sA#1-V!L&wd{Hh2?uk p=y!$E-lFH{zvNzcu>bx~?r>$%*9+IT{09adgQu&X%Q~loCII#VsOSIy literal 0 HcmV?d00001 diff --git a/rtdata/images/Light/actions/spot-prelight.png b/rtdata/images/Light/actions/spot-prelight.png new file mode 100644 index 0000000000000000000000000000000000000000..cb9e555bd57a120ea0c4e10dd6559ab06b31766b GIT binary patch literal 322 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&kmSQK*5Dp-y;YjHK@;M7UB8wRq z_$5J@am9+;)<8kY64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1U{d%8G= zXiQu>VIx_{dC9j-C+I3D|Xj;Jk_>J-xMWxuuiunq6jeg2W=DoeZ z(WngYGT N;OXk;vd$@?2>{Alt-s HISTORY_SNAPSHOT;Capture @@ -1643,6 +1644,9 @@ TP_SHARPENMICRO_AMOUNT;Quantité TP_SHARPENMICRO_LABEL;Microcontraste TP_SHARPENMICRO_MATRIX;Matrice 3×3 au lieu de 5×5 TP_SHARPENMICRO_UNIFORMITY;Uniformité +TP_SPOT_COUNTLABEL;%1 point(s) +TP_SPOT_ENTRYCHANGED;Modification d'un point +TP_SPOT_LABEL;Retrait de taches TP_VIBRANCE_AVOIDCOLORSHIFT;Éviter les dérives de teinte TP_VIBRANCE_CURVEEDITOR_SKINTONES;TT TP_VIBRANCE_CURVEEDITOR_SKINTONES_LABEL;Tons chair diff --git a/rtdata/languages/default b/rtdata/languages/default index c8d145390..53efbf5eb 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -465,7 +465,7 @@ HISTORY_MSG_232;B&W - 'Before' curve type HISTORY_MSG_233;B&W - 'After' curve HISTORY_MSG_234;B&W - 'After' curve type HISTORY_MSG_235;B&W - Auto channel mixer -HISTORY_MSG_236;--unused-- +HISTORY_MSG_236;Spot removal - Point modif. HISTORY_MSG_237;B&W - Mixer HISTORY_MSG_238;GF - Feather HISTORY_MSG_239;GF - Strength @@ -670,6 +670,7 @@ HISTORY_MSG_437;Retinex - M - Method HISTORY_MSG_438;Retinex - M - Equalizer HISTORY_MSG_439;Retinex - Preview HISTORY_MSG_440;CbDL - Method +HISTORY_MSG_441;Spot removal HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1774,6 +1775,9 @@ TP_SHARPENMICRO_AMOUNT;Quantity TP_SHARPENMICRO_LABEL;Microcontrast TP_SHARPENMICRO_MATRIX;3×3 matrix instead of 5×5 TP_SHARPENMICRO_UNIFORMITY;Uniformity +TP_SPOT_COUNTLABEL;%1 point(s) +TP_SPOT_ENTRYCHANGED;Point changed +TP_SPOT_LABEL;Spot removal TP_VIBRANCE_AVOIDCOLORSHIFT;Avoid color shift TP_VIBRANCE_CURVEEDITOR_SKINTONES;HH TP_VIBRANCE_CURVEEDITOR_SKINTONES_LABEL;Skin-tones diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 1f4f3375f..a1ab06657 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -11,7 +11,7 @@ set (RTENGINESOURCEFILES colortemp.cc curves.cc flatcurves.cc diagonalcurves.cc dfmanager.cc ffmanager.cc gauss.cc rawimage.cc image8.cc image16.cc imagefloat.cc imagedata.cc imageio.cc improcfun.cc init.cc dcrop.cc loadinitial.cc procparams.cc rawimagesource.cc demosaic_algos.cc shmap.cc simpleprocess.cc refreshmap.cc fast_demo.cc amaze_demosaic_RT.cc CA_correct_RT.cc cfa_linedn_RT.cc green_equil_RT.cc hilite_recon.cc expo_before_b.cc - stdimagesource.cc myfile.cc iccjpeg.cc improccoordinator.cc pipettebuffer.cc coord.cc + stdimagesource.cc myfile.cc iccjpeg.cc improccoordinator.cc pipettebuffer.cc coord.cc alpha.cc spot.cc processingjob.cc rtthumbnail.cc utils.cc labimage.cc slicer.cc cieimage.cc iplab2rgb.cc ipsharpen.cc iptransform.cc ipresize.cc ipvibrance.cc imagedimensions.cc jpeg_memsrc.cc jdatasrc.cc iimage.cc diff --git a/rtengine/alpha.cc b/rtengine/alpha.cc new file mode 100644 index 000000000..e562350fc --- /dev/null +++ b/rtengine/alpha.cc @@ -0,0 +1,75 @@ +/* + * 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 "alpha.h" + +namespace rtengine +{ + +Alpha::Alpha () {} + +Alpha::Alpha (int width, int height) +{ + if (width > 0 && height > 0) { + surface = Cairo::ImageSurface::create(Cairo::FORMAT_A8, width, height); + } +} + +/* +Alpha::~Alpha () { + surface->unreference(); +} +*/ + +void Alpha::setSize(int width, int height) +{ + if (width > 0 && height > 0) { + if (surface) { + if (width != getWidth() && height != getHeight()) { + surface.clear(); // does this delete the referenced object? Unreferencing doesn't work, since Cairo expect to have a non null refCount in the destructor! + } else { + return; + } + } + + surface = Cairo::ImageSurface::create(Cairo::FORMAT_A8, width, height); + } else if (surface) { + surface.clear(); + } +} + +int Alpha::getWidth() +{ + if (surface) { + return surface->get_width(); + } + + return -1; +} + +int Alpha::getHeight() +{ + if (surface) { + return surface->get_height(); + } + + return -1; +} + +} diff --git a/rtengine/alpha.h b/rtengine/alpha.h new file mode 100644 index 000000000..57a0af343 --- /dev/null +++ b/rtengine/alpha.h @@ -0,0 +1,77 @@ +/* + * 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 _ALPHA_H_ +#define _ALPHA_H_ + +#include +#include + +#define CHECK_BOUNDS 0 + +namespace rtengine +{ + +/// Alpha channel class (8 bits) +class Alpha +{ +protected: + Cairo::RefPtr surface; + +public: + Alpha (); + Alpha (int width, int height); + //~Alpha (); + + void setSize(int width, int height); + int getWidth(); + int getHeight(); + + const Cairo::RefPtr getSurface (); + + // TODO: to make the editing faster, we should add an iterator class + + // Will send back the start of a row + unsigned char* operator () (unsigned row) const; + // Will send back a value at a given row, col position + unsigned char& operator () (unsigned row, unsigned col); + const unsigned char operator () (unsigned row, unsigned col) const; +}; + + + +inline const Cairo::RefPtr Alpha::getSurface () { + return surface; // to be used in bitmap edition +} + +inline const unsigned char Alpha::operator () (unsigned row, + unsigned col) const { + return *(surface->get_data () + row * surface->get_width () + col); +} + +inline unsigned char& Alpha::operator () (unsigned row, unsigned col) { + return *(surface->get_data () + row * surface->get_width () + col); +} + +inline unsigned char* Alpha::operator () (unsigned row) const { + return surface->get_data () + row * surface->get_width (); +} + +} + +#endif diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 77f0598b4..ac571d057 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -31,7 +31,7 @@ namespace rtengine extern const Settings* settings; Crop::Crop (ImProcCoordinator* parent, EditDataProvider *editDataProvider, bool isDetailWindow) - : PipetteBuffer(editDataProvider), origCrop(NULL), laboCrop(NULL), labnCrop(NULL), + : PipetteBuffer(editDataProvider), origCrop(NULL), spotCrop(NULL), laboCrop(NULL), labnCrop(NULL), cropImg(NULL), cbuf_real(NULL), cshmap(NULL), transCrop(NULL), cieCrop(NULL), cbuffer(NULL), updating(false), newUpdatePending(false), skip(10), cropx(0), cropy(0), cropw(-1), croph(-1), @@ -215,18 +215,18 @@ void Crop::update (int todo) if(settings->leveldnautsimpl == 1) { if(params.dirpyrDenoise.Cmethod == "MAN" || params.dirpyrDenoise.Cmethod == "PON" ) { PreviewProps pp (trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage (parent->currWB, tr, origCrop, pp, params.toneCurve, params.icm, params.raw ); + parent->imgsrc->getImage (parent->currWB, tr, baseCrop, pp, params.toneCurve, params.icm, params.raw ); } } else { if(params.dirpyrDenoise.C2method == "MANU") { PreviewProps pp (trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage (parent->currWB, tr, origCrop, pp, params.toneCurve, params.icm, params.raw ); + parent->imgsrc->getImage (parent->currWB, tr, baseCrop, pp, params.toneCurve, params.icm, params.raw ); } } if((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "PRE") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "PREV")) { PreviewProps pp (trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage (parent->currWB, tr, origCrop, pp, params.toneCurve, params.icm, params.raw ); + parent->imgsrc->getImage (parent->currWB, tr, baseCrop, pp, params.toneCurve, params.icm, params.raw ); if((!isDetailWindow) && parent->adnListener && skip == 1 && params.dirpyrDenoise.enabled) { float lowdenoise = 1.f; @@ -308,15 +308,15 @@ void Crop::update (int todo) //setCropSizes (centerTile_X[poscenterX], centerTile_Y[poscenterY], trafw*skip,trafh*skip , skip, true); // we only need image reduced to 1/4 here - int W = origCrop->getWidth(); - int H = origCrop->getHeight(); + int W = baseCrop->getWidth(); + int H = baseCrop->getHeight(); Imagefloat *provicalc = new Imagefloat ((W + 1) / 2, (H + 1) / 2); //for denoise curves for(int ii = 0; ii < H; ii += 2) { for(int jj = 0; jj < W; jj += 2) { - provicalc->r(ii >> 1, jj >> 1) = origCrop->r(ii, jj); - provicalc->g(ii >> 1, jj >> 1) = origCrop->g(ii, jj); - provicalc->b(ii >> 1, jj >> 1) = origCrop->b(ii, jj); + provicalc->r(ii >> 1, jj >> 1) = baseCrop->r(ii, jj); + provicalc->g(ii >> 1, jj >> 1) = baseCrop->g(ii, jj); + provicalc->b(ii >> 1, jj >> 1) = baseCrop->b(ii, jj); } } @@ -337,7 +337,7 @@ void Crop::update (int todo) LUTf gamcurve(65536, 0); float gam, gamthresh, gamslope; parent->ipf.RGB_denoise_infoGamCurve(params.dirpyrDenoise, parent->imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope); - parent->ipf.RGB_denoise_info(origCrop, provicalc, parent->imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, parent->imgsrc->getDirPyrDenoiseExpComp(), chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, nresi, highresi, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc, true); + parent->ipf.RGB_denoise_info(baseCrop, provicalc, parent->imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, parent->imgsrc->getDirPyrDenoiseExpComp(), chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, nresi, highresi, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc, true); // printf("redy=%f skin=%f pcskin=%f\n",redyel, skinc,nsknc); // printf("DCROP skip=%d cha=%4.0f Nb=%d red=%4.0f bl=%4.0f redM=%4.0f bluM=%4.0f L=%4.0f sigL=%4.0f Ch=%4.0f Si=%4.0f\n",skip, chaut,Nb, redaut,blueaut, maxredaut, maxblueaut, lumema, sigma_L, chromina, sigma); float multip = 1.f; @@ -600,10 +600,10 @@ void Crop::update (int todo) //end evaluate noise } - // if(params.dirpyrDenoise.Cmethod=="AUT" || params.dirpyrDenoise.Cmethod=="PON") {//reinit origCrop after Auto - if((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) { //reinit origCrop after Auto + // if(params.dirpyrDenoise.Cmethod=="AUT" || params.dirpyrDenoise.Cmethod=="PON") {//reinit baseCrop after Auto + if((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) { //reinit baseCrop after Auto PreviewProps pp (trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage (parent->currWB, tr, origCrop, pp, params.toneCurve, params.icm, params.raw ); + parent->imgsrc->getImage (parent->currWB, tr, baseCrop, pp, params.toneCurve, params.icm, params.raw ); } DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise; @@ -620,15 +620,15 @@ void Crop::update (int todo) if((noiseLCurve || noiseCCurve ) && skip == 1 && denoiseParams.enabled) { //only allocate memory if enabled and skip // we only need image reduced to 1/4 here - int W = origCrop->getWidth(); - int H = origCrop->getHeight(); + int W = baseCrop->getWidth(); + int H = baseCrop->getHeight(); calclum = new Imagefloat ((W + 1) / 2, (H + 1) / 2); //for denoise curves for(int ii = 0; ii < H; ii += 2) { for(int jj = 0; jj < W; jj += 2) { - calclum->r(ii >> 1, jj >> 1) = origCrop->r(ii, jj); - calclum->g(ii >> 1, jj >> 1) = origCrop->g(ii, jj); - calclum->b(ii >> 1, jj >> 1) = origCrop->b(ii, jj); + calclum->r(ii >> 1, jj >> 1) = baseCrop->r(ii, jj); + calclum->g(ii >> 1, jj >> 1) = baseCrop->g(ii, jj); + calclum->b(ii >> 1, jj >> 1) = baseCrop->b(ii, jj); } } @@ -644,7 +644,7 @@ void Crop::update (int todo) int kall = 0; float chaut, redaut, blueaut, maxredaut, maxblueaut, nresi, highresi; - parent->ipf.RGB_denoise(kall, origCrop, origCrop, calclum, ch_M, max_r, max_b, parent->imgsrc->isRAW(), /*Roffset,*/ denoiseParams, parent->imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, noiseCCurve, chaut, redaut, blueaut, maxredaut, maxblueaut, nresi, highresi); + parent->ipf.RGB_denoise(kall, baseCrop, baseCrop, calclum, ch_M, max_r, max_b, parent->imgsrc->isRAW(), /*Roffset,*/ denoiseParams, parent->imgsrc->getDirPyrDenoiseExpComp(), noiseLCurve, noiseCCurve, chaut, redaut, blueaut, maxredaut, maxblueaut, nresi, highresi); if (parent->adnListener) { parent->adnListener->noiseChanged(nresi, highresi); @@ -663,7 +663,7 @@ void Crop::update (int todo) } } - parent->imgsrc->convertColorSpace(origCrop, params.icm, parent->currWB); + parent->imgsrc->convertColorSpace(baseCrop, params.icm, parent->currWB); delete [] ch_M; delete [] max_r; @@ -771,6 +771,27 @@ void Crop::update (int todo) satLimitOpacity = 100.f * (moyS - 0.85f * eqty); //-0.85 sigma==>20% pixels with low saturation } + if (params.spot.enabled) { + if (todo & M_SPOT) { + if(!spotCrop) { + spotCrop = new Imagefloat (cropw, croph); + } + baseCrop->copyData(spotCrop); + + PreviewProps pp (cropx, cropy, cropw, croph, skip); + parent->ipf.removeSpots(spotCrop, params.spot.entries, pp); + } + } else { + if (spotCrop) { + delete spotCrop; + spotCrop = NULL; + } + } + + if (spotCrop) { + baseCrop = spotCrop; + } + if (todo & M_RGBCURVE) { double rrm, ggm, bbm; DCPProfile *dcpProf = parent->imgsrc->getDCP(params.icm, parent->currWB); diff --git a/rtengine/dcrop.h b/rtengine/dcrop.h index f1230bf01..9b2c3dbaf 100644 --- a/rtengine/dcrop.h +++ b/rtengine/dcrop.h @@ -42,6 +42,7 @@ class Crop : public DetailedCrop, public PipetteBuffer protected: // --- permanently allocated in RAM and only renewed on size changes Imagefloat* origCrop; // "one chunk" allocation + Imagefloat* spotCrop; // "one chunk" allocation LabImage* laboCrop; // "one chunk" allocation LabImage* labnCrop; // "one chunk" allocation Image8* cropImg; // "one chunk" allocation diff --git a/rtengine/iimage.h b/rtengine/iimage.h index 4b0450e54..1bf0ab97f 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -325,6 +325,23 @@ public: } } + /** Copy the a sub-region of the data to another PlanarRGBData */ + void copyData(PlanarWhateverData *dest, int x, int y, int width, int height) + { + assert (dest != NULL); + // Make sure that the size is the same, reallocate if necessary + dest->allocate(width, height); + + if (dest->width == -1) { + printf("ERROR: PlanarRGBData::copyData >>> allocation failed!\n"); + return; + } + + for (int i = y, j = 0; i < y + height; ++i, ++j) { + memcpy (dest->v(i) + x, v(j), width * sizeof(T)); + } + } + void rotate (int deg) { @@ -727,6 +744,25 @@ public: } } + /** Copy the a sub-region of the data to another PlanarRGBData */ + void copyData(PlanarRGBData *dest, int x, int y, int width, int height) + { + assert (dest != NULL); + // Make sure that the size is the same, reallocate if necessary + dest->allocate(width, height); + + if (dest->width == -1) { + printf("ERROR: PlanarRGBData::copyData >>> allocation failed!\n"); + return; + } + + for (int i = y, j = 0; i < y + height; ++i, ++j) { + memcpy (dest->r(i) + x, r(j), width * sizeof(T)); + memcpy (dest->g(i) + x, g(j), width * sizeof(T)); + memcpy (dest->b(i) + x, b(j), width * sizeof(T)); + } + } + void rotate (int deg) { @@ -1342,6 +1378,23 @@ public: memcpy (dest->data, data, 3 * width * height * sizeof(T)); } + /** Copy the a sub-region of the data to another PlanarRGBData */ + void copyData(ChunkyRGBData *dest, int x, int y, int width, int height) + { + assert (dest != NULL); + // Make sure that the size is the same, reallocate if necessary + dest->allocate(width, height); + + if (dest->width == -1) { + printf("ERROR: PlanarRGBData::copyData >>> allocation failed!\n"); + return; + } + + for (int i = y, j = 0; i < y + height; ++i, ++j) { + memcpy (dest->r(i) + x, r(j), 3 * width * sizeof(T)); + } + } + void rotate (int deg) { diff --git a/rtengine/image16.cc b/rtengine/image16.cc index 8ba88bd4c..a822d6aac 100644 --- a/rtengine/image16.cc +++ b/rtengine/image16.cc @@ -124,7 +124,21 @@ Image16* Image16::copy () return cp; } -void Image16::getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, bool first, procparams::ToneCurveParams hrp) +Image16* Image16::copySubRegion (int x, int y, int width, int height) +{ + Image16* cp = NULL; + int realWidth = LIM(x + width, 0, this->width) - x; + int realHeight = LIM(y + height, 0, this->height) - y; + + if (realWidth > 0 && realHeight > 0) { + cp = new Image16 (realWidth, realHeight); + copyData(cp, x, y, realWidth, realHeight); + } + + return cp; +} + +void Image16::getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, const PreviewProps & pp, bool first, procparams::ToneCurveParams hrp) { // compute channel multipliers diff --git a/rtengine/image16.h b/rtengine/image16.h index 0e1ac6786..975596fac 100644 --- a/rtengine/image16.h +++ b/rtengine/image16.h @@ -41,11 +41,12 @@ public: ~Image16 (); Image16* copy (); + Image16* copySubRegion (int x, int y, int width, int height); Image8* to8(); Imagefloat* tofloat(); - virtual void getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, bool first, procparams::ToneCurveParams hrp); + virtual void getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, const PreviewProps & pp, bool first, procparams::ToneCurveParams hrp); virtual const char* getType () const { diff --git a/rtengine/image8.cc b/rtengine/image8.cc index b27851a76..da4bea6ef 100644 --- a/rtengine/image8.cc +++ b/rtengine/image8.cc @@ -94,7 +94,7 @@ Image8* Image8::copy () return cp; } -void Image8::getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, bool first, procparams::ToneCurveParams hrp) +void Image8::getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, const PreviewProps & pp, bool first, procparams::ToneCurveParams hrp) { // compute channel multipliers double drm, dgm, dbm; diff --git a/rtengine/image8.h b/rtengine/image8.h index 188e20146..5f7cfea63 100644 --- a/rtengine/image8.h +++ b/rtengine/image8.h @@ -40,7 +40,7 @@ public: Image8* copy (); - virtual void getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, bool first, procparams::ToneCurveParams hrp); + virtual void getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, const PreviewProps & pp, bool first, procparams::ToneCurveParams hrp); virtual const char* getType () const { diff --git a/rtengine/imagedimensions.cc b/rtengine/imagedimensions.cc index f7d291483..a3c22cfbc 100644 --- a/rtengine/imagedimensions.cc +++ b/rtengine/imagedimensions.cc @@ -20,7 +20,7 @@ #include "imagedimensions.h" #include "rtengine.h" -void ImageDimensions::transform (PreviewProps pp, int tran, int &sx1, int &sy1, int &sx2, int &sy2) +void ImageDimensions::transform (const PreviewProps & pp, int tran, int &sx1, int &sy1, int &sx2, int &sy2) { int sw = width, sh = height; diff --git a/rtengine/imagedimensions.h b/rtengine/imagedimensions.h index e3b98f7c5..485209844 100644 --- a/rtengine/imagedimensions.h +++ b/rtengine/imagedimensions.h @@ -24,8 +24,9 @@ class PreviewProps { public: int x, y, w, h, skip; - PreviewProps (int _x, int _y, int _w, int _h, int _skip) - : x(_x), y(_y), w(_w), h(_h), skip(_skip) {} + PreviewProps (int x, int y, int w, int h, int skip); + + void set (int x, int y, int w, int h, int skip); }; /* @@ -39,25 +40,44 @@ public: int height; public: - ImageDimensions() : width(-1), height(-1) {} - int getW () - { - return width; - } - int getH () - { - return height; - } - int getWidth () const - { - return width; - } - int getHeight () const - { - return height; - } - void transform (PreviewProps pp, int tran, int &sx1, int &sy1, int &sx2, int &sy2); + ImageDimensions (); + int getW (); + int getH (); + int getWidth () const; + int getHeight () const; + void transform (const PreviewProps & pp, int tran, int &sx1, int &sy1, int &sx2, int &sy2); }; +inline PreviewProps::PreviewProps (int x, int y, int w, int h, int skip) : + x (x), y (y), w (w), h (h), skip (skip) { +} + +inline void PreviewProps::set (int x, int y, int w, int h, int skip) { + this->x = x; + this->y = y; + this->w = w; + this->h = h; + this->skip = skip; +} + +inline ImageDimensions::ImageDimensions () : + width (-1), height (-1) { +} + +inline int ImageDimensions::getW () { + return width; +} + +inline int ImageDimensions::getH () { + return height; +} + +inline int ImageDimensions::getWidth () const { + return width; +} + +inline int ImageDimensions::getHeight () const { + return height; +} #endif diff --git a/rtengine/imagefloat.cc b/rtengine/imagefloat.cc index 26ea8ae6e..fae39069b 100644 --- a/rtengine/imagefloat.cc +++ b/rtengine/imagefloat.cc @@ -170,8 +170,22 @@ Imagefloat* Imagefloat::copy () return cp; } +Imagefloat* Imagefloat::copySubRegion (int x, int y, int width, int height) +{ + Imagefloat* cp = NULL; + int realWidth = LIM(x + width, 0, this->width) - x; + int realHeight = LIM(y + height, 0, this->height) - y; + + if (realWidth > 0 && realHeight > 0) { + cp = new Imagefloat (realWidth, realHeight); + copyData(cp, x, y, realWidth, realHeight); + } + + return cp; +} + // This is called by the StdImageSource class. We assume that fp images from StdImageSource don't have to deal with gamma -void Imagefloat::getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, bool first, procparams::ToneCurveParams hrp) +void Imagefloat::getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, const PreviewProps & pp, bool first, procparams::ToneCurveParams hrp) { // compute channel multipliers diff --git a/rtengine/imagefloat.h b/rtengine/imagefloat.h index 50b0d4aeb..649799cc2 100644 --- a/rtengine/imagefloat.h +++ b/rtengine/imagefloat.h @@ -45,11 +45,12 @@ public: ~Imagefloat (); Imagefloat* copy (); + Imagefloat* copySubRegion (int x, int y, int width, int height); Image8* to8(); Image16* to16(); - virtual void getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, bool first, procparams::ToneCurveParams hrp); + virtual void getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, const PreviewProps & pp, bool first, procparams::ToneCurveParams hrp); virtual const char* getType () const { diff --git a/rtengine/imageio.h b/rtengine/imageio.h index 1a13458c1..fc53d6cf4 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -130,7 +130,7 @@ public: return sampleArrangement; } - virtual void getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, bool first, procparams::ToneCurveParams hrp) + virtual void getStdImage (ColorTemp ctemp, int tran, Imagefloat* image, const PreviewProps & pp, bool first, procparams::ToneCurveParams hrp) { printf("getStdImage NULL!\n"); } diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 80fc53f23..21317452e 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -81,7 +81,7 @@ public: virtual bool IsrgbSourceModified() = 0; // tracks whether cached rgb output of demosaic has been modified // use right after demosaicing image, add coarse transformation and put the result in the provided Imagefloat* - virtual void getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hlp, ColorManagementParams cmp, RAWParams raw) {} + virtual void getImage (ColorTemp ctemp, int tran, Imagefloat* image, const PreviewProps & pp, ToneCurveParams hlp, ColorManagementParams cmp, RAWParams raw) {} virtual eSensorType getSensorType () { return ST_NONE; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 2f14c1ded..0ff75ba38 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -30,8 +30,8 @@ namespace rtengine extern const Settings* settings; ImProcCoordinator::ImProcCoordinator () - : orig_prev(NULL), oprevi(NULL), oprevl(NULL), nprevl(NULL), previmg(NULL), workimg(NULL), - ncie(NULL), imgsrc(NULL), shmap(NULL), lastAwbEqual(0.), ipf(¶ms, true), monitorIntent(RI_RELATIVE), scale(10), + : orig_prev(NULL), oprevi(NULL), spotprevi(NULL), oprevl(NULL), nprevl(NULL), previmg(NULL), workimg(NULL), + ncie(NULL), imgsrc(NULL), shmap(NULL), lastAwbEqual(0.), ipf(¶ms, true), previewProps(-1, -1, -1, -1, 1), monitorIntent(RI_RELATIVE), scale(10), highDetailPreprocessComputed(false), highDetailRawComputed(false), allocated(false), bwAutoR(-9000.f), bwAutoG(-9000.f), bwAutoB(-9000.f), CAMMean(0.), @@ -136,7 +136,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { MyMutex::MyLock processingLock(mProcessing); - int numofphases = 14; + int numofphases = 15; int readyphase = 0; bwAutoR = bwAutoG = bwAutoB = -9000.f; @@ -316,11 +316,11 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) // Will (re)allocate the preview's buffers setScale (scale); - PreviewProps pp (0, 0, fw, fh, scale); + previewProps.set(0, 0, fw, fh, scale); // Tells to the ImProcFunctions' tools what is the preview scale, which may lead to some simplifications ipf.setScale (scale); - imgsrc->getImage (currWB, tr, orig_prev, pp, params.toneCurve, params.icm, params.raw); + imgsrc->getImage (currWB, tr, orig_prev, previewProps, params.toneCurve, params.icm, params.raw); //ColorTemp::CAT02 (orig_prev, ¶ms) ; // printf("orig_prevW=%d\n scale=%d",orig_prev->width, scale); /* Issue 2785, disabled some 1:1 tools @@ -377,11 +377,11 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) if (!needstransform && orig_prev != oprevi) { delete oprevi; - oprevi = orig_prev; + spotprevi = oprevi = orig_prev; } if (needstransform && orig_prev == oprevi) { - oprevi = new Imagefloat (pW, pH); + spotprevi = oprevi = new Imagefloat (pW, pH); } if ((todo & M_TRANSFORM) && needstransform) @@ -433,6 +433,24 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) } } + progress ("Spot Removal...", 100 * readyphase / numofphases); + + if ((todo & M_SPOT) && params.spot.enabled && !params.spot.entries.empty()) { + if(spotprevi == oprevi) { + spotprevi = new Imagefloat (pW, pH); + } + + oprevi->copyData(spotprevi); + ipf.removeSpots(spotprevi, params.spot.entries, previewProps); + } else { + if (spotprevi != oprevi) { + delete spotprevi; + spotprevi = oprevi; + } + } + + readyphase++; + progress ("Exposure curve & CIELAB conversion...", 100 * readyphase / numofphases); if ((todo & M_RGBCURVE) || (todo & M_CROP)) { @@ -445,9 +463,9 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) params.toneCurve.curveMode, params.toneCurve.curve, params.toneCurve.curveMode2, params.toneCurve.curve2, vhist16, histCropped, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, scale == 1 ? 1 : 1); - CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, scale == 1 ? 1 : 1); - CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, scale == 1 ? 1 : 1); - CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, scale == 1 ? 1 : 1); + CurveFactory::RGBCurve (params.rgbCurves.rcurve, rCurve, /*scale==1 ? 1 :*/ 1); + CurveFactory::RGBCurve (params.rgbCurves.gcurve, gCurve, /*scale==1 ? 1 :*/ 1); + CurveFactory::RGBCurve (params.rgbCurves.bcurve, bCurve, /*scale==1 ? 1 :*/ 1); TMatrix wprof = iccStore->workingSpaceMatrix (params.icm.working); @@ -484,7 +502,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) if(params.colorToning.enabled && params.colorToning.autosat) { //for colortoning evaluation of saturation settings float moyS = 0.f; float eqty = 0.f; - ipf.moyeqt (oprevi, moyS, eqty);//return image : mean saturation and standard dev of saturation + ipf.moyeqt (spotprevi, moyS, eqty);//return image : mean saturation and standard dev of saturation //printf("moy=%f ET=%f\n", moyS,eqty); float satp = ((moyS + 1.5f * eqty) - 0.3f) / 0.7f; //1.5 sigma ==> 93% pixels with high saturation -0.3 / 0.7 convert to Hombre scale @@ -537,7 +555,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) double bbm = 33.; DCPProfile *dcpProf = imgsrc->getDCP(params.icm, currWB); - ipf.rgbProc (oprevi, oprevl, NULL, hltonecurve, shtonecurve, tonecurve, shmap, params.toneCurve.saturation, + ipf.rgbProc (spotprevi, oprevl, NULL, hltonecurve, shtonecurve, tonecurve, shmap, params.toneCurve.saturation, rCurve, gCurve, bCurve, satLimit , satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, beforeToneCurveBW, afterToneCurveBW, rrm, ggm, bbm, bwAutoR, bwAutoG, bwAutoB, params.toneCurve.expcomp, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, dcpProf); if(params.blackwhite.enabled && params.blackwhite.autoc && abwListener) { @@ -867,11 +885,16 @@ void ImProcCoordinator::freeAll () } if (allocated) { - if (orig_prev != oprevi) { + if (spotprevi && spotprevi != oprevi) { + delete spotprevi; + } + spotprevi = NULL; + + if (oprevi && oprevi != orig_prev) { delete oprevi; } - oprevi = NULL; + delete orig_prev; orig_prev = NULL; delete oprevl; @@ -882,7 +905,6 @@ void ImProcCoordinator::freeAll () if (ncie) { delete ncie; } - ncie = NULL; if (imageListener) { @@ -928,7 +950,7 @@ void ImProcCoordinator::setScale (int prevscale) prevscale--; PreviewProps pp (0, 0, fw, fh, prevscale); imgsrc->getSize (tr, pp, nW, nH); - } while(nH < 400 && prevscale > 1 && (nW * nH < 1000000) ); // sctually hardcoded values, perhaps a better choice is possible + } while(nH < 400 && prevscale > 1 && (nW * nH < 1000000) ); // actually hardcoded values, perhaps a better choice is possible if (settings->verbose) { printf ("setscale starts (%d, %d)\n", nW, nH); @@ -942,7 +964,7 @@ void ImProcCoordinator::setScale (int prevscale) pH = nH; orig_prev = new Imagefloat (pW, pH); - oprevi = orig_prev; + spotprevi = oprevi = orig_prev; oprevl = new LabImage (pW, pH); nprevl = new LabImage (pW, pH); //ncie is only used in ImProcCoordinator::updatePreviewImage, it will be allocated on first use and deleted if not used anymore diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 4d442482e..4d9a5b5c1 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -55,6 +55,7 @@ class ImProcCoordinator : public StagedImageProcessor protected: Imagefloat *orig_prev; Imagefloat *oprevi; + Imagefloat *spotprevi; LabImage *oprevl; LabImage *nprevl; Image8 *previmg; @@ -71,6 +72,7 @@ protected: double lastAwbEqual; ImProcFunctions ipf; + PreviewProps previewProps; Glib::ustring monitorProfile; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 90a046149..d67256a63 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -354,6 +354,9 @@ public: float Mad(float * DataList, const int datalen); float MadRgb(float * DataList, const int datalen); + // spot removal tool + void removeSpots (Imagefloat* img, const std::vector &entries, const PreviewProps &pp); + // pyramid wavelet void dirpyr_equalizer (float ** src, float ** dst, int srcwidth, int srcheight, float ** l_a, float ** l_b, float ** dest_a, float ** dest_b, const double * mult, const double dirpyrThreshold, const double skinprot, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice, int scale);//Emil's directional pyramid wavelet void dirpyr_equalizercam (CieImage* ncie, float ** src, float ** dst, int srcwidth, int srcheight, float ** h_p, float ** C_p, const double * mult, const double dirpyrThreshold, const double skinprot, bool execdir, const bool gamutlab, float b_l, float t_l, float t_r, float b_r, int choice, int scale);//Emil's directional pyramid wavelet diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 3d4f90af1..20b099d6d 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -262,7 +262,7 @@ enum ProcEvent { EvBWAfterCurve = 232, EvBWAfterCurveMode = 233, EvAutoch = 234, -// EvFixedch=235, -- can be reused -- + EvSpotEntry = 235, EvNeutralBW = 236, EvGradientFeather = 237, EvGradientStrength = 238, @@ -467,6 +467,7 @@ enum ProcEvent { EvRetinexmapcurve = 437, EvviewMethod = 438, EvcbdlMethod = 439, + EvSpotEnabled = 440, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 9c4ddbd58..86d88240f 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -46,6 +46,9 @@ const char *RAWParams::XTransSensor::methodstring[RAWParams::XTransSensor::numMe const char *RAWParams::ff_BlurTypestring[RAWParams::numFlatFileBlurTypes] = {/*"Parametric",*/ "Area Flatfield", "Vertical Flatfield", "Horizontal Flatfield", "V+H Flatfield"}; std::vector WBParams::wbEntries; +const short SpotParams::minRadius = 5; +const short SpotParams::maxRadius = 35; + bool ToneCurveParams::HLReconstructionNecessary(LUTu &histRedRaw, LUTu &histGreenRaw, LUTu &histBlueRaw) { if (options.rtSettings.verbose) @@ -856,6 +859,12 @@ void CoarseTransformParams::setDefaults() vflip = false; } +void SpotParams::setDefaults() +{ + enabled = false; + entries.clear(); +} + void RAWParams::setDefaults() { bayersensor.method = RAWParams::BayerSensor::methodstring[RAWParams::BayerSensor::amaze]; @@ -2488,7 +2497,7 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol keyFile.set_integer ("Vignetting Correction", "CenterY", vignetting.centerY); } - + // save resizing settings if (!pedited || pedited->resize.enabled) { keyFile.set_boolean ("Resize", "Enabled", resize.enabled); } @@ -2517,6 +2526,28 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol keyFile.set_integer ("Resize", "Height", resize.height); } + // save spot removal settings + if (!pedited || pedited->spot.enabled) { + keyFile.set_boolean ("Spot removal", "Enabled", spot.enabled); + } + + if (!pedited || pedited->spot.entries) { + std::vector vEntries; + + for (size_t i = 0; i < spot.entries.size(); ++i) { + vEntries.push_back(double(spot.entries.at(i).sourcePos.x)); + vEntries.push_back(double(spot.entries.at(i).sourcePos.y)); + vEntries.push_back(double(spot.entries.at(i).targetPos.x)); + vEntries.push_back(double(spot.entries.at(i).targetPos.y)); + vEntries.push_back(double(spot.entries.at(i).radius)); + vEntries.push_back(double(spot.entries.at(i).feather)); + vEntries.push_back(double(spot.entries.at(i).opacity)); + } + + Glib::ArrayHandle entries = vEntries; + keyFile.set_double_list("Spot removal", "Entries", entries); + } + if (!pedited || pedited->prsharpening.enabled) { keyFile.set_boolean ("PostResizeSharpening", "Enabled", prsharpening.enabled); } @@ -5669,6 +5700,36 @@ int ProcParams::load (Glib::ustring fname, ParamsEdited* pedited) } } + // load spot removal settings + if (keyFile.has_group ("Spot removal")) { + if (keyFile.has_key ("Spot removal", "Enabled")) { + spot.enabled = keyFile.get_boolean ("Spot removal", "Enabled"); + + if (pedited) { + pedited->spot.enabled = true; + } + } + + if (keyFile.has_key ("Spot removal", "Entries")) { + Glib::ArrayHandle entries = keyFile.get_double_list ("Spot removal", "Entries"); + const double epsilon = 0.001; + SpotEntry entry; + + for (size_t i = 0; i < entries.size(); i += 7) { + entry.sourcePos.set(int(entries.data()[i ] + epsilon), int(entries.data()[i + 1] + epsilon)); + entry.targetPos.set(int(entries.data()[i + 2] + epsilon), int(entries.data()[i + 3] + epsilon)); + entry.radius = LIM(int (entries.data()[i + 4] + epsilon), SpotParams::minRadius, SpotParams::maxRadius); + entry.feather = float(entries.data()[i + 5]); + entry.opacity = float(entries.data()[i + 6]); + spot.entries.push_back(entry); + } + + if (pedited) { + pedited->spot.entries = true; + } + } + } + // load post resize sharpening if (keyFile.has_group ("PostResizeSharpening")) { if (keyFile.has_key ("PostResizeSharpening", "Enabled")) { @@ -7787,6 +7848,8 @@ bool ProcParams::operator== (const ProcParams& other) && resize.dataspec == other.resize.dataspec && resize.width == other.resize.width && resize.height == other.resize.height + && spot.enabled == other.spot.enabled + && spot.entries == other.spot.entries && raw.bayersensor.method == other.raw.bayersensor.method && raw.bayersensor.ccSteps == other.raw.bayersensor.ccSteps && raw.bayersensor.black0 == other.raw.bayersensor.black0 diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 7946ce4d9..772cffd77 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -946,6 +946,55 @@ public: int height; }; +class SpotEntry +{ +public: + Coord sourcePos; + Coord targetPos; + int radius; + float feather; + float opacity; + + SpotEntry() : radius(5), feather(1.f), opacity(1.f) {} + + bool operator== (const SpotEntry& other) const + { + return other.sourcePos == sourcePos && other.targetPos == targetPos && + other.radius == radius && other.feather == feather && other.opacity == opacity; + } + + bool operator!= (const SpotEntry& other) const + { + return other.sourcePos != sourcePos || other.targetPos != targetPos || + other.radius != radius || other.feather != feather || other.opacity != opacity; + } + + +}; + +/** + * Parameters of the dust removal tool + */ +class SpotParams +{ + +public: + // REWRITE TODO: all parameter should have getter and setter to maintain their validity + // the following constant can be used to adjust the tools correctly + static const short minRadius; + static const short maxRadius; + + bool enabled; + std::vector entries; + + SpotParams() + { + setDefaults(); + } + void setDefaults(); +}; + + /** * Parameters of the color spaces used during the processing */ @@ -1279,6 +1328,7 @@ public: ChannelMixerParams chmixer; ///< Channel mixer parameters BlackWhiteParams blackwhite; ///< Black & White parameters ResizeParams resize; ///< Resize parameters + SpotParams spot; ///< Spot removal tool ColorManagementParams icm; ///< profiles/color spaces used during the image processing RAWParams raw; ///< RAW parameters before demosaicing WaveletParams wavelet; ///< Wavelet parameters diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 1a4e0dbb5..758a37b29 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -617,7 +617,7 @@ calculate_scale_mul(float scale_mul[4], const float pre_mul_[4], const float c_w return gain; } -void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw ) +void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, const PreviewProps & pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw ) { MyMutex::MyLock lock(getImageMutex); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 0dd6c9098..241f8300b 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -137,7 +137,7 @@ public: void cfaboxblur (RawImage *riFlatFile, float* cfablur, int boxH, int boxW ); void scaleColors (int winx, int winy, int winw, int winh, const RAWParams &raw); // raw for cblack - void getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw); + void getImage (ColorTemp ctemp, int tran, Imagefloat* image, const PreviewProps & pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw); eSensorType getSensorType () { return ri != NULL ? ri->getSensorType() : ST_NONE; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 26e8f53d4..52dae275e 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -119,8 +119,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { ALLNORAW, // EvDPDNLuma, ALLNORAW, // EvDPDNChroma, ALLNORAW, // EvDPDNGamma, - ALLNORAW, // EvDirPyrEqualizer, - ALLNORAW, // EvDirPyrEqlEnabled, + ALLNORAW, // EvDirPyrEqualizer, + ALLNORAW, // EvDirPyrEqlEnabled, LUMINANCECURVE, // EvLSaturation, LUMINANCECURVE, // EvLaCurve, LUMINANCECURVE, // EvLbCurve, @@ -262,7 +262,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RGBCURVE, // EvBWAfterCurve RGBCURVE, // EvBWAfterCurveMode RGBCURVE, // EvAutoch - 0, // --unused-- + SPOT, // EvSpotEntry RGBCURVE, // EvNeutralBW TRANSFORM, // EvGradientFeather TRANSFORM, // EvGradientStrength @@ -275,12 +275,12 @@ int refreshmap[rtengine::NUMOFEVENTS] = { LUMINANCECURVE, // EvLCLCurve LUMINANCECURVE, // EvLLHCurve LUMINANCECURVE, // EvLHHCurve - ALLNORAW, // EvDirPyrEqualizerThreshold + ALLNORAW, // EvDirPyrEqualizerThreshold ALLNORAW, // EvDPDNenhance RGBCURVE, // EvBWMethodalg - ALLNORAW, // EvDirPyrEqualizerSkin - ALLNORAW, // EvDirPyrEqlgamutlab - ALLNORAW, // EvDirPyrEqualizerHueskin + ALLNORAW, // EvDirPyrEqualizerSkin + ALLNORAW, // EvDirPyrEqlgamutlab + ALLNORAW, // EvDirPyrEqualizerHueskin ALLNORAW, // EvDPDNmedian ALLNORAW, // EvDPDNmedmet RGBCURVE, // EvColorToningEnabled @@ -465,7 +465,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvLradius RETINEX, // EvmapMethod DEMOSAIC, // EvRetinexmapcurve - DEMOSAIC, // EvviewMethod - ALLNORAW // EvcbdlMethod + DEMOSAIC, // EvviewMethod + ALLNORAW, // EvcbdlMethod + SPOT // EvSpotEnabled }; diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h index 23e179f9f..adb8cbc27 100644 --- a/rtengine/refreshmap.h +++ b/rtengine/refreshmap.h @@ -20,15 +20,16 @@ #define __REFRESHMAP__ // Use M_VOID if you wish to update the proc params without updating the preview at all ! -#define M_VOID (1<<16) +#define M_VOID (1<<31) // Use M_MINUPDATE if 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<<15) +#define M_MINUPDATE (1<<30) // Force high quality -#define M_HIGHQUAL (1<<14) +#define M_HIGHQUAL (1<<29) // Elementary functions that can be done to // the preview image when an event occurs +#define M_SPOT (1<<14) #define M_MONITOR (1<<13) #define M_RETINEX (1<<12) #define M_CROP (1<<11) @@ -46,22 +47,23 @@ // Bitfield of functions to do to the preview image when an event occurs // Use those or create new ones for your new events -#define FIRST (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL -#define ALL (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL -#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 DEMOSAIC (M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define ALLNORAW (M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define TRANSFORM (M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define AUTOEXP (M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define RGBCURVE (M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define LUMINANCECURVE (M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define SHARPENING (M_LUMINANCE|M_COLOR) -#define IMPULSEDENOISE (M_LUMINANCE|M_COLOR) -#define DEFRINGE (M_LUMINANCE|M_COLOR) -#define DIRPYRDENOISE (M_LUMINANCE|M_COLOR) -#define DIRPYREQUALIZER (M_LUMINANCE|M_COLOR) -#define GAMMA (M_LUMINANCE|M_COLOR) +#define FIRST (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_SPOT|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL +#define ALL (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_SPOT|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL +#define DARKFRAME (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_SPOT|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_SPOT|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define DEMOSAIC (M_RAW|M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_SPOT|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define ALLNORAW (M_INIT|M_LINDENOISE|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_SPOT|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define TRANSFORM (M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_SPOT|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define AUTOEXP (M_AUTOEXP|M_SPOT|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define SPOT (M_SPOT|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define RGBCURVE (M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define LUMINANCECURVE (M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define SHARPENING (M_LUMINANCE|M_COLOR) +#define IMPULSEDENOISE (M_LUMINANCE|M_COLOR) +#define DEFRINGE (M_LUMINANCE|M_COLOR) +#define DIRPYRDENOISE (M_LUMINANCE|M_COLOR) +#define DIRPYREQUALIZER (M_LUMINANCE|M_COLOR) +#define GAMMA (M_LUMINANCE|M_COLOR) #define CROP M_CROP #define RESIZE M_VOID #define EXIF M_VOID diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index c03addb42..15ebe5a5a 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -764,6 +764,10 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p shmap->update (baseImg, shradius, ipf.lumimul, params.sh.hq, 1); } + if (params.spot.enabled && !params.spot.entries.empty()) { + ipf.removeSpots(baseImg, params.spot.entries, pp); + } + // RGB processing LUTf curve1 (65536); diff --git a/rtengine/spot.cc b/rtengine/spot.cc new file mode 100644 index 000000000..b37c1d62c --- /dev/null +++ b/rtengine/spot.cc @@ -0,0 +1,370 @@ +/* + * 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 "improcfun.h" +#include "alpha.h" + +namespace rtengine +{ + +/* Code taken from Gimp 2.8.10 and converted for RawTherapee by Jean-Christophe FRISCH (aka Hombre) on 02.19.2014 + * + * ORIGINAL NOTES + * + * The method used here is similar to the lighting invariant correction + * method but slightly different: we do not divide the RGB components, + * but substract them I2 = I0 - I1, where I0 is the sample image to be + * corrected, I1 is the reference pattern. Then we solve DeltaI=0 + * (Laplace) with I2 Dirichlet conditions at the borders of the + * mask. The solver is a unoptimized red/black checker Gauss-Siedel + * with an over-relaxation factor of 1.8. It can benefit from a + * multi-grid evaluation of an initial solution before the main + * iteration loop. + * + * I reduced the convergence criteria to 0.1% (0.001) as we are + * dealing here with RGB integer components, more is overkill. + * + * Jean-Yves Couleaud cjyves@free.fr + */ + +/* Original Algorithm Design: + * + * T. Georgiev, "Photoshop Healing Brush: a Tool for Seamless Cloning + * http://www.tgeorgiev.net/Photoshop_Healing.pdf + */ +void ImProcFunctions::removeSpots (Imagefloat* img, const std::vector &entries, const PreviewProps &pp) +{ + Alpha mask; + + //printf("img(%04d, %04d)\n", img->width, img->height); + + for (const auto entry : entries) { + float srcX = float (entry.sourcePos.x); + float srcY = float (entry.sourcePos.y); + float dstX = float (entry.targetPos.x); + float dstY = float (entry.targetPos.y); + //float radius = float (entry.radius) + 0.5f; + + float featherRadius = entry.radius * (1.f + entry.feather); + int scaledFeatherRadius = featherRadius / pp.skip; + + int src_XMin = int ((srcX - featherRadius - pp.x) / float (pp.skip) + 0.5f); + int src_XMax = int ((srcX + featherRadius - pp.x) / float (pp.skip) + 0.5f); + int src_YMin = int ((srcY - featherRadius - pp.y) / float (pp.skip) + 0.5f); + int src_YMax = int ((srcY + featherRadius - pp.y) / float (pp.skip) + 0.5f); + + int dst_XMin = int ((dstX - featherRadius - pp.x) / float (pp.skip) + 0.5f); + int dst_XMax = int ((dstX + featherRadius - pp.x) / float (pp.skip) + 0.5f); + int dst_YMin = int ((dstY - featherRadius - pp.y) / float (pp.skip) + 0.5f); + int dst_YMax = int ((dstY + featherRadius - pp.y) / float (pp.skip) + 0.5f); + + //printf(" -> X: %04d > %04d\n -> Y: %04d > %04d\n", dst_XMin, dst_XMax, dst_YMin, dst_YMax); + + // scaled spot is too small, we do not preview it + if (scaledFeatherRadius < 2 && pp.skip != 1) { +#ifndef NDEBUG + if (options.rtSettings.verbose) { + printf ("Skipping spot located at %d x %d, too small for the preview zoom rate\n", entry.sourcePos.x, entry.sourcePos.y); + } +#endif + continue; + } + + // skipping entries totally transparent + if (entry.opacity == 0.) { +#ifndef NDEBUG + if (options.rtSettings.verbose) { + printf ("Skipping spot located at %d x %d: opacity=%.3f\n", entry.sourcePos.x, entry.sourcePos.y, entry.opacity); + } + continue; +#endif + } + + // skipping entries where the source circle isn't completely inside the image bounds + if (src_XMin < 0 || src_XMax >= img->width || src_YMin < 0 || src_YMax >= img->height) { +#ifndef NDEBUG + if (options.rtSettings.verbose) { + printf ("Skipping spot located at %d x %d, from the data at %d x %d, radius=%d, feather=%.3f, opacity=%.3f: source out of bounds\n", entry.sourcePos.x, entry.sourcePos.y, entry.targetPos.x, entry.targetPos.y, entry.radius, entry.feather, entry.opacity); + printf ("%d < 0 || %d >= %d || %d < 0 || %d >= %d\n", + src_XMin, src_XMax, img->width, src_YMin, src_YMax, img->height); + } +#endif + continue; + } + + // skipping entries where the dest circle is completely outside the image bounds + if (dst_XMin >= img->width || dst_XMax <= 0 || dst_YMin >= img->height || dst_YMax <= 0) { +#ifndef NDEBUG + if (options.rtSettings.verbose) { + printf ("Skipping spot located at %d x %d, from the data at %d x %d, radius=%d, feather=%.3f, opacity=%.3f: source out of bounds\n", entry.sourcePos.x, entry.sourcePos.y, entry.targetPos.x, entry.targetPos.y, entry.radius, entry.feather, entry.opacity); + printf ("%d >= %d || %d <= 0 || %d >= %d || %d <= 0\n", + dst_XMin, img->width, dst_XMax, dst_YMin, img->height, dst_YMax); + } +#endif + continue; + } + + // ----------------- Core function ----------------- + +#if 0 + int scaledPPX = pp.x / pp.skip; + int scaledPPY = pp.y / pp.skip; + int scaledPPW = pp.w / pp.skip + (pp.w % pp.skip > 0); + int scaledPPH = pp.h / pp.skip + (pp.h % pp.skip > 0); + + int sizeX = dst_XMax - dst_XMin + 1; + int sizeY = dst_YMax - dst_YMin + 1; + + Imagefloat matrix (sizeX, sizeY); + Imagefloat solution (sizeX, sizeY); + + // allocate the mask and draw it + mask.setSize (sizeX, sizeY); + { + Cairo::RefPtr cr = Cairo::Context::create (mask.getSurface()); + + // clear the bitmap + cr->set_source_rgba (0., 0., 0., 0.); + cr->rectangle (0., 0., sizeX, sizeY); + cr->set_line_width (0.); + cr->fill(); + + // draw the mask + cr->set_antialias (Cairo::ANTIALIAS_GRAY); + cr->set_line_width (featherRadius); + double gradientCenterX = double (sizeX) / 2.; + double gradientCenterY = double (sizeY) / 2.; + { + Cairo::RefPtr radialGradient = Cairo::RadialGradient::create ( + gradientCenterX, gradientCenterY, radius, + gradientCenterX, gradientCenterY, featherRadius + ); + radialGradient->add_color_stop_rgb (0., 0., 0., 1.); + radialGradient->add_color_stop_rgb (1., 0., 0., 0.); + cr->set_source_rgba (0., 0., 0., 1.); + cr->mask (radialGradient); + cr->rectangle (0., 0., sizeX, sizeY); + cr->fill(); + } + } + + // copy the src part to a temporary buffer to avoid possible self modified source + Imagefloat *srcBuff = img->copySubRegion (srcX, srcY, sizeX, sizeY); + + + // subtract pattern to image and store the result as a double in matrix + for (int i = 0, i2 = dst_YMin; i2 < sizeY - 1; ++i, ++i2) { + for (int j = 0, j2 = dst_XMin; i2 < sizeX - 1; ++j, ++j2) { + matrix.r (i, j) = img->r (i2, j2) - srcBuff->r (i, j); + matrix.g (i, j) = img->g (i2, j2) - srcBuff->g (i, j); + matrix.b (i, j) = img->b (i2, j2) - srcBuff->b (i, j); + } + } + + + // FIXME: is a faster implementation needed? +#define EPSILON 0.001 +#define MAX_ITER 500 + + // repeat until convergence or max iterations + for (int n = 0; n < MAX_ITER; ++n) { + + printf ("<<< n=#%d\n", n); + // ---------------------------------------------------------------- + + /* Perform one iteration of the Laplace solver for matrix. Store the + * result in solution and get the square of the cumulative error + * of the solution. + */ + int i, j; + double tmp, diff; + double sqr_err_r = 0.0; + double sqr_err_g = 0.0; + double sqr_err_b = 0.0; + const double w = 1.80 * 0.25; /* Over-relaxation = 1.8 */ + + // we use a red/black checker model of the discretization grid + + // do reds + for (i = 0; i < matrix.getHeight(); ++i) { + for (j = i % 2; j < matrix.getWidth(); j += 2) { + printf ("/%d,%d", j, i); + + if ((0 == mask (i, j)) || (i == 0) || (i == (matrix.getHeight() - 1)) || (j == 0) || (j == (matrix.getWidth() - 1))) { + // do nothing at the boundary or outside mask + solution.r (i, j) = matrix.r (i, j); + solution.g (i, j) = matrix.g (i, j); + solution.b (i, j) = matrix.b (i, j); + } else { + // Use Gauss Siedel to get the correction factor then over-relax it + tmp = solution.r (i, j); + solution.r (i, j) = (matrix.r (i, j) + w * + ( + matrix.r (i, j - 1) + // west + matrix.r (i, j + 1) + // east + matrix.r (i - 1, j) + // north + matrix.r (i + 1, j) - 4.0 * matrix.r (i, j) // south + ) + ); + + diff = solution.r (i, j) - tmp; + sqr_err_r += diff * diff; + + + tmp = solution.g (i, j); + solution.g (i, j) = (matrix.g (i, j) + w * + ( + matrix.g (i, j - 1) + // west + matrix.g (i, j + 1) + // east + matrix.g (i - 1, j) + // north + matrix.g (i + 1, j) - 4.0 * matrix.g (i, j) // south + ) + ); + + diff = solution.g (i, j) - tmp; + sqr_err_g += diff * diff; + + + + tmp = solution.b (i, j); + solution.b (i, j) = (matrix.b (i, j) + w * + ( + matrix.b (i, j - 1) + // west + matrix.b (i, j + 1) + // east + matrix.b (i - 1, j) + // north + matrix.b (i + 1, j) - 4.0 * matrix.b (i, j) // south + ) + ); + + diff = solution.b (i, j) - tmp; + sqr_err_b += diff * diff; + + } + } + } + + + /* Do blacks + * + * As we've done the reds earlier, we can use them right now to + * accelerate the convergence. So we have "solution" in the solver + * instead of "matrix" above + */ + for (i = 0; i < matrix.getHeight(); i++) { + for (j = (i % 2) ? 0 : 1; j < matrix.getWidth(); j += 2) { + printf (":%d,%d", j, i); + + if ((0 == mask (i, j)) || (i == 0) || (i == (matrix.getHeight() - 1)) || (j == 0) || (j == (matrix.getWidth() - 1))) { + // do nothing at the boundary or outside mask + solution.r (i, j) = matrix.r (i, j); + solution.g (i, j) = matrix.g (i, j); + solution.b (i, j) = matrix.b (i, j); + } else { + // Use Gauss Siedel to get the correction factor then over-relax it + tmp = solution.r (i, j); + solution.r (i, j) = (matrix.r (i, j) + w * + ( + matrix.r (i, j - 1) + // west + matrix.r (i, j + 1) + // east + matrix.r (i - 1, j) + // north + matrix.r (i + 1, j) - 4.0 * matrix.r (i, j) // south + ) + ); + + diff = solution.r (i, j) - tmp; + sqr_err_r += diff * diff; + + + + tmp = solution.g (i, j); + solution.g (i, j) = (matrix.g (i, j) + w * + ( + matrix.g (i, j - 1) + // west + matrix.g (i, j + 1) + // east + matrix.g (i - 1, j) + // north + matrix.g (i + 1, j) - 4.0 * matrix.g (i, j) // south + ) + ); + + diff = solution.g (i, j) - tmp; + sqr_err_g += diff * diff; + + + + tmp = solution.b (i, j); + solution.b (i, j) = (matrix.b (i, j) + w * + ( + matrix.b (i, j - 1) + // west + matrix.b (i, j + 1) + // east + matrix.b (i - 1, j) + // north + matrix.b (i + 1, j) - 4.0 * matrix.b (i, j) // south + ) + ); + + diff = solution.b (i, j) - tmp; + sqr_err_b += diff * diff; + } + } + } + + // ---------------------------------------------------------------- + + // copy solution to matrix + solution.copyData (&matrix); + + if (sqr_err_r < EPSILON && sqr_err_g < EPSILON && sqr_err_b < EPSILON) { + break; + } + + printf ("\n>>> n=#%d\n", n); + } + + printf ("\n"); +#endif + + // add solution to original image and store in tempPR + for (int i = 0, i2 = dst_YMin; i2 < dst_YMax - 1; ++i, ++i2) { + if (i2 < 0 || i2 >= img->height) { + continue; + } + for (int j = 0, j2 = dst_XMin; j2 < dst_XMax - 1; ++j, ++j2) { + if (j2 < 0 || j2 >= img->width) { + continue; + } + //float c2 = float (mask (i, j)) / 255.f; + //float c1 = 1.f - c2; + //resultPR->r(i,j) = (unsigned char) CLAMP0255 ( ROUND( double(first->r(i,j)) + double(secondPR->r(i,j)) ) ); + + + img->r (i2, j2) = 65535.0f; //img->r(i2,j2)*c1 + srcBuff->r(i,j)*c2; + img->g (i2, j2) = 0.0f; //img->g(i2,j2)*c1 + srcBuff->g(i,j)*c2; + img->b (i2, j2) = 0.0f; //img->b(i2,j2)*c1 + srcBuff->b(i,j)*c2; + /* + img->r(i2,j2) = img->r(i2,j2)*c1 + (solution.r(i,j) + srcBuff->r(i,j))*c2; + img->g(i2,j2) = img->g(i2,j2)*c1 + (solution.g(i,j) + srcBuff->g(i,j))*c2; + img->b(i2,j2) = img->b(i2,j2)*c1 + (solution.b(i,j) + srcBuff->b(i,j))*c2; + */ + } + } + + } +} + +} + diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index aabb35a30..8c85c287f 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -213,7 +213,7 @@ int StdImageSource::load (Glib::ustring fname, bool batch) return 0; } -void StdImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw) +void StdImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps & pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw) { // the code will use OpenMP as of now. diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 6017fae74..51bbfab1d 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -45,7 +45,7 @@ public: ~StdImageSource (); int load (Glib::ustring fname, bool batch = false); - void getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw); + void getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps & pp, ToneCurveParams hrp, ColorManagementParams cmp, RAWParams raw); ColorTemp getWB () { return wb; diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 1adc6ddd4..b3094091d 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -6,7 +6,7 @@ set (BASESOURCEFILES cachemanager.cc cacheimagedata.cc shcselector.cc perspective.cc thresholdselector.cc thresholdadjuster.cc clipboard.cc thumbimageupdater.cc bqentryupdater.cc lensgeom.cc coloredbar.cc edit.cc coordinateadjuster.cc coarsepanel.cc cacorrection.cc chmixer.cc blackwhite.cc - resize.cc icmpanel.cc crop.cc shadowshighlights.cc + resize.cc icmpanel.cc crop.cc shadowshighlights.cc spot.cc impulsedenoise.cc dirpyrdenoise.cc epd.cc exifpanel.cc toolpanel.cc lensprofile.cc sharpening.cc vibrance.cc rgbcurves.cc colortoning.cc diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 1ae650a5f..0af4e9fdb 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -342,6 +342,10 @@ void ParamsEdited::set (bool v) resize.width = v; resize.height = v; resize.enabled = v; + + spot.enabled = v; + spot.entries = v; + icm.input = v; icm.toneCurve = v; icm.applyLookTable = v; @@ -835,6 +839,8 @@ void ParamsEdited::initFrom (const std::vector resize.width = resize.width && p.resize.width == other.resize.width; resize.height = resize.height && p.resize.height == other.resize.height; resize.enabled = resize.enabled && p.resize.enabled == other.resize.enabled; + spot.enabled = spot.enabled && p.spot.enabled == other.spot.enabled; + spot.entries = spot.entries && p.spot.entries == other.spot.entries; icm.input = icm.input && p.icm.input == other.icm.input; icm.toneCurve = icm.toneCurve && p.icm.toneCurve == other.icm.toneCurve; icm.applyLookTable = icm.applyLookTable && p.icm.applyLookTable == other.icm.applyLookTable; @@ -2164,6 +2170,14 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.resize.enabled = mods.resize.enabled; } + if (spot.enabled) { + toEdit.spot.enabled = mods.spot.enabled; + } + + if (spot.entries) { + toEdit.spot.entries = mods.spot.entries; + } + if (icm.input) { toEdit.icm.input = mods.icm.input; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 8543fbfa8..cf3beb380 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -529,6 +529,13 @@ public: bool enabled; }; +class SpotParamsEdited +{ +public: + bool enabled; + bool entries; +}; + class ColorManagementParamsEdited { @@ -773,6 +780,7 @@ public: ChannelMixerParamsEdited chmixer; BlackWhiteParamsEdited blackwhite; ResizeParamsEdited resize; + SpotParamsEdited spot; ColorManagementParamsEdited icm; RAWParamsEdited raw; DirPyrEqualizerParamsEdited dirpyrequalizer; diff --git a/rtgui/spot.cc b/rtgui/spot.cc new file mode 100644 index 000000000..0d1b1d596 --- /dev/null +++ b/rtgui/spot.cc @@ -0,0 +1,690 @@ +/* + * This file is part of RawTherapee. + */ +#include "spot.h" +#include "rtimage.h" +#include +#include "../rtengine/rt_math.h" +#include "guiutils.h" + +using namespace rtengine; +using namespace rtengine::procparams; + +#define STATIC_VISIBLE_OBJ_NBR 6 +#define STATIC_MO_OBJ_NBR 6 + +Spot::Spot() : FoldableToolPanel (this, "spot", M ("TP_SPOT_LABEL"), true, true), EditSubscriber (ET_OBJECTS), lastObject (-1), activeSpot (-1), + sourceIcon ("spot-normal.png", "spot-active.png", "spot-active.png", "spot-prelight.png", "", Geometry::DP_CENTERCENTER), editedCheckBox(NULL) +{ + countLabel = Gtk::manage (new Gtk::Label (Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), 0))); + + edit = Gtk::manage (new Gtk::ToggleButton()); + edit->add (*Gtk::manage (new RTImage ("editmodehand.png"))); + editConn = edit->signal_toggled().connect ( sigc::mem_fun (*this, &Spot::editToggled) ); + + reset = Gtk::manage (new Gtk::Button ()); + reset->add (*Gtk::manage (new RTImage ("gtk-undo-ltr-small.png", "gtk-undo-rtl-small.png"))); + reset->set_relief (Gtk::RELIEF_NONE); + reset->set_border_width (0); + reset->signal_clicked().connect ( sigc::mem_fun (*this, &Spot::resetPressed) ); + + labelBox = Gtk::manage (new Gtk::HBox()); + labelBox->set_spacing (2); + labelBox->pack_start (*countLabel, false, false, 0); + labelBox->pack_end (*edit, false, false, 0); + labelBox->pack_end (*reset, false, false, 0); + pack_start (*labelBox); + + sourceIcon.datum = Geometry::IMAGE; + sourceIcon.setActive (false); + sourceIcon.state = Geometry::ACTIVE; + sourceCircle.datum = Geometry::IMAGE; + sourceCircle.setActive (false); + sourceCircle.radiusInImageSpace = true; + sourceMODisc.datum = Geometry::IMAGE; + sourceMODisc.setActive (false); + sourceMODisc.radiusInImageSpace = true; + sourceMODisc.filled = true; + sourceMODisc.innerLineWidth = 0.; + targetCircle.datum = Geometry::IMAGE; + targetCircle.setActive (false); + targetCircle.radiusInImageSpace = true; + targetMODisc.datum = Geometry::IMAGE; + targetMODisc.setActive (false); + targetMODisc.radiusInImageSpace = true; + targetMODisc.filled = true; + targetMODisc.innerLineWidth = 0.; + sourceFeatherCircle.datum = Geometry::IMAGE; + sourceFeatherCircle.setActive (false); + sourceFeatherCircle.radiusInImageSpace = true; + targetFeatherCircle.datum = Geometry::IMAGE; + targetFeatherCircle.setActive (false); + targetFeatherCircle.radiusInImageSpace = true; + link.datum = Geometry::IMAGE; + link.setActive (false); + + show_all(); +} + +Spot::~Spot() +{ + // delete all dynamically allocated geometry + if (EditSubscriber::visibleGeometry.size()) { + for (size_t i = 0; i < EditSubscriber::visibleGeometry.size() - STATIC_VISIBLE_OBJ_NBR; ++i) { // static visible geometry at the end if the list + delete EditSubscriber::visibleGeometry.at (i); + } + } + // We do not delete the mouseOverGeometry, because the referenced objects are either + // shared with visibleGeometry or instantiated by the class's ctor +} + +void Spot::read (const ProcParams* pp, const ParamsEdited* pedited) +{ + disableListener (); + + size_t oldSize = spots.size(); + spots = pp->spot.entries; + + if (pedited) { + set_inconsistent (multiImage && !pedited->spot.enabled); + } + + setEnabled (pp->spot.enabled); + lastEnabled = pp->spot.enabled; + + if (spots.size() != oldSize) { + createGeometry(); + } + + updateGeometry(); + + enableListener (); +} + +void Spot::write (ProcParams* pp, ParamsEdited* pedited) +{ + pp->spot.enabled = getEnabled(); + pp->spot.entries = spots; + + if (pedited) { + pedited->spot.enabled = !get_inconsistent(); + pedited->spot.entries = !editedCheckBox->get_active(); + } +} + +void Spot::resetPressed() +{ + if (batchMode) { + // no need to handle the Geometry in batch mode, since point editing is disabled + spots.clear(); + editedConn.block (true); + editedCheckBox->set_active (true); + editedConn.block (false); + + if (listener) { + listener->panelChanged (EvSpotEntry, Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), spots.size())); + } + } else { + if (!spots.empty()) { + spots.clear(); + activeSpot = -1; + lastObject = -1; + createGeometry(); + updateGeometry(); + + if (listener) { + listener->panelChanged (EvSpotEntry, Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), 0)); + } + } + } +} + +void Spot::setBatchMode (bool batchMode) +{ + ToolPanel::setBatchMode (batchMode); + + if (batchMode) { + removeIfThere (labelBox, edit, false); + + if (!editedCheckBox) { + removeIfThere (labelBox, countLabel, false); + countLabel = NULL; + editedCheckBox = Gtk::manage (new Gtk::CheckButton (Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), 0))); + labelBox->pack_start (*editedCheckBox, Gtk::PACK_SHRINK, 2); + labelBox->reorder_child (*editedCheckBox, 0); + editedConn = editedCheckBox->signal_toggled().connect ( sigc::mem_fun (*this, &Spot::editedToggled) ); + editedCheckBox->show(); + } + } +} + +void Spot::editedToggled () +{ + if (listener) { + listener->panelChanged (EvSpotEntry, !editedCheckBox->get_active() ? M ("GENERAL_UNCHANGED") : Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), spots.size())); + } +} + + +void Spot::enabledChanged () +{ + if (listener) { + if (get_inconsistent()) { + listener->panelChanged (EvSpotEnabled, M("GENERAL_UNCHANGED")); + } else if (getEnabled()) { + listener->panelChanged (EvSpotEnabled, M("GENERAL_ENABLED")); + } else { + listener->panelChanged (EvSpotEnabled, M("GENERAL_DISABLED")); + } + } +} + +void Spot::setEditProvider (EditDataProvider* provider) +{ + EditSubscriber::setEditProvider (provider); +} + +void Spot::editToggled () +{ + if (edit->get_active()) { + subscribe(); + } else { + unsubscribe(); + } +} + +Geometry* Spot::getVisibleGeometryFromMO (int MOID) +{ + if (MOID == -1) { + return NULL; + } + + if (MOID == 0) { + return getActiveSpotIcon(); + } + + if (MOID == 1) { // sourceMODisc + return &sourceIcon; + } + + return EditSubscriber::mouseOverGeometry.at (MOID); +} + +void Spot::createGeometry () +{ + int nbrEntry = spots.size(); + + if (!batchMode) { + countLabel->set_text(Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), nbrEntry)); + } + + //printf("CreateGeometry(%d)\n", nbrEntry); + // delete all dynamically allocated geometry + if (EditSubscriber::visibleGeometry.size() > STATIC_VISIBLE_OBJ_NBR) + for (size_t i = 0; i < EditSubscriber::visibleGeometry.size() - STATIC_VISIBLE_OBJ_NBR; ++i) { // static visible geometry at the end if the list + delete EditSubscriber::visibleGeometry.at (i); + } + + size_t i = 0, j = 0; + EditSubscriber::mouseOverGeometry.resize (STATIC_MO_OBJ_NBR + nbrEntry); + EditSubscriber::visibleGeometry.resize (nbrEntry + STATIC_VISIBLE_OBJ_NBR); + + EditSubscriber::mouseOverGeometry.at (i++) = &targetMODisc; // STATIC_MO_OBJ_NBR + 0 + EditSubscriber::mouseOverGeometry.at (i++) = &sourceMODisc; // STATIC_MO_OBJ_NBR + 1 + EditSubscriber::mouseOverGeometry.at (i++) = &targetCircle; // STATIC_MO_OBJ_NBR + 2 + EditSubscriber::mouseOverGeometry.at (i++) = &sourceCircle; // STATIC_MO_OBJ_NBR + 3 + EditSubscriber::mouseOverGeometry.at (i++) = &targetFeatherCircle; // STATIC_MO_OBJ_NBR + 4 + EditSubscriber::mouseOverGeometry.at (i++) = &sourceFeatherCircle; // STATIC_MO_OBJ_NBR + 5 + + // recreate all spots geometry + Cairo::RefPtr normalImg = sourceIcon.getNormalImg(); + Cairo::RefPtr prelightImg = sourceIcon.getPrelightImg(); + Cairo::RefPtr activeImg = sourceIcon.getActiveImg(); + + for (; j < EditSubscriber::visibleGeometry.size() - STATIC_VISIBLE_OBJ_NBR; ++i, ++j) { + EditSubscriber::mouseOverGeometry.at (i) = EditSubscriber::visibleGeometry.at (j) = new OPIcon (normalImg, activeImg, prelightImg, Cairo::RefPtr(NULL), Cairo::RefPtr(NULL), Geometry::DP_CENTERCENTER); + EditSubscriber::visibleGeometry.at (j)->setActive (true); + EditSubscriber::visibleGeometry.at (j)->datum = Geometry::IMAGE; + EditSubscriber::visibleGeometry.at (j)->state = Geometry::NORMAL; + //printf("mouseOverGeometry.at(%d) = %p\n", (unsigned int)i, (void*)EditSubscriber::mouseOverGeometry.at(i)); + } + + EditSubscriber::visibleGeometry.at (j++) = &sourceIcon; // STATIC_VISIBLE_OBJ_NBR + 0 + EditSubscriber::visibleGeometry.at (j++) = &sourceFeatherCircle; // STATIC_VISIBLE_OBJ_NBR + 1 + EditSubscriber::visibleGeometry.at (j++) = &link; // STATIC_VISIBLE_OBJ_NBR + 2 + EditSubscriber::visibleGeometry.at (j++) = &sourceCircle; // STATIC_VISIBLE_OBJ_NBR + 3 + EditSubscriber::visibleGeometry.at (j++) = &targetFeatherCircle; // STATIC_VISIBLE_OBJ_NBR + 4 + EditSubscriber::visibleGeometry.at (j++) = &targetCircle; // STATIC_VISIBLE_OBJ_NBR + 5 +} + +void Spot::updateGeometry() +{ + EditDataProvider* dataProvider = getEditProvider(); + + if (dataProvider) { + int imW, imH; + dataProvider->getImageSize (imW, imH); + + if (activeSpot > -1) { + // Target point circle + targetCircle.center = spots.at (activeSpot).targetPos; + targetCircle.radius = spots.at (activeSpot).radius; + targetCircle.setActive (true); + + // Target point Mouse Over disc + targetMODisc.center = targetCircle.center; + targetMODisc.radius = targetCircle.radius; + targetMODisc.setActive (true); + + // Source point Icon + sourceIcon.position = spots.at (activeSpot).sourcePos; + sourceIcon.setActive (true); + + // Source point circle + sourceCircle.center = spots.at (activeSpot).sourcePos; + sourceCircle.radius = spots.at (activeSpot).radius; + sourceCircle.setActive (true); + + // Source point Mouse Over disc + sourceMODisc.center = sourceCircle.center; + sourceMODisc.radius = sourceCircle.radius; + sourceMODisc.setActive (true); + + // Target point feather circle + targetFeatherCircle.center = spots.at (activeSpot).targetPos; + targetFeatherCircle.radius = float (spots.at (activeSpot).radius) * (1.f + spots.at (activeSpot).feather); + targetFeatherCircle.radiusInImageSpace = true; + targetFeatherCircle.setActive (true); + + // Source point feather circle + sourceFeatherCircle.center = spots.at (activeSpot).sourcePos; + sourceFeatherCircle.radius = targetFeatherCircle.radius; + sourceFeatherCircle.setActive (true); + + // Link line + PolarCoord p; + p = targetCircle.center - sourceCircle.center; + + if (p.radius > sourceCircle.radius + targetCircle.radius) { + PolarCoord p2 (sourceCircle.radius, p.angle); + Coord p3; + p3 = p2; + link.begin = sourceCircle.center + p3; + p2.set (targetCircle.radius, p.angle + 180); + p3 = p2; + link.end = targetCircle.center + p3; + link.setActive (true); + } else { + link.setActive (false); + } + } else { + targetCircle.setActive (false); + targetMODisc.setActive (false); + sourceIcon.setActive (false); + sourceCircle.setActive (false); + sourceMODisc.setActive (false); + targetFeatherCircle.setActive (false); + sourceFeatherCircle.setActive (false); + link.setActive (false); + } + + for (size_t i = 0; i < spots.size(); ++i) { + // Target point icon + OPIcon* geom = static_cast (EditSubscriber::visibleGeometry.at (i)); + geom->position = spots.at (i).targetPos; + geom->setActive (true); + + if (int (i) == activeSpot) { + geom->setHoverable (false); + } + } + } +} + +OPIcon *Spot::getActiveSpotIcon() +{ + if (activeSpot > -1) { + return static_cast (EditSubscriber::visibleGeometry.at (activeSpot)); + } + + return NULL; +} + +void Spot::addNewEntry() +{ + EditDataProvider* editProvider = getEditProvider(); + // we create a new entry + SpotEntry se; + se.targetPos = editProvider->posImage; + se.sourcePos = se.targetPos; + spots.push_back (se); // this make a copy of se ... + activeSpot = spots.size() - 1; + lastObject = 1; + + //printf("ActiveSpot = %d\n", activeSpot); + + createGeometry(); + updateGeometry(); + EditSubscriber::visibleGeometry.at (activeSpot)->state = Geometry::ACTIVE; + sourceIcon.state = Geometry::DRAGGED; + // TODO: find a way to disable the active spot's Mouse Over geometry but still displaying its location... + + if (listener) { + listener->panelChanged (EvSpotEntry, M ("TP_SPOT_ENTRYCHANGED")); + } +} + +void Spot::deleteSelectedEntry() +{ + // delete the activeSpot + if (activeSpot > -1) { + std::vector::iterator i = spots.begin(); + for (int j = 0; j < activeSpot; ++j) { + ++i; + } + spots.erase (i); + } + + lastObject = -1; + activeSpot = -1; + + createGeometry(); + updateGeometry(); + + if (listener) { + listener->panelChanged (EvSpotEntry, M ("TP_SPOT_ENTRYCHANGED")); + } +} + +// TODO +CursorShape Spot::getCursor (const int objectID) +{ + return CSOpenHand; +} + +bool Spot::mouseOver (const int modifierKey) +{ + EditDataProvider* editProvider = getEditProvider(); + + if (editProvider && editProvider->object != lastObject) { + if (lastObject > -1) { + if (EditSubscriber::mouseOverGeometry.at (lastObject) == &targetMODisc) { + getVisibleGeometryFromMO (lastObject)->state = Geometry::ACTIVE; + } else { + getVisibleGeometryFromMO (lastObject)->state = Geometry::NORMAL; + } + + sourceIcon.state = Geometry::ACTIVE; + } + + if (editProvider->object > -1) { + getVisibleGeometryFromMO (editProvider->object)->state = Geometry::PRELIGHT; + + if (editProvider->object >= STATIC_MO_OBJ_NBR) { + // a Spot is being edited + int oldActiveSpot = activeSpot; + activeSpot = editProvider->object - STATIC_MO_OBJ_NBR; + + if (activeSpot != oldActiveSpot) { + if (oldActiveSpot > -1) { + EditSubscriber::visibleGeometry.at (oldActiveSpot)->state = Geometry::NORMAL; + EditSubscriber::mouseOverGeometry.at (oldActiveSpot + STATIC_MO_OBJ_NBR)->state = Geometry::NORMAL; + } + + EditSubscriber::visibleGeometry.at (activeSpot)->state = Geometry::PRELIGHT; + EditSubscriber::mouseOverGeometry.at (activeSpot + STATIC_MO_OBJ_NBR)->state = Geometry::PRELIGHT; + //printf("ActiveSpot = %d (was %d before)\n", activeSpot, oldActiveSpot); + } + } + } + + lastObject = editProvider->object; + + if (lastObject > -1 && EditSubscriber::mouseOverGeometry.at (lastObject) == getActiveSpotIcon()) { + lastObject = 0; // targetMODisc + } + + updateGeometry(); + return true; + } + + return false; +} + +// Create a new Target and Source point or start the drag of a Target point under the cursor +bool Spot::button1Pressed (const int modifierKey) +{ + EditDataProvider* editProvider = getEditProvider(); + + if (editProvider) { + if (lastObject == -1 && (modifierKey & GDK_CONTROL_MASK)) { + addNewEntry(); + EditSubscriber::action = ES_ACTION_DRAGGING; + return true; + } else if (lastObject > -1) { + getVisibleGeometryFromMO (lastObject)->state = Geometry::DRAGGED; + EditSubscriber::action = ES_ACTION_DRAGGING; + return true; + } + } + + return false; +} + +// End the drag of a Target point +bool Spot::button1Released() +{ + Geometry *loGeom = getVisibleGeometryFromMO (lastObject); + + if (!loGeom) { + EditSubscriber::action = ES_ACTION_NONE; + return false; + } + + loGeom->state = Geometry::PRELIGHT; + EditSubscriber::action = ES_ACTION_NONE; + updateGeometry(); + return true; +} + +// Delete a point +bool Spot::button2Pressed (const int modifierKey) +{ + EditDataProvider* editProvider = getEditProvider(); + + if (!editProvider || lastObject == -1 || activeSpot==-1) { + return false; + } + + if (!(modifierKey & (GDK_SHIFT_MASK|GDK_SHIFT_MASK))) { + EditSubscriber::action = ES_ACTION_PICKING; + } + + return false; +} + +// Create a new Target and Source point or start the drag of a Target point under the cursor +bool Spot::button3Pressed (const int modifierKey) +{ + EditDataProvider* editProvider = getEditProvider(); + + if (!editProvider || lastObject == -1 || activeSpot==-1) { + return false; + } + + if ((modifierKey & GDK_CONTROL_MASK) && (EditSubscriber::mouseOverGeometry.at (lastObject) == &targetMODisc || lastObject >= STATIC_MO_OBJ_NBR)) { + lastObject = 1; // sourceMODisc + sourceIcon.state = Geometry::DRAGGED; + EditSubscriber::action = ES_ACTION_DRAGGING; + return true; + } else if (!(modifierKey & (GDK_SHIFT_MASK|GDK_SHIFT_MASK))) { + EditSubscriber::action = ES_ACTION_PICKING; + } + + return false; +} + +bool Spot::button3Released() +{ + Geometry *loGeom = getVisibleGeometryFromMO (lastObject); + + if (!loGeom) { + EditSubscriber::action = ES_ACTION_NONE; + return false; + } + + lastObject = -1; + sourceIcon.state = Geometry::ACTIVE; + updateGeometry(); + EditSubscriber::action = ES_ACTION_NONE; + return true; + + return false; +} + +bool Spot::drag1 (const int modifierKey) +{ + EditDataProvider *editProvider = getEditProvider(); + int imW, imH; + editProvider->getImageSize (imW, imH); + bool modified = false; + + //printf("Drag1 / LastObject=%d\n", lastObject); + + Geometry *loGeom = EditSubscriber::mouseOverGeometry.at (lastObject); + + if (loGeom == &sourceMODisc) { + //printf("sourceMODisc / deltaPrevImage = %d / %d\n", editProvider->deltaPrevImage.x, editProvider->deltaPrevImage.y); + rtengine::Coord currPos = spots.at (activeSpot).sourcePos; + spots.at (activeSpot).sourcePos += editProvider->deltaPrevImage; + spots.at (activeSpot).sourcePos.clip (imW, imH); + + if (spots.at (activeSpot).sourcePos != currPos) { + modified = true; + } + + EditSubscriber::mouseOverGeometry.at (activeSpot + STATIC_MO_OBJ_NBR)->state = Geometry::DRAGGED; + } else if (loGeom == &targetMODisc || lastObject >= STATIC_MO_OBJ_NBR) { + //printf("targetMODisc / deltaPrevImage = %d / %d\n", editProvider->deltaPrevImage.x, editProvider->deltaPrevImage.y); + rtengine::Coord currPos = spots.at (activeSpot).targetPos; + spots.at (activeSpot).targetPos += editProvider->deltaPrevImage; + spots.at (activeSpot).targetPos.clip (imW, imH); + + if (spots.at (activeSpot).targetPos != currPos) { + modified = true; + } + } else if (loGeom == &sourceCircle) { + //printf("sourceCircle / deltaPrevImage = %d / %d\n", editProvider->deltaImage.x, editProvider->deltaImage.y); + int lastRadius = spots.at (activeSpot).radius; + rtengine::Coord currPos = editProvider->posImage + editProvider->deltaImage; + rtengine::PolarCoord currPolar = currPos - spots.at (activeSpot).sourcePos; + spots.at (activeSpot).radius = LIM (int (currPolar.radius), SpotParams::minRadius, SpotParams::maxRadius); + + if (spots.at (activeSpot).radius != lastRadius) { + modified = true; + } + } else if (loGeom == &targetCircle) { + //printf("targetCircle / deltaPrevImage = %d / %d\n", editProvider->deltaImage.x, editProvider->deltaImage.y); + int lastRadius = spots.at (activeSpot).radius; + rtengine::Coord currPos = editProvider->posImage + editProvider->deltaImage; + rtengine::PolarCoord currPolar = currPos - spots.at (activeSpot).targetPos; + spots.at (activeSpot).radius = LIM (int (currPolar.radius), SpotParams::minRadius, SpotParams::maxRadius); + + if (spots.at (activeSpot).radius != lastRadius) { + modified = true; + } + } else if (loGeom == &sourceFeatherCircle) { + //printf("sourceFeatherCircle / deltaPrevImage = %d / %d\n", editProvider->deltaImage.x, editProvider->deltaImage.y); + float currFeather = spots.at (activeSpot).feather; + rtengine::Coord currPos = editProvider->posImage + editProvider->deltaImage; + rtengine::PolarCoord currPolar = currPos -spots.at (activeSpot).sourcePos; + spots.at (activeSpot).feather = LIM01 ((currPolar.radius - double (spots.at (activeSpot).radius)) / double (spots.at (activeSpot).radius)); + + if (spots.at (activeSpot).feather != currFeather) { + modified = true; + } + } else if (loGeom == &targetFeatherCircle) { + //printf("targetFeatherCircle / deltaPrevImage = %d / %d\n", editProvider->deltaImage.x, editProvider->deltaImage.y); + float currFeather = spots.at (activeSpot).feather; + rtengine::Coord currPos = editProvider->posImage + editProvider->deltaImage; + rtengine::PolarCoord currPolar = currPos - spots.at (activeSpot).targetPos; + spots.at (activeSpot).feather = LIM01 ((currPolar.radius - double (spots.at (activeSpot).radius)) / double (spots.at (activeSpot).radius)); + + if (spots.at (activeSpot).feather != currFeather) { + modified = true; + } + } + + if (listener && modified) { + updateGeometry(); + listener->panelChanged (EvSpotEntry, M ("TP_SPOT_ENTRYCHANGED")); + } + + return modified; +} + +bool Spot::drag3 (const int modifierKey) +{ + EditDataProvider *editProvider = getEditProvider(); + int imW, imH; + editProvider->getImageSize (imW, imH); + bool modified = false; + + Geometry *loGeom = EditSubscriber::mouseOverGeometry.at (lastObject); + + if (loGeom == &sourceMODisc) { + rtengine::Coord currPos = spots.at (activeSpot).sourcePos; + spots.at (activeSpot).sourcePos += editProvider->deltaPrevImage; + spots.at (activeSpot).sourcePos.clip (imW, imH); + + if (spots.at (activeSpot).sourcePos != currPos) { + modified = true; + } + } + + if (listener) { + updateGeometry(); + listener->panelChanged (EvSpotEntry, M ("TP_SPOT_ENTRYCHANGED")); + } + + return modified; +} + +bool Spot::pick2(const bool picked) +{ + return pick3(picked); +} + +bool Spot::pick3 (const bool picked) +{ + EditDataProvider* editProvider = getEditProvider(); + + if (!picked) { + if (editProvider->object != lastObject) { + return false; + } + } + + // Object is picked, we delete it + deleteSelectedEntry(); + EditSubscriber::action = ES_ACTION_NONE; + updateGeometry(); + return true; +} + + +void Spot::switchOffEditMode () +{ + if (edit->get_active()) { + // switching off the toggle button + bool wasBlocked = editConn.block (true); + edit->set_active (false); + + if (!wasBlocked) { + editConn.block (false); + } + } + + EditSubscriber::switchOffEditMode(); // disconnect +} + diff --git a/rtgui/spot.h b/rtgui/spot.h new file mode 100644 index 000000000..27b4708bc --- /dev/null +++ b/rtgui/spot.h @@ -0,0 +1,101 @@ +/* + * This file is part of RawTherapee. + */ +#ifndef _SPOT_H_ +#define _SPOT_H_ + +#include +#include "toolpanel.h" +#include "edit.h" + +/** + * @brief Let the user create/edit/delete points for Spot Removal tool + * + * User Interface: + * + * For the rest of this documentation, T represent a "target" point (where the image is edited) and + * S represent the "source" location (where the edition takes its source data). + * + * When the edit button is active, all T points are shown by a small "dot". When the user + * move the cursor over one of them, a circle is displayed to show the radius of the brush, as well + * as a second circle representing the source data (S point). The user can then use the left mouse button + * over the icon to drag the T point. The left mouse button can be used over the S circle or the right + * mouse button can be used over the T point to move the S point. + * + * Using the left mouse button over the circle of the T point will let the user adjust its radius. + * + * Using the left mouse button over the feather circle will let the user adjust its radius by setting + * a coefficient (0.0 = same radius than the inner circle ; 1.0 = 2 times the inner radius). + * + * To create a new point, just move over a free area, and press the left mouse button while holding + * the CTRL key. This will create a new S and T pair of points. The CTRL key can be released, but keep + * the left mouse button pressed and move away to position the S point. + * + * To delete a point, move your mouse over any of its geometry press the middle or right mouse button + * (the point will be deleted on button release). + */ +class Spot : public ToolParamBlock, public FoldableToolPanel, public EditSubscriber +{ + +private: + int lastObject; // current object that is hovered + int activeSpot; // currently active spot, being edited + std::vector spots; // list of edited spots + OPIcon sourceIcon; // to show the source location + Circle sourceCircle; // to show and change the Source radius + Circle sourceMODisc; // to change the Source position + Circle targetCircle; // to show and change the Target radius + Circle targetMODisc; // to change the Target position + Circle sourceFeatherCircle; // to show the Feather radius at the Source position + Circle targetFeatherCircle; // to show the Feather radius at the Target position + Line link; // to show the link between the Source and Target position + + OPIcon *getActiveSpotIcon (); + void updateGeometry (); + void createGeometry (); + void addNewEntry (); + void deleteSelectedEntry (); + void resetPressed (); + +protected: + Gtk::HBox* labelBox; + Gtk::CheckButton* editedCheckBox; + Gtk::Label* countLabel; + Gtk::ToggleButton* edit; + Gtk::Button* reset; + sigc::connection editConn, editedConn; + + void editToggled (); + void editedToggled (); + Geometry* getVisibleGeometryFromMO (int MOID); + +public: + + Spot (); + ~Spot (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = NULL); + + void enabledChanged (); + + void setEditProvider (EditDataProvider* provider); + + void setBatchMode (bool batchMode); + + // EditSubscriber interface + CursorShape getCursor (const int objectID); + bool mouseOver (const int modifierKey); + bool button1Pressed (const int modifierKey); + bool button1Released (); + bool button2Pressed (const int modifierKey); + bool button3Pressed (const int modifierKey); + bool button3Released (); + bool drag1 (const int modifierKey); + bool drag3 (const int modifierKey); + bool pick2 (const bool picked); + bool pick3 (const bool picked); + void switchOffEditMode (); +}; + +#endif diff --git a/rtgui/thumbimageupdater.cc b/rtgui/thumbimageupdater.cc index 29160236e..5f78e817b 100644 --- a/rtgui/thumbimageupdater.cc +++ b/rtgui/thumbimageupdater.cc @@ -39,8 +39,8 @@ public: Job(ThumbBrowserEntryBase* tbe, bool* priority, bool upgrade, ThumbImageUpdateListener* listener): tbe_(tbe), - /*pparams_(pparams), - height_(height), */ + /*pparams_(pparams), + height_(height), */ priority_(priority), upgrade_(upgrade), listener_(listener) diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index a9f78273e..9349fc5f6 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -43,6 +43,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(nullptr), editDataProvider(n shadowshighlights = Gtk::manage (new ShadowsHighlights ()); impulsedenoise = Gtk::manage (new ImpulseDenoise ()); defringe = Gtk::manage (new Defringe ()); + spot = Gtk::manage (new Spot ()); dirpyrdenoise = Gtk::manage (new DirPyrDenoise ()); epd = Gtk::manage (new EdgePreservingDecompositionUI ()); sharpening = Gtk::manage (new Sharpening ()); @@ -110,6 +111,8 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(nullptr), editDataProvider(n toolPanels.push_back (blackwhite); addPanel (exposurePanel, shadowshighlights); toolPanels.push_back (shadowshighlights); + addPanel (detailsPanel, spot); + toolPanels.push_back (spot); addPanel (detailsPanel, sharpening); toolPanels.push_back (sharpening); addPanel (detailsPanel, sharpenEdge); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 46285ce3e..bdd8118c0 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -53,6 +53,7 @@ #include "vignetting.h" #include "retinex.h" #include "gradient.h" +#include "spot.h" #include "pcvignette.h" #include "toolbar.h" #include "lensgeom.h" @@ -118,6 +119,7 @@ protected: Crop* crop; ToneCurve* toneCurve; ShadowsHighlights* shadowshighlights; + Spot* spot; Defringe* defringe; ImpulseDenoise* impulsedenoise; DirPyrDenoise* dirpyrdenoise; diff --git a/tools/source_icons/scalable/spot-active.file b/tools/source_icons/scalable/spot-active.file new file mode 100644 index 000000000..9704c0e95 --- /dev/null +++ b/tools/source_icons/scalable/spot-active.file @@ -0,0 +1 @@ +spot-active.png,w12,actions diff --git a/tools/source_icons/scalable/spot-active.svg b/tools/source_icons/scalable/spot-active.svg new file mode 100644 index 000000000..bc36a7a19 --- /dev/null +++ b/tools/source_icons/scalable/spot-active.svg @@ -0,0 +1,81 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/tools/source_icons/scalable/spot-normal.file b/tools/source_icons/scalable/spot-normal.file new file mode 100644 index 000000000..b521a910d --- /dev/null +++ b/tools/source_icons/scalable/spot-normal.file @@ -0,0 +1 @@ +spot-normal.png,w16,actions diff --git a/tools/source_icons/scalable/spot-normal.svg b/tools/source_icons/scalable/spot-normal.svg new file mode 100644 index 000000000..ca9a933c2 --- /dev/null +++ b/tools/source_icons/scalable/spot-normal.svg @@ -0,0 +1,70 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/tools/source_icons/scalable/spot-prelight.file b/tools/source_icons/scalable/spot-prelight.file new file mode 100644 index 000000000..825705ece --- /dev/null +++ b/tools/source_icons/scalable/spot-prelight.file @@ -0,0 +1 @@ +spot-prelight.png,w12,actions diff --git a/tools/source_icons/scalable/spot-prelight.svg b/tools/source_icons/scalable/spot-prelight.svg new file mode 100644 index 000000000..9cfc1acfa --- /dev/null +++ b/tools/source_icons/scalable/spot-prelight.svg @@ -0,0 +1,74 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + From 81932ba2d63c73fe15e7c53c5feeb3784b2cf7c3 Mon Sep 17 00:00:00 2001 From: Hombre57 Date: Tue, 22 Aug 2017 00:15:56 +0200 Subject: [PATCH 002/135] Some files 'astylized' + slight cleanup --- rtengine/alpha.cc | 27 ++++++++++++++++++++++++--- rtengine/alpha.h | 25 +++---------------------- rtengine/spot.cc | 10 ++++++++++ rtgui/spot.cc | 29 ++++++++++++++++------------- 4 files changed, 53 insertions(+), 38 deletions(-) diff --git a/rtengine/alpha.cc b/rtengine/alpha.cc index e562350fc..8d1fd6b0e 100644 --- a/rtengine/alpha.cc +++ b/rtengine/alpha.cc @@ -27,7 +27,7 @@ Alpha::Alpha () {} Alpha::Alpha (int width, int height) { if (width > 0 && height > 0) { - surface = Cairo::ImageSurface::create(Cairo::FORMAT_A8, width, height); + surface = Cairo::ImageSurface::create (Cairo::FORMAT_A8, width, height); } } @@ -37,7 +37,7 @@ Alpha::~Alpha () { } */ -void Alpha::setSize(int width, int height) +void Alpha::setSize (int width, int height) { if (width > 0 && height > 0) { if (surface) { @@ -48,7 +48,7 @@ void Alpha::setSize(int width, int height) } } - surface = Cairo::ImageSurface::create(Cairo::FORMAT_A8, width, height); + surface = Cairo::ImageSurface::create (Cairo::FORMAT_A8, width, height); } else if (surface) { surface.clear(); } @@ -72,4 +72,25 @@ int Alpha::getHeight() return -1; } + +Cairo::RefPtr Alpha::getSurface () +{ + return surface; // to be used in bitmap edition +} + +unsigned char Alpha::operator () (unsigned row, unsigned col) const +{ + return * (surface->get_data () + row * surface->get_width () + col); +} + +unsigned char& Alpha::operator () (unsigned row, unsigned col) +{ + return * (surface->get_data () + row * surface->get_width () + col); +} + +unsigned char* Alpha::operator () (unsigned row) const +{ + return surface->get_data () + row * surface->get_width (); +} + } diff --git a/rtengine/alpha.h b/rtengine/alpha.h index 57a0af343..90f32265e 100644 --- a/rtengine/alpha.h +++ b/rtengine/alpha.h @@ -38,11 +38,11 @@ public: Alpha (int width, int height); //~Alpha (); - void setSize(int width, int height); + void setSize (int width, int height); int getWidth(); int getHeight(); - const Cairo::RefPtr getSurface (); + Cairo::RefPtr getSurface (); // TODO: to make the editing faster, we should add an iterator class @@ -50,28 +50,9 @@ public: unsigned char* operator () (unsigned row) const; // Will send back a value at a given row, col position unsigned char& operator () (unsigned row, unsigned col); - const unsigned char operator () (unsigned row, unsigned col) const; + unsigned char operator () (unsigned row, unsigned col) const; }; - - -inline const Cairo::RefPtr Alpha::getSurface () { - return surface; // to be used in bitmap edition -} - -inline const unsigned char Alpha::operator () (unsigned row, - unsigned col) const { - return *(surface->get_data () + row * surface->get_width () + col); -} - -inline unsigned char& Alpha::operator () (unsigned row, unsigned col) { - return *(surface->get_data () + row * surface->get_width () + col); -} - -inline unsigned char* Alpha::operator () (unsigned row) const { - return surface->get_data () + row * surface->get_width (); -} - } #endif diff --git a/rtengine/spot.cc b/rtengine/spot.cc index 87f174e72..858a1fd44 100644 --- a/rtengine/spot.cc +++ b/rtengine/spot.cc @@ -79,9 +79,11 @@ void ImProcFunctions::removeSpots (Imagefloat* img, const std::vector // scaled spot is too small, we do not preview it if (scaledFeatherRadius < 2 && pp.getSkip() != 1) { #ifndef NDEBUG + if (options.rtSettings.verbose) { printf ("Skipping spot located at %d x %d, too small for the preview zoom rate\n", entry.sourcePos.x, entry.sourcePos.y); } + #endif continue; } @@ -89,9 +91,11 @@ void ImProcFunctions::removeSpots (Imagefloat* img, const std::vector // skipping entries totally transparent if (entry.opacity == 0.) { #ifndef NDEBUG + if (options.rtSettings.verbose) { printf ("Skipping spot located at %d x %d: opacity=%.3f\n", entry.sourcePos.x, entry.sourcePos.y, entry.opacity); } + continue; #endif } @@ -99,11 +103,13 @@ void ImProcFunctions::removeSpots (Imagefloat* img, const std::vector // skipping entries where the source circle isn't completely inside the image bounds if (src_XMin < 0 || src_XMax >= img->getWidth() || src_YMin < 0 || src_YMax >= img->getHeight()) { #ifndef NDEBUG + if (options.rtSettings.verbose) { printf ("Skipping spot located at %d x %d, from the data at %d x %d, radius=%d, feather=%.3f, opacity=%.3f: source out of bounds\n", entry.sourcePos.x, entry.sourcePos.y, entry.targetPos.x, entry.targetPos.y, entry.radius, entry.feather, entry.opacity); printf ("%d < 0 || %d >= %d || %d < 0 || %d >= %d\n", src_XMin, src_XMax, img->getWidth(), src_YMin, src_YMax, img->getHeight()); } + #endif continue; } @@ -111,11 +117,13 @@ void ImProcFunctions::removeSpots (Imagefloat* img, const std::vector // skipping entries where the dest circle is completely outside the image bounds if (dst_XMin >= img->getWidth() || dst_XMax <= 0 || dst_YMin >= img->getHeight() || dst_YMax <= 0) { #ifndef NDEBUG + if (options.rtSettings.verbose) { printf ("Skipping spot located at %d x %d, from the data at %d x %d, radius=%d, feather=%.3f, opacity=%.3f: source out of bounds\n", entry.sourcePos.x, entry.sourcePos.y, entry.targetPos.x, entry.targetPos.y, entry.radius, entry.feather, entry.opacity); printf ("%d >= %d || %d <= 0 || %d >= %d || %d <= 0\n", dst_XMin, img->getWidth(), dst_XMax, dst_YMin, img->getHeight(), dst_YMax); } + #endif continue; } @@ -343,10 +351,12 @@ void ImProcFunctions::removeSpots (Imagefloat* img, const std::vector if (i2 < 0 || i2 >= img->getHeight()) { continue; } + for (int j = 0, j2 = dst_XMin; j2 < dst_XMax - 1; ++j, ++j2) { if (j2 < 0 || j2 >= img->getWidth()) { continue; } + //float c2 = float (mask (i, j)) / 255.f; //float c1 = 1.f - c2; //resultPR->r(i,j) = (unsigned char) CLAMP0255 ( ROUND( double(first->r(i,j)) + double(secondPR->r(i,j)) ) ); diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 949f592ee..55480ece5 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -14,7 +14,7 @@ using namespace rtengine::procparams; #define STATIC_MO_OBJ_NBR 6 Spot::Spot() : FoldableToolPanel (this, "spot", M ("TP_SPOT_LABEL"), true, true), EditSubscriber (ET_OBJECTS), lastObject (-1), activeSpot (-1), - sourceIcon ("spot-normal.png", "spot-active.png", "spot-active.png", "spot-prelight.png", "", Geometry::DP_CENTERCENTER), editedCheckBox(NULL) + sourceIcon ("spot-normal.png", "spot-active.png", "spot-active.png", "spot-prelight.png", "", Geometry::DP_CENTERCENTER), editedCheckBox (NULL) { countLabel = Gtk::manage (new Gtk::Label (Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), 0))); @@ -74,6 +74,7 @@ Spot::~Spot() delete EditSubscriber::visibleGeometry.at (i); } } + // We do not delete the mouseOverGeometry, because the referenced objects are either // shared with visibleGeometry or instantiated by the class's ctor } @@ -170,11 +171,11 @@ void Spot::enabledChanged () { if (listener) { if (get_inconsistent()) { - listener->panelChanged (EvSpotEnabled, M("GENERAL_UNCHANGED")); + listener->panelChanged (EvSpotEnabled, M ("GENERAL_UNCHANGED")); } else if (getEnabled()) { - listener->panelChanged (EvSpotEnabled, M("GENERAL_ENABLED")); + listener->panelChanged (EvSpotEnabled, M ("GENERAL_ENABLED")); } else { - listener->panelChanged (EvSpotEnabled, M("GENERAL_DISABLED")); + listener->panelChanged (EvSpotEnabled, M ("GENERAL_DISABLED")); } } } @@ -215,7 +216,7 @@ void Spot::createGeometry () int nbrEntry = spots.size(); if (!batchMode) { - countLabel->set_text(Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), nbrEntry)); + countLabel->set_text (Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), nbrEntry)); } //printf("CreateGeometry(%d)\n", nbrEntry); @@ -242,7 +243,7 @@ void Spot::createGeometry () Cairo::RefPtr activeImg = sourceIcon.getActiveImg(); for (; j < EditSubscriber::visibleGeometry.size() - STATIC_VISIBLE_OBJ_NBR; ++i, ++j) { - EditSubscriber::mouseOverGeometry.at (i) = EditSubscriber::visibleGeometry.at (j) = new OPIcon (normalImg, activeImg, prelightImg, Cairo::RefPtr(NULL), Cairo::RefPtr(NULL), Geometry::DP_CENTERCENTER); + EditSubscriber::mouseOverGeometry.at (i) = EditSubscriber::visibleGeometry.at (j) = new OPIcon (normalImg, activeImg, prelightImg, Cairo::RefPtr (NULL), Cairo::RefPtr (NULL), Geometry::DP_CENTERCENTER); EditSubscriber::visibleGeometry.at (j)->setActive (true); EditSubscriber::visibleGeometry.at (j)->datum = Geometry::IMAGE; EditSubscriber::visibleGeometry.at (j)->state = Geometry::NORMAL; @@ -379,9 +380,11 @@ void Spot::deleteSelectedEntry() // delete the activeSpot if (activeSpot > -1) { std::vector::iterator i = spots.begin(); + for (int j = 0; j < activeSpot; ++j) { ++i; } + spots.erase (i); } @@ -492,11 +495,11 @@ bool Spot::button2Pressed (const int modifierKey) { EditDataProvider* editProvider = getEditProvider(); - if (!editProvider || lastObject == -1 || activeSpot==-1) { + if (!editProvider || lastObject == -1 || activeSpot == -1) { return false; } - if (!(modifierKey & (GDK_SHIFT_MASK|GDK_SHIFT_MASK))) { + if (! (modifierKey & (GDK_SHIFT_MASK | GDK_SHIFT_MASK))) { EditSubscriber::action = ES_ACTION_PICKING; } @@ -508,7 +511,7 @@ bool Spot::button3Pressed (const int modifierKey) { EditDataProvider* editProvider = getEditProvider(); - if (!editProvider || lastObject == -1 || activeSpot==-1) { + if (!editProvider || lastObject == -1 || activeSpot == -1) { return false; } @@ -517,7 +520,7 @@ bool Spot::button3Pressed (const int modifierKey) sourceIcon.state = Geometry::DRAGGED; EditSubscriber::action = ES_ACTION_DRAGGING; return true; - } else if (!(modifierKey & (GDK_SHIFT_MASK|GDK_SHIFT_MASK))) { + } else if (! (modifierKey & (GDK_SHIFT_MASK | GDK_SHIFT_MASK))) { EditSubscriber::action = ES_ACTION_PICKING; } @@ -597,7 +600,7 @@ bool Spot::drag1 (const int modifierKey) //printf("sourceFeatherCircle / deltaPrevImage = %d / %d\n", editProvider->deltaImage.x, editProvider->deltaImage.y); float currFeather = spots.at (activeSpot).feather; rtengine::Coord currPos = editProvider->posImage + editProvider->deltaImage; - rtengine::PolarCoord currPolar (currPos -spots.at (activeSpot).sourcePos); + rtengine::PolarCoord currPolar (currPos - spots.at (activeSpot).sourcePos); spots.at (activeSpot).feather = LIM01 ((currPolar.radius - double (spots.at (activeSpot).radius)) / double (spots.at (activeSpot).radius)); if (spots.at (activeSpot).feather != currFeather) { @@ -650,9 +653,9 @@ bool Spot::drag3 (const int modifierKey) return modified; } -bool Spot::pick2(const bool picked) +bool Spot::pick2 (const bool picked) { - return pick3(picked); + return pick3 (picked); } bool Spot::pick3 (const bool picked) From e0c04955e3cc20202514c284c368b78cf0a7437c Mon Sep 17 00:00:00 2001 From: Hombre Date: Tue, 19 Mar 2019 22:29:10 +0100 Subject: [PATCH 003/135] Fix build crash (see #5232), but this branch is still not usable --- rtengine/dcrop.cc | 45 +++++++++++++++++++------------------- rtgui/bayerpreprocess.cc | 1 + rtgui/bayerrawexposure.cc | 1 + rtgui/crophandler.h | 3 ++- rtgui/edit.cc | 44 ++++++++++++++++++------------------- rtgui/edit.h | 34 ++++++++++++++-------------- rtgui/exifpanel.cc | 1 + rtgui/labgrid.cc | 1 + rtgui/lensprofile.cc | 1 + rtgui/preprocess.cc | 1 + rtgui/rawcacorrection.cc | 1 + rtgui/rawexposure.cc | 3 +-- rtgui/sharpenedge.cc | 2 +- rtgui/spot.cc | 14 ++++++------ rtgui/spot.h | 4 ++-- rtgui/toolpanel.h | 2 +- rtgui/xtransrawexposure.cc | 2 +- 17 files changed, 84 insertions(+), 76 deletions(-) diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 0445e64a6..fd86b4e5b 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -746,6 +746,29 @@ void Crop::update(int todo) parent->ipf.ToneMapFattal02(f); } + // Apply Spot removal + if (params.spot.enabled) { + if (todo & M_SPOT) { + if(!spotCrop) { + spotCrop = new Imagefloat (cropw, croph); + } + baseCrop->copyData (spotCrop); + + PreviewProps pp (cropx, cropy, cropw, croph, skip); + parent->ipf.removeSpots (spotCrop, params.spot.entries, pp); + } + } else { + if (spotCrop) { + delete spotCrop; + } + + spotCrop = NULL; + } + + if (spotCrop) { + baseCrop = spotCrop; + } + // crop back to the size expected by the rest of the pipeline if (need_cropping) { Imagefloat *c = origCrop; @@ -798,28 +821,6 @@ void Crop::update(int todo) transCrop = nullptr; } - if (params.spot.enabled) { - if (todo & M_SPOT) { - if(!spotCrop) { - spotCrop = new Imagefloat (cropw, croph); - } - baseCrop->copyData (spotCrop); - - PreviewProps pp (cropx, cropy, cropw, croph, skip); - parent->ipf.removeSpots (spotCrop, params.spot.entries, pp); - } - } else { - if (spotCrop) { - delete spotCrop; - } - - spotCrop = NULL; - } - - if (spotCrop) { - baseCrop = spotCrop; - } - if ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled) { const int W = baseCrop->getWidth(); diff --git a/rtgui/bayerpreprocess.cc b/rtgui/bayerpreprocess.cc index 89fd6fcb6..4910b2798 100644 --- a/rtgui/bayerpreprocess.cc +++ b/rtgui/bayerpreprocess.cc @@ -21,6 +21,7 @@ #include "bayerpreprocess.h" #include "eventmapper.h" #include "guiutils.h" +#include "options.h" #include "../rtengine/procparams.h" diff --git a/rtgui/bayerrawexposure.cc b/rtgui/bayerrawexposure.cc index d49486511..86cd9794b 100644 --- a/rtgui/bayerrawexposure.cc +++ b/rtgui/bayerrawexposure.cc @@ -19,6 +19,7 @@ #include "bayerrawexposure.h" #include "guiutils.h" +#include "options.h" #include "../rtengine/procparams.h" diff --git a/rtgui/crophandler.h b/rtgui/crophandler.h index e0b48d348..3be052a52 100644 --- a/rtgui/crophandler.h +++ b/rtgui/crophandler.h @@ -27,10 +27,11 @@ #include "../rtengine/rtengine.h" -#include "edit.h" #include "lockablecolorpicker.h" #include "threadutils.h" +class EditSubscriber; + class CropDisplayHandler { diff --git a/rtgui/edit.cc b/rtgui/edit.cc index c59c2dc04..896e61b68 100644 --- a/rtgui/edit.cc +++ b/rtgui/edit.cc @@ -802,11 +802,11 @@ void OPIcon::drivenPointToRectangle(const rtengine::Coord &pos, bottomRight.y = topLeft.y + H - 1; } -OPIcon::OPIcon(const Cairo::RefPtr &normal, - const Cairo::RefPtr &active, - const Cairo::RefPtr &prelight, - const Cairo::RefPtr &dragged, - const Cairo::RefPtr &insensitive, +OPIcon::OPIcon(const Cairo::RefPtr &normal, + const Cairo::RefPtr &active, + const Cairo::RefPtr &prelight, + const Cairo::RefPtr &dragged, + const Cairo::RefPtr &insensitive, DrivenPoint drivenPoint) : drivenPoint(drivenPoint) { @@ -835,53 +835,53 @@ OPIcon::OPIcon(Glib::ustring normalImage, Glib::ustring activeImage, Glib::ustri Glib::ustring draggedImage, Glib::ustring insensitiveImage, DrivenPoint drivenPoint) : drivenPoint(drivenPoint) { if (!normalImage.empty()) { - normalImg->setImage(normalImage); + normalImg = RTImage::createImgSurfFromFile(normalImage); } if (!prelightImage.empty()) { - prelightImg->setImage(prelightImage); + prelightImg = RTImage::createImgSurfFromFile(prelightImage); } if (!activeImage.empty()) { - activeImg->setImage(activeImage); + activeImg = RTImage::createImgSurfFromFile(activeImage); } if (!draggedImage.empty()) { - draggedImg->setImage(draggedImage); + draggedImg = RTImage::createImgSurfFromFile(draggedImage); } if (!insensitiveImage.empty()) { - insensitiveImg->setImage(insensitiveImage); + insensitiveImg = RTImage::createImgSurfFromFile(insensitiveImage); } } -const Cairo::RefPtr OPIcon::getNormalImg() +const Cairo::RefPtr OPIcon::getNormalImg() { return normalImg; } -const Cairo::RefPtr OPIcon::getPrelightImg() +const Cairo::RefPtr OPIcon::getPrelightImg() { return prelightImg; } -const Cairo::RefPtr OPIcon::getActiveImg() +const Cairo::RefPtr OPIcon::getActiveImg() { return activeImg; } -const Cairo::RefPtr OPIcon::getDraggedImg() +const Cairo::RefPtr OPIcon::getDraggedImg() { return draggedImg; } -const Cairo::RefPtr OPIcon::getInsensitiveImg() +const Cairo::RefPtr OPIcon::getInsensitiveImg() { return insensitiveImg; } -void OPIcon::drawImage(Cairo::RefPtr &img, +void OPIcon::drawImage(Cairo::RefPtr &img, Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { - int imgW = img->getWidth(); - int imgH = img->getHeight(); + int imgW = img->get_width(); + int imgH = img->get_height(); rtengine::Coord pos; @@ -896,19 +896,19 @@ void OPIcon::drawImage(Cairo::RefPtr &img, rtengine::Coord tl, br; // Coordinate of the rectangle in the CropBuffer coordinate system drivenPointToRectangle(pos, tl, br, imgW, imgH); - cr->set_source(img->get(), tl.x, tl.y); + cr->set_source(img, tl.x, tl.y); cr->set_line_width(0.); cr->rectangle(tl.x, tl.y, imgW, imgH); cr->fill(); } -void OPIcon::drawMOImage(Cairo::RefPtr &img, Cairo::RefPtr &cr, +void OPIcon::drawMOImage(Cairo::RefPtr &img, Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { // test of F_HOVERABLE has already been done - int imgW = img->getWidth(); - int imgH = img->getHeight(); + int imgW = img->get_width(); + int imgH = img->get_height(); rtengine::Coord pos; diff --git a/rtgui/edit.h b/rtgui/edit.h index 786339745..f690cf80b 100644 --- a/rtgui/edit.h +++ b/rtgui/edit.h @@ -407,34 +407,34 @@ class OPIcon : public Geometry // OP stands for "On Preview" { private: - Cairo::RefPtr normalImg; - Cairo::RefPtr prelightImg; - Cairo::RefPtr activeImg; - Cairo::RefPtr draggedImg; - Cairo::RefPtr insensitiveImg; + Cairo::RefPtr normalImg; + Cairo::RefPtr prelightImg; + Cairo::RefPtr activeImg; + Cairo::RefPtr draggedImg; + Cairo::RefPtr insensitiveImg; static void updateImages(); void changeImage(Glib::ustring &newImage); - void drawImage (Cairo::RefPtr &img, Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); - void drawMOImage (Cairo::RefPtr &img, Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawImage (Cairo::RefPtr &img, Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawMOImage (Cairo::RefPtr &img, Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); void drivenPointToRectangle(const rtengine::Coord &pos, rtengine::Coord &topLeft, rtengine::Coord &bottomRight, int W, int H); public: DrivenPoint drivenPoint; rtengine::Coord position; - OPIcon (const Cairo::RefPtr &normal, - const Cairo::RefPtr &active, - const Cairo::RefPtr &prelight = {}, - const Cairo::RefPtr &dragged = {}, - const Cairo::RefPtr &insensitive = {}, + OPIcon (const Cairo::RefPtr &normal, + const Cairo::RefPtr &active, + const Cairo::RefPtr &prelight = {}, + const Cairo::RefPtr &dragged = {}, + const Cairo::RefPtr &insensitive = {}, DrivenPoint drivenPoint = DP_CENTERCENTER); OPIcon (Glib::ustring normalImage, Glib::ustring activeImage, Glib::ustring prelightImage = "", Glib::ustring draggedImage = "", Glib::ustring insensitiveImage = "", DrivenPoint drivenPoint = DP_CENTERCENTER); - const Cairo::RefPtr getNormalImg(); - const Cairo::RefPtr getPrelightImg(); - const Cairo::RefPtr getActiveImg(); - const Cairo::RefPtr getDraggedImg(); - const Cairo::RefPtr getInsensitiveImg(); + const Cairo::RefPtr getNormalImg(); + const Cairo::RefPtr getPrelightImg(); + const Cairo::RefPtr getActiveImg(); + const Cairo::RefPtr getDraggedImg(); + const Cairo::RefPtr getInsensitiveImg(); void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 4ba3f6c44..c5036798e 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -20,6 +20,7 @@ #include "guiutils.h" #include "rtimage.h" +#include "options.h" #include "../rtengine/procparams.h" diff --git a/rtgui/labgrid.cc b/rtgui/labgrid.cc index 81d4ee170..bc99f8ca6 100644 --- a/rtgui/labgrid.cc +++ b/rtgui/labgrid.cc @@ -37,6 +37,7 @@ */ #include "labgrid.h" +#include "options.h" using rtengine::Color; diff --git a/rtgui/lensprofile.cc b/rtgui/lensprofile.cc index 85dcb992a..0dd3cb1b7 100644 --- a/rtgui/lensprofile.cc +++ b/rtgui/lensprofile.cc @@ -26,6 +26,7 @@ #include "guiutils.h" #include "rtimage.h" +#include "options.h" #include "../rtengine/lcp.h" #include "../rtengine/procparams.h" diff --git a/rtgui/preprocess.cc b/rtgui/preprocess.cc index 0d8933a98..65646dea3 100644 --- a/rtgui/preprocess.cc +++ b/rtgui/preprocess.cc @@ -21,6 +21,7 @@ #include "preprocess.h" #include "guiutils.h" +#include "options.h" #include "../rtengine/procparams.h" diff --git a/rtgui/rawcacorrection.cc b/rtgui/rawcacorrection.cc index 57b8ff4ac..06780559d 100644 --- a/rtgui/rawcacorrection.cc +++ b/rtgui/rawcacorrection.cc @@ -21,6 +21,7 @@ #include "eventmapper.h" #include "guiutils.h" #include "rtimage.h" +#include "options.h" #include "../rtengine/procparams.h" diff --git a/rtgui/rawexposure.cc b/rtgui/rawexposure.cc index 6f08e64c7..2129c9616 100644 --- a/rtgui/rawexposure.cc +++ b/rtgui/rawexposure.cc @@ -19,9 +19,8 @@ #include #include "rawexposure.h" - #include "guiutils.h" - +#include "options.h" #include "../rtengine/procparams.h" using namespace rtengine; diff --git a/rtgui/sharpenedge.cc b/rtgui/sharpenedge.cc index b6528e4c9..679b898a6 100644 --- a/rtgui/sharpenedge.cc +++ b/rtgui/sharpenedge.cc @@ -22,7 +22,7 @@ #include "sharpenedge.h" #include "guiutils.h" - +#include "options.h" #include "../rtengine/procparams.h" using namespace rtengine; diff --git a/rtgui/spot.cc b/rtgui/spot.cc index bc3c8709f..1c9199c99 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -15,16 +15,16 @@ using namespace rtengine::procparams; #define STATIC_MO_OBJ_NBR 6 Spot::Spot() : FoldableToolPanel (this, "spot", M ("TP_SPOT_LABEL"), true, true), EditSubscriber (ET_OBJECTS), lastObject (-1), activeSpot (-1), - sourceIcon ("spot-normal.png", "spot-active.png", "spot-active.png", "spot-prelight.png", "", Geometry::DP_CENTERCENTER), editedCheckBox (NULL) + sourceIcon ("spot-normal.png", "spot-active.png", "spot-active.png", "spot-prelight.png", "", Geometry::DP_CENTERCENTER), editedCheckBox (nullptr) { countLabel = Gtk::manage (new Gtk::Label (Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), 0))); edit = Gtk::manage (new Gtk::ToggleButton()); - edit->add (*Gtk::manage (new RTImage ("editmodehand.png"))); + edit->add (*Gtk::manage (new RTImage ("edit-point.png"))); editConn = edit->signal_toggled().connect ( sigc::mem_fun (*this, &Spot::editToggled) ); reset = Gtk::manage (new Gtk::Button ()); - reset->add (*Gtk::manage (new RTImage ("gtk-undo-ltr-small.png", "gtk-undo-rtl-small.png"))); + reset->add (*Gtk::manage (new RTImage ("undo-small.png"))); reset->set_relief (Gtk::RELIEF_NONE); reset->set_border_width (0); reset->signal_clicked().connect ( sigc::mem_fun (*this, &Spot::resetPressed) ); @@ -150,7 +150,7 @@ void Spot::setBatchMode (bool batchMode) if (!editedCheckBox) { removeIfThere (labelBox, countLabel, false); - countLabel = NULL; + countLabel = nullptr; editedCheckBox = Gtk::manage (new Gtk::CheckButton (Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), 0))); labelBox->pack_start (*editedCheckBox, Gtk::PACK_SHRINK, 2); labelBox->reorder_child (*editedCheckBox, 0); @@ -198,7 +198,7 @@ void Spot::editToggled () Geometry* Spot::getVisibleGeometryFromMO (int MOID) { if (MOID == -1) { - return NULL; + return nullptr; } if (MOID == 0) { @@ -244,7 +244,7 @@ void Spot::createGeometry () Cairo::RefPtr activeImg = sourceIcon.getActiveImg(); for (; j < EditSubscriber::visibleGeometry.size() - STATIC_VISIBLE_OBJ_NBR; ++i, ++j) { - EditSubscriber::mouseOverGeometry.at (i) = EditSubscriber::visibleGeometry.at (j) = new OPIcon (normalImg, activeImg, prelightImg, Cairo::RefPtr (NULL), Cairo::RefPtr (NULL), Geometry::DP_CENTERCENTER); + EditSubscriber::mouseOverGeometry.at (i) = EditSubscriber::visibleGeometry.at (j) = new OPIcon (normalImg, activeImg, prelightImg, Cairo::RefPtr (nullptr), Cairo::RefPtr (nullptr), Geometry::DP_CENTERCENTER); EditSubscriber::visibleGeometry.at (j)->setActive (true); EditSubscriber::visibleGeometry.at (j)->datum = Geometry::IMAGE; EditSubscriber::visibleGeometry.at (j)->state = Geometry::NORMAL; @@ -349,7 +349,7 @@ OPIcon *Spot::getActiveSpotIcon() return static_cast (EditSubscriber::visibleGeometry.at (activeSpot)); } - return NULL; + return nullptr; } void Spot::addNewEntry() diff --git a/rtgui/spot.h b/rtgui/spot.h index d62ab7b2f..acce47bec 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -81,8 +81,8 @@ public: Spot (); ~Spot (); - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = NULL); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = NULL); + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); void enabledChanged (); diff --git a/rtgui/toolpanel.h b/rtgui/toolpanel.h index 521d52949..f48e3d0d4 100644 --- a/rtgui/toolpanel.h +++ b/rtgui/toolpanel.h @@ -25,10 +25,10 @@ #include "guiutils.h" #include "multilangmgr.h" #include "paramsedited.h" -#include "edit.h" class ToolPanel; class FoldableToolPanel; +class EditDataProvider; class ToolPanelListener { diff --git a/rtgui/xtransrawexposure.cc b/rtgui/xtransrawexposure.cc index b58a6e72a..a01e8e20a 100644 --- a/rtgui/xtransrawexposure.cc +++ b/rtgui/xtransrawexposure.cc @@ -21,7 +21,7 @@ #include "xtransrawexposure.h" #include "guiutils.h" - +#include "options.h" #include "../rtengine/procparams.h" using namespace rtengine; From 5b0cea2be3580858904c8ed2112b30efa357560e Mon Sep 17 00:00:00 2001 From: Hombre Date: Tue, 26 Mar 2019 22:07:23 +0100 Subject: [PATCH 004/135] Fix crash when starting RT (see #5230) --- rtgui/editwidgets.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rtgui/editwidgets.cc b/rtgui/editwidgets.cc index 667b8cb37..129d81bc7 100644 --- a/rtgui/editwidgets.cc +++ b/rtgui/editwidgets.cc @@ -731,23 +731,23 @@ OPIcon::OPIcon(Glib::ustring normalImage, Glib::ustring activeImage, Glib::ustri Glib::ustring draggedImage, Glib::ustring insensitiveImage, DrivenPoint drivenPoint) : drivenPoint(drivenPoint) { if (!normalImage.empty()) { - normalImg->setImage(normalImage); + normalImg = Cairo::RefPtr(new RTSurface(normalImage)); } if (!prelightImage.empty()) { - prelightImg->setImage(prelightImage); + prelightImg = Cairo::RefPtr(new RTSurface(prelightImage)); } if (!activeImage.empty()) { - activeImg->setImage(activeImage); + activeImg = Cairo::RefPtr(new RTSurface(activeImage)); } if (!draggedImage.empty()) { - draggedImg->setImage(draggedImage); + draggedImg = Cairo::RefPtr(new RTSurface(draggedImage)); } if (!insensitiveImage.empty()) { - insensitiveImg->setImage(insensitiveImage); + insensitiveImg = Cairo::RefPtr(new RTSurface(insensitiveImage)); } } From 765c20d64a2f8ea90de75b81ffeee81c72bdc664 Mon Sep 17 00:00:00 2001 From: Hombre Date: Tue, 26 Mar 2019 22:11:49 +0100 Subject: [PATCH 005/135] Line endings of new `edit` files converted to Unix (see #5230) --- rtgui/editcallbacks.cc | 554 ++++++------ rtgui/editcallbacks.h | 390 ++++----- rtgui/editcoordsys.h | 122 +-- rtgui/editwidgets.cc | 1870 ++++++++++++++++++++-------------------- rtgui/editwidgets.h | 1084 +++++++++++------------ 5 files changed, 2010 insertions(+), 2010 deletions(-) diff --git a/rtgui/editcallbacks.cc b/rtgui/editcallbacks.cc index 02eb02a5b..d51d672a5 100644 --- a/rtgui/editcallbacks.cc +++ b/rtgui/editcallbacks.cc @@ -1,277 +1,277 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2019 Jean-Christophe FRISCH - * - * 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 "editcallbacks.h" - -EditSubscriber::EditSubscriber (EditType editType) : - ID(EUID_None), - editingType(editType), - bufferType(BT_SINGLEPLANE_FLOAT), - provider(nullptr), - action(EditSubscriber::Action::NONE) -{} - -void EditSubscriber::setEditProvider(EditDataProvider *provider) -{ - this->provider = provider; -} - -void EditSubscriber::setEditID(EditUniqueID ID, BufferType buffType) -{ - this->ID = ID; - bufferType = buffType; -} - -bool EditSubscriber::isCurrentSubscriber() const -{ - //if (provider && provider->getCurrSubscriber()) - // return provider->getCurrSubscriber()->getEditID() == ID; - - if (provider) { - return provider->getCurrSubscriber() == this; - } - - return false; -} - -void EditSubscriber::subscribe() -{ - if (provider) { - provider->subscribe(this); - } -} - -void EditSubscriber::unsubscribe() -{ - if (provider) { - provider->unsubscribe(); - } -} - -void EditSubscriber::switchOffEditMode() -{ - unsubscribe(); -} - -EditUniqueID EditSubscriber::getEditID() const -{ - return ID; -} - -EditType EditSubscriber::getEditingType() const -{ - return editingType; -} - -BufferType EditSubscriber::getPipetteBufferType() const -{ - return bufferType; -} - -bool EditSubscriber::isDragging() const -{ - return action == EditSubscriber::Action::DRAGGING; -} - -bool EditSubscriber::isPicking() const -{ - return action == EditSubscriber::Action::PICKING; -} - -//-------------------------------------------------------------------------------------------------- - - -EditDataProvider::EditDataProvider() : - currSubscriber(nullptr), - object(0), - pipetteVal1(0.f), - pipetteVal2(0.f), - pipetteVal3(0.f), - posScreen(-1, -1), - posImage(-1, -1), - deltaScreen(0, 0), - deltaImage(0, 0), - deltaPrevScreen(0, 0), - deltaPrevImage(0, 0) -{} - -void EditDataProvider::subscribe(EditSubscriber *subscriber) -{ - if (currSubscriber) { - currSubscriber->switchOffEditMode(); - } - - currSubscriber = subscriber; -} - -void EditDataProvider::unsubscribe() -{ - currSubscriber = nullptr; -} - -void EditDataProvider::switchOffEditMode() -{ - if (currSubscriber) { - currSubscriber->switchOffEditMode (); - } -} - -int EditDataProvider::getObject() const -{ - return object; -} - -void EditDataProvider::setObject(int newObject) -{ - object = newObject; -} - -float EditDataProvider::getPipetteVal1() const -{ - return pipetteVal1; -} - -float EditDataProvider::getPipetteVal2() const -{ - return pipetteVal2; -} - -float EditDataProvider::getPipetteVal3() const -{ - return pipetteVal3; -} - -void EditDataProvider::setPipetteVal1(float newVal) -{ - pipetteVal1 = newVal; -} - -void EditDataProvider::setPipetteVal2(float newVal) -{ - pipetteVal2 = newVal; -} - -void EditDataProvider::setPipetteVal3(float newVal) -{ - pipetteVal3 = newVal; -} - -CursorShape EditDataProvider::getCursor(int objectID) const -{ - if (currSubscriber) { - currSubscriber->getCursor(objectID); - } - - return CSHandOpen; -} - -EditSubscriber* EditDataProvider::getCurrSubscriber() const -{ - return currSubscriber; -} - -EditDataProvider* EditSubscriber::getEditProvider() -{ - return provider; -} - -CursorShape EditSubscriber::getCursor(int objectID) const -{ - return CSHandOpen; -} - -bool EditSubscriber::mouseOver(int modifierKey) -{ - return false; -} - -bool EditSubscriber::button1Pressed(int modifierKey) -{ - return false; -} - -bool EditSubscriber::button1Released() -{ - return false; -} - -bool EditSubscriber::button2Pressed(int modifierKey) -{ - return false; -} - -bool EditSubscriber::button2Released() -{ - return false; -} - -bool EditSubscriber::button3Pressed(int modifierKey) -{ - return false; -} - -bool EditSubscriber::button3Released() -{ - return false; -} - -bool EditSubscriber::drag1(int modifierKey) -{ - return false; -} - -bool EditSubscriber::drag2(int modifierKey) -{ - return false; -} - -bool EditSubscriber::drag3(int modifierKey) -{ - return false; -} - -bool EditSubscriber::pick1(bool picked) -{ - return false; -} - -bool EditSubscriber::pick2(bool picked) -{ - return false; -} - -bool EditSubscriber::pick3(bool picked) -{ - return false; -} - -const std::vector& EditSubscriber::getVisibleGeometry() -{ - return visibleGeometry; -} - -const std::vector& EditSubscriber::getMouseOverGeometry() -{ - return mouseOverGeometry; -} - -int EditDataProvider::getPipetteRectSize() const -{ - return 8; // TODO: make a GUI -} +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2019 Jean-Christophe FRISCH + * + * 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 "editcallbacks.h" + +EditSubscriber::EditSubscriber (EditType editType) : + ID(EUID_None), + editingType(editType), + bufferType(BT_SINGLEPLANE_FLOAT), + provider(nullptr), + action(EditSubscriber::Action::NONE) +{} + +void EditSubscriber::setEditProvider(EditDataProvider *provider) +{ + this->provider = provider; +} + +void EditSubscriber::setEditID(EditUniqueID ID, BufferType buffType) +{ + this->ID = ID; + bufferType = buffType; +} + +bool EditSubscriber::isCurrentSubscriber() const +{ + //if (provider && provider->getCurrSubscriber()) + // return provider->getCurrSubscriber()->getEditID() == ID; + + if (provider) { + return provider->getCurrSubscriber() == this; + } + + return false; +} + +void EditSubscriber::subscribe() +{ + if (provider) { + provider->subscribe(this); + } +} + +void EditSubscriber::unsubscribe() +{ + if (provider) { + provider->unsubscribe(); + } +} + +void EditSubscriber::switchOffEditMode() +{ + unsubscribe(); +} + +EditUniqueID EditSubscriber::getEditID() const +{ + return ID; +} + +EditType EditSubscriber::getEditingType() const +{ + return editingType; +} + +BufferType EditSubscriber::getPipetteBufferType() const +{ + return bufferType; +} + +bool EditSubscriber::isDragging() const +{ + return action == EditSubscriber::Action::DRAGGING; +} + +bool EditSubscriber::isPicking() const +{ + return action == EditSubscriber::Action::PICKING; +} + +//-------------------------------------------------------------------------------------------------- + + +EditDataProvider::EditDataProvider() : + currSubscriber(nullptr), + object(0), + pipetteVal1(0.f), + pipetteVal2(0.f), + pipetteVal3(0.f), + posScreen(-1, -1), + posImage(-1, -1), + deltaScreen(0, 0), + deltaImage(0, 0), + deltaPrevScreen(0, 0), + deltaPrevImage(0, 0) +{} + +void EditDataProvider::subscribe(EditSubscriber *subscriber) +{ + if (currSubscriber) { + currSubscriber->switchOffEditMode(); + } + + currSubscriber = subscriber; +} + +void EditDataProvider::unsubscribe() +{ + currSubscriber = nullptr; +} + +void EditDataProvider::switchOffEditMode() +{ + if (currSubscriber) { + currSubscriber->switchOffEditMode (); + } +} + +int EditDataProvider::getObject() const +{ + return object; +} + +void EditDataProvider::setObject(int newObject) +{ + object = newObject; +} + +float EditDataProvider::getPipetteVal1() const +{ + return pipetteVal1; +} + +float EditDataProvider::getPipetteVal2() const +{ + return pipetteVal2; +} + +float EditDataProvider::getPipetteVal3() const +{ + return pipetteVal3; +} + +void EditDataProvider::setPipetteVal1(float newVal) +{ + pipetteVal1 = newVal; +} + +void EditDataProvider::setPipetteVal2(float newVal) +{ + pipetteVal2 = newVal; +} + +void EditDataProvider::setPipetteVal3(float newVal) +{ + pipetteVal3 = newVal; +} + +CursorShape EditDataProvider::getCursor(int objectID) const +{ + if (currSubscriber) { + currSubscriber->getCursor(objectID); + } + + return CSHandOpen; +} + +EditSubscriber* EditDataProvider::getCurrSubscriber() const +{ + return currSubscriber; +} + +EditDataProvider* EditSubscriber::getEditProvider() +{ + return provider; +} + +CursorShape EditSubscriber::getCursor(int objectID) const +{ + return CSHandOpen; +} + +bool EditSubscriber::mouseOver(int modifierKey) +{ + return false; +} + +bool EditSubscriber::button1Pressed(int modifierKey) +{ + return false; +} + +bool EditSubscriber::button1Released() +{ + return false; +} + +bool EditSubscriber::button2Pressed(int modifierKey) +{ + return false; +} + +bool EditSubscriber::button2Released() +{ + return false; +} + +bool EditSubscriber::button3Pressed(int modifierKey) +{ + return false; +} + +bool EditSubscriber::button3Released() +{ + return false; +} + +bool EditSubscriber::drag1(int modifierKey) +{ + return false; +} + +bool EditSubscriber::drag2(int modifierKey) +{ + return false; +} + +bool EditSubscriber::drag3(int modifierKey) +{ + return false; +} + +bool EditSubscriber::pick1(bool picked) +{ + return false; +} + +bool EditSubscriber::pick2(bool picked) +{ + return false; +} + +bool EditSubscriber::pick3(bool picked) +{ + return false; +} + +const std::vector& EditSubscriber::getVisibleGeometry() +{ + return visibleGeometry; +} + +const std::vector& EditSubscriber::getMouseOverGeometry() +{ + return mouseOverGeometry; +} + +int EditDataProvider::getPipetteRectSize() const +{ + return 8; // TODO: make a GUI +} diff --git a/rtgui/editcallbacks.h b/rtgui/editcallbacks.h index 842182d6d..c4003f9ca 100644 --- a/rtgui/editcallbacks.h +++ b/rtgui/editcallbacks.h @@ -1,195 +1,195 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2019 Jean-Christophe FRISCH - * - * 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 . - */ -#pragma once - -#include "editid.h" -#include "cursormanager.h" -#include "../rtengine/coord.h" - -class Geometry; -class EditDataProvider; - -/** @file - * See editwidgets.h for documentation - */ - -/// @brief Method for client tools needing Edit information -class EditSubscriber -{ - -public: - -private: - EditUniqueID ID; /// this will be used in improcfun to locate the data that has to be stored in the buffer; it must be unique in RT - EditType editingType; - BufferType bufferType; - EditDataProvider *provider; - -protected: - std::vector visibleGeometry; /// displayed geometry - std::vector mouseOverGeometry; /// mouseOver geometry, drawn in a hidden buffer - enum class Action { - NONE, /// - DRAGGING, /// set action to this value in the buttonPressed event to start dragging and ask for drag event - PICKING /// set action to this value in the buttonPressed event whenever the user is picking something through a single click. In this case, the pickX events will be called INSTEAD of buttonXReleased ! - }; - - Action action; /// object mode only, ignored in Pipette mode - -public: - explicit EditSubscriber (EditType editType); - virtual ~EditSubscriber () = default; - - void setEditProvider(EditDataProvider *provider); - EditDataProvider* getEditProvider (); - void setEditID(EditUniqueID ID, BufferType buffType); - bool isCurrentSubscriber() const; - virtual void subscribe(); - virtual void unsubscribe(); - virtual void switchOffEditMode(); /// Occurs when the user want to stop the editing mode - EditUniqueID getEditID() const; - EditType getEditingType() const; - BufferType getPipetteBufferType() const; - bool isDragging() const; /// Returns true if something is being dragged and drag events has to be sent (object mode only) - bool isPicking() const; /// Returns true if something is being picked - - /** @brief Get the cursor to be displayed when above handles - @param objectID object currently "hovered" */ - virtual CursorShape getCursor (int objectID) const; - - /** @brief Triggered when the mouse is moving over an object - This method is also triggered when the cursor is moving over the image in ET_PIPETTE mode - @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) - @return true if the preview has to be redrawn, false otherwise */ - virtual bool mouseOver (int modifierKey); - - /** @brief Triggered when mouse button 1 is pressed, together with the CTRL modifier key if the subscriber is of type ET_PIPETTE - Once the key is pressed, RT will enter in drag1 mode on subsequent mouse movements - @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) - @return true if the preview has to be redrawn, false otherwise */ - virtual bool button1Pressed (int modifierKey); - - /** @brief Triggered when mouse button 1 is released - @return true if the preview has to be redrawn, false otherwise */ - virtual bool button1Released (); - - /** @brief Triggered when mouse button 2 is pressed (middle button) - Once the key is pressed, RT will enter in drag2 mode on subsequent mouse movements - @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) - @return true if the preview has to be redrawn, false otherwise */ - virtual bool button2Pressed (int modifierKey); - - /** @brief Triggered when mouse button 2 is released (middle button) - @return true if the preview has to be redrawn, false otherwise */ - virtual bool button2Released (); - - /** @brief Triggered when mouse button 3 is pressed (right button) - Once the key is pressed, RT will enter in drag3 mode on subsequent mouse movements - @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) - @return true if the preview has to be redrawn, false otherwise */ - virtual bool button3Pressed (int modifierKey); - - /** @brief Triggered when mouse button 3 is released (right button) - @return true if the preview has to be redrawn, false otherwise */ - virtual bool button3Released (); - - /** @brief Triggered when the user is moving while holding down mouse button 1 - @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) - @return true if the preview has to be redrawn, false otherwise */ - virtual bool drag1 (int modifierKey); - - /** @brief Triggered when the user is moving while holding down mouse button 2 - @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) - @return true if the preview has to be redrawn, false otherwise */ - virtual bool drag2 (int modifierKey); - - /** @brief Triggered when the user is moving while holding down mouse button 3 - @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) - @return true if the preview has to be redrawn, false otherwise */ - virtual bool drag3 (int modifierKey); - - /** @brief Triggered when the user is releasing mouse button 1 while in action==ES_ACTION_PICKING mode - No modifier key is provided, since having a different modifier key than on button press will set picked to false. - @param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys. - If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected. - @return true if the preview has to be redrawn, false otherwise */ - virtual bool pick1 (bool picked); - - /** @brief Triggered when the user is releasing mouse button 2 while in action==ES_ACTION_PICKING mode - @param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys. - If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected. - @return true if the preview has to be redrawn, false otherwise */ - virtual bool pick2 (bool picked); - - /** @brief Triggered when the user is releasing mouse button 3 while in action==ES_ACTION_PICKING mode - @param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys. - If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected. - @return true if the preview has to be redrawn, false otherwise */ - virtual bool pick3 (bool picked); - - /** @brief Get the geometry to be shown to the user */ - const std::vector& getVisibleGeometry (); - - /** @brief Get the geometry to be drawn in the "mouse over" channel, hidden from the user */ - const std::vector& getMouseOverGeometry (); -}; - -/** @brief Class to handle the furniture of data to the subscribers. - * - * It is admitted that only one Subscriber can ask data at a time. If the Subscriber is of type ET_PIPETTE, it will have to - * trigger the usual event so that the image will be reprocessed to compute the buffer of the current subscriber. - */ -class EditDataProvider -{ - -private: - EditSubscriber *currSubscriber; - int object; /// ET_OBJECTS mode: Object detected under the cursor, 0 otherwise; ET_PIPETTE mode: 1 if above the image, 0 otherwise - float pipetteVal1; /// Current pipette values - float pipetteVal2; /// Current pipette values; if bufferType==BT_SINGLEPLANE_FLOAT, will be set to 0 - float pipetteVal3; /// Current pipette values; if bufferType==BT_SINGLEPLANE_FLOAT, will be set to 0 - -public: - - rtengine::Coord posScreen; /// Location of the mouse button press, in preview image space - rtengine::Coord posImage; /// Location of the mouse button press, in the full image space - rtengine::Coord deltaScreen; /// Delta relative to posScreen - rtengine::Coord deltaImage; /// Delta relative to posImage - rtengine::Coord deltaPrevScreen; /// Delta relative to the previous mouse location, in preview image space - rtengine::Coord deltaPrevImage; /// Delta relative to the previous mouse location, in the full image space - - EditDataProvider(); - virtual ~EditDataProvider() = default; - - virtual void subscribe(EditSubscriber *subscriber); - virtual void unsubscribe(); /// Occurs when the subscriber has been switched off first - virtual void switchOffEditMode (); /// Occurs when the user want to stop the editing mode - int getObject() const; - void setObject(int newObject); - float getPipetteVal1() const; - float getPipetteVal2() const; - float getPipetteVal3() const; - void setPipetteVal1(float newVal); - void setPipetteVal2(float newVal); - void setPipetteVal3(float newVal); - virtual CursorShape getCursor(int objectID) const; - int getPipetteRectSize () const; - EditSubscriber* getCurrSubscriber() const; - virtual void getImageSize (int &w, int&h) = 0; -}; +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2019 Jean-Christophe FRISCH + * + * 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 . + */ +#pragma once + +#include "editid.h" +#include "cursormanager.h" +#include "../rtengine/coord.h" + +class Geometry; +class EditDataProvider; + +/** @file + * See editwidgets.h for documentation + */ + +/// @brief Method for client tools needing Edit information +class EditSubscriber +{ + +public: + +private: + EditUniqueID ID; /// this will be used in improcfun to locate the data that has to be stored in the buffer; it must be unique in RT + EditType editingType; + BufferType bufferType; + EditDataProvider *provider; + +protected: + std::vector visibleGeometry; /// displayed geometry + std::vector mouseOverGeometry; /// mouseOver geometry, drawn in a hidden buffer + enum class Action { + NONE, /// + DRAGGING, /// set action to this value in the buttonPressed event to start dragging and ask for drag event + PICKING /// set action to this value in the buttonPressed event whenever the user is picking something through a single click. In this case, the pickX events will be called INSTEAD of buttonXReleased ! + }; + + Action action; /// object mode only, ignored in Pipette mode + +public: + explicit EditSubscriber (EditType editType); + virtual ~EditSubscriber () = default; + + void setEditProvider(EditDataProvider *provider); + EditDataProvider* getEditProvider (); + void setEditID(EditUniqueID ID, BufferType buffType); + bool isCurrentSubscriber() const; + virtual void subscribe(); + virtual void unsubscribe(); + virtual void switchOffEditMode(); /// Occurs when the user want to stop the editing mode + EditUniqueID getEditID() const; + EditType getEditingType() const; + BufferType getPipetteBufferType() const; + bool isDragging() const; /// Returns true if something is being dragged and drag events has to be sent (object mode only) + bool isPicking() const; /// Returns true if something is being picked + + /** @brief Get the cursor to be displayed when above handles + @param objectID object currently "hovered" */ + virtual CursorShape getCursor (int objectID) const; + + /** @brief Triggered when the mouse is moving over an object + This method is also triggered when the cursor is moving over the image in ET_PIPETTE mode + @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) + @return true if the preview has to be redrawn, false otherwise */ + virtual bool mouseOver (int modifierKey); + + /** @brief Triggered when mouse button 1 is pressed, together with the CTRL modifier key if the subscriber is of type ET_PIPETTE + Once the key is pressed, RT will enter in drag1 mode on subsequent mouse movements + @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) + @return true if the preview has to be redrawn, false otherwise */ + virtual bool button1Pressed (int modifierKey); + + /** @brief Triggered when mouse button 1 is released + @return true if the preview has to be redrawn, false otherwise */ + virtual bool button1Released (); + + /** @brief Triggered when mouse button 2 is pressed (middle button) + Once the key is pressed, RT will enter in drag2 mode on subsequent mouse movements + @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) + @return true if the preview has to be redrawn, false otherwise */ + virtual bool button2Pressed (int modifierKey); + + /** @brief Triggered when mouse button 2 is released (middle button) + @return true if the preview has to be redrawn, false otherwise */ + virtual bool button2Released (); + + /** @brief Triggered when mouse button 3 is pressed (right button) + Once the key is pressed, RT will enter in drag3 mode on subsequent mouse movements + @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) + @return true if the preview has to be redrawn, false otherwise */ + virtual bool button3Pressed (int modifierKey); + + /** @brief Triggered when mouse button 3 is released (right button) + @return true if the preview has to be redrawn, false otherwise */ + virtual bool button3Released (); + + /** @brief Triggered when the user is moving while holding down mouse button 1 + @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) + @return true if the preview has to be redrawn, false otherwise */ + virtual bool drag1 (int modifierKey); + + /** @brief Triggered when the user is moving while holding down mouse button 2 + @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) + @return true if the preview has to be redrawn, false otherwise */ + virtual bool drag2 (int modifierKey); + + /** @brief Triggered when the user is moving while holding down mouse button 3 + @param modifierKey Gtk's event modifier key (GDK_CONTROL_MASK | GDK_SHIFT_MASK | ...) + @return true if the preview has to be redrawn, false otherwise */ + virtual bool drag3 (int modifierKey); + + /** @brief Triggered when the user is releasing mouse button 1 while in action==ES_ACTION_PICKING mode + No modifier key is provided, since having a different modifier key than on button press will set picked to false. + @param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys. + If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected. + @return true if the preview has to be redrawn, false otherwise */ + virtual bool pick1 (bool picked); + + /** @brief Triggered when the user is releasing mouse button 2 while in action==ES_ACTION_PICKING mode + @param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys. + If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected. + @return true if the preview has to be redrawn, false otherwise */ + virtual bool pick2 (bool picked); + + /** @brief Triggered when the user is releasing mouse button 3 while in action==ES_ACTION_PICKING mode + @param picked True if the cursor is still above the the same object than on button pressed and with the same modifier keys. + If false, the user moved the cursor away or the modifier key is different, so the element is considered as NOT selected. + @return true if the preview has to be redrawn, false otherwise */ + virtual bool pick3 (bool picked); + + /** @brief Get the geometry to be shown to the user */ + const std::vector& getVisibleGeometry (); + + /** @brief Get the geometry to be drawn in the "mouse over" channel, hidden from the user */ + const std::vector& getMouseOverGeometry (); +}; + +/** @brief Class to handle the furniture of data to the subscribers. + * + * It is admitted that only one Subscriber can ask data at a time. If the Subscriber is of type ET_PIPETTE, it will have to + * trigger the usual event so that the image will be reprocessed to compute the buffer of the current subscriber. + */ +class EditDataProvider +{ + +private: + EditSubscriber *currSubscriber; + int object; /// ET_OBJECTS mode: Object detected under the cursor, 0 otherwise; ET_PIPETTE mode: 1 if above the image, 0 otherwise + float pipetteVal1; /// Current pipette values + float pipetteVal2; /// Current pipette values; if bufferType==BT_SINGLEPLANE_FLOAT, will be set to 0 + float pipetteVal3; /// Current pipette values; if bufferType==BT_SINGLEPLANE_FLOAT, will be set to 0 + +public: + + rtengine::Coord posScreen; /// Location of the mouse button press, in preview image space + rtengine::Coord posImage; /// Location of the mouse button press, in the full image space + rtengine::Coord deltaScreen; /// Delta relative to posScreen + rtengine::Coord deltaImage; /// Delta relative to posImage + rtengine::Coord deltaPrevScreen; /// Delta relative to the previous mouse location, in preview image space + rtengine::Coord deltaPrevImage; /// Delta relative to the previous mouse location, in the full image space + + EditDataProvider(); + virtual ~EditDataProvider() = default; + + virtual void subscribe(EditSubscriber *subscriber); + virtual void unsubscribe(); /// Occurs when the subscriber has been switched off first + virtual void switchOffEditMode (); /// Occurs when the user want to stop the editing mode + int getObject() const; + void setObject(int newObject); + float getPipetteVal1() const; + float getPipetteVal2() const; + float getPipetteVal3() const; + void setPipetteVal1(float newVal); + void setPipetteVal2(float newVal); + void setPipetteVal3(float newVal); + virtual CursorShape getCursor(int objectID) const; + int getPipetteRectSize () const; + EditSubscriber* getCurrSubscriber() const; + virtual void getImageSize (int &w, int&h) = 0; +}; diff --git a/rtgui/editcoordsys.h b/rtgui/editcoordsys.h index 1af0f5e37..829225e3f 100644 --- a/rtgui/editcoordsys.h +++ b/rtgui/editcoordsys.h @@ -1,61 +1,61 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2019 Jean-Christophe FRISCH - * - * 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 . - */ - -/** @file - * See editwidgets.h for documentation - */ - - /** @brief Coordinate system where the widgets will be drawn - * - * The EditCoordSystem is used to define a screen and an image coordinate system. - */ -#pragma once - - - class EditCoordSystem - { - public: - virtual ~EditCoordSystem() {} - - /// Convert the widget's DrawingArea (i.e. preview area) coords to the edit buffer coords - virtual void screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& cropy) = 0; - /// Convert the widget's DrawingArea (i.e. preview area) coords to the full image coords - virtual void screenCoordToImage (int phyx, int phyy, int& imgx, int& imgy) = 0; - /// Convert the image coords to the widget's DrawingArea (i.e. preview area) coords - virtual void imageCoordToScreen (int imgx, int imgy, int& phyx, int& phyy) = 0; - /// Convert the image coords to the crop's canvas coords (full image + padding) - virtual void imageCoordToCropCanvas (int imgx, int imgy, int& phyx, int& phyy) = 0; - /// Convert the image coords to the edit buffer coords (includes borders) - virtual void imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phyy) = 0; - /// Convert the image coords to the displayed image coords (no borders here) - virtual void imageCoordToCropImage (int imgx, int imgy, int& phyx, int& phyy) = 0; - /// Convert a size value from the preview's scale to the image's scale - virtual int scaleValueToImage (int value) = 0; - /// Convert a size value from the preview's scale to the image's scale - virtual float scaleValueToImage (float value) = 0; - /// Convert a size value from the preview's scale to the image's scale - virtual double scaleValueToImage (double value) = 0; - /// Convert a size value from the image's scale to the preview's scale - virtual int scaleValueToCanvas (int value) = 0; - /// Convert a size value from the image's scale to the preview's scale - virtual float scaleValueToCanvas (float value) = 0; - /// Convert a size value from the image's scale to the preview's scale - virtual double scaleValueToCanvas (double value) = 0; - }; - +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2019 Jean-Christophe FRISCH + * + * 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 . + */ + +/** @file + * See editwidgets.h for documentation + */ + + /** @brief Coordinate system where the widgets will be drawn + * + * The EditCoordSystem is used to define a screen and an image coordinate system. + */ +#pragma once + + + class EditCoordSystem + { + public: + virtual ~EditCoordSystem() {} + + /// Convert the widget's DrawingArea (i.e. preview area) coords to the edit buffer coords + virtual void screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& cropy) = 0; + /// Convert the widget's DrawingArea (i.e. preview area) coords to the full image coords + virtual void screenCoordToImage (int phyx, int phyy, int& imgx, int& imgy) = 0; + /// Convert the image coords to the widget's DrawingArea (i.e. preview area) coords + virtual void imageCoordToScreen (int imgx, int imgy, int& phyx, int& phyy) = 0; + /// Convert the image coords to the crop's canvas coords (full image + padding) + virtual void imageCoordToCropCanvas (int imgx, int imgy, int& phyx, int& phyy) = 0; + /// Convert the image coords to the edit buffer coords (includes borders) + virtual void imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phyy) = 0; + /// Convert the image coords to the displayed image coords (no borders here) + virtual void imageCoordToCropImage (int imgx, int imgy, int& phyx, int& phyy) = 0; + /// Convert a size value from the preview's scale to the image's scale + virtual int scaleValueToImage (int value) = 0; + /// Convert a size value from the preview's scale to the image's scale + virtual float scaleValueToImage (float value) = 0; + /// Convert a size value from the preview's scale to the image's scale + virtual double scaleValueToImage (double value) = 0; + /// Convert a size value from the image's scale to the preview's scale + virtual int scaleValueToCanvas (int value) = 0; + /// Convert a size value from the image's scale to the preview's scale + virtual float scaleValueToCanvas (float value) = 0; + /// Convert a size value from the image's scale to the preview's scale + virtual double scaleValueToCanvas (double value) = 0; + }; + diff --git a/rtgui/editwidgets.cc b/rtgui/editwidgets.cc index 129d81bc7..16cd67cd4 100644 --- a/rtgui/editwidgets.cc +++ b/rtgui/editwidgets.cc @@ -1,935 +1,935 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2019 Jean-Christophe FRISCH - * - * 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 "editwidgets.h" -#include "editbuffer.h" -#include "editcallbacks.h" -#include "../rtengine/rt_math.h" - -RGBColor Geometry::getInnerLineColor () -{ - RGBColor color; - - if (flags & F_AUTO_COLOR) { - if (state == NORMAL) { - color.setColor (1., 1., 1.); // White - } else if (state == ACTIVE) { - color.setColor (1., 1., 0.); // Yellow - } else if (state == PRELIGHT) { - color.setColor (1., 100. / 255., 0.); // Orange - } else if (state == DRAGGED) { - color.setColor (1., 0., 0.); // Red - } - } else { - color = innerLineColor; - } - - return color; -} - -RGBColor Geometry::getOuterLineColor () -{ - RGBColor color; - - if (flags & F_AUTO_COLOR) { - /* - if (state == NORMAL) { color.setColor (0., 0., 0.); } // Black - else if (state == PRELIGHT) { color.setColor (0., 0., 0.); } // Black - else if (state == DRAGGED) { color.setColor (1., 0., 0.); } // Black - */ - color.setColor (0., 0., 0.); // Black - } else { - color = outerLineColor; - } - - return color; -} - -#ifdef GUIVERSION - -void Circle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if ((flags & F_VISIBLE) && state != INSENSITIVE) { - RGBColor color; - - if (flags & F_AUTO_COLOR) { - color = getOuterLineColor(); - } else { - color = outerLineColor; - } - - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); - cr->set_line_width( getOuterLineWidth() ); - - rtengine::Coord center_ = center; - double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius); - - if (datum == IMAGE) { - coordSystem.imageCoordToScreen (center.x, center.y, center_.x, center_.y); - } else if (datum == CLICKED_POINT) { - center_ += objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*rtengine::RT_PI); - cr->stroke(); - } -} - -void Circle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if (flags & F_VISIBLE) { - if (state != INSENSITIVE) { - RGBColor color; - - if (flags & F_AUTO_COLOR) { - color = getInnerLineColor(); - } else { - color = innerLineColor; - } - - cr->set_source_rgb(color.getR(), color.getG(), color.getB()); - } - - cr->set_line_width( innerLineWidth ); - - rtengine::Coord center_ = center; - double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius); - - if (datum == IMAGE) { - coordSystem.imageCoordToScreen (center.x, center.y, center_.x, center_.y); - } else if (datum == CLICKED_POINT) { - center_ += objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - if (filled && state != INSENSITIVE) { - cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*rtengine::RT_PI); - - if (innerLineWidth > 0.) { - cr->fill_preserve(); - cr->stroke(); - } else { - cr->fill(); - } - } else if (innerLineWidth > 0.) { - cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*rtengine::RT_PI); - - if (state == INSENSITIVE) { - std::valarray ds(1); - ds[0] = 4; - cr->set_source_rgba(1.0, 1.0, 1.0, 0.618); - cr->stroke_preserve(); - cr->set_source_rgba(0.0, 0.0, 0.0, 0.618); - cr->set_dash(ds, 0); - cr->stroke(); - ds.resize(0); - cr->set_dash(ds, 0); - } else { - cr->stroke(); - } - } - } -} - -void Circle::drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if (flags & F_HOVERABLE) { - cr->set_line_width( getMouseOverLineWidth() ); - rtengine::Coord center_ = center; - double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius); - - if (datum == IMAGE) { - coordSystem.imageCoordToCropCanvas (center.x, center.y, center_.x, center_.y); - } else if (datum == CLICKED_POINT) { - center_ += objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - // setting the color to the objet's ID - if (objectBuffer->getObjectMode() == OM_255) { - cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); - } else { - cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); - } - cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0, 2.*rtengine::RT_PI); - - if (filled) { - if (innerLineWidth > 0.) { - cr->fill_preserve(); - cr->stroke(); - } else { - cr->fill(); - } - } else { - cr->stroke(); - } - } -} - -void Line::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if ((flags & F_VISIBLE) && state != INSENSITIVE) { - RGBColor color; - - if (flags & F_AUTO_COLOR) { - color = getOuterLineColor(); - } else { - color = outerLineColor; - } - - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); - cr->set_line_width( getOuterLineWidth() ); - - rtengine::Coord begin_ = begin; - rtengine::Coord end_ = end; - - if (datum == IMAGE) { - coordSystem.imageCoordToScreen (begin.x, begin.y, begin_.x, begin_.y); - coordSystem.imageCoordToScreen (end.x, end.y, end_.x, end_.y); - } else if (datum == CLICKED_POINT) { - begin_ += objectBuffer->getDataProvider()->posScreen; - end_ += objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - begin_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - end_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - cr->move_to(begin_.x + 0.5, begin_.y + 0.5); - cr->line_to(end_.x + 0.5, end_.y + 0.5); - cr->stroke(); - } -} - -void Line::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if ((flags & F_VISIBLE) && innerLineWidth > 0.) { - if (state != INSENSITIVE) { - RGBColor color; - - if (flags & F_AUTO_COLOR) { - color = getInnerLineColor(); - } else { - color = innerLineColor; - } - - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); - } - - cr->set_line_width(innerLineWidth); - - rtengine::Coord begin_ = begin; - rtengine::Coord end_ = end; - - if (datum == IMAGE) { - coordSystem.imageCoordToScreen (begin.x, begin.y, begin_.x, begin_.y); - coordSystem.imageCoordToScreen (end.x, end.y, end_.x, end_.y); - } else if (datum == CLICKED_POINT) { - begin_ += objectBuffer->getDataProvider()->posScreen; - end_ += objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - begin_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - end_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - cr->move_to(begin_.x + 0.5, begin_.y + 0.5); - cr->line_to(end_.x + 0.5, end_.y + 0.5); - - if (state == INSENSITIVE) { - std::valarray ds(1); - ds[0] = 4; - cr->set_source_rgba(1.0, 1.0, 1.0, 0.618); - cr->stroke_preserve(); - cr->set_source_rgba(0.0, 0.0, 0.0, 0.618); - cr->set_dash(ds, 0); - cr->stroke(); - ds.resize(0); - cr->set_dash(ds, 0); - } else { - cr->stroke(); - } - } -} - -void Line::drawToMOChannel(Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if (flags & F_HOVERABLE) { - cr->set_line_width( getMouseOverLineWidth() ); - rtengine::Coord begin_ = begin; - rtengine::Coord end_ = end; - - if (datum == IMAGE) { - coordSystem.imageCoordToCropCanvas (begin.x, begin.y, begin_.x, begin_.y); - coordSystem.imageCoordToCropCanvas (end.x, end.y, end_.x, end_.y); - } else if (datum == CLICKED_POINT) { - begin_ += objectBuffer->getDataProvider()->posScreen; - end_ += objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - begin_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - end_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - // setting the color to the objet's ID - if (objectBuffer->getObjectMode() == OM_255) { - cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); - } else { - cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); - } - cr->move_to(begin_.x + 0.5, begin_.y + 0.5); - cr->line_to(end_.x + 0.5, end_.y + 0.5); - cr->stroke(); - } -} - -void Polyline::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if ((flags & F_VISIBLE) && state != INSENSITIVE && points.size() > 1) { - RGBColor color; - - if (flags & F_AUTO_COLOR) { - color = getOuterLineColor(); - } else { - color = outerLineColor; - } - - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); - cr->set_line_width( getOuterLineWidth() ); - - rtengine::Coord currPos; - - for (unsigned int i = 0; i < points.size(); ++i) { - currPos = points.at(i); - - if (datum == IMAGE) { - coordSystem.imageCoordToScreen (points.at(i).x, points.at(i).y, currPos.x, currPos.y); - } else if (datum == CLICKED_POINT) { - currPos += objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - currPos += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - if (!i) { - cr->move_to(currPos.x + 0.5, currPos.y + 0.5); - } else { - cr->line_to(currPos.x + 0.5, currPos.y + 0.5); - } - } - - if (filled) { - cr->fill_preserve(); - cr->stroke(); - } else { - cr->stroke(); - } - } -} - -void Polyline::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if ((flags & F_VISIBLE) && points.size() > 1) { - if (state != INSENSITIVE) { - RGBColor color; - - if (flags & F_AUTO_COLOR) { - color = getInnerLineColor(); - } else { - color = innerLineColor; - } - - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); - } - - cr->set_line_width( innerLineWidth ); - - if (filled && state != INSENSITIVE) { - rtengine::Coord currPos; - - for (unsigned int i = 0; i < points.size(); ++i) { - currPos = points.at(i); - - if (datum == IMAGE) { - coordSystem.imageCoordToScreen (points.at(i).x, points.at(i).y, currPos.x, currPos.y); - } else if (datum == CLICKED_POINT) { - currPos += objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - currPos += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - if (!i) { - cr->move_to(currPos.x + 0.5, currPos.y + 0.5); - } else { - cr->line_to(currPos.x + 0.5, currPos.y + 0.5); - } - } - - if (innerLineWidth > 0.) { - cr->fill_preserve(); - cr->stroke(); - } else { - cr->fill(); - } - } else if (innerLineWidth > 0.) { - rtengine::Coord currPos; - - for (unsigned int i = 0; i < points.size(); ++i) { - currPos = points.at(i); - - if (datum == IMAGE) { - coordSystem.imageCoordToScreen (points.at(i).x, points.at(i).y, currPos.x, currPos.y); - } else if (datum == CLICKED_POINT) { - currPos += objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - currPos += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - if (!i) { - cr->move_to(currPos.x + 0.5, currPos.y + 0.5); - } else { - cr->line_to(currPos.x + 0.5, currPos.y + 0.5); - } - } - - if (state == INSENSITIVE) { - std::valarray ds(1); - ds[0] = 4; - cr->set_source_rgba(1.0, 1.0, 1.0, 0.618); - cr->stroke_preserve(); - cr->set_source_rgba(0.0, 0.0, 0.0, 0.618); - cr->set_dash(ds, 0); - cr->stroke(); - ds.resize(0); - cr->set_dash(ds, 0); - } else { - cr->stroke(); - } - } - } -} - -void Polyline::drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if ((flags & F_HOVERABLE) && points.size() > 1) { - rtengine::Coord currPos; - - // setting the color to the objet's ID - if (objectBuffer->getObjectMode() == OM_255) { - cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); - } else { - cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); - } - - for (unsigned int i = 0; i < points.size(); ++i) { - cr->set_line_width( getMouseOverLineWidth() ); - currPos = points.at(i); - - if (datum == IMAGE) { - coordSystem.imageCoordToCropCanvas (points.at(i).x, points.at(i).y, currPos.x, currPos.y); - } else if (datum == CLICKED_POINT) { - currPos += objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - currPos += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - if (!i) { - cr->move_to(currPos.x + 0.5, currPos.y + 0.5); - } else { - cr->line_to(currPos.x + 0.5, currPos.y + 0.5); - } - } - - if (filled) { - if (innerLineWidth > 0.) { - cr->fill_preserve(); - cr->stroke(); - } else { - cr->fill(); - } - } else { - cr->stroke(); - } - } -} - -void Rectangle::setXYWH(int left, int top, int width, int height) -{ - topLeft.set(left, top); - bottomRight.set(left + width, top + height); -} - -void Rectangle::setXYXY(int left, int top, int right, int bottom) -{ - topLeft.set(left, top); - bottomRight.set(right, bottom); -} - -void Rectangle::setXYWH(rtengine::Coord topLeft, rtengine::Coord widthHeight) -{ - this->topLeft = topLeft; - this->bottomRight = topLeft + widthHeight; -} - -void Rectangle::setXYXY(rtengine::Coord topLeft, rtengine::Coord bottomRight) -{ - this->topLeft = topLeft; - this->bottomRight = bottomRight; -} - -void Rectangle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if ((flags & F_VISIBLE) && state != INSENSITIVE) { - RGBColor color; - - if (flags & F_AUTO_COLOR) { - color = getOuterLineColor(); - } else { - color = outerLineColor; - } - - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); - cr->set_line_width( getOuterLineWidth() ); - - rtengine::Coord tl, br; - - if (datum == IMAGE) { - coordSystem.imageCoordToScreen (topLeft.x, topLeft.y, tl.x, tl.y); - } else if (datum == CLICKED_POINT) { - tl = topLeft + objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - tl = topLeft + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - if (datum == IMAGE) { - coordSystem.imageCoordToScreen (bottomRight.x, bottomRight.y, br.x, br.y); - } else if (datum == CLICKED_POINT) { - br = bottomRight + objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - br = bottomRight + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y); - - if (filled) { - cr->fill_preserve(); - cr->stroke(); - } else { - cr->stroke(); - } - } -} - -void Rectangle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if (flags & F_VISIBLE) { - if (state != INSENSITIVE) { - RGBColor color; - - if (flags & F_AUTO_COLOR) { - color = getInnerLineColor(); - } else { - color = innerLineColor; - } - - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); - } - - cr->set_line_width( innerLineWidth ); - - rtengine::Coord tl, br; - - if (datum == IMAGE) { - coordSystem.imageCoordToScreen (topLeft.x, topLeft.y, tl.x, tl.y); - } else if (datum == CLICKED_POINT) { - tl = topLeft + objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - tl = topLeft + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - if (datum == IMAGE) { - coordSystem.imageCoordToScreen (bottomRight.x, bottomRight.y, br.x, br.y); - } else if (datum == CLICKED_POINT) { - br = bottomRight + objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - br = bottomRight + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - if (filled && state != INSENSITIVE) { - cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y); - - if (innerLineWidth > 0.) { - cr->fill_preserve(); - cr->stroke(); - } else { - cr->fill(); - } - } else if (innerLineWidth > 0.) { - cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y); - - if (state == INSENSITIVE) { - std::valarray ds(1); - ds[0] = 4; - cr->set_source_rgba(1.0, 1.0, 1.0, 0.618); - cr->stroke_preserve(); - cr->set_source_rgba(0.0, 0.0, 0.0, 0.618); - cr->set_dash(ds, 0); - cr->stroke(); - ds.resize(0); - cr->set_dash(ds, 0); - } else { - cr->stroke(); - } - } - } -} - -void Rectangle::drawToMOChannel(Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if (flags & F_HOVERABLE) { - cr->set_line_width( getMouseOverLineWidth() ); - - rtengine::Coord tl, br; - - if (datum == IMAGE) { - coordSystem.imageCoordToCropCanvas (topLeft.x, topLeft.y, tl.x, tl.y); - } else if (datum == CLICKED_POINT) { - tl = topLeft + objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - tl = topLeft + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - if (datum == IMAGE) { - coordSystem.imageCoordToCropCanvas (bottomRight.x, bottomRight.y, br.x, br.y); - } else if (datum == CLICKED_POINT) { - br = bottomRight + objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) { - br = bottomRight + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; - } - - // setting the color to the objet's ID - if (objectBuffer->getObjectMode() == OM_255) { - cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); - } else { - cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); - } - cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y); - - if (filled) { - if (innerLineWidth > 0.) { - cr->fill_preserve(); - cr->stroke(); - } else { - cr->fill(); - } - } else { - cr->stroke(); - } - } -} - -void OPIcon::drivenPointToRectangle(const rtengine::Coord &pos, - rtengine::Coord &topLeft, rtengine::Coord &bottomRight, int W, int H) -{ - switch (drivenPoint) { - case (DP_CENTERCENTER): - topLeft.x = pos.x - W / 2; - topLeft.y = pos.y - H / 2; - break; - - case (DP_TOPLEFT): - topLeft.x = pos.x; - topLeft.y = pos.y; - break; - - case (DP_TOPCENTER): - topLeft.x = pos.x - W / 2; - topLeft.y = pos.y; - break; - - case (DP_TOPRIGHT): - topLeft.x = pos.x - W; - topLeft.y = pos.y; - break; - - case (DP_CENTERRIGHT): - topLeft.x = pos.x - W; - topLeft.y = pos.y - H / 2; - break; - - case (DP_BOTTOMRIGHT): - topLeft.x = pos.x - W; - topLeft.y = pos.y - H; - break; - - case (DP_BOTTOMCENTER): - topLeft.x = pos.x - W / 2; - topLeft.y = pos.y - H; - break; - - case (DP_BOTTOMLEFT): - topLeft.x = pos.x; - topLeft.y = pos.y - H; - break; - - case (DP_CENTERLEFT): - topLeft.x = pos.x; - topLeft.y = pos.y - H / 2; - break; - } - - bottomRight.x = topLeft.x + W - 1; - bottomRight.y = topLeft.y + H - 1; -} - -OPIcon::OPIcon(const Cairo::RefPtr &normal, - const Cairo::RefPtr &active, - const Cairo::RefPtr &prelight, - const Cairo::RefPtr &dragged, - const Cairo::RefPtr &insensitive, - DrivenPoint drivenPoint) : - drivenPoint(drivenPoint) -{ - if (normal) { - normalImg = normal; - } - - if (prelight) { - prelightImg = prelight; - } - - if (active) { - activeImg = active; - } - - if (dragged) { - draggedImg = dragged; - } - - if (insensitive) { - insensitiveImg = insensitive; - } -} - -OPIcon::OPIcon(Glib::ustring normalImage, Glib::ustring activeImage, Glib::ustring prelightImage, - Glib::ustring draggedImage, Glib::ustring insensitiveImage, DrivenPoint drivenPoint) : drivenPoint(drivenPoint) -{ - if (!normalImage.empty()) { - normalImg = Cairo::RefPtr(new RTSurface(normalImage)); - } - - if (!prelightImage.empty()) { - prelightImg = Cairo::RefPtr(new RTSurface(prelightImage)); - } - - if (!activeImage.empty()) { - activeImg = Cairo::RefPtr(new RTSurface(activeImage)); - } - - if (!draggedImage.empty()) { - draggedImg = Cairo::RefPtr(new RTSurface(draggedImage)); - } - - if (!insensitiveImage.empty()) { - insensitiveImg = Cairo::RefPtr(new RTSurface(insensitiveImage)); - } -} - -const Cairo::RefPtr OPIcon::getNormalImg() -{ - return normalImg; -} -const Cairo::RefPtr OPIcon::getPrelightImg() -{ - return prelightImg; -} -const Cairo::RefPtr OPIcon::getActiveImg() -{ - return activeImg; -} -const Cairo::RefPtr OPIcon::getDraggedImg() -{ - return draggedImg; -} -const Cairo::RefPtr OPIcon::getInsensitiveImg() -{ - return insensitiveImg; -} - -void OPIcon::drawImage(Cairo::RefPtr &img, - Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, - EditCoordSystem &coordSystem) -{ - int imgW = img->getWidth(); - int imgH = img->getHeight(); - - rtengine::Coord pos; - - if (datum == IMAGE) { - coordSystem.imageCoordToScreen(position.x, position.y, pos.x, pos.y); - } else if (datum == CLICKED_POINT) { - pos = position + objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) - pos = position + objectBuffer->getDataProvider()->posScreen - + objectBuffer->getDataProvider()->deltaScreen; - - rtengine::Coord tl, br; // Coordinate of the rectangle in the CropBuffer coordinate system - drivenPointToRectangle(pos, tl, br, imgW, imgH); - - cr->set_source(img->get(), tl.x, tl.y); - cr->set_line_width(0.); - cr->rectangle(tl.x, tl.y, imgW, imgH); - cr->fill(); -} - -void OPIcon::drawMOImage(Cairo::RefPtr &img, Cairo::RefPtr &cr, - unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - // test of F_HOVERABLE has already been done - - int imgW = img->getWidth(); - int imgH = img->getHeight(); - - rtengine::Coord pos; - - if (datum == IMAGE) - coordSystem.imageCoordToCropCanvas (position.x, position.y, pos.x, pos.y); - else if (datum == CLICKED_POINT) { - pos = position + objectBuffer->getDataProvider()->posScreen; - } else if (datum == CURSOR) - pos = position + objectBuffer->getDataProvider()->posScreen - + objectBuffer->getDataProvider()->deltaScreen; - - rtengine::Coord tl, br; // Coordinate of the rectangle in the CropBuffer coordinate system - drivenPointToRectangle(pos, tl, br, imgW, imgH); - - // drawing the lower byte's value - if (objectBuffer->getObjectMode() == OM_255) { - cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); - } else { - cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); - } - cr->set_line_width(0.); - cr->rectangle(tl.x, tl.y, imgW, imgH); - cr->fill(); -} - -void OPIcon::drawOuterGeometry(Cairo::RefPtr &cr, - ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) {} - -void OPIcon::drawInnerGeometry(Cairo::RefPtr &cr, - ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if (flags & F_VISIBLE) { - // Here we will handle fall-back solutions - - State tmpState = state; // can be updated through the successive test - - if (tmpState == INSENSITIVE) { - if (!insensitiveImg) { - tmpState = NORMAL; - } else { - OPIcon::drawImage(insensitiveImg, cr, objectBuffer, coordSystem); - return; - } - } - - if (tmpState == DRAGGED) { - if (!draggedImg) { - tmpState = ACTIVE; - } else { - OPIcon::drawImage(draggedImg, cr, objectBuffer, coordSystem); - return; - } - } - - if (tmpState == ACTIVE) { - if (!activeImg) { - tmpState = PRELIGHT; - } else { - OPIcon::drawImage(activeImg, cr, objectBuffer, coordSystem); - return; - } - } - - if (tmpState == PRELIGHT) { - if (!prelightImg) { - tmpState = NORMAL; - } else { - OPIcon::drawImage(prelightImg, cr, objectBuffer, coordSystem); - return; - } - } - - if (tmpState == NORMAL && normalImg) { - OPIcon::drawImage(normalImg, cr, objectBuffer, coordSystem); - } - } -} - -void OPIcon::drawToMOChannel(Cairo::RefPtr &cr, unsigned short id, - ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) -{ - if (flags & F_HOVERABLE) { - // Here we will handle fallback solutions - State tmpState = state; - - if (tmpState == INSENSITIVE) { - if (!insensitiveImg) { - tmpState = NORMAL; - } else { - OPIcon::drawMOImage(insensitiveImg, cr, id, objectBuffer, coordSystem); - return; - } - } - - if (tmpState == DRAGGED) { - if (!draggedImg) { - tmpState = ACTIVE; - } else { - OPIcon::drawMOImage(draggedImg, cr, id, objectBuffer, coordSystem); - return; - } - } - - if (tmpState == ACTIVE) { - if (!activeImg) { - tmpState = PRELIGHT; - } else { - OPIcon::drawMOImage(activeImg, cr, id, objectBuffer, coordSystem); - return; - } - } - - if (tmpState == PRELIGHT) { - if (!prelightImg) { - tmpState = NORMAL; - } else { - OPIcon::drawMOImage(prelightImg, cr, id, objectBuffer, coordSystem); - return; - } - } - - if (tmpState == NORMAL && normalImg) { - OPIcon::drawMOImage(normalImg, cr, id, objectBuffer, coordSystem); - } - } -} - -#endif +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2019 Jean-Christophe FRISCH + * + * 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 "editwidgets.h" +#include "editbuffer.h" +#include "editcallbacks.h" +#include "../rtengine/rt_math.h" + +RGBColor Geometry::getInnerLineColor () +{ + RGBColor color; + + if (flags & F_AUTO_COLOR) { + if (state == NORMAL) { + color.setColor (1., 1., 1.); // White + } else if (state == ACTIVE) { + color.setColor (1., 1., 0.); // Yellow + } else if (state == PRELIGHT) { + color.setColor (1., 100. / 255., 0.); // Orange + } else if (state == DRAGGED) { + color.setColor (1., 0., 0.); // Red + } + } else { + color = innerLineColor; + } + + return color; +} + +RGBColor Geometry::getOuterLineColor () +{ + RGBColor color; + + if (flags & F_AUTO_COLOR) { + /* + if (state == NORMAL) { color.setColor (0., 0., 0.); } // Black + else if (state == PRELIGHT) { color.setColor (0., 0., 0.); } // Black + else if (state == DRAGGED) { color.setColor (1., 0., 0.); } // Black + */ + color.setColor (0., 0., 0.); // Black + } else { + color = outerLineColor; + } + + return color; +} + +#ifdef GUIVERSION + +void Circle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if ((flags & F_VISIBLE) && state != INSENSITIVE) { + RGBColor color; + + if (flags & F_AUTO_COLOR) { + color = getOuterLineColor(); + } else { + color = outerLineColor; + } + + cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_line_width( getOuterLineWidth() ); + + rtengine::Coord center_ = center; + double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius); + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen (center.x, center.y, center_.x, center_.y); + } else if (datum == CLICKED_POINT) { + center_ += objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*rtengine::RT_PI); + cr->stroke(); + } +} + +void Circle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if (flags & F_VISIBLE) { + if (state != INSENSITIVE) { + RGBColor color; + + if (flags & F_AUTO_COLOR) { + color = getInnerLineColor(); + } else { + color = innerLineColor; + } + + cr->set_source_rgb(color.getR(), color.getG(), color.getB()); + } + + cr->set_line_width( innerLineWidth ); + + rtengine::Coord center_ = center; + double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius); + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen (center.x, center.y, center_.x, center_.y); + } else if (datum == CLICKED_POINT) { + center_ += objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + if (filled && state != INSENSITIVE) { + cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*rtengine::RT_PI); + + if (innerLineWidth > 0.) { + cr->fill_preserve(); + cr->stroke(); + } else { + cr->fill(); + } + } else if (innerLineWidth > 0.) { + cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*rtengine::RT_PI); + + if (state == INSENSITIVE) { + std::valarray ds(1); + ds[0] = 4; + cr->set_source_rgba(1.0, 1.0, 1.0, 0.618); + cr->stroke_preserve(); + cr->set_source_rgba(0.0, 0.0, 0.0, 0.618); + cr->set_dash(ds, 0); + cr->stroke(); + ds.resize(0); + cr->set_dash(ds, 0); + } else { + cr->stroke(); + } + } + } +} + +void Circle::drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if (flags & F_HOVERABLE) { + cr->set_line_width( getMouseOverLineWidth() ); + rtengine::Coord center_ = center; + double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius); + + if (datum == IMAGE) { + coordSystem.imageCoordToCropCanvas (center.x, center.y, center_.x, center_.y); + } else if (datum == CLICKED_POINT) { + center_ += objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + // setting the color to the objet's ID + if (objectBuffer->getObjectMode() == OM_255) { + cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); + } else { + cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); + } + cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0, 2.*rtengine::RT_PI); + + if (filled) { + if (innerLineWidth > 0.) { + cr->fill_preserve(); + cr->stroke(); + } else { + cr->fill(); + } + } else { + cr->stroke(); + } + } +} + +void Line::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if ((flags & F_VISIBLE) && state != INSENSITIVE) { + RGBColor color; + + if (flags & F_AUTO_COLOR) { + color = getOuterLineColor(); + } else { + color = outerLineColor; + } + + cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_line_width( getOuterLineWidth() ); + + rtengine::Coord begin_ = begin; + rtengine::Coord end_ = end; + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen (begin.x, begin.y, begin_.x, begin_.y); + coordSystem.imageCoordToScreen (end.x, end.y, end_.x, end_.y); + } else if (datum == CLICKED_POINT) { + begin_ += objectBuffer->getDataProvider()->posScreen; + end_ += objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + begin_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + end_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + cr->move_to(begin_.x + 0.5, begin_.y + 0.5); + cr->line_to(end_.x + 0.5, end_.y + 0.5); + cr->stroke(); + } +} + +void Line::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if ((flags & F_VISIBLE) && innerLineWidth > 0.) { + if (state != INSENSITIVE) { + RGBColor color; + + if (flags & F_AUTO_COLOR) { + color = getInnerLineColor(); + } else { + color = innerLineColor; + } + + cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + } + + cr->set_line_width(innerLineWidth); + + rtengine::Coord begin_ = begin; + rtengine::Coord end_ = end; + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen (begin.x, begin.y, begin_.x, begin_.y); + coordSystem.imageCoordToScreen (end.x, end.y, end_.x, end_.y); + } else if (datum == CLICKED_POINT) { + begin_ += objectBuffer->getDataProvider()->posScreen; + end_ += objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + begin_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + end_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + cr->move_to(begin_.x + 0.5, begin_.y + 0.5); + cr->line_to(end_.x + 0.5, end_.y + 0.5); + + if (state == INSENSITIVE) { + std::valarray ds(1); + ds[0] = 4; + cr->set_source_rgba(1.0, 1.0, 1.0, 0.618); + cr->stroke_preserve(); + cr->set_source_rgba(0.0, 0.0, 0.0, 0.618); + cr->set_dash(ds, 0); + cr->stroke(); + ds.resize(0); + cr->set_dash(ds, 0); + } else { + cr->stroke(); + } + } +} + +void Line::drawToMOChannel(Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if (flags & F_HOVERABLE) { + cr->set_line_width( getMouseOverLineWidth() ); + rtengine::Coord begin_ = begin; + rtengine::Coord end_ = end; + + if (datum == IMAGE) { + coordSystem.imageCoordToCropCanvas (begin.x, begin.y, begin_.x, begin_.y); + coordSystem.imageCoordToCropCanvas (end.x, end.y, end_.x, end_.y); + } else if (datum == CLICKED_POINT) { + begin_ += objectBuffer->getDataProvider()->posScreen; + end_ += objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + begin_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + end_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + // setting the color to the objet's ID + if (objectBuffer->getObjectMode() == OM_255) { + cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); + } else { + cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); + } + cr->move_to(begin_.x + 0.5, begin_.y + 0.5); + cr->line_to(end_.x + 0.5, end_.y + 0.5); + cr->stroke(); + } +} + +void Polyline::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if ((flags & F_VISIBLE) && state != INSENSITIVE && points.size() > 1) { + RGBColor color; + + if (flags & F_AUTO_COLOR) { + color = getOuterLineColor(); + } else { + color = outerLineColor; + } + + cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_line_width( getOuterLineWidth() ); + + rtengine::Coord currPos; + + for (unsigned int i = 0; i < points.size(); ++i) { + currPos = points.at(i); + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen (points.at(i).x, points.at(i).y, currPos.x, currPos.y); + } else if (datum == CLICKED_POINT) { + currPos += objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + currPos += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + if (!i) { + cr->move_to(currPos.x + 0.5, currPos.y + 0.5); + } else { + cr->line_to(currPos.x + 0.5, currPos.y + 0.5); + } + } + + if (filled) { + cr->fill_preserve(); + cr->stroke(); + } else { + cr->stroke(); + } + } +} + +void Polyline::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if ((flags & F_VISIBLE) && points.size() > 1) { + if (state != INSENSITIVE) { + RGBColor color; + + if (flags & F_AUTO_COLOR) { + color = getInnerLineColor(); + } else { + color = innerLineColor; + } + + cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + } + + cr->set_line_width( innerLineWidth ); + + if (filled && state != INSENSITIVE) { + rtengine::Coord currPos; + + for (unsigned int i = 0; i < points.size(); ++i) { + currPos = points.at(i); + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen (points.at(i).x, points.at(i).y, currPos.x, currPos.y); + } else if (datum == CLICKED_POINT) { + currPos += objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + currPos += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + if (!i) { + cr->move_to(currPos.x + 0.5, currPos.y + 0.5); + } else { + cr->line_to(currPos.x + 0.5, currPos.y + 0.5); + } + } + + if (innerLineWidth > 0.) { + cr->fill_preserve(); + cr->stroke(); + } else { + cr->fill(); + } + } else if (innerLineWidth > 0.) { + rtengine::Coord currPos; + + for (unsigned int i = 0; i < points.size(); ++i) { + currPos = points.at(i); + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen (points.at(i).x, points.at(i).y, currPos.x, currPos.y); + } else if (datum == CLICKED_POINT) { + currPos += objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + currPos += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + if (!i) { + cr->move_to(currPos.x + 0.5, currPos.y + 0.5); + } else { + cr->line_to(currPos.x + 0.5, currPos.y + 0.5); + } + } + + if (state == INSENSITIVE) { + std::valarray ds(1); + ds[0] = 4; + cr->set_source_rgba(1.0, 1.0, 1.0, 0.618); + cr->stroke_preserve(); + cr->set_source_rgba(0.0, 0.0, 0.0, 0.618); + cr->set_dash(ds, 0); + cr->stroke(); + ds.resize(0); + cr->set_dash(ds, 0); + } else { + cr->stroke(); + } + } + } +} + +void Polyline::drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if ((flags & F_HOVERABLE) && points.size() > 1) { + rtengine::Coord currPos; + + // setting the color to the objet's ID + if (objectBuffer->getObjectMode() == OM_255) { + cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); + } else { + cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); + } + + for (unsigned int i = 0; i < points.size(); ++i) { + cr->set_line_width( getMouseOverLineWidth() ); + currPos = points.at(i); + + if (datum == IMAGE) { + coordSystem.imageCoordToCropCanvas (points.at(i).x, points.at(i).y, currPos.x, currPos.y); + } else if (datum == CLICKED_POINT) { + currPos += objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + currPos += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + if (!i) { + cr->move_to(currPos.x + 0.5, currPos.y + 0.5); + } else { + cr->line_to(currPos.x + 0.5, currPos.y + 0.5); + } + } + + if (filled) { + if (innerLineWidth > 0.) { + cr->fill_preserve(); + cr->stroke(); + } else { + cr->fill(); + } + } else { + cr->stroke(); + } + } +} + +void Rectangle::setXYWH(int left, int top, int width, int height) +{ + topLeft.set(left, top); + bottomRight.set(left + width, top + height); +} + +void Rectangle::setXYXY(int left, int top, int right, int bottom) +{ + topLeft.set(left, top); + bottomRight.set(right, bottom); +} + +void Rectangle::setXYWH(rtengine::Coord topLeft, rtengine::Coord widthHeight) +{ + this->topLeft = topLeft; + this->bottomRight = topLeft + widthHeight; +} + +void Rectangle::setXYXY(rtengine::Coord topLeft, rtengine::Coord bottomRight) +{ + this->topLeft = topLeft; + this->bottomRight = bottomRight; +} + +void Rectangle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if ((flags & F_VISIBLE) && state != INSENSITIVE) { + RGBColor color; + + if (flags & F_AUTO_COLOR) { + color = getOuterLineColor(); + } else { + color = outerLineColor; + } + + cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_line_width( getOuterLineWidth() ); + + rtengine::Coord tl, br; + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen (topLeft.x, topLeft.y, tl.x, tl.y); + } else if (datum == CLICKED_POINT) { + tl = topLeft + objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + tl = topLeft + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen (bottomRight.x, bottomRight.y, br.x, br.y); + } else if (datum == CLICKED_POINT) { + br = bottomRight + objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + br = bottomRight + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y); + + if (filled) { + cr->fill_preserve(); + cr->stroke(); + } else { + cr->stroke(); + } + } +} + +void Rectangle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if (flags & F_VISIBLE) { + if (state != INSENSITIVE) { + RGBColor color; + + if (flags & F_AUTO_COLOR) { + color = getInnerLineColor(); + } else { + color = innerLineColor; + } + + cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + } + + cr->set_line_width( innerLineWidth ); + + rtengine::Coord tl, br; + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen (topLeft.x, topLeft.y, tl.x, tl.y); + } else if (datum == CLICKED_POINT) { + tl = topLeft + objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + tl = topLeft + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen (bottomRight.x, bottomRight.y, br.x, br.y); + } else if (datum == CLICKED_POINT) { + br = bottomRight + objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + br = bottomRight + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + if (filled && state != INSENSITIVE) { + cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y); + + if (innerLineWidth > 0.) { + cr->fill_preserve(); + cr->stroke(); + } else { + cr->fill(); + } + } else if (innerLineWidth > 0.) { + cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y); + + if (state == INSENSITIVE) { + std::valarray ds(1); + ds[0] = 4; + cr->set_source_rgba(1.0, 1.0, 1.0, 0.618); + cr->stroke_preserve(); + cr->set_source_rgba(0.0, 0.0, 0.0, 0.618); + cr->set_dash(ds, 0); + cr->stroke(); + ds.resize(0); + cr->set_dash(ds, 0); + } else { + cr->stroke(); + } + } + } +} + +void Rectangle::drawToMOChannel(Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if (flags & F_HOVERABLE) { + cr->set_line_width( getMouseOverLineWidth() ); + + rtengine::Coord tl, br; + + if (datum == IMAGE) { + coordSystem.imageCoordToCropCanvas (topLeft.x, topLeft.y, tl.x, tl.y); + } else if (datum == CLICKED_POINT) { + tl = topLeft + objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + tl = topLeft + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + if (datum == IMAGE) { + coordSystem.imageCoordToCropCanvas (bottomRight.x, bottomRight.y, br.x, br.y); + } else if (datum == CLICKED_POINT) { + br = bottomRight + objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) { + br = bottomRight + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; + } + + // setting the color to the objet's ID + if (objectBuffer->getObjectMode() == OM_255) { + cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); + } else { + cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); + } + cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y); + + if (filled) { + if (innerLineWidth > 0.) { + cr->fill_preserve(); + cr->stroke(); + } else { + cr->fill(); + } + } else { + cr->stroke(); + } + } +} + +void OPIcon::drivenPointToRectangle(const rtengine::Coord &pos, + rtengine::Coord &topLeft, rtengine::Coord &bottomRight, int W, int H) +{ + switch (drivenPoint) { + case (DP_CENTERCENTER): + topLeft.x = pos.x - W / 2; + topLeft.y = pos.y - H / 2; + break; + + case (DP_TOPLEFT): + topLeft.x = pos.x; + topLeft.y = pos.y; + break; + + case (DP_TOPCENTER): + topLeft.x = pos.x - W / 2; + topLeft.y = pos.y; + break; + + case (DP_TOPRIGHT): + topLeft.x = pos.x - W; + topLeft.y = pos.y; + break; + + case (DP_CENTERRIGHT): + topLeft.x = pos.x - W; + topLeft.y = pos.y - H / 2; + break; + + case (DP_BOTTOMRIGHT): + topLeft.x = pos.x - W; + topLeft.y = pos.y - H; + break; + + case (DP_BOTTOMCENTER): + topLeft.x = pos.x - W / 2; + topLeft.y = pos.y - H; + break; + + case (DP_BOTTOMLEFT): + topLeft.x = pos.x; + topLeft.y = pos.y - H; + break; + + case (DP_CENTERLEFT): + topLeft.x = pos.x; + topLeft.y = pos.y - H / 2; + break; + } + + bottomRight.x = topLeft.x + W - 1; + bottomRight.y = topLeft.y + H - 1; +} + +OPIcon::OPIcon(const Cairo::RefPtr &normal, + const Cairo::RefPtr &active, + const Cairo::RefPtr &prelight, + const Cairo::RefPtr &dragged, + const Cairo::RefPtr &insensitive, + DrivenPoint drivenPoint) : + drivenPoint(drivenPoint) +{ + if (normal) { + normalImg = normal; + } + + if (prelight) { + prelightImg = prelight; + } + + if (active) { + activeImg = active; + } + + if (dragged) { + draggedImg = dragged; + } + + if (insensitive) { + insensitiveImg = insensitive; + } +} + +OPIcon::OPIcon(Glib::ustring normalImage, Glib::ustring activeImage, Glib::ustring prelightImage, + Glib::ustring draggedImage, Glib::ustring insensitiveImage, DrivenPoint drivenPoint) : drivenPoint(drivenPoint) +{ + if (!normalImage.empty()) { + normalImg = Cairo::RefPtr(new RTSurface(normalImage)); + } + + if (!prelightImage.empty()) { + prelightImg = Cairo::RefPtr(new RTSurface(prelightImage)); + } + + if (!activeImage.empty()) { + activeImg = Cairo::RefPtr(new RTSurface(activeImage)); + } + + if (!draggedImage.empty()) { + draggedImg = Cairo::RefPtr(new RTSurface(draggedImage)); + } + + if (!insensitiveImage.empty()) { + insensitiveImg = Cairo::RefPtr(new RTSurface(insensitiveImage)); + } +} + +const Cairo::RefPtr OPIcon::getNormalImg() +{ + return normalImg; +} +const Cairo::RefPtr OPIcon::getPrelightImg() +{ + return prelightImg; +} +const Cairo::RefPtr OPIcon::getActiveImg() +{ + return activeImg; +} +const Cairo::RefPtr OPIcon::getDraggedImg() +{ + return draggedImg; +} +const Cairo::RefPtr OPIcon::getInsensitiveImg() +{ + return insensitiveImg; +} + +void OPIcon::drawImage(Cairo::RefPtr &img, + Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, + EditCoordSystem &coordSystem) +{ + int imgW = img->getWidth(); + int imgH = img->getHeight(); + + rtengine::Coord pos; + + if (datum == IMAGE) { + coordSystem.imageCoordToScreen(position.x, position.y, pos.x, pos.y); + } else if (datum == CLICKED_POINT) { + pos = position + objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) + pos = position + objectBuffer->getDataProvider()->posScreen + + objectBuffer->getDataProvider()->deltaScreen; + + rtengine::Coord tl, br; // Coordinate of the rectangle in the CropBuffer coordinate system + drivenPointToRectangle(pos, tl, br, imgW, imgH); + + cr->set_source(img->get(), tl.x, tl.y); + cr->set_line_width(0.); + cr->rectangle(tl.x, tl.y, imgW, imgH); + cr->fill(); +} + +void OPIcon::drawMOImage(Cairo::RefPtr &img, Cairo::RefPtr &cr, + unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + // test of F_HOVERABLE has already been done + + int imgW = img->getWidth(); + int imgH = img->getHeight(); + + rtengine::Coord pos; + + if (datum == IMAGE) + coordSystem.imageCoordToCropCanvas (position.x, position.y, pos.x, pos.y); + else if (datum == CLICKED_POINT) { + pos = position + objectBuffer->getDataProvider()->posScreen; + } else if (datum == CURSOR) + pos = position + objectBuffer->getDataProvider()->posScreen + + objectBuffer->getDataProvider()->deltaScreen; + + rtengine::Coord tl, br; // Coordinate of the rectangle in the CropBuffer coordinate system + drivenPointToRectangle(pos, tl, br, imgW, imgH); + + // drawing the lower byte's value + if (objectBuffer->getObjectMode() == OM_255) { + cr->set_source_rgba (0., 0., 0., ((id + 1) & 0xFF) / 255.); + } else { + cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); + } + cr->set_line_width(0.); + cr->rectangle(tl.x, tl.y, imgW, imgH); + cr->fill(); +} + +void OPIcon::drawOuterGeometry(Cairo::RefPtr &cr, + ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) {} + +void OPIcon::drawInnerGeometry(Cairo::RefPtr &cr, + ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if (flags & F_VISIBLE) { + // Here we will handle fall-back solutions + + State tmpState = state; // can be updated through the successive test + + if (tmpState == INSENSITIVE) { + if (!insensitiveImg) { + tmpState = NORMAL; + } else { + OPIcon::drawImage(insensitiveImg, cr, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == DRAGGED) { + if (!draggedImg) { + tmpState = ACTIVE; + } else { + OPIcon::drawImage(draggedImg, cr, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == ACTIVE) { + if (!activeImg) { + tmpState = PRELIGHT; + } else { + OPIcon::drawImage(activeImg, cr, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == PRELIGHT) { + if (!prelightImg) { + tmpState = NORMAL; + } else { + OPIcon::drawImage(prelightImg, cr, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == NORMAL && normalImg) { + OPIcon::drawImage(normalImg, cr, objectBuffer, coordSystem); + } + } +} + +void OPIcon::drawToMOChannel(Cairo::RefPtr &cr, unsigned short id, + ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) +{ + if (flags & F_HOVERABLE) { + // Here we will handle fallback solutions + State tmpState = state; + + if (tmpState == INSENSITIVE) { + if (!insensitiveImg) { + tmpState = NORMAL; + } else { + OPIcon::drawMOImage(insensitiveImg, cr, id, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == DRAGGED) { + if (!draggedImg) { + tmpState = ACTIVE; + } else { + OPIcon::drawMOImage(draggedImg, cr, id, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == ACTIVE) { + if (!activeImg) { + tmpState = PRELIGHT; + } else { + OPIcon::drawMOImage(activeImg, cr, id, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == PRELIGHT) { + if (!prelightImg) { + tmpState = NORMAL; + } else { + OPIcon::drawMOImage(prelightImg, cr, id, objectBuffer, coordSystem); + return; + } + } + + if (tmpState == NORMAL && normalImg) { + OPIcon::drawMOImage(normalImg, cr, id, objectBuffer, coordSystem); + } + } +} + +#endif diff --git a/rtgui/editwidgets.h b/rtgui/editwidgets.h index ec935291e..1ae185f7a 100644 --- a/rtgui/editwidgets.h +++ b/rtgui/editwidgets.h @@ -1,542 +1,542 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2019 Jean-Christophe FRISCH - * - * 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 . - */ -#pragma once - -#ifdef GUIVERSION - -#include "rtsurface.h" -#include "editbuffer.h" -#include "editcoordsys.h" -#include "../rtengine/coord.h" - -class ObjectMOBuffer; - -/** @file - * - * The Edit mechanism is designed to let tools (subscribers) communicate with the preview area (provider). - * Subscribers will be tools that need to create some graphics in the preview area, to let the user interact - * with it in a more user friendly way. - * - * Do not confuse with _local_ editing, which is another topic implemented in another class. The Edit feature - * is also not supported in batch editing from the File Browser. - * - * Edit tool can be of 2 types: pipette editing and object editing. - * - * ## Pipette edition - * - * By using this class, a pipette mechanism can be handled on the preview. - * - * Each pipette Edit tool must have a unique ID, that will identify them, and which let the ImProcCoordinator - * or other mechanism act as appropriated. They are all defined in rtgui/editid.h. A buffer type has to be given - * too, to know which kind of buffer to allocate (see EditSubscriber::BufferType). - * - * Only the first mouse button can be used to manipulate the pipette on the Preview, that's why the developer has - * to implement at least the following 4 methods: - * - mouseOver - * - button1Pressed - * - drag1 - * - button1Released - * - * Actually, only curves does use this class, and everything is handled for curve implementor (as much as possible). - * See the curve's class documentation to see how to implement the curve's pipette feature. - * - * ### Event handling - * - * The mouseOver method is called on each mouse movement, excepted when dragging a point. This method can then access - * the pipetteVal array values, which contain the mean of the pixel read in the buffer, or -1 if the cursor is outside - * of the image. In this case, EditDataProvider::object is also set to 0 (and 1 if over the image). - * - * When the user will click on the left mouse button while pressing the CTRL key, button1Pressed will be called. - * Setting "dragging" to true (or false) is not required for the pipette type editing. - * - * The drag1 method will be called on all subsequent mouse move. The pipetteVal[3] array will already be filled with - * the mean of the read values under the cursor (actually a fixed square of 8px). If the BufferType is BT_SINGLEPLANE_FLOAT, - * only the first array value will be filled. - * - * Then the button1Released will be called to stop the dragging. - * - * ## Object edition - * - * By using this class, objects can be drawn and manipulated on the preview. - * - * The developer has to handle the buttonPress, buttonRelease, drag and mouseOver methods that he needs. There - * are buttonPress, buttonRelease and drag methods dedicated to each mouse button, for better flexibility - * (e.g.button2Press, button2Release, drag2 will handle event when mouse button 2 is used first). RT actually - * does not handle multiple mouse button event (e.g. button1 + button2), only one at a time. The first button pressed - * set the mechanism, all other combined button press are ignored. - * - * The developer also have to fill 2 display list with object of the Geometry subclass. Each geometric shape - * _can_ be used in one or the other, or both list at a time. - * - * The first list (visibleGeometry) is used to be displayed on the preview. The developer will have to set their state - * manually (see Geometry::State), but the display shape, line width and color can be handled automatically, or with - * specific values. To be displayed, the F_VISIBLE flag has to be set through the setActive or setVisible methods. - * - * The second list (mouseOverGeometry) is used in a backbuffer, the color used to draw the shape being the id of the - * mouseOverGeometry. As an example, you could create a line to be shown in the preview, but create 2 filled Circle object - * to be used as mouseOver detection, one on each end of the line. The association between both shape (visible and mouseOver) - * is handled by the developer. To be displayed on this backbuffer, the F_HOVERABLE flag has to be set through the - * setActive or setHoverable methods. For overlapping mouse over geometry, the priority is set by the order in the list : - * the last item is detected first (think of it like a stack piled up). - * - * - * ### Event handling - * - * RT will draw in the back buffer all mouseOverGeometry set by the developer once the Edit button is pressed, and handle - * the events automatically. - * - * RT will call the mouseOver method on each mouse movement where no mouse button is pressed. - * - * On mouse button press over a mouseOverGeometry (that has F_HOVERABLE set), it will call the button press method corresponding - * to the button (e.g. button1Pressed for mouse button 1), with the modifier key as parameter. Any other mouse button pressed at - * the same time will be ignored. It's up to the developer to decide whether this action is starting a 'drag' or 'pick' action, - * by setting the 'action' parameter to the appropriated value. - * - * If the user sets action to ES_ACTION_DRAGGING, RT will then send drag1 events (to stay with our button 1 pressed example) on each - * mouse movement. It's up to the developer of the tool to handle the dragging. The EditProvider class will help you in this by - * handling the actual position in various coordinate system and ways. - * - * When the user will release the mouse button, RT will call the button1Release event (in our example). The developer have - * then to set action to ES_ACTION_NONE. - * - * If the user sets action to ES_ACTION_PICKING, RT will keep in memory the mouseOver object that was selected when pressing the mouse - * (e.g. button 1), as well as the modifier keys. - * - * The element is said to be picked when the mouse button is released over the same mouse over object and with the same active - * modifier keys. In this case, the corresponding picked event (e.g. picked1 in our example) and the 'picked' flag will be true. - * If any of those condition is false, picked1 will still be be called to terminate the initiated picking action, but 'picked' - * will be false. This is necessary because the user may want to update the geometry if the picking is aborted. The developer have - * then to set action to ES_ACTION_NONE. - * - * Picking an on-screen element correspond to single-clicking on it. No double click is supported so far. - * - * Each of these methods have to returns a boolean value saying that the preview has to be refreshed or not (i.e. the displayed - * geometry). - * - * ## Other general internal implementation notes - * - * When a tool is being constructed, unique IDs are affected to the EditSubscribers of the Pipette type. - * Then the EditorPanel class will ask all ToolPanel to register the 'after' preview ImageArea object as data provider. - * The Subscribers have now to provide a toggle button to click on to start the Edit listening. When toggling on, the Subscriber - * register itself to the DataProvider, then an event is thrown through the standard ToolPanelListener::panelChanged - * method to update the preview with new graphics to be displayed. If a previous Edit button was active, it will be deactivated - * (the Edit buttons are mutually exclusive). For the Pipette type, a buffer will be created and has to be populated - * by the developer in rtengine's pipeline. The unique pipette ID will be used to know where to fill the buffer, as each pipette - * will need different data, corresponding to the state of the image right before the tool that needs pipette values. E.g for - * the HSV tool, the Hue and Saturation and Value curves are applied on the current state of the image. That's why the pipette - * of the H, S and V curve will share the same data of this "current state", otherwise the read value would be wrong. - * - * When the Edit process stops, the Subscriber is removed from the DataProvider, so buffers can be freed up. - * A new ToolPanelListener::panelChanged event is also thrown to update the preview again, without the tool's - * graphical objects. The Edit button is also toggled off (by the user or programmatically). - * - * It means that each Edit buttons toggled on will start an update of the preview which might or might not create - * a new History entry, depending on the ProcEvent used. - * - */ - -class RGBColor -{ - double r; - double g; - double b; - -public: - RGBColor (); - explicit RGBColor (double r, double g, double b); - explicit RGBColor (char r, char g, char b); - - void setColor (double r, double g, double b); - void setColor (char r, char g, char b); - - double getR (); - double getG (); - double getB (); -}; - -class RGBAColor : public RGBColor -{ - double a; - -public: - RGBAColor (); - explicit RGBAColor (double r, double g, double b, double a); - explicit RGBAColor (char r, char g, char b, char a); - - void setColor (double r, double g, double b, double a); - void setColor (char r, char g, char b, char a); - - double getA (); -}; - -/// @brief Displayable and MouseOver geometry base class -class Geometry -{ -public: - /// @brief Graphical state of the element - enum State { - NORMAL, /// Default state - ACTIVE, /// Focused state - PRELIGHT, /// Hovered state - DRAGGED, /// When being dragged - INSENSITIVE /// Displayed but insensitive - }; - - /// @brief Coordinate space and origin of the point - enum Datum { - IMAGE, /// Image coordinate system with image's top left corner as origin - CLICKED_POINT, /// Screen coordinate system with clicked point as origin - CURSOR /// Screen coordinate system with actual cursor position as origin - }; - enum Flags { - F_VISIBLE = 1 << 0, /// true if the geometry have to be drawn on the visible layer - F_HOVERABLE = 1 << 1, /// true if the geometry have to be drawn on the "mouse over" layer - F_AUTO_COLOR = 1 << 2, /// true if the color depend on the state value, not the color field above - }; - - /// @brief Key point of the image's rectangle that is used to locate the icon copy to the target point: - enum DrivenPoint { - DP_CENTERCENTER, - DP_TOPLEFT, - DP_TOPCENTER, - DP_TOPRIGHT, - DP_CENTERRIGHT, - DP_BOTTOMRIGHT, - DP_BOTTOMCENTER, - DP_BOTTOMLEFT, - DP_CENTERLEFT - }; - -protected: - RGBColor innerLineColor; - RGBColor outerLineColor; - short flags; - -public: - float innerLineWidth; // ...outerLineWidth = innerLineWidth+2 - Datum datum; - State state; // set by the Subscriber - - Geometry (); - virtual ~Geometry() {} - - void setInnerLineColor (double r, double g, double b); - void setInnerLineColor (char r, char g, char b); - RGBColor getInnerLineColor (); - void setOuterLineColor (double r, double g, double b); - void setOuterLineColor (char r, char g, char b); - RGBColor getOuterLineColor (); - double getOuterLineWidth (); - double getMouseOverLineWidth (); - void setAutoColor (bool aColor); - bool isVisible (); - void setVisible (bool visible); - bool isHoverable (); - void setHoverable (bool visible); - - - // setActive will enable/disable the visible and hoverable flags in one shot! - void setActive (bool active); - - virtual void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) = 0; - virtual void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) = 0; - virtual void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) = 0; -}; - -class Circle : public Geometry -{ -public: - rtengine::Coord center; - int radius; - bool filled; - bool radiusInImageSpace; /// If true, the radius depend on the image scale; if false, it is a fixed 'screen' size - - Circle (); - Circle (rtengine::Coord& center, int radius, bool filled = false, bool radiusInImageSpace = false); - Circle (int centerX, int centerY, int radius, bool filled = false, bool radiusInImageSpace = false); - - void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; - void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; - void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; -}; - -class Line : public Geometry -{ -public: - rtengine::Coord begin; - rtengine::Coord end; - - Line (); - Line (rtengine::Coord& begin, rtengine::Coord& end); - Line (int beginX, int beginY, int endX, int endY); - - void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; - void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; - void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; -}; - -class Polyline : public Geometry -{ -public: - std::vector points; - bool filled; - - Polyline (); - - void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; - void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; - void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; -}; - -class Rectangle : public Geometry -{ -public: - rtengine::Coord topLeft; - rtengine::Coord bottomRight; - bool filled; - - Rectangle (); - - void setXYWH(int left, int top, int width, int height); - void setXYXY(int left, int top, int right, int bottom); - void setXYWH(rtengine::Coord topLeft, rtengine::Coord widthHeight); - void setXYXY(rtengine::Coord topLeft, rtengine::Coord bottomRight); - void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; - void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; - void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; -}; - -class OPIcon : public Geometry // OP stands for "On Preview" -{ - -private: - Cairo::RefPtr normalImg; - Cairo::RefPtr prelightImg; - Cairo::RefPtr activeImg; - Cairo::RefPtr draggedImg; - Cairo::RefPtr insensitiveImg; - - static void updateImages(); - void changeImage(Glib::ustring &newImage); - void drawImage (Cairo::RefPtr &img, Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); - void drawMOImage (Cairo::RefPtr &img, Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); - void drivenPointToRectangle(const rtengine::Coord &pos, rtengine::Coord &topLeft, rtengine::Coord &bottomRight, int W, int H); - -public: - DrivenPoint drivenPoint; - rtengine::Coord position; - - OPIcon (const Cairo::RefPtr &normal, - const Cairo::RefPtr &active, - const Cairo::RefPtr &prelight = {}, - const Cairo::RefPtr &dragged = {}, - const Cairo::RefPtr &insensitive = {}, - DrivenPoint drivenPoint = DP_CENTERCENTER); - OPIcon (Glib::ustring normalImage, Glib::ustring activeImage, Glib::ustring prelightImage = "", Glib::ustring draggedImage = "", Glib::ustring insensitiveImage = "", DrivenPoint drivenPoint = DP_CENTERCENTER); - const Cairo::RefPtr getNormalImg(); - const Cairo::RefPtr getPrelightImg(); - const Cairo::RefPtr getActiveImg(); - const Cairo::RefPtr getDraggedImg(); - const Cairo::RefPtr getInsensitiveImg(); - void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; - void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; - void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; -}; - -class OPAdjuster : public Geometry // OP stands for "On Preview" -{ - -}; - -inline void RGBColor::setColor (double r, double g, double b) { - this->r = r; - this->g = g; - this->b = b; -} - -inline void RGBColor::setColor (char r, char g, char b) { - this->r = double (r) / 255.; - this->g = double (g) / 255.; - this->b = double (b) / 255.; -} - -inline double RGBColor::getR () { - return r; -} - -inline double RGBColor::getG () { - return g; -} - -inline double RGBColor::getB () { - return b; -} - -inline void RGBAColor::setColor (double r, double g, double b, double a) { - RGBColor::setColor (r, g, b); - this->a = a; -} - -inline void RGBAColor::setColor (char r, char g, char b, char a) { - RGBColor::setColor (r, g, b); - this->a = double (a) / 255.; -} - -inline double RGBAColor::getA () { - return a; -} - -inline void Geometry::setInnerLineColor (double r, double g, double b) { - innerLineColor.setColor (r, g, b); - flags &= ~F_AUTO_COLOR; -} - -inline void Geometry::setInnerLineColor (char r, char g, char b) { - innerLineColor.setColor (r, g, b); - flags &= ~F_AUTO_COLOR; -} - -inline void Geometry::setOuterLineColor (double r, double g, double b) { - outerLineColor.setColor (r, g, b); - flags &= ~F_AUTO_COLOR; -} - -inline double Geometry::getOuterLineWidth () { - return double (innerLineWidth) + 2.; -} - -inline void Geometry::setOuterLineColor (char r, char g, char b) { - outerLineColor.setColor (r, g, b); - flags &= ~F_AUTO_COLOR; -} - -inline double Geometry::getMouseOverLineWidth () { - return getOuterLineWidth () + 2.; -} - -inline void Geometry::setAutoColor (bool aColor) { - if (aColor) { - flags |= F_AUTO_COLOR; - } else { - flags &= ~F_AUTO_COLOR; - } -} - -inline bool Geometry::isVisible () { - return flags & F_VISIBLE; -} - -inline void Geometry::setVisible (bool visible) { - if (visible) { - flags |= F_VISIBLE; - } else { - flags &= ~F_VISIBLE; - } -} - -inline bool Geometry::isHoverable () { - return flags & F_HOVERABLE; -} - -inline void Geometry::setHoverable (bool hoverable) { - if (hoverable) { - flags |= F_HOVERABLE; - } else { - flags &= ~F_HOVERABLE; - } -} - -inline void Geometry::setActive (bool active) { - if (active) { - flags |= (F_VISIBLE | F_HOVERABLE); - } else { - flags &= ~(F_VISIBLE | F_HOVERABLE); - } -} - -inline Geometry::Geometry () : - innerLineColor (char (255), char (255), char (255)), outerLineColor ( - char (0), char (0), char (0)), flags ( - F_VISIBLE | F_HOVERABLE | F_AUTO_COLOR), innerLineWidth (1.5f), datum ( - IMAGE), state (NORMAL) { -} - -inline RGBAColor::RGBAColor () : - RGBColor (0., 0., 0.), a (0.) { -} - -inline RGBColor::RGBColor () : - r (0.), g (0.), b (0.) { -} - -inline RGBColor::RGBColor (double r, double g, double b) : - r (r), g (g), b (b) { -} - -inline RGBColor::RGBColor (char r, char g, char b) : - r (double (r) / 255.), g (double (g) / 255.), b (double (b) / 255.) { -} - -inline RGBAColor::RGBAColor (double r, double g, double b, double a) : - RGBColor (r, g, b), a (a) { -} - -inline RGBAColor::RGBAColor (char r, char g, char b, char a) : - RGBColor (r, g, b), a (double (a) / 255.) { -} - -inline Circle::Circle () : - center (100, 100), radius (10), filled (false), radiusInImageSpace ( - false) { -} - -inline Rectangle::Rectangle () : - topLeft (0, 0), bottomRight (10, 10), filled (false) { -} - -inline Polyline::Polyline () : - filled (false) { -} - -inline Line::Line () : - begin (10, 10), end (100, 100) { -} - -inline Circle::Circle (rtengine::Coord& center, int radius, bool filled, - bool radiusInImageSpace) : - center (center), radius (radius), filled (filled), radiusInImageSpace ( - radiusInImageSpace) { -} - -inline Circle::Circle (int centerX, int centerY, int radius, bool filled, - bool radiusInImageSpace) : - center (centerX, centerY), radius (radius), filled (filled), radiusInImageSpace ( - radiusInImageSpace) { -} - -inline Line::Line (rtengine::Coord& begin, rtengine::Coord& end) : - begin (begin), end (end) { -} - -inline Line::Line (int beginX, int beginY, int endX, int endY) : - begin (beginX, beginY), end (endX, endY) { -} - -#endif - +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2019 Jean-Christophe FRISCH + * + * 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 . + */ +#pragma once + +#ifdef GUIVERSION + +#include "rtsurface.h" +#include "editbuffer.h" +#include "editcoordsys.h" +#include "../rtengine/coord.h" + +class ObjectMOBuffer; + +/** @file + * + * The Edit mechanism is designed to let tools (subscribers) communicate with the preview area (provider). + * Subscribers will be tools that need to create some graphics in the preview area, to let the user interact + * with it in a more user friendly way. + * + * Do not confuse with _local_ editing, which is another topic implemented in another class. The Edit feature + * is also not supported in batch editing from the File Browser. + * + * Edit tool can be of 2 types: pipette editing and object editing. + * + * ## Pipette edition + * + * By using this class, a pipette mechanism can be handled on the preview. + * + * Each pipette Edit tool must have a unique ID, that will identify them, and which let the ImProcCoordinator + * or other mechanism act as appropriated. They are all defined in rtgui/editid.h. A buffer type has to be given + * too, to know which kind of buffer to allocate (see EditSubscriber::BufferType). + * + * Only the first mouse button can be used to manipulate the pipette on the Preview, that's why the developer has + * to implement at least the following 4 methods: + * - mouseOver + * - button1Pressed + * - drag1 + * - button1Released + * + * Actually, only curves does use this class, and everything is handled for curve implementor (as much as possible). + * See the curve's class documentation to see how to implement the curve's pipette feature. + * + * ### Event handling + * + * The mouseOver method is called on each mouse movement, excepted when dragging a point. This method can then access + * the pipetteVal array values, which contain the mean of the pixel read in the buffer, or -1 if the cursor is outside + * of the image. In this case, EditDataProvider::object is also set to 0 (and 1 if over the image). + * + * When the user will click on the left mouse button while pressing the CTRL key, button1Pressed will be called. + * Setting "dragging" to true (or false) is not required for the pipette type editing. + * + * The drag1 method will be called on all subsequent mouse move. The pipetteVal[3] array will already be filled with + * the mean of the read values under the cursor (actually a fixed square of 8px). If the BufferType is BT_SINGLEPLANE_FLOAT, + * only the first array value will be filled. + * + * Then the button1Released will be called to stop the dragging. + * + * ## Object edition + * + * By using this class, objects can be drawn and manipulated on the preview. + * + * The developer has to handle the buttonPress, buttonRelease, drag and mouseOver methods that he needs. There + * are buttonPress, buttonRelease and drag methods dedicated to each mouse button, for better flexibility + * (e.g.button2Press, button2Release, drag2 will handle event when mouse button 2 is used first). RT actually + * does not handle multiple mouse button event (e.g. button1 + button2), only one at a time. The first button pressed + * set the mechanism, all other combined button press are ignored. + * + * The developer also have to fill 2 display list with object of the Geometry subclass. Each geometric shape + * _can_ be used in one or the other, or both list at a time. + * + * The first list (visibleGeometry) is used to be displayed on the preview. The developer will have to set their state + * manually (see Geometry::State), but the display shape, line width and color can be handled automatically, or with + * specific values. To be displayed, the F_VISIBLE flag has to be set through the setActive or setVisible methods. + * + * The second list (mouseOverGeometry) is used in a backbuffer, the color used to draw the shape being the id of the + * mouseOverGeometry. As an example, you could create a line to be shown in the preview, but create 2 filled Circle object + * to be used as mouseOver detection, one on each end of the line. The association between both shape (visible and mouseOver) + * is handled by the developer. To be displayed on this backbuffer, the F_HOVERABLE flag has to be set through the + * setActive or setHoverable methods. For overlapping mouse over geometry, the priority is set by the order in the list : + * the last item is detected first (think of it like a stack piled up). + * + * + * ### Event handling + * + * RT will draw in the back buffer all mouseOverGeometry set by the developer once the Edit button is pressed, and handle + * the events automatically. + * + * RT will call the mouseOver method on each mouse movement where no mouse button is pressed. + * + * On mouse button press over a mouseOverGeometry (that has F_HOVERABLE set), it will call the button press method corresponding + * to the button (e.g. button1Pressed for mouse button 1), with the modifier key as parameter. Any other mouse button pressed at + * the same time will be ignored. It's up to the developer to decide whether this action is starting a 'drag' or 'pick' action, + * by setting the 'action' parameter to the appropriated value. + * + * If the user sets action to ES_ACTION_DRAGGING, RT will then send drag1 events (to stay with our button 1 pressed example) on each + * mouse movement. It's up to the developer of the tool to handle the dragging. The EditProvider class will help you in this by + * handling the actual position in various coordinate system and ways. + * + * When the user will release the mouse button, RT will call the button1Release event (in our example). The developer have + * then to set action to ES_ACTION_NONE. + * + * If the user sets action to ES_ACTION_PICKING, RT will keep in memory the mouseOver object that was selected when pressing the mouse + * (e.g. button 1), as well as the modifier keys. + * + * The element is said to be picked when the mouse button is released over the same mouse over object and with the same active + * modifier keys. In this case, the corresponding picked event (e.g. picked1 in our example) and the 'picked' flag will be true. + * If any of those condition is false, picked1 will still be be called to terminate the initiated picking action, but 'picked' + * will be false. This is necessary because the user may want to update the geometry if the picking is aborted. The developer have + * then to set action to ES_ACTION_NONE. + * + * Picking an on-screen element correspond to single-clicking on it. No double click is supported so far. + * + * Each of these methods have to returns a boolean value saying that the preview has to be refreshed or not (i.e. the displayed + * geometry). + * + * ## Other general internal implementation notes + * + * When a tool is being constructed, unique IDs are affected to the EditSubscribers of the Pipette type. + * Then the EditorPanel class will ask all ToolPanel to register the 'after' preview ImageArea object as data provider. + * The Subscribers have now to provide a toggle button to click on to start the Edit listening. When toggling on, the Subscriber + * register itself to the DataProvider, then an event is thrown through the standard ToolPanelListener::panelChanged + * method to update the preview with new graphics to be displayed. If a previous Edit button was active, it will be deactivated + * (the Edit buttons are mutually exclusive). For the Pipette type, a buffer will be created and has to be populated + * by the developer in rtengine's pipeline. The unique pipette ID will be used to know where to fill the buffer, as each pipette + * will need different data, corresponding to the state of the image right before the tool that needs pipette values. E.g for + * the HSV tool, the Hue and Saturation and Value curves are applied on the current state of the image. That's why the pipette + * of the H, S and V curve will share the same data of this "current state", otherwise the read value would be wrong. + * + * When the Edit process stops, the Subscriber is removed from the DataProvider, so buffers can be freed up. + * A new ToolPanelListener::panelChanged event is also thrown to update the preview again, without the tool's + * graphical objects. The Edit button is also toggled off (by the user or programmatically). + * + * It means that each Edit buttons toggled on will start an update of the preview which might or might not create + * a new History entry, depending on the ProcEvent used. + * + */ + +class RGBColor +{ + double r; + double g; + double b; + +public: + RGBColor (); + explicit RGBColor (double r, double g, double b); + explicit RGBColor (char r, char g, char b); + + void setColor (double r, double g, double b); + void setColor (char r, char g, char b); + + double getR (); + double getG (); + double getB (); +}; + +class RGBAColor : public RGBColor +{ + double a; + +public: + RGBAColor (); + explicit RGBAColor (double r, double g, double b, double a); + explicit RGBAColor (char r, char g, char b, char a); + + void setColor (double r, double g, double b, double a); + void setColor (char r, char g, char b, char a); + + double getA (); +}; + +/// @brief Displayable and MouseOver geometry base class +class Geometry +{ +public: + /// @brief Graphical state of the element + enum State { + NORMAL, /// Default state + ACTIVE, /// Focused state + PRELIGHT, /// Hovered state + DRAGGED, /// When being dragged + INSENSITIVE /// Displayed but insensitive + }; + + /// @brief Coordinate space and origin of the point + enum Datum { + IMAGE, /// Image coordinate system with image's top left corner as origin + CLICKED_POINT, /// Screen coordinate system with clicked point as origin + CURSOR /// Screen coordinate system with actual cursor position as origin + }; + enum Flags { + F_VISIBLE = 1 << 0, /// true if the geometry have to be drawn on the visible layer + F_HOVERABLE = 1 << 1, /// true if the geometry have to be drawn on the "mouse over" layer + F_AUTO_COLOR = 1 << 2, /// true if the color depend on the state value, not the color field above + }; + + /// @brief Key point of the image's rectangle that is used to locate the icon copy to the target point: + enum DrivenPoint { + DP_CENTERCENTER, + DP_TOPLEFT, + DP_TOPCENTER, + DP_TOPRIGHT, + DP_CENTERRIGHT, + DP_BOTTOMRIGHT, + DP_BOTTOMCENTER, + DP_BOTTOMLEFT, + DP_CENTERLEFT + }; + +protected: + RGBColor innerLineColor; + RGBColor outerLineColor; + short flags; + +public: + float innerLineWidth; // ...outerLineWidth = innerLineWidth+2 + Datum datum; + State state; // set by the Subscriber + + Geometry (); + virtual ~Geometry() {} + + void setInnerLineColor (double r, double g, double b); + void setInnerLineColor (char r, char g, char b); + RGBColor getInnerLineColor (); + void setOuterLineColor (double r, double g, double b); + void setOuterLineColor (char r, char g, char b); + RGBColor getOuterLineColor (); + double getOuterLineWidth (); + double getMouseOverLineWidth (); + void setAutoColor (bool aColor); + bool isVisible (); + void setVisible (bool visible); + bool isHoverable (); + void setHoverable (bool visible); + + + // setActive will enable/disable the visible and hoverable flags in one shot! + void setActive (bool active); + + virtual void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) = 0; + virtual void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) = 0; + virtual void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) = 0; +}; + +class Circle : public Geometry +{ +public: + rtengine::Coord center; + int radius; + bool filled; + bool radiusInImageSpace; /// If true, the radius depend on the image scale; if false, it is a fixed 'screen' size + + Circle (); + Circle (rtengine::Coord& center, int radius, bool filled = false, bool radiusInImageSpace = false); + Circle (int centerX, int centerY, int radius, bool filled = false, bool radiusInImageSpace = false); + + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; +}; + +class Line : public Geometry +{ +public: + rtengine::Coord begin; + rtengine::Coord end; + + Line (); + Line (rtengine::Coord& begin, rtengine::Coord& end); + Line (int beginX, int beginY, int endX, int endY); + + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; +}; + +class Polyline : public Geometry +{ +public: + std::vector points; + bool filled; + + Polyline (); + + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; +}; + +class Rectangle : public Geometry +{ +public: + rtengine::Coord topLeft; + rtengine::Coord bottomRight; + bool filled; + + Rectangle (); + + void setXYWH(int left, int top, int width, int height); + void setXYXY(int left, int top, int right, int bottom); + void setXYWH(rtengine::Coord topLeft, rtengine::Coord widthHeight); + void setXYXY(rtengine::Coord topLeft, rtengine::Coord bottomRight); + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; +}; + +class OPIcon : public Geometry // OP stands for "On Preview" +{ + +private: + Cairo::RefPtr normalImg; + Cairo::RefPtr prelightImg; + Cairo::RefPtr activeImg; + Cairo::RefPtr draggedImg; + Cairo::RefPtr insensitiveImg; + + static void updateImages(); + void changeImage(Glib::ustring &newImage); + void drawImage (Cairo::RefPtr &img, Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drawMOImage (Cairo::RefPtr &img, Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem); + void drivenPointToRectangle(const rtengine::Coord &pos, rtengine::Coord &topLeft, rtengine::Coord &bottomRight, int W, int H); + +public: + DrivenPoint drivenPoint; + rtengine::Coord position; + + OPIcon (const Cairo::RefPtr &normal, + const Cairo::RefPtr &active, + const Cairo::RefPtr &prelight = {}, + const Cairo::RefPtr &dragged = {}, + const Cairo::RefPtr &insensitive = {}, + DrivenPoint drivenPoint = DP_CENTERCENTER); + OPIcon (Glib::ustring normalImage, Glib::ustring activeImage, Glib::ustring prelightImage = "", Glib::ustring draggedImage = "", Glib::ustring insensitiveImage = "", DrivenPoint drivenPoint = DP_CENTERCENTER); + const Cairo::RefPtr getNormalImg(); + const Cairo::RefPtr getPrelightImg(); + const Cairo::RefPtr getActiveImg(); + const Cairo::RefPtr getDraggedImg(); + const Cairo::RefPtr getInsensitiveImg(); + void drawOuterGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; + void drawInnerGeometry (Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; + void drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) override; +}; + +class OPAdjuster : public Geometry // OP stands for "On Preview" +{ + +}; + +inline void RGBColor::setColor (double r, double g, double b) { + this->r = r; + this->g = g; + this->b = b; +} + +inline void RGBColor::setColor (char r, char g, char b) { + this->r = double (r) / 255.; + this->g = double (g) / 255.; + this->b = double (b) / 255.; +} + +inline double RGBColor::getR () { + return r; +} + +inline double RGBColor::getG () { + return g; +} + +inline double RGBColor::getB () { + return b; +} + +inline void RGBAColor::setColor (double r, double g, double b, double a) { + RGBColor::setColor (r, g, b); + this->a = a; +} + +inline void RGBAColor::setColor (char r, char g, char b, char a) { + RGBColor::setColor (r, g, b); + this->a = double (a) / 255.; +} + +inline double RGBAColor::getA () { + return a; +} + +inline void Geometry::setInnerLineColor (double r, double g, double b) { + innerLineColor.setColor (r, g, b); + flags &= ~F_AUTO_COLOR; +} + +inline void Geometry::setInnerLineColor (char r, char g, char b) { + innerLineColor.setColor (r, g, b); + flags &= ~F_AUTO_COLOR; +} + +inline void Geometry::setOuterLineColor (double r, double g, double b) { + outerLineColor.setColor (r, g, b); + flags &= ~F_AUTO_COLOR; +} + +inline double Geometry::getOuterLineWidth () { + return double (innerLineWidth) + 2.; +} + +inline void Geometry::setOuterLineColor (char r, char g, char b) { + outerLineColor.setColor (r, g, b); + flags &= ~F_AUTO_COLOR; +} + +inline double Geometry::getMouseOverLineWidth () { + return getOuterLineWidth () + 2.; +} + +inline void Geometry::setAutoColor (bool aColor) { + if (aColor) { + flags |= F_AUTO_COLOR; + } else { + flags &= ~F_AUTO_COLOR; + } +} + +inline bool Geometry::isVisible () { + return flags & F_VISIBLE; +} + +inline void Geometry::setVisible (bool visible) { + if (visible) { + flags |= F_VISIBLE; + } else { + flags &= ~F_VISIBLE; + } +} + +inline bool Geometry::isHoverable () { + return flags & F_HOVERABLE; +} + +inline void Geometry::setHoverable (bool hoverable) { + if (hoverable) { + flags |= F_HOVERABLE; + } else { + flags &= ~F_HOVERABLE; + } +} + +inline void Geometry::setActive (bool active) { + if (active) { + flags |= (F_VISIBLE | F_HOVERABLE); + } else { + flags &= ~(F_VISIBLE | F_HOVERABLE); + } +} + +inline Geometry::Geometry () : + innerLineColor (char (255), char (255), char (255)), outerLineColor ( + char (0), char (0), char (0)), flags ( + F_VISIBLE | F_HOVERABLE | F_AUTO_COLOR), innerLineWidth (1.5f), datum ( + IMAGE), state (NORMAL) { +} + +inline RGBAColor::RGBAColor () : + RGBColor (0., 0., 0.), a (0.) { +} + +inline RGBColor::RGBColor () : + r (0.), g (0.), b (0.) { +} + +inline RGBColor::RGBColor (double r, double g, double b) : + r (r), g (g), b (b) { +} + +inline RGBColor::RGBColor (char r, char g, char b) : + r (double (r) / 255.), g (double (g) / 255.), b (double (b) / 255.) { +} + +inline RGBAColor::RGBAColor (double r, double g, double b, double a) : + RGBColor (r, g, b), a (a) { +} + +inline RGBAColor::RGBAColor (char r, char g, char b, char a) : + RGBColor (r, g, b), a (double (a) / 255.) { +} + +inline Circle::Circle () : + center (100, 100), radius (10), filled (false), radiusInImageSpace ( + false) { +} + +inline Rectangle::Rectangle () : + topLeft (0, 0), bottomRight (10, 10), filled (false) { +} + +inline Polyline::Polyline () : + filled (false) { +} + +inline Line::Line () : + begin (10, 10), end (100, 100) { +} + +inline Circle::Circle (rtengine::Coord& center, int radius, bool filled, + bool radiusInImageSpace) : + center (center), radius (radius), filled (filled), radiusInImageSpace ( + radiusInImageSpace) { +} + +inline Circle::Circle (int centerX, int centerY, int radius, bool filled, + bool radiusInImageSpace) : + center (centerX, centerY), radius (radius), filled (filled), radiusInImageSpace ( + radiusInImageSpace) { +} + +inline Line::Line (rtengine::Coord& begin, rtengine::Coord& end) : + begin (begin), end (end) { +} + +inline Line::Line (int beginX, int beginY, int endX, int endY) : + begin (beginX, beginY), end (endX, endY) { +} + +#endif + From 4d43dd7e09da6df3350f097e1f06563a89a42a43 Mon Sep 17 00:00:00 2001 From: Hombre Date: Thu, 1 Aug 2019 01:50:47 +0200 Subject: [PATCH 006/135] Bugfixing crash when reprocessing the preview --- rtengine/improccoordinator.cc | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 63d6127b9..f27fafad6 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -525,16 +525,20 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) progress ("Spot Removal...", 100 * readyphase / numofphases); - if ((todo & M_SPOT) && params->spot.enabled && !params->spot.entries.empty ()) { - // First update the image with spot healing - ipf.removeSpots (oprevi, params->spot.entries, previewProps); + if (params->spot.enabled && !params->spot.entries.empty ()) { + if ((todo & M_SPOT)) { + // First update the image with spot healing + ipf.removeSpots (oprevi, params->spot.entries, previewProps); - // Then create fork the image to cache the data - if (spot_prev == nullptr) { - spot_prev = new Imagefloat (pW, pH); + // Then fork the image to cache the data + if (spot_prev == nullptr) { + spot_prev = new Imagefloat (pW, pH); + } + oprevi->copyData (spot_prev); + } + if (spot_prev) { + oprevi = spot_prev; } - - oprevi->copyData (spot_prev); } else { if (spot_prev) { delete spot_prev; @@ -1125,7 +1129,7 @@ void ImProcCoordinator::setScale(int prevscale) pH = nH; orig_prev = new Imagefloat(pW, pH); - spot_prev = oprevi = orig_prev; + oprevi = orig_prev; oprevl = new LabImage(pW, pH); nprevl = new LabImage(pW, pH); //ncie is only used in ImProcCoordinator::updatePreviewImage, it will be allocated on first use and deleted if not used anymore From 7d310e688c9837d31c262678df3c71a278ce11f0 Mon Sep 17 00:00:00 2001 From: Hombre Date: Sun, 4 Aug 2019 16:07:35 +0200 Subject: [PATCH 007/135] Adding a new spot adjust editing mode in rtengine / preview window --- rtdata/languages/Francais | 4 +- rtdata/languages/default | 15 ++-- rtengine/dcrop.cc | 56 +++++++++------ rtengine/improccoordinator.cc | 128 +++++++++++++++++++++++----------- rtengine/improccoordinator.h | 5 +- rtengine/procevents.h | 4 +- rtengine/refreshmap.cc | 6 +- rtengine/refreshmap.h | 21 +++--- rtgui/spot.cc | 32 ++++++--- rtgui/spot.h | 8 +++ rtgui/toolpanel.h | 4 ++ rtgui/toolpanelcoord.cc | 13 ++++ rtgui/toolpanelcoord.h | 1 + 13 files changed, 198 insertions(+), 99 deletions(-) diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index dfa2e7ff3..8011b9189 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -474,7 +474,7 @@ HISTORY_MSG_232;N&B - Type de courbe 'Avant' HISTORY_MSG_233;N&B - Courbe 'Après' HISTORY_MSG_234;N&B - Type de courbe 'Après' HISTORY_MSG_235;N&B - Mixeur de Canaux - Auto -HISTORY_MSG_236;Retrait de taches - Modif. de points +HISTORY_MSG_236;--inutilisé-- HISTORY_MSG_237;N&B - Mixeur de Canaux HISTORY_MSG_238;FD - Étendu HISTORY_MSG_239;FD - Force @@ -764,6 +764,8 @@ HISTORY_MSG_SHARPENING_CONTRAST;Netteté - Seuil de contraste HISTORY_MSG_SH_COLORSPACE;O/HL - Espace couleur HISTORY_MSG_SOFTLIGHT_ENABLED;Lumière douce HISTORY_MSG_SOFTLIGHT_STRENGTH;Lumière douce - Force +HISTORY_MSG_SPOT;Retrait de taches +HISTORY_MSG_SPOT_ENTRY;Retrait de taches - Modif. de points HISTORY_MSG_TM_FATTAL_ANCHOR;CPD - Ancre HISTORY_NEWSNAPSHOT;Ajouter HISTORY_NEWSNAPSHOT_TOOLTIP;Raccourci: Alt-s diff --git a/rtdata/languages/default b/rtdata/languages/default index e065abd7f..3296a4c84 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -75,6 +75,7 @@ EXIFPANEL_RESET;Reset EXIFPANEL_RESETALL;Reset All EXIFPANEL_RESETALLHINT;Reset all tags to their original values. EXIFPANEL_RESETHINT;Reset the selected tags to their original values. +EXIFPANEL_SHOWALL;Show all EXIFPANEL_SUBDIRECTORY;Subdirectory EXPORT_BYPASS;Processing steps to bypass EXPORT_BYPASS_ALL;Select / Unselect All @@ -283,9 +284,9 @@ HISTORY_MSG_30;RLD - Radius HISTORY_MSG_31;RLD - Amount HISTORY_MSG_32;RLD - Damping HISTORY_MSG_33;RLD - Iterations -HISTORY_MSG_34;LCP distortion correction -HISTORY_MSG_35;LCP vignetting correction -HISTORY_MSG_36;LCP CA correction +HISTORY_MSG_34;Lens Correction - Distortion +HISTORY_MSG_35;Lens Correction - Vignetting +HISTORY_MSG_36;Lens Correction - CA HISTORY_MSG_37;Exposure - Auto levels HISTORY_MSG_38;White Balance - Method HISTORY_MSG_39;WB - Temperature @@ -334,7 +335,7 @@ HISTORY_MSG_81;Resize HISTORY_MSG_82;Profile changed HISTORY_MSG_83;S/H - Sharp mask HISTORY_MSG_84;Perspective correction -HISTORY_MSG_85;LCP +HISTORY_MSG_85;Lens Correction - LCP file HISTORY_MSG_86;RGB Curves - Luminosity mode HISTORY_MSG_87;Impulse Noise Reduction HISTORY_MSG_88;Impulse NR threshold @@ -483,7 +484,7 @@ HISTORY_MSG_232;B&W - 'Before' curve type HISTORY_MSG_233;B&W - 'After' curve HISTORY_MSG_234;B&W - 'After' curve type HISTORY_MSG_235;B&W - CM - Auto -HISTORY_MSG_236;Spot removal - Point modif. +HISTORY_MSG_236;--unused-- HISTORY_MSG_237;B&W - CM HISTORY_MSG_238;GF - Feather HISTORY_MSG_239;GF - Strength @@ -672,7 +673,7 @@ HISTORY_MSG_421;Retinex - Gamma HISTORY_MSG_422;Retinex - Gamma HISTORY_MSG_423;Retinex - Gamma slope HISTORY_MSG_424;Retinex - HL threshold -HISTORY_MSG_425;Spot removal +HISTORY_MSG_425;Retinex - Log base HISTORY_MSG_426;Retinex - Hue equalizer HISTORY_MSG_427;Output rendering intent HISTORY_MSG_428;Monitor rendering intent @@ -775,6 +776,8 @@ HISTORY_MSG_SHARPENING_CONTRAST;Sharpening - Contrast threshold HISTORY_MSG_SH_COLORSPACE;S/H - Colorspace HISTORY_MSG_SOFTLIGHT_ENABLED;Soft light HISTORY_MSG_SOFTLIGHT_STRENGTH;Soft light - Strength +HISTORY_MSG_SPOT;Spot removal +HISTORY_MSG_SPOT_ENTRY;Spot removal - Point modif. HISTORY_MSG_TM_FATTAL_ANCHOR;DRC - Anchor HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 7d4bad381..afd9e3774 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -618,6 +618,12 @@ void Crop::update(int todo) parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); } + if ((todo & M_SPOT) && params.spot.enabled && !params.spot.entries.empty()) { + PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); + //parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); + parent->ipf.removeSpots(origCrop, params.spot.entries, pp); + } + DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise; if (params.dirpyrDenoise.Lmethod == "CUR") { @@ -692,6 +698,33 @@ void Crop::update(int todo) // has to be called after setCropSizes! Tools prior to this point can't handle the Edit mechanism, but that shouldn't be a problem. createBuffer(cropw, croph); + if ((todo & M_SPOT_ADJUST) && params.spot.enabled && !params.spot.entries.empty()) { + PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); + parent->ipf.removeSpots(origCrop, params.spot.entries, pp); + } + + // Apply Spot removal + if (todo & (M_SPOT|M_SPOT_ADJUST)) { + if (params.spot.enabled && !params.spot.entries.empty()) { + if(!spotCrop) { + spotCrop = new Imagefloat (cropw, croph); + } + baseCrop->copyData (spotCrop); + PreviewProps pp (trafx, trafy, trafw * skip, trafh * skip, skip); + //parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); + parent->ipf.removeSpots (spotCrop, params.spot.entries, pp); + } else { + if (spotCrop) { + delete spotCrop; + spotCrop = nullptr; + } + } + } + + if (spotCrop) { + baseCrop = spotCrop; + } + std::unique_ptr fattalCrop; if ((todo & M_HDR) && (params.fattal.enabled || params.dehaze.enabled)) { @@ -747,29 +780,6 @@ void Crop::update(int todo) parent->ipf.ToneMapFattal02(f); } - // Apply Spot removal - if (params.spot.enabled) { - if (todo & M_SPOT) { - if(!spotCrop) { - spotCrop = new Imagefloat (cropw, croph); - } - baseCrop->copyData (spotCrop); - - PreviewProps pp (cropx, cropy, cropw, croph, skip); - parent->ipf.removeSpots (spotCrop, params.spot.entries, pp); - } - } else { - if (spotCrop) { - delete spotCrop; - } - - spotCrop = NULL; - } - - if (spotCrop) { - baseCrop = spotCrop; - } - // crop back to the size expected by the rest of the pipeline if (need_cropping) { Imagefloat *c = origCrop; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index f27fafad6..91ba5b60c 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -40,7 +40,7 @@ extern const Settings* settings; ImProcCoordinator::ImProcCoordinator() : orig_prev(nullptr), oprevi(nullptr), - spot_prev (nullptr), + spotprev(nullptr), oprevl(nullptr), nprevl(nullptr), fattal_11_dcrop_cache(nullptr), @@ -50,7 +50,6 @@ ImProcCoordinator::ImProcCoordinator() : imgsrc (nullptr), lastAwbEqual (0.), lastAwbTempBias (0.0), - previewProps(-1, -1, -1, -1, 1), monitorIntent (RI_RELATIVE), softProof(false), gamutCheck(false), @@ -217,7 +216,7 @@ DetailedCrop* ImProcCoordinator::createCrop(::EditDataProvider *editDataProvider void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) { - MyMutex::MyLock processingLock (mProcessing); + MyMutex::MyLock processingLock(mProcessing); constexpr int numofphases = 15; int readyphase = 0; @@ -234,6 +233,41 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } + if (todo & M_SPOT_ADJUST) { + // TWEAKING THE PROCPARAMS FOR THE SPOT ADJUSTMENT MODE + + // -> using fast demozaicing method + highDetailNeeded = false; + //params->raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST); + //params->raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST); + + // -> disabling all transform + //params->coarse = CoarseTransformParams(); + params->lensProf = LensProfParams(); + params->cacorrection = CACorrParams(); + params->distortion = DistortionParams(); + params->rotate = RotateParams(); + params->perspective = PerspectiveParams(); + params->vignetting = VignettingParams(); + + // -> disabling standard crop + params->crop.enabled = false; + + // -> disabling time consuming and unnecessary tool + params->sh.enabled = false; + params->blackwhite.enabled = false; + params->dehaze.enabled = false; + params->wavelet.enabled = false; + params->filmSimulation.enabled = false; + params->sharpenEdge.enabled = false; + params->sharpenMicro.enabled = false; + params->sharpening.enabled = false; + params->softlight.enabled = false; + params->gradient.enabled = false; + params->pcvignette.enabled = false; + params->colorappearance.enabled = false; + } + if (((todo & ALL) == ALL) || (todo & M_MONITOR) || panningRelatedChange || (highDetailNeeded && options.prevdemo != PD_Sidecar)) { bwAutoR = bwAutoG = bwAutoB = -9000.f; @@ -451,11 +485,11 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // Will (re)allocate the preview's buffers setScale(scale); - previewProps.set(0, 0, fw, fh, scale); + PreviewProps pp(0, 0, fw, fh, scale); // Tells to the ImProcFunctions' tools what is the preview scale, which may lead to some simplifications ipf.setScale(scale); - imgsrc->getImage(currWB, tr, orig_prev, previewProps, params->toneCurve, params->raw); + imgsrc->getImage(currWB, tr, orig_prev, pp, params->toneCurve, params->raw); denoiseInfoStore.valid = false; //ColorTemp::CAT02 (orig_prev, ¶ms) ; // printf("orig_prevW=%d\n scale=%d",orig_prev->width, scale); @@ -507,47 +541,48 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) readyphase++; + oprevi = orig_prev; + + progress ("Spot Removal...", 100 * readyphase / numofphases); + + if (todo & (M_SPOT|M_SPOT_ADJUST)) { + if (params->spot.enabled && !params->spot.entries.empty()) { + allocCache(spotprev); + orig_prev->copyData (spotprev); + + PreviewProps pp(0, 0, fw, fh, scale); + ipf.removeSpots (spotprev, params->spot.entries, pp); + } else { + if (spotprev) { + delete spotprev; + spotprev = nullptr; + } + } + } + if (spotprev) { + if (oprevi == orig_prev) { + allocCache(oprevi); + } + spotprev->copyData(oprevi); + } + + readyphase++; + if ((todo & M_HDR) && (params->fattal.enabled || params->dehaze.enabled)) { if (fattal_11_dcrop_cache) { delete fattal_11_dcrop_cache; fattal_11_dcrop_cache = nullptr; } - ipf.dehaze(orig_prev); - ipf.ToneMapFattal02(orig_prev); - - if (oprevi != orig_prev) { - delete oprevi; + if (oprevi == orig_prev) { + oprevi = new Imagefloat (pW, pH); + orig_prev->copyData (oprevi); } + + ipf.dehaze(oprevi); + ipf.ToneMapFattal02(oprevi); } - oprevi = orig_prev; - - progress ("Spot Removal...", 100 * readyphase / numofphases); - - if (params->spot.enabled && !params->spot.entries.empty ()) { - if ((todo & M_SPOT)) { - // First update the image with spot healing - ipf.removeSpots (oprevi, params->spot.entries, previewProps); - - // Then fork the image to cache the data - if (spot_prev == nullptr) { - spot_prev = new Imagefloat (pW, pH); - } - oprevi->copyData (spot_prev); - } - if (spot_prev) { - oprevi = spot_prev; - } - } else { - if (spot_prev) { - delete spot_prev; - spot_prev = nullptr; - } - } - - readyphase++; - progress ("Rotate / Distortion...", 100 * readyphase / numofphases); // Remove transformation if unneeded bool needstransform = ipf.needsTransform(); @@ -1063,16 +1098,16 @@ void ImProcCoordinator::freeAll() { if (allocated) { - if (spot_prev && spot_prev != oprevi) { - delete spot_prev; + if (spotprev && spotprev != oprevi) { + delete spotprev; } - spot_prev = nullptr; + spotprev = nullptr; - if (oprevi && oprevi != orig_prev) { + if (orig_prev != oprevi) { delete oprevi; } + oprevi = nullptr; - delete orig_prev; orig_prev = nullptr; delete oprevl; @@ -1099,6 +1134,15 @@ void ImProcCoordinator::freeAll() allocated = false; } +void ImProcCoordinator::allocCache (Imagefloat* &imgfloat) +{ + if (imgfloat == nullptr) { + imgfloat = new Imagefloat(pW, pH); + } else { + imgfloat->allocate(pW, pH); + } +} + /** @brief Handles image buffer (re)allocation and trigger sizeChanged of SizeListener[s] * If the scale change, this method will free all buffers and reallocate ones of the new size. * It will then tell to the SizeListener that size has changed (sizeChanged) diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index a12f5e83e..dac034abf 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -57,7 +57,7 @@ class ImProcCoordinator : public StagedImageProcessor protected: Imagefloat *orig_prev; Imagefloat *oprevi; - Imagefloat *spot_prev; + Imagefloat *spotprev; LabImage *oprevl; LabImage *nprevl; Imagefloat *fattal_11_dcrop_cache; // global cache for ToneMapFattal02 used in 1:1 detail windows (except when denoise is active) @@ -73,8 +73,6 @@ protected: double lastAwbEqual; double lastAwbTempBias; - PreviewProps previewProps; - Glib::ustring monitorProfile; RenderingIntent monitorIntent; bool softProof; @@ -183,6 +181,7 @@ protected: void progress (Glib::ustring str, int pr); void reallocAll (); + void allocCache (Imagefloat* &imgfloat); void updateLRGBHistograms (); void setScale (int prevscale); void updatePreviewImage (int todo, bool panningRelatedChange); diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 1de9437d5..bb6a30038 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -262,7 +262,7 @@ enum ProcEventCode { EvBWAfterCurve = 232, EvBWAfterCurveMode = 233, EvAutoch = 234, - EvSpotEntry = 235, +// EvFixedch=235, -- can be reused -- EvNeutralBW = 236, EvGradientFeather = 237, EvGradientStrength = 238, @@ -451,7 +451,7 @@ enum ProcEventCode { EvLgam = 421, EvLslope = 422, EvLhighl = 423, - EvSpotEnabled = 424, +// EvLbaselog = 424, -- can be reused -- EvRetinexlhcurve = 425, EvOIntent = 426, EvMonitorTransform = 427, diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 22ebbcbb8..d741b1744 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -262,7 +262,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RGBCURVE, // EvBWAfterCurve RGBCURVE, // EvBWAfterCurveMode RGBCURVE, // EvAutoch - SPOT, // EvSpotEntry + 0, // --unused-- RGBCURVE, // EvNeutralBW TRANSFORM, // EvGradientFeather TRANSFORM, // EvGradientStrength @@ -451,7 +451,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DEMOSAIC, // EvLgam DEMOSAIC, // EvLslope RETINEX, // EvLhighl - SPOT, // EvSpotEnabled + 0, // --unused-- DEMOSAIC, // EvRetinexlhcurve OUTPUTPROFILE, // EvOIntent MONITORTRANSFORM, // EvMonitorTransform: no history message @@ -470,7 +470,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { RETINEX, // EvRetinexgaintransmission RETINEX, // EvLskal OUTPUTPROFILE, // EvOBPCompens - ALLNORAW, // EvWBtempBias + ALLNORAW, // EvWBtempBias DARKFRAME, // EvRawImageNum 0, // unused 0, // unused diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h index 97945e6e1..114e07b2e 100644 --- a/rtengine/refreshmap.h +++ b/rtengine/refreshmap.h @@ -22,6 +22,9 @@ #include #include "procevents.h" +// Use M_SPOT_ADJUST to update the rendering for On Preview Adjustment of the Spot tool +#define M_SPOT_ADJUST (1<<19) + // Use M_VOID if you wish to update the proc params without updating the preview at all ! #define M_VOID (1<<18) // Use M_MINUPDATE if you wish to update the preview without modifying the image (think about it like a "refreshPreview") @@ -51,16 +54,16 @@ // Bitfield of functions to do to the preview image when an event occurs // Use those or create new ones for your new events -#define FIRST (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_HDR|M_SPOT|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR|M_MONITOR) // without HIGHQUAL -#define ALL (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_HDR|M_SPOT|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL -#define DARKFRAME (M_PREPROC|M_RAW|M_INIT|M_LINDENOISE|M_HDR|M_SPOT|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_HDR|M_SPOT|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define DEMOSAIC (M_RAW|M_INIT|M_LINDENOISE|M_HDR|M_SPOT|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define ALLNORAW (M_INIT|M_LINDENOISE|M_HDR|M_SPOT|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define HDR (M_LINDENOISE|M_HDR|M_SPOT|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define SPOT (M_SPOT|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define FIRST (M_PREPROC|M_RAW|M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR|M_MONITOR) // without HIGHQUAL +#define ALL (M_PREPROC|M_RAW|M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) // without HIGHQUAL +#define DARKFRAME (M_PREPROC|M_RAW|M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define FLATFIELD (M_PREPROC|M_RAW|M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define DEMOSAIC (M_RAW|M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define ALLNORAW (M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define HDR (M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define SPOTADJUST (M_SPOT_ADJUST|M_HDR|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define TRANSFORM (M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define AUTOEXP (M_HDR|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define AUTOEXP (M_SPOT|M_HDR|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define RGBCURVE (M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define LUMINANCECURVE (M_LUMACURVE|M_LUMINANCE|M_COLOR) #define SHARPENING (M_LUMINANCE|M_COLOR) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 3d59b9c41..80a21793c 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -7,6 +7,8 @@ #include #include "../rtengine/rt_math.h" #include "guiutils.h" +#include "eventmapper.h" +#include "../rtengine/refreshmap.h" using namespace rtengine; using namespace rtengine::procparams; @@ -64,6 +66,12 @@ Spot::Spot() : FoldableToolPanel (this, "spot", M ("TP_SPOT_LABEL"), true, true) link.datum = Geometry::IMAGE; link.setActive (false); + auto m = ProcEventMapper::getInstance(); + EvSpotEnabled = m->newEvent(ALLNORAW, "TP_SPOT_LABEL"); + EvSpotEnabledOPA = m->newEvent(SPOTADJUST, ""); + EvSpotEntry = m->newEvent(SPOTADJUST, "HISTORY_MSG_SPOT_ENTRY"); + EvSpotEntryOPA = m->newEvent(SPOTADJUST, "HISTORY_MSG_SPOT_ENTRY"); + show_all(); } @@ -135,7 +143,7 @@ void Spot::resetPressed() updateGeometry(); if (listener) { - listener->panelChanged (EvSpotEntry, Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), 0)); + listener->panelChanged (edit->get_active() ? EvSpotEntryOPA : EvSpotEntry, Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), 0)); } } } @@ -167,16 +175,15 @@ void Spot::editedToggled () } } - void Spot::enabledChanged () { if (listener) { if (get_inconsistent()) { - listener->panelChanged (EvSpotEnabled, M ("GENERAL_UNCHANGED")); + listener->panelChanged (edit->get_active() ? EvSpotEnabledOPA : EvSpotEnabled, M ("GENERAL_UNCHANGED")); } else if (getEnabled()) { - listener->panelChanged (EvSpotEnabled, M ("GENERAL_ENABLED")); + listener->panelChanged (edit->get_active() ? EvSpotEnabledOPA : EvSpotEnabled, M ("GENERAL_ENABLED")); } else { - listener->panelChanged (EvSpotEnabled, M ("GENERAL_DISABLED")); + listener->panelChanged (edit->get_active() ? EvSpotEnabledOPA : EvSpotEnabled, M ("GENERAL_DISABLED")); } } } @@ -188,10 +195,14 @@ void Spot::setEditProvider (EditDataProvider* provider) void Spot::editToggled () { - if (edit->get_active()) { - subscribe(); - } else { - unsubscribe(); + if (listener) { + if (edit->get_active()) { + listener->refreshPreview(EvSpotEnabledOPA); // reprocess the preview w/o creating History entry + subscribe(); + } else { + unsubscribe(); + listener->refreshPreview(EvSpotEnabled); // reprocess the preview w/o creating History entry + } } } @@ -372,7 +383,7 @@ void Spot::addNewEntry() // TODO: find a way to disable the active spot's Mouse Over geometry but still displaying its location... if (listener) { - listener->panelChanged (EvSpotEntry, M ("TP_SPOT_ENTRYCHANGED")); + listener->panelChanged (EvSpotEntryOPA, M ("TP_SPOT_ENTRYCHANGED")); } } @@ -690,5 +701,6 @@ void Spot::switchOffEditMode () } EditSubscriber::switchOffEditMode(); // disconnect + listener->refreshPreview(EvSpotEnabled); // reprocess the preview w/o creating History entry } diff --git a/rtgui/spot.h b/rtgui/spot.h index e719070a5..50c196051 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -98,6 +98,14 @@ public: bool pick2 (const bool picked); bool pick3 (const bool picked); void switchOffEditMode (); + + rtengine::ProcEvent EvSpotEnabled; + rtengine::ProcEvent EvSpotEnabledOPA; // used to toggle-on the Spot 'On Preview Adjustment' mode + rtengine::ProcEvent EvSpotEntry; + rtengine::ProcEvent EvSpotEntryOPA; + + rtengine::ProcEvent evt; + }; #endif diff --git a/rtgui/toolpanel.h b/rtgui/toolpanel.h index 8f6595c08..cbf9a4226 100644 --- a/rtgui/toolpanel.h +++ b/rtgui/toolpanel.h @@ -35,6 +35,10 @@ class ToolPanelListener { public: virtual ~ToolPanelListener() = default; + + /// @brief Ask to refresh the preview not triggered by a parameter change (e.g. 'On Preview' editing). + virtual void refreshPreview(const rtengine::ProcEvent& event) = 0; + /// @brief Used to notify all listeners that a parameters has been effectively changed virtual void panelChanged(const rtengine::ProcEvent& event, const Glib::ustring& descr) = 0; }; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 691cfbcc6..c1143b781 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -379,6 +379,19 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt } +void ToolPanelCoordinator::refreshPreview (const rtengine::ProcEvent& event) +{ + if (!ipc) { + return; + } + + ProcParams* params = ipc->beginUpdateParams (); + for (auto toolPanel : toolPanels) { + toolPanel->write (params); + } + + ipc->endUpdateParams (event); // starts the IPC processing +} void ToolPanelCoordinator::panelChanged(const rtengine::ProcEvent& event, const Glib::ustring& descr) { diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index c380e8475..2347a85ed 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -237,6 +237,7 @@ public: } // toolpanellistener interface + void refreshPreview(const rtengine::ProcEvent& event) override; void panelChanged(const rtengine::ProcEvent& event, const Glib::ustring& descr) override; void imageTypeChanged (bool isRaw, bool isBayer, bool isXtrans, bool isMono = false) override; From 0db64d49a29bd04a1d17ea25681fd92d699bd304 Mon Sep 17 00:00:00 2001 From: Hombre Date: Tue, 6 Aug 2019 02:04:48 +0200 Subject: [PATCH 008/135] Introducing TweakOperator, for better tool's special mode handling --- rtengine/dcrop.cc | 9 +-- rtengine/improccoordinator.cc | 126 +++++++++++++++++++--------------- rtengine/improccoordinator.h | 11 ++- rtengine/refreshmap.h | 5 +- rtengine/rtengine.h | 16 ++++- rtengine/tweakoperator.h | 45 ++++++++++++ rtgui/batchtoolpanelcoord.cc | 8 +++ rtgui/batchtoolpanelcoord.h | 2 + rtgui/cropwindow.cc | 2 +- rtgui/spot.cc | 34 +++++++++ rtgui/spot.h | 6 +- rtgui/toolpanel.h | 4 ++ rtgui/toolpanelcoord.cc | 14 ++++ rtgui/toolpanelcoord.h | 3 + 14 files changed, 212 insertions(+), 73 deletions(-) create mode 100644 rtengine/tweakoperator.h diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index afd9e3774..8fdc6b5d1 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -142,6 +142,7 @@ void Crop::update(int todo) // 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; const bool overrideWindow = cropImageListener; + bool spotsDone = false; if (overrideWindow) { cropImageListener->getWindow(wx, wy, ww, wh, ws); @@ -619,6 +620,7 @@ void Crop::update(int todo) } if ((todo & M_SPOT) && params.spot.enabled && !params.spot.entries.empty()) { + spotsDone = true; PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); //parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); parent->ipf.removeSpots(origCrop, params.spot.entries, pp); @@ -698,13 +700,8 @@ void Crop::update(int todo) // has to be called after setCropSizes! Tools prior to this point can't handle the Edit mechanism, but that shouldn't be a problem. createBuffer(cropw, croph); - if ((todo & M_SPOT_ADJUST) && params.spot.enabled && !params.spot.entries.empty()) { - PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); - parent->ipf.removeSpots(origCrop, params.spot.entries, pp); - } - // Apply Spot removal - if (todo & (M_SPOT|M_SPOT_ADJUST)) { + if ((todo & M_SPOT) && !spotsDone) { if (params.spot.enabled && !params.spot.entries.empty()) { if(!spotCrop) { spotCrop = new Imagefloat (cropw, croph); diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 91ba5b60c..c5b6952f5 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -25,6 +25,7 @@ #include "improcfun.h" #include "iccstore.h" #include "procparams.h" +#include "tweakoperator.h" #include #include #include @@ -130,6 +131,7 @@ ImProcCoordinator::ImProcCoordinator() : hListener(nullptr), resultValid(false), params(new procparams::ProcParams), + tweakOperator(nullptr), lastOutputProfile("BADFOOD"), lastOutputIntent(RI__COUNT), lastOutputBPC(false), @@ -200,9 +202,32 @@ void ImProcCoordinator::assign(ImageSource* imgsrc) this->imgsrc = imgsrc; } -void ImProcCoordinator::getParams(procparams::ProcParams* dst) +void ImProcCoordinator::getParams(procparams::ProcParams* dst, bool tweaked) { - *dst = *params; + if (!tweaked && paramsBackup.operator bool()) { + *dst = *paramsBackup; + } else { + *dst = *params; + } +} + +void ImProcCoordinator::backupParams() +{ + if (!params) { + return; + } + if (!paramsBackup) { + paramsBackup.reset(new ProcParams()); + } + *paramsBackup = *params; +} + +void ImProcCoordinator::restoreParams() +{ + if (!paramsBackup || !params) { + return; + } + *params = *paramsBackup; } DetailedCrop* ImProcCoordinator::createCrop(::EditDataProvider *editDataProvider, bool isDetailWindow) @@ -233,41 +258,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } - if (todo & M_SPOT_ADJUST) { - // TWEAKING THE PROCPARAMS FOR THE SPOT ADJUSTMENT MODE - - // -> using fast demozaicing method - highDetailNeeded = false; - //params->raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST); - //params->raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST); - - // -> disabling all transform - //params->coarse = CoarseTransformParams(); - params->lensProf = LensProfParams(); - params->cacorrection = CACorrParams(); - params->distortion = DistortionParams(); - params->rotate = RotateParams(); - params->perspective = PerspectiveParams(); - params->vignetting = VignettingParams(); - - // -> disabling standard crop - params->crop.enabled = false; - - // -> disabling time consuming and unnecessary tool - params->sh.enabled = false; - params->blackwhite.enabled = false; - params->dehaze.enabled = false; - params->wavelet.enabled = false; - params->filmSimulation.enabled = false; - params->sharpenEdge.enabled = false; - params->sharpenMicro.enabled = false; - params->sharpening.enabled = false; - params->softlight.enabled = false; - params->gradient.enabled = false; - params->pcvignette.enabled = false; - params->colorappearance.enabled = false; - } - if (((todo & ALL) == ALL) || (todo & M_MONITOR) || panningRelatedChange || (highDetailNeeded && options.prevdemo != PD_Sidecar)) { bwAutoR = bwAutoG = bwAutoB = -9000.f; @@ -545,7 +535,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) progress ("Spot Removal...", 100 * readyphase / numofphases); - if (todo & (M_SPOT|M_SPOT_ADJUST)) { + if (todo & M_SPOT) { if (params->spot.enabled && !params->spot.entries.empty()) { allocCache(spotprev); orig_prev->copyData (spotprev); @@ -1089,10 +1079,21 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) delete oprevi; oprevi = nullptr; } - - } +void ImProcCoordinator::setTweakOperator (TweakOperator *tOperator) +{ + if (tOperator) { + tweakOperator = tOperator; + } +} + +void ImProcCoordinator::unsetTweakOperator (TweakOperator *tOperator) +{ + if (tOperator && tOperator == tweakOperator) { + tweakOperator = nullptr; + } +} void ImProcCoordinator::freeAll() { @@ -1432,35 +1433,37 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a MyMutex::MyLock lock(mProcessing); int fW, fH; + std::unique_ptr validParams(new ProcParams()); + getParams(validParams.get()); - int tr = getCoarseBitMask(params->coarse); + int tr = getCoarseBitMask(validParams->coarse); imgsrc->getFullSize(fW, fH, tr); PreviewProps pp(0, 0, fW, fH, 1); - ProcParams ppar = *params; + ProcParams ppar = *validParams; ppar.toneCurve.hrenabled = false; ppar.icm.inputProfile = "(none)"; Imagefloat* im = new Imagefloat(fW, fH); imgsrc->preprocess(ppar.raw, ppar.lensProf, ppar.coarse); double dummy = 0.0; imgsrc->demosaic(ppar.raw, false, dummy); - ColorTemp currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method); + ColorTemp currWB = ColorTemp(validParams->wb.temperature, validParams->wb.green, validParams->wb.equal, validParams->wb.method); - if (params->wb.method == "Camera") { + if (validParams->wb.method == "Camera") { currWB = imgsrc->getWB(); - } else if (params->wb.method == "Auto") { - if (lastAwbEqual != params->wb.equal || lastAwbTempBias != params->wb.tempBias) { + } else if (validParams->wb.method == "Auto") { + if (lastAwbEqual != validParams->wb.equal || lastAwbTempBias != validParams->wb.tempBias) { double rm, gm, bm; imgsrc->getAutoWBMultipliers(rm, gm, bm); if (rm != -1.) { - autoWB.update(rm, gm, bm, params->wb.equal, params->wb.tempBias); - lastAwbEqual = params->wb.equal; - lastAwbTempBias = params->wb.tempBias; + autoWB.update(rm, gm, bm, validParams->wb.equal, validParams->wb.tempBias); + lastAwbEqual = validParams->wb.equal; + lastAwbTempBias = validParams->wb.tempBias; } else { lastAwbEqual = -1.; lastAwbTempBias = 0.0; - autoWB.useDefaults(params->wb.equal); + autoWB.useDefaults(validParams->wb.equal); } } @@ -1482,12 +1485,12 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a im = trImg; } - if (params->crop.enabled) { - Imagefloat *tmpim = new Imagefloat(params->crop.w, params->crop.h); - int cx = params->crop.x; - int cy = params->crop.y; - int cw = params->crop.w; - int ch = params->crop.h; + if (validParams->crop.enabled) { + Imagefloat *tmpim = new Imagefloat(validParams->crop.w, validParams->crop.h); + int cx = validParams->crop.x; + int cy = validParams->crop.y; + int cw = validParams->crop.w; + int ch = validParams->crop.h; #ifdef _OPENMP #pragma omp parallel for #endif @@ -1518,7 +1521,7 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a } int imw, imh; - double tmpScale = ipf.resizeScale(params.get(), fW, fH, imw, imh); + double tmpScale = ipf.resizeScale(validParams.get(), fW, fH, imw, imh); if (tmpScale != 1.0) { Imagefloat* tempImage = new Imagefloat(imw, imh); @@ -1628,6 +1631,15 @@ void ImProcCoordinator::process() *params = *nextParams; int change = changeSinceLast; changeSinceLast = 0; + + if (tweakOperator) { + // TWEAKING THE PROCPARAMS FOR THE SPOT ADJUSTMENT MODE + backupParams(); + tweakOperator->tweakParams(*params); + } else if (paramsBackup) { + paramsBackup.release(); + } + paramsUpdateMutex.unlock(); // M_VOID means no update, and is a bit higher that the rest diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index dac034abf..e66867d2b 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -37,6 +37,7 @@ namespace rtengine using namespace procparams; class Crop; +class TweakOperator; /** @brief Manages the image processing, espc. of the preview windows * @@ -180,14 +181,20 @@ protected: MyMutex minit; // to gain mutually exclusive access to ... to what exactly? void progress (Glib::ustring str, int pr); + void backupParams(); + void restoreParams(); void reallocAll (); void allocCache (Imagefloat* &imgfloat); void updateLRGBHistograms (); void setScale (int prevscale); void updatePreviewImage (int todo, bool panningRelatedChange); + void setTweakOperator (TweakOperator *tOperator); + void unsetTweakOperator (TweakOperator *tOperator); MyMutex mProcessing; - const std::unique_ptr params; + const std::unique_ptr params; // used for the rendering, can be eventually tweaked + std::unique_ptr paramsBackup; // backup of the untweaked procparams + TweakOperator* tweakOperator; // for optimization purpose, the output profile, output rendering intent and // output BPC will trigger a regeneration of the profile on parameter change only @@ -228,7 +235,7 @@ public: ~ImProcCoordinator () override; void assign (ImageSource* imgsrc); - void getParams (procparams::ProcParams* dst) override; + void getParams (procparams::ProcParams* dst, bool tweaked=false) override; void startProcessing (int changeCode) override; ProcParams* beginUpdateParams () override; diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h index 114e07b2e..1de3bd250 100644 --- a/rtengine/refreshmap.h +++ b/rtengine/refreshmap.h @@ -22,9 +22,6 @@ #include #include "procevents.h" -// Use M_SPOT_ADJUST to update the rendering for On Preview Adjustment of the Spot tool -#define M_SPOT_ADJUST (1<<19) - // Use M_VOID if you wish to update the proc params without updating the preview at all ! #define M_VOID (1<<18) // Use M_MINUPDATE if you wish to update the preview without modifying the image (think about it like a "refreshPreview") @@ -61,7 +58,7 @@ #define DEMOSAIC (M_RAW|M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define ALLNORAW (M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define HDR (M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define SPOTADJUST (M_SPOT_ADJUST|M_HDR|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define SPOTADJUST (M_SPOT|M_HDR|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define TRANSFORM (M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define AUTOEXP (M_SPOT|M_HDR|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define RGBCURVE (M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index f772975b0..e821c25c7 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -70,6 +70,7 @@ class IImage8; class IImage16; class IImagefloat; class ImageSource; +class TweakOperator; /** * This class provides functions to obtain exif and IPTC metadata information @@ -454,9 +455,20 @@ public: /** Returns the initial image corresponding to the image processor. * @return the initial image corresponding to the image processor */ virtual InitialImage* getInitialImage () = 0; + /** Set the TweakOperator + * @param tOperator is a pointer to the object that will alter the ProcParams for the rendering */ + virtual void setTweakOperator (TweakOperator *tOperator) = 0; + /** Unset the TweakOperator + * @param tOperator is a pointer to the object that were altering the ProcParams for the rendering + * It will only unset the tweak operator if tOperator is the same than the currently set operator. + * If it doesn't match, the currently set TweakOperator will remain set. */ + virtual void unsetTweakOperator (TweakOperator *tOperator) = 0; /** Returns the current processing parameters. - * @param dst is the location where the image processing parameters are copied (it is assumed that the memory is allocated by the caller) */ - virtual void getParams (procparams::ProcParams* dst) = 0; + * Since the ProcParams can be tweaked by a GUI to operate on the image at a specific stage or with disabled tool, + * you'll have to specify if you want the tweaked version for the current special mode, or the untweaked one. + * @param dst is the location where the image processing parameters are copied (it is assumed that the memory is allocated by the caller) + * @param tweaked is used to chose betwen the tweaked ProcParams (if there is one) or the untweaked one */ + virtual void getParams (procparams::ProcParams* dst, bool tweaked=false) = 0; /** An essential member function. Call this when a setting has been changed. This function returns a pointer to the * processing parameters, that you have to update to reflect the changed situation. When ready, call the paramsUpdateReady * function to start the image update. diff --git a/rtengine/tweakoperator.h b/rtengine/tweakoperator.h new file mode 100644 index 000000000..e75ea89f2 --- /dev/null +++ b/rtengine/tweakoperator.h @@ -0,0 +1,45 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2019 Jean-Christophe FRISCH + * + * 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 . + */ +#pragma once + +namespace rtengine +{ + +namespace procparams +{ + +class ProcParams; + +} + +/** This class can let objects alter the collected values of the ProcParams for a specific + * purpose, e.g. displaying a preview image at a specific point in the pipeline or with + * disabled tools. Before starting the rendering, the engine will call the TweakOperator + * (if set) to modify the ProcParams. The untweaked one will still exist as a backup, and + * can be sent back if necessary. */ +class TweakOperator +{ +public: + virtual ~TweakOperator() {} + + /** Callback that will alter the ProcParams before hte image is computed. */ + virtual void tweakParams(procparams::ProcParams& pparams) = 0; +}; + +} diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index 1a0eaeb28..c493897f0 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -558,6 +558,14 @@ void BatchToolPanelCoordinator::panelChanged(const rtengine::ProcEvent& event, c } } +void BatchToolPanelCoordinator::setTweakOperator (rtengine::TweakOperator *tOperator) +{ +} + +void BatchToolPanelCoordinator::unsetTweakOperator (rtengine::TweakOperator *tOperator) +{ +} + void BatchToolPanelCoordinator::getAutoWB (double& temp, double& green, double equal, double tempBias) { diff --git a/rtgui/batchtoolpanelcoord.h b/rtgui/batchtoolpanelcoord.h index f5889f967..f3183b746 100644 --- a/rtgui/batchtoolpanelcoord.h +++ b/rtgui/batchtoolpanelcoord.h @@ -55,6 +55,8 @@ public: // toolpanellistener interface void panelChanged(const rtengine::ProcEvent& event, const Glib::ustring& descr) override; + void setTweakOperator (rtengine::TweakOperator *tOperator) override; + void unsetTweakOperator (rtengine::TweakOperator *tOperator) override; // profilechangelistener interface void profileChange( diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index b29aa5eeb..ed40700a3 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -1092,7 +1092,7 @@ void CropWindow::pointerMoved (int bstate, int x, int y) rtengine::StagedImageProcessor* ipc = iarea->getImProcCoordinator(); if(ipc) { procparams::ProcParams params; - ipc->getParams(¶ms); + ipc->getParams(¶ms, true); isRaw = params.raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::NONE) || params.raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::NONE); if(isRaw) { ImageSource *isrc = static_cast(ipc->getInitialImage()); diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 80a21793c..9f7830a15 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -197,10 +197,12 @@ void Spot::editToggled () { if (listener) { if (edit->get_active()) { + listener->setTweakOperator(this); listener->refreshPreview(EvSpotEnabledOPA); // reprocess the preview w/o creating History entry subscribe(); } else { unsubscribe(); + listener->unsetTweakOperator(this); listener->refreshPreview(EvSpotEnabled); // reprocess the preview w/o creating History entry } } @@ -701,6 +703,38 @@ void Spot::switchOffEditMode () } EditSubscriber::switchOffEditMode(); // disconnect + listener->unsetTweakOperator(this); listener->refreshPreview(EvSpotEnabled); // reprocess the preview w/o creating History entry } +void Spot::tweakParams(procparams::ProcParams& pparams) +{ + //params->raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST); + //params->raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST); + + // -> disabling all transform + //params->coarse = CoarseTransformParams(); + pparams.lensProf = LensProfParams(); + pparams.cacorrection = CACorrParams(); + pparams.distortion = DistortionParams(); + pparams.rotate = RotateParams(); + pparams.perspective = PerspectiveParams(); + pparams.vignetting = VignettingParams(); + + // -> disabling standard crop + pparams.crop.enabled = false; + + // -> disabling time consuming and unnecessary tool + pparams.sh.enabled = false; + pparams.blackwhite.enabled = false; + pparams.dehaze.enabled = false; + pparams.wavelet.enabled = false; + pparams.filmSimulation.enabled = false; + pparams.sharpenEdge.enabled = false; + pparams.sharpenMicro.enabled = false; + pparams.sharpening.enabled = false; + pparams.softlight.enabled = false; + pparams.gradient.enabled = false; + pparams.pcvignette.enabled = false; + pparams.colorappearance.enabled = false; +} diff --git a/rtgui/spot.h b/rtgui/spot.h index 50c196051..b163848c0 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -8,6 +8,7 @@ #include "toolpanel.h" #include "editwidgets.h" #include "../rtengine/procparams.h" +#include "../rtengine/tweakoperator.h" /** * @brief Let the user create/edit/delete points for Spot Removal tool @@ -36,7 +37,7 @@ * (the point will be deleted on button release). */ -class Spot : public ToolParamBlock, public FoldableToolPanel, public EditSubscriber +class Spot : public ToolParamBlock, public FoldableToolPanel, public EditSubscriber, public rtengine::TweakOperator { private: @@ -99,6 +100,9 @@ public: bool pick3 (const bool picked); void switchOffEditMode (); + //TweakOperator interface + void tweakParams(rtengine::procparams::ProcParams& pparams) override; + rtengine::ProcEvent EvSpotEnabled; rtengine::ProcEvent EvSpotEnabledOPA; // used to toggle-on the Spot 'On Preview Adjustment' mode rtengine::ProcEvent EvSpotEntry; diff --git a/rtgui/toolpanel.h b/rtgui/toolpanel.h index cbf9a4226..f2d5890a9 100644 --- a/rtgui/toolpanel.h +++ b/rtgui/toolpanel.h @@ -40,6 +40,10 @@ public: virtual void refreshPreview(const rtengine::ProcEvent& event) = 0; /// @brief Used to notify all listeners that a parameters has been effectively changed virtual void panelChanged(const rtengine::ProcEvent& event, const Glib::ustring& descr) = 0; + /// @brief Set the TweakOperator to the StagedImageProcessor, to let some tool enter into special modes + virtual void setTweakOperator (rtengine::TweakOperator *tOperator) = 0; + /// @brief Unset the TweakOperator to the StagedImageProcessor + virtual void unsetTweakOperator (rtengine::TweakOperator *tOperator) = 0; }; /// @brief This class control the space around the group of tools inside a tab, as well as the space separating each tool. */ diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index c1143b781..af6c3e507 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -379,6 +379,20 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt } +void ToolPanelCoordinator::setTweakOperator (rtengine::TweakOperator *tOperator) +{ + if (ipc && tOperator) { + ipc->setTweakOperator(tOperator); + } +} + +void ToolPanelCoordinator::unsetTweakOperator (rtengine::TweakOperator *tOperator) +{ + if (ipc && tOperator) { + ipc->unsetTweakOperator(tOperator); + } +} + void ToolPanelCoordinator::refreshPreview (const rtengine::ProcEvent& event) { if (!ipc) { diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 2347a85ed..3789f1610 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -239,7 +239,10 @@ public: // toolpanellistener interface void refreshPreview(const rtengine::ProcEvent& event) override; void panelChanged(const rtengine::ProcEvent& event, const Glib::ustring& descr) override; + void setTweakOperator (rtengine::TweakOperator *tOperator) override; + void unsetTweakOperator (rtengine::TweakOperator *tOperator) override; + // FilmNegProvider interface void imageTypeChanged (bool isRaw, bool isBayer, bool isXtrans, bool isMono = false) override; // void autoContrastChanged (double autoContrast); From 122e0b89bedf3f5c1cb9b3ed971e3b620c78e5a7 Mon Sep 17 00:00:00 2001 From: Hombre Date: Fri, 9 Aug 2019 03:24:46 +0200 Subject: [PATCH 009/135] First functionnal version of Spot-Removal tool Still needs code cleanup, better algorithm and reantrance handling --- rtengine/dcrop.cc | 6 +- rtengine/improccoordinator.cc | 7 +- rtengine/improcfun.h | 2 +- rtengine/procparams.cc | 5 + rtengine/procparams.h | 1 + rtengine/simpleprocess.cc | 2 +- rtengine/spot.cc | 317 ++++++++++++++++++++++++++++++++-- 7 files changed, 313 insertions(+), 27 deletions(-) diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 8fdc6b5d1..72f5c6d72 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -623,7 +623,7 @@ void Crop::update(int todo) spotsDone = true; PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); //parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); - parent->ipf.removeSpots(origCrop, params.spot.entries, pp); + parent->ipf.removeSpots(origCrop, parent->imgsrc, params.spot.entries, pp, parent->currWB, tr); } DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise; @@ -708,8 +708,8 @@ void Crop::update(int todo) } baseCrop->copyData (spotCrop); PreviewProps pp (trafx, trafy, trafw * skip, trafh * skip, skip); - //parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); - parent->ipf.removeSpots (spotCrop, params.spot.entries, pp); + int tr = getCoarseBitMask(params.coarse); + parent->ipf.removeSpots (spotCrop, parent->imgsrc, params.spot.entries, pp, parent->currWB, tr); } else { if (spotCrop) { delete spotCrop; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index c5b6952f5..2c49bdef1 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -538,10 +538,9 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (todo & M_SPOT) { if (params->spot.enabled && !params->spot.entries.empty()) { allocCache(spotprev); - orig_prev->copyData (spotprev); - + orig_prev->copyData(spotprev); PreviewProps pp(0, 0, fw, fh, scale); - ipf.removeSpots (spotprev, params->spot.entries, pp); + ipf.removeSpots(spotprev, imgsrc, params->spot.entries, pp, currWB, tr); } else { if (spotprev) { delete spotprev; @@ -551,7 +550,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } if (spotprev) { if (oprevi == orig_prev) { - allocCache(oprevi); + oprevi = new Imagefloat(pW, pH); } spotprev->copyData(oprevi); } diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index dc5f6939a..5700a354b 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -333,7 +333,7 @@ public: float MadRgb(const float * DataList, int datalen); // spot removal tool - void removeSpots (Imagefloat* img, const std::vector &entries, const PreviewProps &pp); + void removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector &entries, const PreviewProps &pp, const ColorTemp &currWB, int tr); // pyramid wavelet void dirpyr_equalizer(float ** src, float ** dst, int srcwidth, int srcheight, float ** l_a, float ** l_b, const double * mult, const double dirpyrThreshold, const double skinprot, float b_l, float t_l, float t_r, int scale); //Emil's directional pyramid wavelet diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 62fefbb69..1adc9c8e5 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -1551,6 +1551,11 @@ SpotEntry::SpotEntry() : { } +float SpotEntry::getFeatherRadius() const +{ + return radius * (1.f + feather); +} + bool SpotEntry::operator ==(const SpotEntry& other) const { return other.sourcePos == sourcePos && other.targetPos == targetPos && diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 129310660..de04e5636 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1039,6 +1039,7 @@ struct SpotEntry { float opacity; SpotEntry(); + float getFeatherRadius() const; bool operator ==(const SpotEntry& other) const; bool operator !=(const SpotEntry& other) const; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index dc3f7c125..38ccb5133 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -927,7 +927,7 @@ private: // Spot Removal if (params.spot.enabled && !params.spot.entries.empty ()) { - ipf.removeSpots (baseImg, params.spot.entries, pp); + ipf.removeSpots (baseImg, imgsrc, params.spot.entries, pp, currWB, tr); } // RGB processing diff --git a/rtengine/spot.cc b/rtengine/spot.cc index f23fb036d..60bfb2f6c 100644 --- a/rtengine/spot.cc +++ b/rtengine/spot.cc @@ -20,6 +20,7 @@ #include "improcfun.h" #include "alpha.h" #include "procparams.h" +#include "imagesource.h" namespace rtengine { @@ -49,31 +50,305 @@ namespace rtengine * T. Georgiev, "Photoshop Healing Brush: a Tool for Seamless Cloning * http://www.tgeorgiev.net/Photoshop_Healing.pdf */ -void ImProcFunctions::removeSpots (Imagefloat* img, const std::vector &entries, const PreviewProps &pp) + +#if 1 + +class SpotBox { + +public: + enum class Type { + SOURCE, + TARGET + }; + +private: + Type type; + +public: + int topLeftX; + int topLeftY; + int bottomRightX; + int bottomRightY; + Imagefloat* img; + + SpotBox (int tl_x, int tl_y, int br_x, int br_y, Type type) : + type(type), + topLeftX(tl_x), + topLeftY(tl_y), + bottomRightX(br_x), + bottomRightY(br_y), + img(nullptr) + {} + + SpotBox (int tl_x, int tl_y, Imagefloat* image, Type type) : + type(type), + topLeftX(tl_x), + topLeftY(tl_y), + bottomRightX(image ? tl_x + image->getWidth() - 1 : 0), + bottomRightY(image ? tl_y + image->getHeight() - 1 : 0), + img(image) + {} + + SpotBox (SpotEntry &spot, Type type) : + type(type), + img(nullptr) + { + float featherRadius = spot.radius * (1.f + spot.feather); + topLeftX = int ((type == Type::SOURCE ? spot.sourcePos.x : spot.targetPos.x) - featherRadius); + bottomRightX = int ((type == Type::SOURCE ? spot.sourcePos.x : spot.targetPos.x) + featherRadius); + topLeftY = int ((type == Type::SOURCE ? spot.sourcePos.y : spot.targetPos.y) - featherRadius); + bottomRightY = int ((type == Type::SOURCE ? spot.sourcePos.y : spot.targetPos.y) + featherRadius); + } + + void translate(int dx, int dy) { + topLeftX += dx; + topLeftY += dy; + bottomRightX += dx; + bottomRightY += dy; + } + + void operator /(float v) { + topLeftX = int(topLeftX / v + 0.5f); + topLeftY = int(topLeftY / v + 0.5f); + bottomRightX = int(bottomRightX / v + 0.5f); + bottomRightY = int(bottomRightY / v + 0.5f); + } + + void operator *(float v) { + topLeftX *= v; + topLeftY *= v; + bottomRightX *= v; + bottomRightY *= v; + } + + bool intersects(const SpotBox &other) const { + return (other.topLeftX <= bottomRightX && other.bottomRightX >= topLeftX) + && (other.topLeftY <= bottomRightY && other.bottomRightY >= topLeftY); + } + + int getWidth() { + return bottomRightX - topLeftX + 1; + } + + int getHeight() { + return bottomRightY - topLeftY + 1; + } +}; + + +void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector &entries, const PreviewProps &pp, const ColorTemp &currWB, int tr) { + // ---------- Get the image areas (src & dst) from the source image + + printf("\n=======================================================================\n\n"); + + std::vector< std::shared_ptr > srcSpotBoxs; + std::vector< std::shared_ptr > dstSpotBoxs; + for (auto entry : params->spot.entries) { + Coord origin; + int size = int(entry.getFeatherRadius() * 2.f + 0.5f); + int scaledSize = int(entry.getFeatherRadius() * 2.f / float(pp.getSkip()) + 0.5f); + //printf("size: %d - skip: %d -> scaledSize: %d", size, pp.getSkip(), scaledSize); + + // ------ Source area + Imagefloat *currSrcSpot = new Imagefloat(scaledSize, scaledSize); + for (int y = 0; y < currSrcSpot->getHeight(); ++y) { + for (int x = 0; x < currSrcSpot->getWidth(); ++x) { + currSrcSpot->r(y,x) = 0.f; + currSrcSpot->g(y,x) = 0.f; + currSrcSpot->b(y,x) = 0.f; + } + } + entry.sourcePos.get(origin.x, origin.y); + origin.x -= entry.getFeatherRadius(); + origin.y -= entry.getFeatherRadius(); + PreviewProps spp(origin.x, origin.y, size, size, pp.getSkip()); + imgsrc->getImage(currWB, tr, currSrcSpot, spp, params->toneCurve, params->raw); + //printf(" / src size: %d,%d", currSrcSpot->getWidth(), currSrcSpot->getHeight()); + + std::shared_ptr srcSpotBox(new SpotBox(origin.x / pp.getSkip(), origin.y / pp.getSkip(), currSrcSpot, SpotBox::Type::SOURCE)); + srcSpotBoxs.push_back(srcSpotBox); + + // ------ Destination area + Imagefloat *currDstSpot = new Imagefloat(scaledSize, scaledSize); + for (int y = 0; y < currDstSpot->getHeight(); ++y) { + for (int x = 0; x < currDstSpot->getWidth(); ++x) { + currDstSpot->r(y,x) = 0.f; + currDstSpot->g(y,x) = 0.f; + currDstSpot->b(y,x) = 0.f; + } + } + entry.targetPos.get(origin.x, origin.y); + origin.x -= entry.getFeatherRadius(); + origin.y -= entry.getFeatherRadius(); + spp.set(origin.x, origin.y, size, size, pp.getSkip()); + imgsrc->getImage(currWB, tr, currDstSpot, spp, params->toneCurve, params->raw); + //printf(" / dst size: %d,%d\n", currDstSpot->getWidth(), currDstSpot->getHeight()); + + std::shared_ptr dstSpotBox(new SpotBox(origin.x / pp.getSkip(), origin.y / pp.getSkip(), currDstSpot, SpotBox::Type::TARGET)); + + dstSpotBoxs.push_back(dstSpotBox); + } + + // Filter out out of preview Spots + + /* + for (size_t i = entries.size(); i >= 0; ++i) { + float featherRadius = entries.at(i).radius * (1.f + entries.at(i).feather); + + SpotBox srcBox(entries.at(i), SpotBox::Type::SOURCE); + srcBox.translate(-pp.getX(), -pp.getY()); + srcBox /= float (pp.getSkip()); + + SpotBox dstBox(entries.at(i), SpotBox::Type::TARGET); + dstBox.translate(-pp.getX(), -pp.getY()); + dstBox /= float (pp.getSkip()); + + } + */ + + + + // ---------- Copy spots from src to dst + + for (int i = entries.size() - 1; i >= 0; --i) { + // 1. copy src to dst + std::shared_ptr srcSpotBox = srcSpotBoxs.at(i); + std::shared_ptr dstSpotBox = dstSpotBoxs.at(i); + float scaledRadius = float(entries.at(i).radius) / float(pp.getSkip()); + float scaledFeatherRadius = entries.at(i).getFeatherRadius() / float(pp.getSkip()); + Imagefloat *srcImg = srcSpotBox->img; + Imagefloat *dstImg = dstSpotBox->img; + + //printf("#%d: srcSpotBox @ %p - img @ %p / dstSpotBox @ %p - img @ %p\n", i, + // srcSpotBox.get(), srcSpotBox->img, dstSpotBox.get(), dstSpotBox->img ); + + //printf("#%d: srcSpotBox(%d,%d) srcImg(%d,%d) / dstSpotBox(%d,%d) dstImg(%d,%d)\n", i, + // srcSpotBox->getWidth(), srcSpotBox->getHeight(), srcImg->getWidth(), srcImg->getHeight(), + // dstSpotBox->getWidth(), dstSpotBox->getHeight(), dstImg->getWidth(), dstImg->getHeight() + // ); + + for (int y = 0; y < srcSpotBox->getHeight(); ++y) { + float dy = float(y - float(srcSpotBox->getHeight()) / 2.f); + for (int x = 0; x < srcSpotBox->getWidth(); ++x) { + float dx = float(x - float(srcSpotBox->getWidth()) / 2.f); + float r = sqrt(dx * dx + dy * dy); + if (r >= scaledFeatherRadius) { + continue; + } + if (r <= scaledRadius) { + dstImg->r(y, x) = srcImg->r(y, x); + dstImg->g(y, x) = srcImg->g(y, x); + dstImg->b(y, x) = srcImg->b(y, x); + } else { + float opacity = (scaledFeatherRadius - r) / (scaledFeatherRadius - scaledRadius); + dstImg->r(y, x) = (srcImg->r(y, x) - dstImg->r(y, x)) * opacity + dstImg->r(y,x); + dstImg->g(y, x) = (srcImg->g(y, x) - dstImg->g(y, x)) * opacity + dstImg->g(y,x); + dstImg->b(y, x) = (srcImg->b(y, x) - dstImg->b(y, x)) * opacity + dstImg->b(y,x); + } + } + } + //printf("\n\n"); + + // 2. copy dst to later src and dst + + } + + // 3. copy all dst to the finale image + + // Putting the dest image in a SpotBox + SpotBox imgSpotBox(pp.getX() / pp.getSkip(), pp.getY() / pp.getSkip(), img, SpotBox::Type::TARGET); + /* + printf("#--: spotBox(X1:%d, Y1:%d, X2:%d, Y2:%d, W:%d, H:%d) img(W:%d, H:%d)\n\n", + imgSpotBox.topLeftX, imgSpotBox.topLeftY, imgSpotBox.bottomRightX, imgSpotBox.bottomRightY, + imgSpotBox.getWidth(), imgSpotBox.getHeight(), + imgSpotBox.img->getWidth(), imgSpotBox.img->getHeight() + ); + */ + + for (size_t i = 0; i < entries.size(); ++i) { + // 1. copy src to dst + std::shared_ptr dstSpotBox = dstSpotBoxs.at(i); + Imagefloat *dstImg = dstSpotBox->img; + + /* + printf("#%llu: spotBox(X1:%d, Y1:%d, X2:%d, Y2:%d, W:%d, H:%d) img(W:%d, H:%d)\n", i, + dstSpotBox->topLeftX, dstSpotBox->topLeftY, dstSpotBox->bottomRightX, dstSpotBox->bottomRightY, + dstSpotBox->getWidth(), dstSpotBox->getHeight(), + dstImg->getWidth(), dstImg->getHeight() + ); + */ + + if (dstSpotBox->intersects(imgSpotBox)) { + int beginX = rtengine::max(dstSpotBox->topLeftX, imgSpotBox.topLeftX); + int endX = rtengine::min(dstSpotBox->bottomRightX, imgSpotBox.bottomRightX); + int beginY = rtengine::max(dstSpotBox->topLeftY, imgSpotBox.topLeftY); + int endY = rtengine::min(dstSpotBox->bottomRightY, imgSpotBox.bottomRightY); + + //printf("--- Intersection: X1:%d, Y1:%d -> X2:%d, Y2:%d\n", beginX, beginY, endX, endY); + + int dstSpotOffsetY = beginY - dstSpotBox->topLeftY; + int imgOffsetY = beginY - imgSpotBox.topLeftY; + + for (int y = beginY; y <= endY; ++y) { + int dstSpotOffsetX = beginX - dstSpotBox->topLeftX; + int imgOffsetX = beginX - imgSpotBox.topLeftX; + + for (int x = beginX; x <= endX; ++x) { + /* + if (y == beginY && x == beginX) { + printf("--- dstSpotOffsetX = beginX - dstSpotBox->topLeftX = %d - %d = %d\n", beginX, dstSpotBox->topLeftX, dstSpotOffsetX); + printf("--- dstSpotOffsetY = beginY - dstSpotBox->topLeftY = %d - %d = %d\n", beginY, dstSpotBox->topLeftY, dstSpotOffsetY); + printf("--- imgOffsetX = beginX - imgSpotBox.topLeftX = %d - %d = %d\n", beginX, imgSpotBox.topLeftX, imgOffsetX); + printf("--- imgOffsetX = beginY - imgSpotBox.topLeftY = %d - %d = %d\n", beginY, imgSpotBox.topLeftY, imgOffsetY); + } + */ + img->r(imgOffsetY, imgOffsetX) = dstImg->r(dstSpotOffsetY, dstSpotOffsetX); + img->g(imgOffsetY, imgOffsetX) = dstImg->g(dstSpotOffsetY, dstSpotOffsetX); + img->b(imgOffsetY, imgOffsetX) = dstImg->b(dstSpotOffsetY, dstSpotOffsetX); + ++imgOffsetX; + ++dstSpotOffsetX; + } + ++imgOffsetY; + ++dstSpotOffsetY; + } + //} else { + // printf("#%llu: No intersection !\n", i); + } + } + + for (auto srcSpotBox : srcSpotBoxs) { + delete srcSpotBox->img; + } + for (auto dstSpotBox : dstSpotBoxs) { + delete dstSpotBox->img; + } +} + +#endif + + + + + +#if 0 +void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector &entries, const PreviewProps &pp, const ColorTemp &currWB, int tr) +{ + Alpha mask; - //printf("img(%04d, %04d)\n", img->width, img->height); for (const auto entry : entries) { - float srcX = float (entry.sourcePos.x); - float srcY = float (entry.sourcePos.y); - float dstX = float (entry.targetPos.x); - float dstY = float (entry.targetPos.y); - //float radius = float (entry.radius) + 0.5f; - - float featherRadius = entry.radius * (1.f + entry.feather); + float featherRadius = entry.getFeatherRadius(); int scaledFeatherRadius = featherRadius / pp.getSkip (); - int src_XMin = int ((srcX - featherRadius - pp.getX()) / float (pp.getSkip()) + 0.5f); - int src_XMax = int ((srcX + featherRadius - pp.getX()) / float (pp.getSkip()) + 0.5f); - int src_YMin = int ((srcY - featherRadius - pp.getY()) / float (pp.getSkip()) + 0.5f); - int src_YMax = int ((srcY + featherRadius - pp.getY()) / float (pp.getSkip()) + 0.5f); + SpotBox srcBox(entry, SpotBox::Type::SOURCE); + srcBox.translate(-pp.getX(), -pp.getY()); + srcBox /= float (pp.getSkip()); - int dst_XMin = int ((dstX - featherRadius - pp.getX()) / float (pp.getSkip()) + 0.5f); - int dst_XMax = int ((dstX + featherRadius - pp.getX()) / float (pp.getSkip()) + 0.5f); - int dst_YMin = int ((dstY - featherRadius - pp.getY()) / float (pp.getSkip()) + 0.5f); - int dst_YMax = int ((dstY + featherRadius - pp.getY()) / float (pp.getSkip()) + 0.5f); + SpotBox dstBox(entry, SpotBox::Type::TARGET); + dstBox.translate(-pp.getX(), -pp.getY()); + dstBox /= float (pp.getSkip()); //printf(" -> X: %04d > %04d\n -> Y: %04d > %04d\n", dst_XMin, dst_XMax, dst_YMin, dst_YMax); @@ -101,7 +376,7 @@ void ImProcFunctions::removeSpots (Imagefloat* img, const std::vector #endif } - // skipping entries where the source circle isn't completely inside the image bounds + // skipping entries where the source circle isn't inside the image bounds, even partially if (src_XMin < 0 || src_XMax >= img->getWidth() || src_YMin < 0 || src_YMax >= img->getHeight()) { #ifndef NDEBUG @@ -116,6 +391,7 @@ void ImProcFunctions::removeSpots (Imagefloat* img, const std::vector } // skipping entries where the dest circle is completely outside the image bounds + /* if (dst_XMin >= img->getWidth() || dst_XMax <= 0 || dst_YMin >= img->getHeight() || dst_YMax <= 0) { #ifndef NDEBUG @@ -128,6 +404,7 @@ void ImProcFunctions::removeSpots (Imagefloat* img, const std::vector #endif continue; } + */ // ----------------- Core function ----------------- @@ -347,6 +624,9 @@ void ImProcFunctions::removeSpots (Imagefloat* img, const std::vector printf ("\n"); #endif + + + // add solution to original image and store in tempPR for (int i = 0, i2 = dst_YMin; i2 < dst_YMax - 1; ++i, ++i2) { if (i2 < 0 || i2 >= img->getHeight()) { @@ -376,6 +656,7 @@ void ImProcFunctions::removeSpots (Imagefloat* img, const std::vector } } +#endif } From 4d4f54cbc24033fe1bf32c34657847ff07022c1e Mon Sep 17 00:00:00 2001 From: Hombre Date: Wed, 14 Aug 2019 15:52:22 +0200 Subject: [PATCH 010/135] Spot-Removal (#2239): Adding recusivity and border handling Warning: Debug builds will be slow due to the amount of debug output (no problem for Release builds). Code cleanup will be done when after testing phase. --- rtengine/simpleprocess.cc | 13 +- rtengine/spot.cc | 757 +++++++++++++++++++++++++++----------- rtgui/spot.cc | 16 + rtgui/spot.h | 16 + 4 files changed, 586 insertions(+), 216 deletions(-) diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 38ccb5133..6934cc8e8 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -781,7 +781,12 @@ private: params.toneCurve.brightness = 0; params.toneCurve.contrast = 0; params.toneCurve.black = 0; - } + } + + // Spot Removal + if (params.spot.enabled && !params.spot.entries.empty ()) { + ipf.removeSpots (baseImg, imgsrc, params.spot.entries, pp, currWB, tr); + } // at this stage, we can flush the raw data to free up quite an important amount of memory // commented out because it makes the application crash when batch processing... @@ -924,12 +929,6 @@ private: } } - // Spot Removal - - if (params.spot.enabled && !params.spot.entries.empty ()) { - ipf.removeSpots (baseImg, imgsrc, params.spot.entries, pp, currWB, tr); - } - // RGB processing curve1 (65536); diff --git a/rtengine/spot.cc b/rtengine/spot.cc index 60bfb2f6c..2090324dd 100644 --- a/rtengine/spot.cc +++ b/rtengine/spot.cc @@ -21,6 +21,19 @@ #include "alpha.h" #include "procparams.h" #include "imagesource.h" +#include + +namespace +{ + +// "ceil" rounding +template +constexpr T skips(T a, T b) +{ + return a / b + static_cast(a % b); +} + +} namespace rtengine { @@ -58,271 +71,597 @@ class SpotBox { public: enum class Type { SOURCE, - TARGET + TARGET, + FINAL }; + struct Rectangle { + public: + int x1; + int y1; + int x2; + int y2; + + Rectangle() : x1(0), y1(0), x2(0), y2(0) {} + Rectangle(const Rectangle &other) : x1(other.x1), y1(other.y1), x2(other.x2), y2(other.y2) {} + Rectangle(int X1, int Y1, int X2, int Y2) : x1(X1), y1(Y1), x2(X2), y2(Y2) {} + + bool intersects(const Rectangle &other) const { + return (other.x1 <= x2 && other.x2 >= x1) + && (other.y1 <= y2 && other.y2 >= y1); + } + + bool getIntersection(const Rectangle &other, std::unique_ptr &intersection) const { + if (intersects(other)) { + if (!intersection) { + intersection.reset(new Rectangle()); + } + intersection->x1 = rtengine::max(x1, other.x1); + intersection->x2 = rtengine::min(x2, other.x2); + intersection->y1 = rtengine::max(y1, other.y1); + intersection->y2 = rtengine::min(y2, other.y2); + + if (intersection->x1 > intersection->x2 || intersection->y1 > intersection->y2) { + intersection.release(); + return false; + } + return true; + } + if (intersection) { + intersection.release(); + } + return false; + } + + Rectangle& operator+=(const Coord &v) { + x1 += v.x; + y1 += v.y; + x2 += v.x; + y2 += v.y; + return *this; + } + + Rectangle& operator-=(const Coord &v) { + x1 -= v.x; + y1 -= v.y; + x2 -= v.x; + y2 -= v.y; + return *this; + } + + Rectangle& operator/=(const int &v) { + if (v == 1) { + return *this; + } + + /* + float fv = float(v); + x1 = int(float(x1) / fv + 0.5f); + y1 = int(float(y1) / fv + 0.5f); + x2 = int(float(x2) / fv + 0.5f); + y2 = int(float(y2) / fv + 0.5f); + */ + + // Aletrnate rounding possibility + int w = x2 - x1 + 1; + int h = x2 - x1 + 1; + w = w / v + (w % v > 0); + h = h / v + (h % v > 0); + x1 /= v; + y1 /= v; + x2 = x1 + w - 1; + y2 = y1 + h - 1; + + return *this; + } +}; + private: Type type; + Imagefloat* image; public: - int topLeftX; - int topLeftY; - int bottomRightX; - int bottomRightY; - Imagefloat* img; + // top/left and bottom/right coordinates of the spot in image space (at some point divided by scale factor) + Rectangle spotArea; + // top/left and bottom/right coordinates of the spot in scaled image space (on borders, imgArea won't cover spotArea) + Rectangle imgArea; + // top/left and bottom/right coordinates of useful part of the image in scaled image space (rounding error workaround) + Rectangle intersectionArea; + float radius; + float featherRadius; - SpotBox (int tl_x, int tl_y, int br_x, int br_y, Type type) : + SpotBox (int tl_x, int tl_y, int br_x, int br_y, int radius, int feather_radius, Imagefloat* image, Type type) : type(type), - topLeftX(tl_x), - topLeftY(tl_y), - bottomRightX(br_x), - bottomRightY(br_y), - img(nullptr) + image(image), + spotArea(tl_x, tl_y, br_x, br_y), + imgArea(spotArea), + intersectionArea(), + radius(radius), + featherRadius(feather_radius) {} - SpotBox (int tl_x, int tl_y, Imagefloat* image, Type type) : + SpotBox (int tl_x, int tl_y, int radius, int feather_radius, Imagefloat* image, Type type) : type(type), - topLeftX(tl_x), - topLeftY(tl_y), - bottomRightX(image ? tl_x + image->getWidth() - 1 : 0), - bottomRightY(image ? tl_y + image->getHeight() - 1 : 0), - img(image) + image(image), + spotArea(tl_x, tl_y, image ? tl_x + image->getWidth() - 1 : 0, image ? tl_y + image->getHeight() - 1 : 0), + imgArea(spotArea), + intersectionArea(), + radius(radius), + featherRadius(feather_radius) {} SpotBox (SpotEntry &spot, Type type) : type(type), - img(nullptr) + image(nullptr), + intersectionArea(), + radius(spot.radius), + featherRadius(int(spot.getFeatherRadius() + 0.5f)) // rounding to int before resizing { - float featherRadius = spot.radius * (1.f + spot.feather); - topLeftX = int ((type == Type::SOURCE ? spot.sourcePos.x : spot.targetPos.x) - featherRadius); - bottomRightX = int ((type == Type::SOURCE ? spot.sourcePos.x : spot.targetPos.x) + featherRadius); - topLeftY = int ((type == Type::SOURCE ? spot.sourcePos.y : spot.targetPos.y) - featherRadius); - bottomRightY = int ((type == Type::SOURCE ? spot.sourcePos.y : spot.targetPos.y) + featherRadius); + spotArea.x1 = int ((type == Type::SOURCE ? spot.sourcePos.x : spot.targetPos.x) - featherRadius); + spotArea.x2 = int ((type == Type::SOURCE ? spot.sourcePos.x : spot.targetPos.x) + featherRadius); + spotArea.y1 = int ((type == Type::SOURCE ? spot.sourcePos.y : spot.targetPos.y) - featherRadius); + spotArea.y2 = int ((type == Type::SOURCE ? spot.sourcePos.y : spot.targetPos.y) + featherRadius); + imgArea = spotArea; } - void translate(int dx, int dy) { - topLeftX += dx; - topLeftY += dy; - bottomRightX += dx; - bottomRightY += dy; + ~SpotBox() { + if (image && type != Type::FINAL) { + delete image; + } } - void operator /(float v) { - topLeftX = int(topLeftX / v + 0.5f); - topLeftY = int(topLeftY / v + 0.5f); - bottomRightX = int(bottomRightX / v + 0.5f); - bottomRightY = int(bottomRightY / v + 0.5f); - } - - void operator *(float v) { - topLeftX *= v; - topLeftY *= v; - bottomRightX *= v; - bottomRightY *= v; - } - - bool intersects(const SpotBox &other) const { - return (other.topLeftX <= bottomRightX && other.bottomRightX >= topLeftX) - && (other.topLeftY <= bottomRightY && other.bottomRightY >= topLeftY); + SpotBox& operator /=(const int& v) { + if (v == 1) { + return *this; + } + spotArea /= v; + imgArea /= v; + radius = radius / float(v); + featherRadius = getWidth() / 2.f; + // intersectionArea doesn't need resize, because it's set after resizing + return *this; } int getWidth() { - return bottomRightX - topLeftX + 1; + return spotArea.x2 - spotArea.x1 + 1; } int getHeight() { - return bottomRightY - topLeftY + 1; + return spotArea.y2 - spotArea.y1 + 1; } -}; + int getImageWidth() { + return imgArea.x2 - imgArea.x1 + 1; + } -void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector &entries, const PreviewProps &pp, const ColorTemp &currWB, int tr) -{ - // ---------- Get the image areas (src & dst) from the source image + int getImageHeight() { + return imgArea.y2 - imgArea.y1 + 1; + } - printf("\n=======================================================================\n\n"); + int getIntersectionWidth() { + return intersectionArea.x2 - intersectionArea.x1 + 1; + } - std::vector< std::shared_ptr > srcSpotBoxs; - std::vector< std::shared_ptr > dstSpotBoxs; - for (auto entry : params->spot.entries) { - Coord origin; - int size = int(entry.getFeatherRadius() * 2.f + 0.5f); - int scaledSize = int(entry.getFeatherRadius() * 2.f / float(pp.getSkip()) + 0.5f); - //printf("size: %d - skip: %d -> scaledSize: %d", size, pp.getSkip(), scaledSize); + int getIntersectionHeight() { + return intersectionArea.y2 - intersectionArea.y1 + 1; + } - // ------ Source area - Imagefloat *currSrcSpot = new Imagefloat(scaledSize, scaledSize); - for (int y = 0; y < currSrcSpot->getHeight(); ++y) { - for (int x = 0; x < currSrcSpot->getWidth(); ++x) { - currSrcSpot->r(y,x) = 0.f; - currSrcSpot->g(y,x) = 0.f; - currSrcSpot->b(y,x) = 0.f; - } + bool checkImageSize() { + if (!image || getImageWidth() != image->getWidth() || getImageHeight() != image->getHeight()) { + return false; } - entry.sourcePos.get(origin.x, origin.y); - origin.x -= entry.getFeatherRadius(); - origin.y -= entry.getFeatherRadius(); - PreviewProps spp(origin.x, origin.y, size, size, pp.getSkip()); - imgsrc->getImage(currWB, tr, currSrcSpot, spp, params->toneCurve, params->raw); - //printf(" / src size: %d,%d", currSrcSpot->getWidth(), currSrcSpot->getHeight()); + return true; + } - std::shared_ptr srcSpotBox(new SpotBox(origin.x / pp.getSkip(), origin.y / pp.getSkip(), currSrcSpot, SpotBox::Type::SOURCE)); - srcSpotBoxs.push_back(srcSpotBox); - - // ------ Destination area - Imagefloat *currDstSpot = new Imagefloat(scaledSize, scaledSize); - for (int y = 0; y < currDstSpot->getHeight(); ++y) { - for (int x = 0; x < currDstSpot->getWidth(); ++x) { - currDstSpot->r(y,x) = 0.f; - currDstSpot->g(y,x) = 0.f; - currDstSpot->b(y,x) = 0.f; - } + void tuneImageSize() { + if (!image) { + return; } - entry.targetPos.get(origin.x, origin.y); - origin.x -= entry.getFeatherRadius(); - origin.y -= entry.getFeatherRadius(); - spp.set(origin.x, origin.y, size, size, pp.getSkip()); - imgsrc->getImage(currWB, tr, currDstSpot, spp, params->toneCurve, params->raw); - //printf(" / dst size: %d,%d\n", currDstSpot->getWidth(), currDstSpot->getHeight()); - - std::shared_ptr dstSpotBox(new SpotBox(origin.x / pp.getSkip(), origin.y / pp.getSkip(), currDstSpot, SpotBox::Type::TARGET)); - - dstSpotBoxs.push_back(dstSpotBox); - } - - // Filter out out of preview Spots - - /* - for (size_t i = entries.size(); i >= 0; ++i) { - float featherRadius = entries.at(i).radius * (1.f + entries.at(i).feather); - - SpotBox srcBox(entries.at(i), SpotBox::Type::SOURCE); - srcBox.translate(-pp.getX(), -pp.getY()); - srcBox /= float (pp.getSkip()); - - SpotBox dstBox(entries.at(i), SpotBox::Type::TARGET); - dstBox.translate(-pp.getX(), -pp.getY()); - dstBox /= float (pp.getSkip()); - - } - */ - - - - // ---------- Copy spots from src to dst - - for (int i = entries.size() - 1; i >= 0; --i) { - // 1. copy src to dst - std::shared_ptr srcSpotBox = srcSpotBoxs.at(i); - std::shared_ptr dstSpotBox = dstSpotBoxs.at(i); - float scaledRadius = float(entries.at(i).radius) / float(pp.getSkip()); - float scaledFeatherRadius = entries.at(i).getFeatherRadius() / float(pp.getSkip()); - Imagefloat *srcImg = srcSpotBox->img; - Imagefloat *dstImg = dstSpotBox->img; - - //printf("#%d: srcSpotBox @ %p - img @ %p / dstSpotBox @ %p - img @ %p\n", i, - // srcSpotBox.get(), srcSpotBox->img, dstSpotBox.get(), dstSpotBox->img ); - - //printf("#%d: srcSpotBox(%d,%d) srcImg(%d,%d) / dstSpotBox(%d,%d) dstImg(%d,%d)\n", i, - // srcSpotBox->getWidth(), srcSpotBox->getHeight(), srcImg->getWidth(), srcImg->getHeight(), - // dstSpotBox->getWidth(), dstSpotBox->getHeight(), dstImg->getWidth(), dstImg->getHeight() - // ); - - for (int y = 0; y < srcSpotBox->getHeight(); ++y) { - float dy = float(y - float(srcSpotBox->getHeight()) / 2.f); - for (int x = 0; x < srcSpotBox->getWidth(); ++x) { - float dx = float(x - float(srcSpotBox->getWidth()) / 2.f); - float r = sqrt(dx * dx + dy * dy); - if (r >= scaledFeatherRadius) { - continue; - } - if (r <= scaledRadius) { - dstImg->r(y, x) = srcImg->r(y, x); - dstImg->g(y, x) = srcImg->g(y, x); - dstImg->b(y, x) = srcImg->b(y, x); - } else { - float opacity = (scaledFeatherRadius - r) / (scaledFeatherRadius - scaledRadius); - dstImg->r(y, x) = (srcImg->r(y, x) - dstImg->r(y, x)) * opacity + dstImg->r(y,x); - dstImg->g(y, x) = (srcImg->g(y, x) - dstImg->g(y, x)) * opacity + dstImg->g(y,x); - dstImg->b(y, x) = (srcImg->b(y, x) - dstImg->b(y, x)) * opacity + dstImg->b(y,x); - } - } + if (getImageWidth() > image->getWidth()) { + imgArea.x2 = imgArea.x1 + image->getWidth() - 1; + } + if (getImageHeight() > image->getHeight()) { + imgArea.y2 = imgArea.y1 + image->getHeight() - 1; } - //printf("\n\n"); - - // 2. copy dst to later src and dst - } - // 3. copy all dst to the finale image + Imagefloat *getImage() { // TODO: this should send back a const value, but getImage don't want it to be const... + return image; + } - // Putting the dest image in a SpotBox - SpotBox imgSpotBox(pp.getX() / pp.getSkip(), pp.getY() / pp.getSkip(), img, SpotBox::Type::TARGET); - /* - printf("#--: spotBox(X1:%d, Y1:%d, X2:%d, Y2:%d, W:%d, H:%d) img(W:%d, H:%d)\n\n", - imgSpotBox.topLeftX, imgSpotBox.topLeftY, imgSpotBox.bottomRightX, imgSpotBox.bottomRightY, - imgSpotBox.getWidth(), imgSpotBox.getHeight(), - imgSpotBox.img->getWidth(), imgSpotBox.img->getHeight() - ); - */ + void allocImage() { + int newW = imgArea.x2 - imgArea.x1 + 1; + int newH = imgArea.y2 - imgArea.y1 + 1; - for (size_t i = 0; i < entries.size(); ++i) { - // 1. copy src to dst - std::shared_ptr dstSpotBox = dstSpotBoxs.at(i); - Imagefloat *dstImg = dstSpotBox->img; + if (image && type != Type::FINAL && (image->getWidth() != newW || image->getHeight() != newH)) { + delete image; + image = nullptr; + } + if (image == nullptr) { + image = new Imagefloat(newW, newH); + } + } + + bool spotIntersects(const SpotBox &other) const { + return spotArea.intersects(other.spotArea); + } + + bool getSpotIntersection(const SpotBox &other, std::unique_ptr &intersection) const { + return spotArea.getIntersection(other.spotArea, intersection); + } + + bool imageIntersects(const SpotBox &other, bool atDestLocation=false) const { + if (atDestLocation) { + Coord v(other.spotArea.x1 - spotArea.x1, other.spotArea.y1 - spotArea.y1); + Rectangle imgArea2(imgArea.x1, imgArea.y1, imgArea.x2, imgArea.y2); + imgArea2 += v; + return imgArea2.intersects(other.imgArea); + } + return imgArea.intersects(other.imgArea); + } + + bool mutuallyClipImageArea(SpotBox &other) { + Coord v(other.spotArea.x1 - spotArea.x1, other.spotArea.y1 - spotArea.y1); + Rectangle imgArea2 = imgArea; + imgArea2 += v; + std::unique_ptr intersection; + if (!imgArea2.getIntersection(other.imgArea, intersection)) { + return false; + } + other.intersectionArea = *intersection; + Coord v2(-v.x, -v.y); + *intersection -= v; + intersectionArea = *intersection; + return true; + } + + bool setIntersectionWith(const SpotBox &other) { + if (!spotIntersects(other)) { + return false; + } + imgArea.x1 = rtengine::max(spotArea.x1, other.spotArea.x1); + imgArea.x2 = rtengine::min(spotArea.x2, other.spotArea.x2); + imgArea.y1 = rtengine::max(spotArea.y1, other.spotArea.y1); + imgArea.y2 = rtengine::min(spotArea.y2, other.spotArea.y2); + if (imgArea.x1 > imgArea.x2 || imgArea.y1 > imgArea.y2) { + return false; + } + return true; + } + + bool processIntersectionWith(SpotBox &destBox) { + Imagefloat *dstImg = destBox.image; + + if (image == nullptr || dstImg == nullptr) { + std::cerr << "One of the source or destination SpotBox image is missing !" << std::endl; + return false; + } /* printf("#%llu: spotBox(X1:%d, Y1:%d, X2:%d, Y2:%d, W:%d, H:%d) img(W:%d, H:%d)\n", i, - dstSpotBox->topLeftX, dstSpotBox->topLeftY, dstSpotBox->bottomRightX, dstSpotBox->bottomRightY, - dstSpotBox->getWidth(), dstSpotBox->getHeight(), - dstImg->getWidth(), dstImg->getHeight() + spotArea.x1, spotArea.y1, spotArea.x2, spotArea.y2, + getWidth(), getHeight(), + destBox.getWidth(), destBox.getHeight() ); */ - if (dstSpotBox->intersects(imgSpotBox)) { - int beginX = rtengine::max(dstSpotBox->topLeftX, imgSpotBox.topLeftX); - int endX = rtengine::min(dstSpotBox->bottomRightX, imgSpotBox.bottomRightX); - int beginY = rtengine::max(dstSpotBox->topLeftY, imgSpotBox.topLeftY); - int endY = rtengine::min(dstSpotBox->bottomRightY, imgSpotBox.bottomRightY); +#ifndef NDEBUG + printf("[processIntersectionWith] srcSpotBox @ %p(%d, %d) - img @ %p(%d, %d) / dstSpotBox @ %p(%d, %d) - img @ %p(%d, %d)\n", + this, getWidth(), getHeight(), image, destBox.getWidth(), destBox.getHeight(), + &destBox, destBox.getWidth(), destBox.getHeight(), destBox.image, dstImg->getWidth(), dstImg->getHeight()); + printf(" [spot] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n", + spotArea.x1, spotArea.y1, spotArea.x2, spotArea.y2, + destBox.spotArea.x1, destBox.spotArea.y1, destBox.spotArea.x2, destBox.spotArea.y2); + printf(" [img ] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n", + imgArea.x1, imgArea.y1, imgArea.x2, imgArea.y2, + destBox.imgArea.x1, destBox.imgArea.y1, destBox.imgArea.x2, destBox.imgArea.y2); + printf(" [intr] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n", + intersectionArea.x1, intersectionArea.y1, intersectionArea.x2, intersectionArea.y2, + destBox.intersectionArea.x1, destBox.intersectionArea.y1, destBox.intersectionArea.x2, destBox.intersectionArea.y2); + printf(" radius = %.3f\n", radius); +#endif - //printf("--- Intersection: X1:%d, Y1:%d -> X2:%d, Y2:%d\n", beginX, beginY, endX, endY); + int srcImgY = intersectionArea.y1 - imgArea.y1; + int dstImgY = destBox.intersectionArea.y1 - destBox.imgArea.y1; + for (int y = intersectionArea.y1; y <= intersectionArea.y2; ++y) { + float dy = float(y - spotArea.y1) - featherRadius; - int dstSpotOffsetY = beginY - dstSpotBox->topLeftY; - int imgOffsetY = beginY - imgSpotBox.topLeftY; + int srcImgX = intersectionArea.x1 - imgArea.x1; + int dstImgX = destBox.intersectionArea.x1 - destBox.imgArea.x1; + for (int x = intersectionArea.x1; x <= intersectionArea.x2; ++x) { + float dx = float(x - spotArea.x1) - featherRadius; + float r = sqrt(dx * dx + dy * dy); - for (int y = beginY; y <= endY; ++y) { - int dstSpotOffsetX = beginX - dstSpotBox->topLeftX; - int imgOffsetX = beginX - imgSpotBox.topLeftX; - - for (int x = beginX; x <= endX; ++x) { - /* - if (y == beginY && x == beginX) { - printf("--- dstSpotOffsetX = beginX - dstSpotBox->topLeftX = %d - %d = %d\n", beginX, dstSpotBox->topLeftX, dstSpotOffsetX); - printf("--- dstSpotOffsetY = beginY - dstSpotBox->topLeftY = %d - %d = %d\n", beginY, dstSpotBox->topLeftY, dstSpotOffsetY); - printf("--- imgOffsetX = beginX - imgSpotBox.topLeftX = %d - %d = %d\n", beginX, imgSpotBox.topLeftX, imgOffsetX); - printf("--- imgOffsetX = beginY - imgSpotBox.topLeftY = %d - %d = %d\n", beginY, imgSpotBox.topLeftY, imgOffsetY); - } - */ - img->r(imgOffsetY, imgOffsetX) = dstImg->r(dstSpotOffsetY, dstSpotOffsetX); - img->g(imgOffsetY, imgOffsetX) = dstImg->g(dstSpotOffsetY, dstSpotOffsetX); - img->b(imgOffsetY, imgOffsetX) = dstImg->b(dstSpotOffsetY, dstSpotOffsetX); - ++imgOffsetX; - ++dstSpotOffsetX; + if (r >= featherRadius) { + ++srcImgX; + ++dstImgX; + continue; + } + if (r <= radius) { + dstImg->r(dstImgY, dstImgX) = image->r(srcImgY, srcImgX); + dstImg->g(dstImgY, dstImgX) = image->g(srcImgY, srcImgX); + dstImg->b(dstImgY, dstImgX) = image->b(srcImgY, srcImgX); + } else { + float opacity = (featherRadius - r) / (featherRadius - radius); + dstImg->r(dstImgY, dstImgX) = (image->r(srcImgY, srcImgX) - dstImg->r(dstImgY, dstImgX)) * opacity + dstImg->r(dstImgY,dstImgX); + dstImg->g(dstImgY, dstImgX) = (image->g(srcImgY, srcImgX) - dstImg->g(dstImgY, dstImgX)) * opacity + dstImg->g(dstImgY,dstImgX); + dstImg->b(dstImgY, dstImgX) = (image->b(srcImgY, srcImgX) - dstImg->b(dstImgY, dstImgX)) * opacity + dstImg->b(dstImgY,dstImgX); + } + ++srcImgX; + ++dstImgX; + } + ++srcImgY; + ++dstImgY; + } + + return true; + } + + // Copy the intersecting part + bool copyImgTo(SpotBox &destBox) { + Imagefloat *destImg = destBox.image; + + if (image == nullptr || destImg == nullptr) { + std::cerr << "One of the source or destination SpotBox image is missing !" << std::endl; + return false; + } + + /* + printf("#%llu: spotBox(X1:%d, Y1:%d, X2:%d, Y2:%d, W:%d, H:%d) img(W:%d, H:%d)\n", i, + spotArea.x1, spotArea.y1, spotArea.x2, spotArea.y2, + getWidth(), getHeight(), + destBox.getWidth(), destBox.getHeight() + ); + */ + + std::unique_ptr intersection; + + if (!intersectionArea.getIntersection(destBox.intersectionArea, intersection)) { + return false; + } + + Imagefloat *srcImg = image; + Imagefloat *dstImg = destBox.image; + +#ifndef NDEBUG + printf("[copyImgTo] srcSpotBox @ %p(%d, %d) - img @ %p(%d, %d) / dstSpotBox @ %p(%d, %d) - img @ %p(%d, %d)\n", + this, getWidth(), getHeight(), image, srcImg->getWidth(), srcImg->getHeight(), + &destBox, destBox.getWidth(), destBox.getHeight(), destBox.image, dstImg->getWidth(), dstImg->getHeight()); + printf(" [spot] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n", + spotArea.x1, spotArea.y1, spotArea.x2, spotArea.y2, + destBox.spotArea.x1, destBox.spotArea.y1, destBox.spotArea.x2, destBox.spotArea.y2); + printf(" [img ] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n", + imgArea.x1, imgArea.y1, imgArea.x2, imgArea.y2, + destBox.imgArea.x1, destBox.imgArea.y1, destBox.imgArea.x2, destBox.imgArea.y2); + printf(" [intr] intersection (%d, %d) -> (%d, %d)\n", + intersection->x1, intersection->y1, intersection->x2, intersection->y2); +#endif + + int srcImgY = intersection->y1 - imgArea.y1; + int dstImgY = intersection->y1 - destBox.imgArea.y1; + for (int y = intersection->y1; y <= intersection->y2; ++y) { + int srcImgX = intersection->x1 - imgArea.x1; + int dstImgX = intersection->x1 - destBox.imgArea.x1; + + for (int x = intersection->x1; x <= intersection->x2; ++x) { + dstImg->r(dstImgY, dstImgX) = srcImg->r(srcImgY, srcImgX); + dstImg->g(dstImgY, dstImgX) = srcImg->g(srcImgY, srcImgX); + dstImg->b(dstImgY, dstImgX) = srcImg->b(srcImgY, srcImgX); + ++srcImgX; + ++dstImgX; + } + ++srcImgY; + ++dstImgY; + } + + return true; + } +}; + +void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector &entries, const PreviewProps &pp, const ColorTemp &currWB, int tr) +{ + //Get the clipped image areas (src & dst) from the source image + + std::vector< std::shared_ptr > srcSpotBoxs; + std::vector< std::shared_ptr > dstSpotBoxs; + int fullImgWidth = 0; + int fullImgHeight = 0; + imgsrc->getFullSize(fullImgWidth, fullImgHeight, tr); + SpotBox fullImageBox(0, 0, fullImgWidth - 1, fullImgHeight - 1, 0, 0, nullptr, SpotBox::Type::FINAL); + SpotBox cropBox(pp.getX(), pp.getY(), + pp.getX() + pp.getWidth() - 1, pp.getY() + pp.getHeight() - 1, + 0, 0, img, SpotBox::Type::FINAL); + + std::set visibleSpots; // list of dest spots intersecting the preview's crop + int i = 0; + + for (auto entry : params->spot.entries) { + std::shared_ptr srcSpotBox(new SpotBox(entry, SpotBox::Type::SOURCE)); + std::shared_ptr dstSpotBox(new SpotBox(entry, SpotBox::Type::TARGET)); + if ( !srcSpotBox->setIntersectionWith(fullImageBox) + || !dstSpotBox->setIntersectionWith(fullImageBox) + || !srcSpotBox->imageIntersects(*dstSpotBox, true)) + { + continue; + ++i; + } + + // If spot intersect the preview image, add it to the visible spots + if (dstSpotBox->spotIntersects(cropBox)) { +#ifndef NDEBUG + printf("Spot visible insere: %d\n", i); +#endif + visibleSpots.insert(i); + } + ++i; + + // Source area + PreviewProps spp(srcSpotBox->imgArea.x1, srcSpotBox->imgArea.y1, + srcSpotBox->getImageWidth(), srcSpotBox->getImageHeight(), pp.getSkip()); + int w = 0; + int h = 0; + imgsrc->getSize(spp, w, h); + *srcSpotBox /= pp.getSkip(); + srcSpotBox->allocImage(); + Imagefloat *_image_ = srcSpotBox->getImage(); + for (int y = 0; y < (int)_image_->getHeight(); ++y) { + for (int x = 0; x < (int)_image_->getWidth(); ++x) { + _image_->r(y, x) = 60000.f; + _image_->g(y, x) = 500.f; + _image_->b(y, x) = 500.f; + } + } + +#ifndef NDEBUG + printf("~~~~~ Image Size Before : %d, %d\n", _image_->getWidth(), _image_->getHeight()); +#endif + imgsrc->getImage(currWB, tr, srcSpotBox->getImage(), spp, params->toneCurve, params->raw); +#ifndef NDEBUG + printf("~~~~~ Image Size After : %d, %d\n", _image_->getWidth(), _image_->getHeight()); +#endif + assert(srcSpotBox->checkImageSize()); + //printf(" / src size: %d,%d", currSrcSpot->getWidth(), currSrcSpot->getHeight()); + + + // Destination area + spp.set(dstSpotBox->imgArea.x1, dstSpotBox->imgArea.y1, dstSpotBox->getImageWidth(), + dstSpotBox->getImageHeight(), pp.getSkip()); + *dstSpotBox /= pp.getSkip(); + dstSpotBox->allocImage(); + _image_ = dstSpotBox->getImage(); + for (int y = 0; y < (int)_image_->getHeight(); ++y) { + for (int x = 0; x < (int)_image_->getWidth(); ++x) { + _image_->r(y, x) = 500.f; + _image_->g(y, x) = 500.f; + _image_->b(y, x) = 60000.f; + } + } +#ifndef NDEBUG + printf("~~~~~ Image Size Before : %d, %d\n", _image_->getWidth(), _image_->getHeight()); +#endif + imgsrc->getImage(currWB, tr, dstSpotBox->getImage(), spp, params->toneCurve, params->raw); +#ifndef NDEBUG + printf("~~~~~ Image Size After : %d, %d\n", _image_->getWidth(), _image_->getHeight()); +#endif + assert(dstSpotBox->checkImageSize()); + //printf(" / src size: %d,%d", currDstSpot->getWidth(), currDstSpot->getHeight()); + + // Update the intersectionArea between src and dest + if (srcSpotBox->mutuallyClipImageArea(*dstSpotBox)) { + srcSpotBoxs.push_back(srcSpotBox); + dstSpotBoxs.push_back(dstSpotBox); + +#ifndef NDEBUG + printf("Taille de l'image pour spot #%d: src(%d, %d) / dst(%d, %d)\n", i-1, + srcSpotBox->getImageWidth(), srcSpotBox->getImageHeight(), + dstSpotBox->getImageWidth(), dstSpotBox->getImageHeight() + ); +#endif + } + + } + + // Construct list of upstream dependancies + + std::set requiredSpots = visibleSpots; // starting point, visible spots are necessarilly required spots +#ifndef NDEBUG + printf("Required spots: "); +#endif + for (auto i = requiredSpots.rbegin(); i != requiredSpots.rend(); i++) { + int spotNbr = *i; +#ifndef NDEBUG + printf("%d ", spotNbr); +#endif + requiredSpots.insert(spotNbr); + if (spotNbr > 0) { + for (int j = spotNbr - 1; j >= 0; --j) { + if ((srcSpotBoxs.at(spotNbr))->imageIntersects(*dstSpotBoxs.at(j))) { + requiredSpots.insert(spotNbr); +#ifndef NDEBUG + printf("%d ", spotNbr); +#endif } - ++imgOffsetY; - ++dstSpotOffsetY; } - //} else { - // printf("#%llu: No intersection !\n", i); } } +#ifndef NDEBUG + printf("\n"); +#endif - for (auto srcSpotBox : srcSpotBoxs) { - delete srcSpotBox->img; + // Process spots and copy them downstream + + for (auto i = requiredSpots.begin(); i != requiredSpots.end(); i++) { + // Process +#ifndef NDEBUG + printf("========>>> Processing spot #%d\n", *i); +#endif + srcSpotBoxs.at(*i)->processIntersectionWith(*dstSpotBoxs.at(*i)); + + // Propagate + std::set positiveSpots; // For DEBUG purpose only ! + auto j = i; + ++j; + while (j != requiredSpots.end()) { + bool intersectionFound = false; + int i_ = *i; + int j_ = *j; +#ifndef NDEBUG + printf("Propagating to SRC #%d ?\n", j_); +#endif + intersectionFound |= dstSpotBoxs.at(i_)->copyImgTo(*srcSpotBoxs.at(j_)); +#ifndef NDEBUG + printf("Propagating to DSTC #%d ?\n", j_); +#endif + intersectionFound |= dstSpotBoxs.at(i_)->copyImgTo(*dstSpotBoxs.at(j_)); + if (intersectionFound) { + positiveSpots.insert(j_); + } + ++j; + } +#ifndef NDEBUG + printf("||| DEST spot #%d propagated to : ", *i); + for (auto g : positiveSpots) { + printf("%d ", g); + } + printf("\n"); +#endif } - for (auto dstSpotBox : dstSpotBoxs) { - delete dstSpotBox->img; + + // Copy the dest spot to the preview image +#ifndef NDEBUG + printf("cropBox (%d, %d) -> (%d, %d)", + cropBox.imgArea.x1, cropBox.imgArea.y1, + cropBox.imgArea.x2, cropBox.imgArea.y2); +#endif + cropBox /= pp.getSkip(); +#ifndef NDEBUG + printf(" -> [/skip] (%d, %d) -> (%d, %d)", + cropBox.imgArea.x1, cropBox.imgArea.y1, + cropBox.imgArea.x2, cropBox.imgArea.y2); +#endif + cropBox.tuneImageSize(); + cropBox.intersectionArea = cropBox.imgArea; +#ifndef NDEBUG + printf(" -> [/tuned] (%d, %d) -> (%d, %d)\n", + cropBox.imgArea.x1, cropBox.imgArea.y1, + cropBox.imgArea.x2, cropBox.imgArea.y2); +#endif + + int f = 0; + for (auto i : visibleSpots) { + f += dstSpotBoxs.at(i)->copyImgTo(cropBox) ? 1 : 0; } +#ifndef NDEBUG + printf("Nombre de copie finale : %d\n", f); +#endif + + /* + printf("#--: spotBox(X1:%d, Y1:%d, X2:%d, Y2:%d, W:%d, H:%d) img(W:%d, H:%d)\n\n", + cropBox.spotArea.x1, cropBox.spotArea.y1, cropBox.spotArea.x2, cropBox.spotArea.y2, + cropBox.getWidth(), cropBox.getHeight(), + cropBox.image->getWidth(), cropBox.image->getHeight() + ); + */ } #endif diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 9f7830a15..024f1ae26 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -1,6 +1,22 @@ /* * This file is part of RawTherapee. + * + * Copyright (c) 2019 Jean-Christophe FRISCH + * + * 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 "editcallbacks.h" #include "spot.h" #include "rtimage.h" diff --git a/rtgui/spot.h b/rtgui/spot.h index b163848c0..f1a4cc604 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -1,6 +1,22 @@ /* * This file is part of RawTherapee. + * + * Copyright (c) 2019 Jean-Christophe FRISCH + * + * 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 _SPOT_H_ #define _SPOT_H_ From b4d77986a6b8b0d9ecb2e375893b329e4e195790 Mon Sep 17 00:00:00 2001 From: Hombre Date: Thu, 15 Aug 2019 02:15:26 +0200 Subject: [PATCH 011/135] Non active anchors are now thinner + bugfix + code cleanup See issue #2239 --- rtdata/images/svg/spot-normal.svg | 65 ++-- rtengine/dcrop.cc | 4 +- rtengine/improccoordinator.cc | 2 +- rtengine/improcfun.h | 2 +- rtengine/simpleprocess.cc | 2 +- rtengine/spot.cc | 626 ++++++++++-------------------- 6 files changed, 246 insertions(+), 455 deletions(-) diff --git a/rtdata/images/svg/spot-normal.svg b/rtdata/images/svg/spot-normal.svg index ca9a933c2..d0320e31f 100644 --- a/rtdata/images/svg/spot-normal.svg +++ b/rtdata/images/svg/spot-normal.svg @@ -9,62 +9,65 @@ xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - width="16px" - height="16px" - id="svg2985" + width="11" + height="11" + id="svg2" version="1.1" - inkscape:version="0.48.4 r9939" - sodipodi:docname="New document 2"> + inkscape:version="0.92.3 (2405546, 2018-03-11)" + sodipodi:docname="spot-normal.svg"> + id="defs4" /> + id="metadata7"> image/svg+xml - + + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,-1041.3622)"> + style="fill:#000000;fill-opacity:0.66666667;stroke:none" + d="M 6,1043.3622 5.378906,1046.7411 2,1047.3622 v 1 l 3.378906,0.6211 L 6,1052.3622 H 7 L 7.621094,1048.9833 11,1048.3622 v -1 L 7.621094,1046.7411 7,1043.3622 Z" + id="path818" + inkscape:connector-curvature="0" /> + d="m 5,1042.3622 h 1 l 0.8286408,4.5 L 6,1051.3622 H 5 l -0.8286408,-4.5 z" + id="rect2989" + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccccc" /> + diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 72f5c6d72..488a56b46 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -623,7 +623,7 @@ void Crop::update(int todo) spotsDone = true; PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); //parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); - parent->ipf.removeSpots(origCrop, parent->imgsrc, params.spot.entries, pp, parent->currWB, tr); + parent->ipf.removeSpots(origCrop, parent->imgsrc, params.spot.entries, pp, parent->currWB, nullptr, tr); } DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise; @@ -709,7 +709,7 @@ void Crop::update(int todo) baseCrop->copyData (spotCrop); PreviewProps pp (trafx, trafy, trafw * skip, trafh * skip, skip); int tr = getCoarseBitMask(params.coarse); - parent->ipf.removeSpots (spotCrop, parent->imgsrc, params.spot.entries, pp, parent->currWB, tr); + parent->ipf.removeSpots (spotCrop, parent->imgsrc, params.spot.entries, pp, parent->currWB, ¶ms.icm, tr); } else { if (spotCrop) { delete spotCrop; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 2c49bdef1..22bafd844 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -540,7 +540,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) allocCache(spotprev); orig_prev->copyData(spotprev); PreviewProps pp(0, 0, fw, fh, scale); - ipf.removeSpots(spotprev, imgsrc, params->spot.entries, pp, currWB, tr); + ipf.removeSpots(spotprev, imgsrc, params->spot.entries, pp, currWB, ¶ms->icm, tr); } else { if (spotprev) { delete spotprev; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 5700a354b..a1b79fc38 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -333,7 +333,7 @@ public: float MadRgb(const float * DataList, int datalen); // spot removal tool - void removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector &entries, const PreviewProps &pp, const ColorTemp &currWB, int tr); + void removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector &entries, const PreviewProps &pp, const ColorTemp &currWB, const ColorManagementParams *cmp, int tr); // pyramid wavelet void dirpyr_equalizer(float ** src, float ** dst, int srcwidth, int srcheight, float ** l_a, float ** l_b, const double * mult, const double dirpyrThreshold, const double skinprot, float b_l, float t_l, float t_r, int scale); //Emil's directional pyramid wavelet diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 6934cc8e8..c50306f6f 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -785,7 +785,7 @@ private: // Spot Removal if (params.spot.enabled && !params.spot.entries.empty ()) { - ipf.removeSpots (baseImg, imgsrc, params.spot.entries, pp, currWB, tr); + ipf.removeSpots (baseImg, imgsrc, params.spot.entries, pp, currWB, nullptr, tr); } // at this stage, we can flush the raw data to free up quite an important amount of memory diff --git a/rtengine/spot.cc b/rtengine/spot.cc index 2090324dd..b12f5bc40 100644 --- a/rtengine/spot.cc +++ b/rtengine/spot.cc @@ -38,34 +38,6 @@ constexpr T skips(T a, T b) namespace rtengine { -/* Code taken from Gimp 2.8.10 and converted for RawTherapee by Jean-Christophe FRISCH (aka Hombre) on 02.19.2014 - * - * ORIGINAL NOTES - * - * The method used here is similar to the lighting invariant correction - * method but slightly different: we do not divide the RGB components, - * but substract them I2 = I0 - I1, where I0 is the sample image to be - * corrected, I1 is the reference pattern. Then we solve DeltaI=0 - * (Laplace) with I2 Dirichlet conditions at the borders of the - * mask. The solver is a unoptimized red/black checker Gauss-Siedel - * with an over-relaxation factor of 1.8. It can benefit from a - * multi-grid evaluation of an initial solution before the main - * iteration loop. - * - * I reduced the convergence criteria to 0.1% (0.001) as we are - * dealing here with RGB integer components, more is overkill. - * - * Jean-Yves Couleaud cjyves@free.fr - */ - -/* Original Algorithm Design: - * - * T. Georgiev, "Photoshop Healing Brush: a Tool for Seamless Cloning - * http://www.tgeorgiev.net/Photoshop_Healing.pdf - */ - -#if 1 - class SpotBox { public: @@ -329,6 +301,9 @@ public: return true; } +#define ALGO 1 + +#if ALGO==1 bool processIntersectionWith(SpotBox &destBox) { Imagefloat *dstImg = destBox.image; @@ -337,30 +312,6 @@ public: return false; } - /* - printf("#%llu: spotBox(X1:%d, Y1:%d, X2:%d, Y2:%d, W:%d, H:%d) img(W:%d, H:%d)\n", i, - spotArea.x1, spotArea.y1, spotArea.x2, spotArea.y2, - getWidth(), getHeight(), - destBox.getWidth(), destBox.getHeight() - ); - */ - -#ifndef NDEBUG - printf("[processIntersectionWith] srcSpotBox @ %p(%d, %d) - img @ %p(%d, %d) / dstSpotBox @ %p(%d, %d) - img @ %p(%d, %d)\n", - this, getWidth(), getHeight(), image, destBox.getWidth(), destBox.getHeight(), - &destBox, destBox.getWidth(), destBox.getHeight(), destBox.image, dstImg->getWidth(), dstImg->getHeight()); - printf(" [spot] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n", - spotArea.x1, spotArea.y1, spotArea.x2, spotArea.y2, - destBox.spotArea.x1, destBox.spotArea.y1, destBox.spotArea.x2, destBox.spotArea.y2); - printf(" [img ] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n", - imgArea.x1, imgArea.y1, imgArea.x2, imgArea.y2, - destBox.imgArea.x1, destBox.imgArea.y1, destBox.imgArea.x2, destBox.imgArea.y2); - printf(" [intr] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n", - intersectionArea.x1, intersectionArea.y1, intersectionArea.x2, intersectionArea.y2, - destBox.intersectionArea.x1, destBox.intersectionArea.y1, destBox.intersectionArea.x2, destBox.intersectionArea.y2); - printf(" radius = %.3f\n", radius); -#endif - int srcImgY = intersectionArea.y1 - imgArea.y1; int dstImgY = destBox.intersectionArea.y1 - destBox.imgArea.y1; for (int y = intersectionArea.y1; y <= intersectionArea.y2; ++y) { @@ -396,358 +347,44 @@ public: return true; } - - // Copy the intersecting part - bool copyImgTo(SpotBox &destBox) { - Imagefloat *destImg = destBox.image; - - if (image == nullptr || destImg == nullptr) { - std::cerr << "One of the source or destination SpotBox image is missing !" << std::endl; - return false; - } - - /* - printf("#%llu: spotBox(X1:%d, Y1:%d, X2:%d, Y2:%d, W:%d, H:%d) img(W:%d, H:%d)\n", i, - spotArea.x1, spotArea.y1, spotArea.x2, spotArea.y2, - getWidth(), getHeight(), - destBox.getWidth(), destBox.getHeight() - ); - */ - - std::unique_ptr intersection; - - if (!intersectionArea.getIntersection(destBox.intersectionArea, intersection)) { - return false; - } - - Imagefloat *srcImg = image; - Imagefloat *dstImg = destBox.image; - -#ifndef NDEBUG - printf("[copyImgTo] srcSpotBox @ %p(%d, %d) - img @ %p(%d, %d) / dstSpotBox @ %p(%d, %d) - img @ %p(%d, %d)\n", - this, getWidth(), getHeight(), image, srcImg->getWidth(), srcImg->getHeight(), - &destBox, destBox.getWidth(), destBox.getHeight(), destBox.image, dstImg->getWidth(), dstImg->getHeight()); - printf(" [spot] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n", - spotArea.x1, spotArea.y1, spotArea.x2, spotArea.y2, - destBox.spotArea.x1, destBox.spotArea.y1, destBox.spotArea.x2, destBox.spotArea.y2); - printf(" [img ] srcSpotBox (%d, %d) -> (%d, %d) / dstSpotBox (%d, %d) -> (%d, %d)\n", - imgArea.x1, imgArea.y1, imgArea.x2, imgArea.y2, - destBox.imgArea.x1, destBox.imgArea.y1, destBox.imgArea.x2, destBox.imgArea.y2); - printf(" [intr] intersection (%d, %d) -> (%d, %d)\n", - intersection->x1, intersection->y1, intersection->x2, intersection->y2); #endif - int srcImgY = intersection->y1 - imgArea.y1; - int dstImgY = intersection->y1 - destBox.imgArea.y1; - for (int y = intersection->y1; y <= intersection->y2; ++y) { - int srcImgX = intersection->x1 - imgArea.x1; - int dstImgX = intersection->x1 - destBox.imgArea.x1; - - for (int x = intersection->x1; x <= intersection->x2; ++x) { - dstImg->r(dstImgY, dstImgX) = srcImg->r(srcImgY, srcImgX); - dstImg->g(dstImgY, dstImgX) = srcImg->g(srcImgY, srcImgX); - dstImg->b(dstImgY, dstImgX) = srcImg->b(srcImgY, srcImgX); - ++srcImgX; - ++dstImgX; - } - ++srcImgY; - ++dstImgY; - } - - return true; - } -}; - -void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector &entries, const PreviewProps &pp, const ColorTemp &currWB, int tr) -{ - //Get the clipped image areas (src & dst) from the source image - - std::vector< std::shared_ptr > srcSpotBoxs; - std::vector< std::shared_ptr > dstSpotBoxs; - int fullImgWidth = 0; - int fullImgHeight = 0; - imgsrc->getFullSize(fullImgWidth, fullImgHeight, tr); - SpotBox fullImageBox(0, 0, fullImgWidth - 1, fullImgHeight - 1, 0, 0, nullptr, SpotBox::Type::FINAL); - SpotBox cropBox(pp.getX(), pp.getY(), - pp.getX() + pp.getWidth() - 1, pp.getY() + pp.getHeight() - 1, - 0, 0, img, SpotBox::Type::FINAL); - - std::set visibleSpots; // list of dest spots intersecting the preview's crop - int i = 0; - - for (auto entry : params->spot.entries) { - std::shared_ptr srcSpotBox(new SpotBox(entry, SpotBox::Type::SOURCE)); - std::shared_ptr dstSpotBox(new SpotBox(entry, SpotBox::Type::TARGET)); - if ( !srcSpotBox->setIntersectionWith(fullImageBox) - || !dstSpotBox->setIntersectionWith(fullImageBox) - || !srcSpotBox->imageIntersects(*dstSpotBox, true)) - { - continue; - ++i; - } - - // If spot intersect the preview image, add it to the visible spots - if (dstSpotBox->spotIntersects(cropBox)) { -#ifndef NDEBUG - printf("Spot visible insere: %d\n", i); -#endif - visibleSpots.insert(i); - } - ++i; - - // Source area - PreviewProps spp(srcSpotBox->imgArea.x1, srcSpotBox->imgArea.y1, - srcSpotBox->getImageWidth(), srcSpotBox->getImageHeight(), pp.getSkip()); - int w = 0; - int h = 0; - imgsrc->getSize(spp, w, h); - *srcSpotBox /= pp.getSkip(); - srcSpotBox->allocImage(); - Imagefloat *_image_ = srcSpotBox->getImage(); - for (int y = 0; y < (int)_image_->getHeight(); ++y) { - for (int x = 0; x < (int)_image_->getWidth(); ++x) { - _image_->r(y, x) = 60000.f; - _image_->g(y, x) = 500.f; - _image_->b(y, x) = 500.f; - } - } - -#ifndef NDEBUG - printf("~~~~~ Image Size Before : %d, %d\n", _image_->getWidth(), _image_->getHeight()); -#endif - imgsrc->getImage(currWB, tr, srcSpotBox->getImage(), spp, params->toneCurve, params->raw); -#ifndef NDEBUG - printf("~~~~~ Image Size After : %d, %d\n", _image_->getWidth(), _image_->getHeight()); -#endif - assert(srcSpotBox->checkImageSize()); - //printf(" / src size: %d,%d", currSrcSpot->getWidth(), currSrcSpot->getHeight()); +#if ALGO==2 + bool processIntersectionWith(SpotBox &destBox) { + /* The following disabled code has been taken from Gimp 2.8.10 and converted + * for RawTherapee by Jean-Christophe FRISCH (aka Hombre) on 02.19.2014. + * It has not been tested, at all, an can (does) contain bugs. Feel free to + * replace the actual working code by this one, if results are better. + */ - // Destination area - spp.set(dstSpotBox->imgArea.x1, dstSpotBox->imgArea.y1, dstSpotBox->getImageWidth(), - dstSpotBox->getImageHeight(), pp.getSkip()); - *dstSpotBox /= pp.getSkip(); - dstSpotBox->allocImage(); - _image_ = dstSpotBox->getImage(); - for (int y = 0; y < (int)_image_->getHeight(); ++y) { - for (int x = 0; x < (int)_image_->getWidth(); ++x) { - _image_->r(y, x) = 500.f; - _image_->g(y, x) = 500.f; - _image_->b(y, x) = 60000.f; - } - } -#ifndef NDEBUG - printf("~~~~~ Image Size Before : %d, %d\n", _image_->getWidth(), _image_->getHeight()); -#endif - imgsrc->getImage(currWB, tr, dstSpotBox->getImage(), spp, params->toneCurve, params->raw); -#ifndef NDEBUG - printf("~~~~~ Image Size After : %d, %d\n", _image_->getWidth(), _image_->getHeight()); -#endif - assert(dstSpotBox->checkImageSize()); - //printf(" / src size: %d,%d", currDstSpot->getWidth(), currDstSpot->getHeight()); - - // Update the intersectionArea between src and dest - if (srcSpotBox->mutuallyClipImageArea(*dstSpotBox)) { - srcSpotBoxs.push_back(srcSpotBox); - dstSpotBoxs.push_back(dstSpotBox); - -#ifndef NDEBUG - printf("Taille de l'image pour spot #%d: src(%d, %d) / dst(%d, %d)\n", i-1, - srcSpotBox->getImageWidth(), srcSpotBox->getImageHeight(), - dstSpotBox->getImageWidth(), dstSpotBox->getImageHeight() - ); -#endif - } - - } - - // Construct list of upstream dependancies - - std::set requiredSpots = visibleSpots; // starting point, visible spots are necessarilly required spots -#ifndef NDEBUG - printf("Required spots: "); -#endif - for (auto i = requiredSpots.rbegin(); i != requiredSpots.rend(); i++) { - int spotNbr = *i; -#ifndef NDEBUG - printf("%d ", spotNbr); -#endif - requiredSpots.insert(spotNbr); - if (spotNbr > 0) { - for (int j = spotNbr - 1; j >= 0; --j) { - if ((srcSpotBoxs.at(spotNbr))->imageIntersects(*dstSpotBoxs.at(j))) { - requiredSpots.insert(spotNbr); -#ifndef NDEBUG - printf("%d ", spotNbr); -#endif - } - } - } - } -#ifndef NDEBUG - printf("\n"); -#endif - - // Process spots and copy them downstream - - for (auto i = requiredSpots.begin(); i != requiredSpots.end(); i++) { - // Process -#ifndef NDEBUG - printf("========>>> Processing spot #%d\n", *i); -#endif - srcSpotBoxs.at(*i)->processIntersectionWith(*dstSpotBoxs.at(*i)); - - // Propagate - std::set positiveSpots; // For DEBUG purpose only ! - auto j = i; - ++j; - while (j != requiredSpots.end()) { - bool intersectionFound = false; - int i_ = *i; - int j_ = *j; -#ifndef NDEBUG - printf("Propagating to SRC #%d ?\n", j_); -#endif - intersectionFound |= dstSpotBoxs.at(i_)->copyImgTo(*srcSpotBoxs.at(j_)); -#ifndef NDEBUG - printf("Propagating to DSTC #%d ?\n", j_); -#endif - intersectionFound |= dstSpotBoxs.at(i_)->copyImgTo(*dstSpotBoxs.at(j_)); - if (intersectionFound) { - positiveSpots.insert(j_); - } - ++j; - } -#ifndef NDEBUG - printf("||| DEST spot #%d propagated to : ", *i); - for (auto g : positiveSpots) { - printf("%d ", g); - } - printf("\n"); -#endif - } - - // Copy the dest spot to the preview image -#ifndef NDEBUG - printf("cropBox (%d, %d) -> (%d, %d)", - cropBox.imgArea.x1, cropBox.imgArea.y1, - cropBox.imgArea.x2, cropBox.imgArea.y2); -#endif - cropBox /= pp.getSkip(); -#ifndef NDEBUG - printf(" -> [/skip] (%d, %d) -> (%d, %d)", - cropBox.imgArea.x1, cropBox.imgArea.y1, - cropBox.imgArea.x2, cropBox.imgArea.y2); -#endif - cropBox.tuneImageSize(); - cropBox.intersectionArea = cropBox.imgArea; -#ifndef NDEBUG - printf(" -> [/tuned] (%d, %d) -> (%d, %d)\n", - cropBox.imgArea.x1, cropBox.imgArea.y1, - cropBox.imgArea.x2, cropBox.imgArea.y2); -#endif - - int f = 0; - for (auto i : visibleSpots) { - f += dstSpotBoxs.at(i)->copyImgTo(cropBox) ? 1 : 0; - } -#ifndef NDEBUG - printf("Nombre de copie finale : %d\n", f); -#endif - - /* - printf("#--: spotBox(X1:%d, Y1:%d, X2:%d, Y2:%d, W:%d, H:%d) img(W:%d, H:%d)\n\n", - cropBox.spotArea.x1, cropBox.spotArea.y1, cropBox.spotArea.x2, cropBox.spotArea.y2, - cropBox.getWidth(), cropBox.getHeight(), - cropBox.image->getWidth(), cropBox.image->getHeight() - ); - */ -} - -#endif + /* ORIGINAL NOTES + * + * The method used here is similar to the lighting invariant correction + * method but slightly different: we do not divide the RGB components, + * but substract them I2 = I0 - I1, where I0 is the sample image to be + * corrected, I1 is the reference pattern. Then we solve DeltaI=0 + * (Laplace) with I2 Dirichlet conditions at the borders of the + * mask. The solver is a unoptimized red/black checker Gauss-Siedel + * with an over-relaxation factor of 1.8. It can benefit from a + * multi-grid evaluation of an initial solution before the main + * iteration loop. + * + * I reduced the convergence criteria to 0.1% (0.001) as we are + * dealing here with RGB integer components, more is overkill. + * + * Jean-Yves Couleaud cjyves@free.fr + */ - - - -#if 0 -void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector &entries, const PreviewProps &pp, const ColorTemp &currWB, int tr) -{ - - Alpha mask; - - - for (const auto entry : entries) { - float featherRadius = entry.getFeatherRadius(); - int scaledFeatherRadius = featherRadius / pp.getSkip (); - - SpotBox srcBox(entry, SpotBox::Type::SOURCE); - srcBox.translate(-pp.getX(), -pp.getY()); - srcBox /= float (pp.getSkip()); - - SpotBox dstBox(entry, SpotBox::Type::TARGET); - dstBox.translate(-pp.getX(), -pp.getY()); - dstBox /= float (pp.getSkip()); - - //printf(" -> X: %04d > %04d\n -> Y: %04d > %04d\n", dst_XMin, dst_XMax, dst_YMin, dst_YMax); - - // scaled spot is too small, we do not preview it - if (scaledFeatherRadius < 2 && pp.getSkip() != 1) { -#ifndef NDEBUG - - if (options.rtSettings.verbose) { - printf ("Skipping spot located at %d x %d, too small for the preview zoom rate\n", entry.sourcePos.x, entry.sourcePos.y); - } - -#endif - continue; - } - - // skipping entries totally transparent - if (entry.opacity == 0.) { -#ifndef NDEBUG - - if (options.rtSettings.verbose) { - printf ("Skipping spot located at %d x %d: opacity=%.3f\n", entry.sourcePos.x, entry.sourcePos.y, entry.opacity); - } - - continue; -#endif - } - - // skipping entries where the source circle isn't inside the image bounds, even partially - if (src_XMin < 0 || src_XMax >= img->getWidth() || src_YMin < 0 || src_YMax >= img->getHeight()) { -#ifndef NDEBUG - - if (options.rtSettings.verbose) { - printf ("Skipping spot located at %d x %d, from the data at %d x %d, radius=%d, feather=%.3f, opacity=%.3f: source out of bounds\n", entry.sourcePos.x, entry.sourcePos.y, entry.targetPos.x, entry.targetPos.y, entry.radius, entry.feather, entry.opacity); - printf ("%d < 0 || %d >= %d || %d < 0 || %d >= %d\n", - src_XMin, src_XMax, img->getWidth(), src_YMin, src_YMax, img->getHeight()); - } - -#endif - continue; - } - - // skipping entries where the dest circle is completely outside the image bounds - /* - if (dst_XMin >= img->getWidth() || dst_XMax <= 0 || dst_YMin >= img->getHeight() || dst_YMax <= 0) { -#ifndef NDEBUG - - if (options.rtSettings.verbose) { - printf ("Skipping spot located at %d x %d, from the data at %d x %d, radius=%d, feather=%.3f, opacity=%.3f: source out of bounds\n", entry.sourcePos.x, entry.sourcePos.y, entry.targetPos.x, entry.targetPos.y, entry.radius, entry.feather, entry.opacity); - printf ("%d >= %d || %d <= 0 || %d >= %d || %d <= 0\n", - dst_XMin, img->getWidth(), dst_XMax, dst_YMin, img->getHeight(), dst_YMax); - } - -#endif - continue; - } - */ + /* Original Algorithm Design: + * + * T. Georgiev, "Photoshop Healing Brush: a Tool for Seamless Cloning + * http://www.tgeorgiev.net/Photoshop_Healing.pdf + */ // ----------------- Core function ----------------- -#if 0 int scaledPPX = pp.getX() / pp.skip; int scaledPPY = pp.getY() / pp.skip; int scaledPPW = pp.getWidth() / pp.skip + (pp.getWidth() % pp.getSkip() > 0); @@ -810,7 +447,6 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s // repeat until convergence or max iterations for (int n = 0; n < MAX_ITER; ++n) { - printf ("<<< n=#%d\n", n); // ---------------------------------------------------------------- /* Perform one iteration of the Laplace solver for matrix. Store the @@ -829,8 +465,6 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s // do reds for (i = 0; i < matrix.getHeight(); ++i) { for (j = i % 2; j < matrix.getWidth(); j += 2) { - printf ("/%d,%d", j, i); - if ((0 == mask (i, j)) || (i == 0) || (i == (matrix.getHeight() - 1)) || (j == 0) || (j == (matrix.getWidth() - 1))) { // do nothing at the boundary or outside mask solution.r (i, j) = matrix.r (i, j); @@ -893,8 +527,6 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s */ for (i = 0; i < matrix.getHeight(); i++) { for (j = (i % 2) ? 0 : 1; j < matrix.getWidth(); j += 2) { - printf (":%d,%d", j, i); - if ((0 == mask (i, j)) || (i == 0) || (i == (matrix.getHeight() - 1)) || (j == 0) || (j == (matrix.getWidth() - 1))) { // do nothing at the boundary or outside mask solution.r (i, j) = matrix.r (i, j); @@ -956,16 +588,8 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s if (sqr_err_r < EPSILON && sqr_err_g < EPSILON && sqr_err_b < EPSILON) { break; } - - printf ("\n>>> n=#%d\n", n); } - printf ("\n"); -#endif - - - - // add solution to original image and store in tempPR for (int i = 0, i2 = dst_YMin; i2 < dst_YMax - 1; ++i, ++i2) { if (i2 < 0 || i2 >= img->getHeight()) { @@ -977,25 +601,189 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s continue; } - //float c2 = float (mask (i, j)) / 255.f; - //float c1 = 1.f - c2; - //resultPR->r(i,j) = (unsigned char) CLAMP0255 ( ROUND( double(first->r(i,j)) + double(secondPR->r(i,j)) ) ); - - - img->r (i2, j2) = 65535.0f; //img->r(i2,j2)*c1 + srcBuff->r(i,j)*c2; - img->g (i2, j2) = 0.0f; //img->g(i2,j2)*c1 + srcBuff->g(i,j)*c2; - img->b (i2, j2) = 0.0f; //img->b(i2,j2)*c1 + srcBuff->b(i,j)*c2; - /* + float c2 = float (mask (i, j)) / 255.f; + float c1 = 1.f - c2; + resultPR->r(i,j) = (unsigned char) CLAMP0255 ( ROUND( double(first->r(i,j)) + double(secondPR->r(i,j)) ) ); img->r(i2,j2) = img->r(i2,j2)*c1 + (solution.r(i,j) + srcBuff->r(i,j))*c2; img->g(i2,j2) = img->g(i2,j2)*c1 + (solution.g(i,j) + srcBuff->g(i,j))*c2; img->b(i2,j2) = img->b(i2,j2)*c1 + (solution.b(i,j) + srcBuff->b(i,j))*c2; - */ + } + } + } +#endif + + // Copy the intersecting part + bool copyImgTo(SpotBox &destBox) { + Imagefloat *destImg = destBox.image; + + if (image == nullptr || destImg == nullptr) { + std::cerr << "One of the source or destination SpotBox image is missing !" << std::endl; + return false; + } + + std::unique_ptr intersection; + + if (!intersectionArea.getIntersection(destBox.intersectionArea, intersection)) { + return false; + } + + Imagefloat *srcImg = image; + Imagefloat *dstImg = destBox.image; + + int srcImgY = intersection->y1 - imgArea.y1; + int dstImgY = intersection->y1 - destBox.imgArea.y1; + for (int y = intersection->y1; y <= intersection->y2; ++y) { + int srcImgX = intersection->x1 - imgArea.x1; + int dstImgX = intersection->x1 - destBox.imgArea.x1; + + for (int x = intersection->x1; x <= intersection->x2; ++x) { + dstImg->r(dstImgY, dstImgX) = srcImg->r(srcImgY, srcImgX); + dstImg->g(dstImgY, dstImgX) = srcImg->g(srcImgY, srcImgX); + dstImg->b(dstImgY, dstImgX) = srcImg->b(srcImgY, srcImgX); + ++srcImgX; + ++dstImgX; + } + ++srcImgY; + ++dstImgY; + } + + return true; + } +}; + +void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector &entries, const PreviewProps &pp, const ColorTemp &currWB, const ColorManagementParams *cmp, int tr) +{ + //Get the clipped image areas (src & dst) from the source image + + std::vector< std::shared_ptr > srcSpotBoxs; + std::vector< std::shared_ptr > dstSpotBoxs; + int fullImgWidth = 0; + int fullImgHeight = 0; + imgsrc->getFullSize(fullImgWidth, fullImgHeight, tr); + SpotBox fullImageBox(0, 0, fullImgWidth - 1, fullImgHeight - 1, 0, 0, nullptr, SpotBox::Type::FINAL); + SpotBox cropBox(pp.getX(), pp.getY(), + pp.getX() + pp.getWidth() - 1, pp.getY() + pp.getHeight() - 1, + 0, 0, img, SpotBox::Type::FINAL); + + std::set visibleSpots; // list of dest spots intersecting the preview's crop + int i = 0; + + for (auto entry : params->spot.entries) { + std::shared_ptr srcSpotBox(new SpotBox(entry, SpotBox::Type::SOURCE)); + std::shared_ptr dstSpotBox(new SpotBox(entry, SpotBox::Type::TARGET)); + if ( !srcSpotBox->setIntersectionWith(fullImageBox) + || !dstSpotBox->setIntersectionWith(fullImageBox) + || !srcSpotBox->imageIntersects(*dstSpotBox, true)) + { + continue; + ++i; + } + + // If spot intersect the preview image, add it to the visible spots + if (dstSpotBox->spotIntersects(cropBox)) { + visibleSpots.insert(i); + } + ++i; + + // Source area + PreviewProps spp(srcSpotBox->imgArea.x1, srcSpotBox->imgArea.y1, + srcSpotBox->getImageWidth(), srcSpotBox->getImageHeight(), pp.getSkip()); + int w = 0; + int h = 0; + imgsrc->getSize(spp, w, h); + *srcSpotBox /= pp.getSkip(); + srcSpotBox->allocImage(); + Imagefloat *srcImage = srcSpotBox->getImage(); + for (int y = 0; y < (int)srcImage->getHeight(); ++y) { + for (int x = 0; x < (int)srcImage->getWidth(); ++x) { + srcImage->r(y, x) = 60000.f; + srcImage->g(y, x) = 500.f; + srcImage->b(y, x) = 500.f; } } + imgsrc->getImage(currWB, tr, srcSpotBox->getImage(), spp, params->toneCurve, params->raw); + if (cmp) { + imgsrc->convertColorSpace(srcImage, *cmp, currWB); + } + assert(srcSpotBox->checkImageSize()); + + + // Destination area + spp.set(dstSpotBox->imgArea.x1, dstSpotBox->imgArea.y1, dstSpotBox->getImageWidth(), + dstSpotBox->getImageHeight(), pp.getSkip()); + *dstSpotBox /= pp.getSkip(); + dstSpotBox->allocImage(); + Imagefloat *dstImage = dstSpotBox->getImage(); + for (int y = 0; y < (int)dstImage->getHeight(); ++y) { + for (int x = 0; x < (int)dstImage->getWidth(); ++x) { + dstImage->r(y, x) = 500.f; + dstImage->g(y, x) = 500.f; + dstImage->b(y, x) = 60000.f; + } + } + imgsrc->getImage(currWB, tr, dstSpotBox->getImage(), spp, params->toneCurve, params->raw); + if (cmp) { + imgsrc->convertColorSpace(dstImage, *cmp, currWB); + } + assert(dstSpotBox->checkImageSize()); + + // Update the intersectionArea between src and dest + if (srcSpotBox->mutuallyClipImageArea(*dstSpotBox)) { + srcSpotBoxs.push_back(srcSpotBox); + dstSpotBoxs.push_back(dstSpotBox); + } + + } + + // Construct list of upstream dependancies + + std::set requiredSpots = visibleSpots; // starting point, visible spots are necessarilly required spots + for (auto i = requiredSpots.rbegin(); i != requiredSpots.rend(); i++) { + int spotNbr = *i; + requiredSpots.insert(spotNbr); + if (spotNbr > 0) { + for (int j = spotNbr - 1; j >= 0; --j) { + if ((srcSpotBoxs.at(spotNbr))->imageIntersects(*dstSpotBoxs.at(j))) { + requiredSpots.insert(spotNbr); + } + } + } + } + + // Process spots and copy them downstream + + for (auto i = requiredSpots.begin(); i != requiredSpots.end(); i++) { + // Process + srcSpotBoxs.at(*i)->processIntersectionWith(*dstSpotBoxs.at(*i)); + + // Propagate + std::set positiveSpots; // For DEBUG purpose only ! + auto j = i; + ++j; + while (j != requiredSpots.end()) { + bool intersectionFound = false; + int i_ = *i; + int j_ = *j; + intersectionFound |= dstSpotBoxs.at(i_)->copyImgTo(*srcSpotBoxs.at(j_)); + intersectionFound |= dstSpotBoxs.at(i_)->copyImgTo(*dstSpotBoxs.at(j_)); + if (intersectionFound) { + positiveSpots.insert(j_); + } + ++j; + } + } + + // Copy the dest spot to the preview image + cropBox /= pp.getSkip(); + cropBox.tuneImageSize(); + cropBox.intersectionArea = cropBox.imgArea; + + int f = 0; + for (auto i : visibleSpots) { + f += dstSpotBoxs.at(i)->copyImgTo(cropBox) ? 1 : 0; } } -#endif } From a46b85f226c04046b6b50066e226be93abf4e6a6 Mon Sep 17 00:00:00 2001 From: Hombre Date: Thu, 15 Aug 2019 19:01:30 +0200 Subject: [PATCH 012/135] Fix crash reported in #2239 + suppress warning from header files Crash reported here https://github.com/Beep6581/RawTherapee/issues/2239#issuecomment-521585237 --- rtengine/improccoordinator.h | 4 ++-- rtengine/improcfun.h | 2 +- rtgui/spot.cc | 20 ++++++++++--------- rtgui/spot.h | 38 ++++++++++++++++++------------------ 4 files changed, 33 insertions(+), 31 deletions(-) diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index e66867d2b..061876968 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -188,8 +188,6 @@ protected: void updateLRGBHistograms (); void setScale (int prevscale); void updatePreviewImage (int todo, bool panningRelatedChange); - void setTweakOperator (TweakOperator *tOperator); - void unsetTweakOperator (TweakOperator *tOperator); MyMutex mProcessing; const std::unique_ptr params; // used for the rendering, can be eventually tweaked @@ -275,6 +273,8 @@ public: DetailedCrop* createCrop (::EditDataProvider *editDataProvider, bool isDetailWindow) override; + void setTweakOperator (TweakOperator *tOperator) override; + void unsetTweakOperator (TweakOperator *tOperator) override; bool getAutoWB (double& temp, double& green, double equal, double tempBias) override; void getCamWB (double& temp, double& green) override; void getSpotWB (int x, int y, int rectSize, double& temp, double& green) override; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index a1b79fc38..01c85953a 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -42,8 +42,8 @@ namespace procparams { class ProcParams; -class SpotEntry; +struct SpotEntry; struct DirPyrDenoiseParams; struct SharpeningParams; struct VignettingParams; diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 024f1ae26..9c5702aa3 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -117,6 +117,8 @@ void Spot::read (const ProcParams* pp, const ParamsEdited* pedited) setEnabled (pp->spot.enabled); lastEnabled = pp->spot.enabled; + activeSpot = -1; + lastObject = -1; if (spots.size() != oldSize) { createGeometry(); @@ -430,12 +432,12 @@ void Spot::deleteSelectedEntry() } // TODO -CursorShape Spot::getCursor (const int objectID) +CursorShape Spot::getCursor (int objectID) { return CSHandOpen; } -bool Spot::mouseOver (const int modifierKey) +bool Spot::mouseOver (int modifierKey) { EditDataProvider* editProvider = getEditProvider(); @@ -485,7 +487,7 @@ bool Spot::mouseOver (const int modifierKey) } // Create a new Target and Source point or start the drag of a Target point under the cursor -bool Spot::button1Pressed (const int modifierKey) +bool Spot::button1Pressed (int modifierKey) { EditDataProvider* editProvider = getEditProvider(); @@ -521,7 +523,7 @@ bool Spot::button1Released() } // Delete a point -bool Spot::button2Pressed (const int modifierKey) +bool Spot::button2Pressed (int modifierKey) { EditDataProvider* editProvider = getEditProvider(); @@ -537,7 +539,7 @@ bool Spot::button2Pressed (const int modifierKey) } // Create a new Target and Source point or start the drag of a Target point under the cursor -bool Spot::button3Pressed (const int modifierKey) +bool Spot::button3Pressed (int modifierKey) { EditDataProvider* editProvider = getEditProvider(); @@ -575,7 +577,7 @@ bool Spot::button3Released() return false; } -bool Spot::drag1 (const int modifierKey) +bool Spot::drag1 (int modifierKey) { EditDataProvider *editProvider = getEditProvider(); int imW, imH; @@ -656,7 +658,7 @@ bool Spot::drag1 (const int modifierKey) return modified; } -bool Spot::drag3 (const int modifierKey) +bool Spot::drag3 (int modifierKey) { EditDataProvider *editProvider = getEditProvider(); int imW, imH; @@ -683,12 +685,12 @@ bool Spot::drag3 (const int modifierKey) return modified; } -bool Spot::pick2 (const bool picked) +bool Spot::pick2 (bool picked) { return pick3 (picked); } -bool Spot::pick3 (const bool picked) +bool Spot::pick3 (bool picked) { EditDataProvider* editProvider = getEditProvider(); diff --git a/rtgui/spot.h b/rtgui/spot.h index f1a4cc604..eea5e8933 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -53,7 +53,7 @@ * (the point will be deleted on button release). */ -class Spot : public ToolParamBlock, public FoldableToolPanel, public EditSubscriber, public rtengine::TweakOperator +class Spot : public ToolParamBlock, public FoldableToolPanel, public rtengine::TweakOperator, public EditSubscriber { private: @@ -93,31 +93,31 @@ public: Spot (); ~Spot (); - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr); - void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr); + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; - void enabledChanged (); + void enabledChanged () override; - void setEditProvider (EditDataProvider* provider); + void setEditProvider (EditDataProvider* provider) override; - void setBatchMode (bool batchMode); + void setBatchMode (bool batchMode) override; // EditSubscriber interface - CursorShape getCursor (const int objectID); - bool mouseOver (const int modifierKey); - bool button1Pressed (const int modifierKey); - bool button1Released (); - bool button2Pressed (const int modifierKey); - bool button3Pressed (const int modifierKey); - bool button3Released (); - bool drag1 (const int modifierKey); - bool drag3 (const int modifierKey); - bool pick2 (const bool picked); - bool pick3 (const bool picked); - void switchOffEditMode (); + CursorShape getCursor (int objectID); + bool mouseOver (int modifierKey) override; + bool button1Pressed (int modifierKey) override; + bool button1Released () override; + bool button2Pressed (int modifierKey) override; + bool button3Pressed (int modifierKey) override; + bool button3Released () override; + bool drag1 (int modifierKey) override; + bool drag3 (int modifierKey) override; + bool pick2 (bool picked) override; + bool pick3 (bool picked) override; + void switchOffEditMode () override; //TweakOperator interface - void tweakParams(rtengine::procparams::ProcParams& pparams) override; + void tweakParams(rtengine::procparams::ProcParams& pparams); rtengine::ProcEvent EvSpotEnabled; rtengine::ProcEvent EvSpotEnabledOPA; // used to toggle-on the Spot 'On Preview Adjustment' mode From 68e26fb6489d0bb58eee14d2e543fed4589ff69c Mon Sep 17 00:00:00 2001 From: Hombre Date: Thu, 15 Aug 2019 20:23:29 +0200 Subject: [PATCH 013/135] More bugfix for issue #2239 --- rtengine/spot.cc | 13 ++----------- rtgui/spot.cc | 2 +- rtgui/spot.h | 4 ++-- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/rtengine/spot.cc b/rtengine/spot.cc index b12f5bc40..2244d882e 100644 --- a/rtengine/spot.cc +++ b/rtengine/spot.cc @@ -106,17 +106,8 @@ public: return *this; } - /* - float fv = float(v); - x1 = int(float(x1) / fv + 0.5f); - y1 = int(float(y1) / fv + 0.5f); - x2 = int(float(x2) / fv + 0.5f); - y2 = int(float(y2) / fv + 0.5f); - */ - - // Aletrnate rounding possibility int w = x2 - x1 + 1; - int h = x2 - x1 + 1; + int h = y2 - y1 + 1; w = w / v + (w % v > 0); h = h / v + (h % v > 0); x1 /= v; @@ -188,7 +179,7 @@ public: } spotArea /= v; imgArea /= v; - radius = radius / float(v); + radius /= float(v); featherRadius = getWidth() / 2.f; // intersectionArea doesn't need resize, because it's set after resizing return *this; diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 9c5702aa3..9a957f77a 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -432,7 +432,7 @@ void Spot::deleteSelectedEntry() } // TODO -CursorShape Spot::getCursor (int objectID) +CursorShape Spot::getCursor (int objectID) const { return CSHandOpen; } diff --git a/rtgui/spot.h b/rtgui/spot.h index eea5e8933..aa0daa4ca 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -103,7 +103,7 @@ public: void setBatchMode (bool batchMode) override; // EditSubscriber interface - CursorShape getCursor (int objectID); + CursorShape getCursor (int objectID) const; bool mouseOver (int modifierKey) override; bool button1Pressed (int modifierKey) override; bool button1Released () override; @@ -117,7 +117,7 @@ public: void switchOffEditMode () override; //TweakOperator interface - void tweakParams(rtengine::procparams::ProcParams& pparams); + void tweakParams(rtengine::procparams::ProcParams& pparams) override; rtengine::ProcEvent EvSpotEnabled; rtengine::ProcEvent EvSpotEnabledOPA; // used to toggle-on the Spot 'On Preview Adjustment' mode From 50064b7e3c890a6437fef656a6b6a853071acc44 Mon Sep 17 00:00:00 2001 From: Hombre Date: Thu, 15 Aug 2019 23:39:44 +0200 Subject: [PATCH 014/135] Supressing a warning when building (see issue #2239) --- rtgui/spot.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/spot.h b/rtgui/spot.h index aa0daa4ca..7604d7846 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -103,7 +103,7 @@ public: void setBatchMode (bool batchMode) override; // EditSubscriber interface - CursorShape getCursor (int objectID) const; + CursorShape getCursor (int objectID) const override; bool mouseOver (int modifierKey) override; bool button1Pressed (int modifierKey) override; bool button1Released () override; From 0d19cd40a6371bbcde6b9939149ef06cbca4880f Mon Sep 17 00:00:00 2001 From: Hombre Date: Fri, 16 Aug 2019 02:46:55 +0200 Subject: [PATCH 015/135] Adding documentation of Spot Removal in a tooltip (see issue #2239) --- rtdata/languages/Francais | 1 + rtdata/languages/default | 1 + rtgui/spot.cc | 1 + 3 files changed, 3 insertions(+) diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 8011b9189..0fce8721c 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -2010,6 +2010,7 @@ TP_SOFTLIGHT_LABEL;Lumière douce TP_SOFTLIGHT_STRENGTH;Force TP_SPOT_COUNTLABEL;%1 point(s) TP_SPOT_ENTRYCHANGED;Modification d'un point +TP_SPOT_HINT;Cliquez sur ce bouton pour pouvoir opérer sur la zone de prévisualisation.\n\nPour ajouter un spot, pressez Ctrl et le bouton gauche de la souris, tirez le cercle (la touche Ctrl peut être relâchée) vers la position source, puis relâchez le bouton de la souris.\n\nPour éditer un spot, placez le curseur au-dessus de la marque blanche situant une zone éditée, faisant apparaître la géométrie d'édition.\n\nPour déplacer le spot source ou destination, placez le curseur en son centre et tirez le.\n\nLe cercle intérieur (zone d'effet maximum) et le cercle "d'adoucicement" peuvent être redimmensionné en plaçant le curseur dessus (le cercle devient orange) et en le tirant (le cercle devient rouge).\n\nQuand les changements sont terminés, un clic droit en dehors de tout spot termine le mode d'édition, ou cliquez à nouveau sur ce bouton. TP_SPOT_LABEL;Retrait de taches TP_TM_FATTAL_AMOUNT;Quantité TP_TM_FATTAL_ANCHOR;Ancre diff --git a/rtdata/languages/default b/rtdata/languages/default index 3296a4c84..d887d9864 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2043,6 +2043,7 @@ TP_SOFTLIGHT_LABEL;Soft Light TP_SOFTLIGHT_STRENGTH;Strength TP_SPOT_COUNTLABEL;%1 point(s) TP_SPOT_ENTRYCHANGED;Point changed +TP_SPOT_HINT;Click on this button to be able to operate on the preview area.\n\nTo edit a spot, hover the white mark locating an edited aera, making the editing geometry appear.\n\nTo add a spot, press Ctrl and left mouse button, drag the circle (Ctrl key can be released) to a source location, then release the mouse button.\n\nTo move the source or destination spot, hover its center then drag it.\n\nThe inner circle (maximum effect area) and the "feather" circle can be resized by hovering them (the circle becomes orange) and draging it (the circle becomes red).\n\nWhen the changes are done, right click outside any spot to end the Spot editing mode, or click on this button again. TP_SPOT_LABEL;Spot removal TP_TM_FATTAL_AMOUNT;Amount TP_TM_FATTAL_ANCHOR;Anchor diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 9a957f77a..6392b95ab 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -40,6 +40,7 @@ Spot::Spot() : FoldableToolPanel (this, "spot", M ("TP_SPOT_LABEL"), true, true) edit = Gtk::manage (new Gtk::ToggleButton()); edit->add (*Gtk::manage (new RTImage ("edit-point.png"))); editConn = edit->signal_toggled().connect ( sigc::mem_fun (*this, &Spot::editToggled) ); + edit->set_tooltip_text(M("TP_SPOT_HINT")); reset = Gtk::manage (new Gtk::Button ()); reset->add (*Gtk::manage (new RTImage ("undo-small.png"))); From 82e7caa635eb109fe5a7669a6ea69eb9316a013d Mon Sep 17 00:00:00 2001 From: Hombre Date: Sun, 1 Sep 2019 02:08:48 +0200 Subject: [PATCH 016/135] Spot removal : differentiating source/dest, betted cursor handling + some code cleanup from floessie (see issue #2239) --- rtengine/spot.cc | 47 +++++------- rtgui/cropwindow.cc | 27 +++++-- rtgui/curveeditor.cc | 2 +- rtgui/curveeditor.h | 2 +- rtgui/editcallbacks.cc | 8 +-- rtgui/editcallbacks.h | 10 +-- rtgui/editwidgets.cc | 157 +++++++++++++++++++++-------------------- rtgui/editwidgets.h | 20 +++++- rtgui/filmnegative.cc | 2 +- rtgui/filmnegative.h | 2 +- rtgui/gradient.cc | 2 +- rtgui/gradient.h | 2 +- rtgui/spot.cc | 64 +++++++++++++++-- rtgui/spot.h | 9 ++- 14 files changed, 222 insertions(+), 132 deletions(-) diff --git a/rtengine/spot.cc b/rtengine/spot.cc index 2244d882e..e9d43ef31 100644 --- a/rtengine/spot.cc +++ b/rtengine/spot.cc @@ -23,18 +23,6 @@ #include "imagesource.h" #include -namespace -{ - -// "ceil" rounding -template -constexpr T skips(T a, T b) -{ - return a / b + static_cast(a % b); -} - -} - namespace rtengine { @@ -48,14 +36,12 @@ public: }; struct Rectangle { - public: int x1; int y1; int x2; int y2; - Rectangle() : x1(0), y1(0), x2(0), y2(0) {} - Rectangle(const Rectangle &other) : x1(other.x1), y1(other.y1), x2(other.x2), y2(other.y2) {} + Rectangle() : Rectangle(0, 0, 0, 0) {} Rectangle(int X1, int Y1, int X2, int Y2) : x1(X1), y1(Y1), x2(X2), y2(Y2) {} bool intersects(const Rectangle &other) const { @@ -65,21 +51,24 @@ public: bool getIntersection(const Rectangle &other, std::unique_ptr &intersection) const { if (intersects(other)) { - if (!intersection) { - intersection.reset(new Rectangle()); - } - intersection->x1 = rtengine::max(x1, other.x1); - intersection->x2 = rtengine::min(x2, other.x2); - intersection->y1 = rtengine::max(y1, other.y1); - intersection->y2 = rtengine::min(y2, other.y2); + std::unique_ptr intsec( + new Rectangle( + rtengine::max(x1, other.x1), + rtengine::max(y1, other.y1), + rtengine::min(x2, other.x2), + rtengine::min(y2, other.y2) + ) + ); - if (intersection->x1 > intersection->x2 || intersection->y1 > intersection->y2) { - intersection.release(); + if (intsec->x1 > intsec->x2 || intsec->y1 > intsec->y2) { return false; } + + intersection = std::move(intsec); return true; } if (intersection) { + // There's no intersection, we delete the Rectangle structure intersection.release(); } return false; @@ -101,15 +90,15 @@ public: return *this; } - Rectangle& operator/=(const int &v) { + Rectangle& operator/=(int v) { if (v == 1) { return *this; } int w = x2 - x1 + 1; int h = y2 - y1 + 1; - w = w / v + (w % v > 0); - h = h / v + (h % v > 0); + w = w / v + static_cast(w % v); + h = h / v + static_cast(h % v); x1 /= v; y1 /= v; x2 = x1 + w - 1; @@ -117,7 +106,7 @@ public: return *this; } -}; + }; private: Type type; @@ -173,7 +162,7 @@ public: } } - SpotBox& operator /=(const int& v) { + SpotBox& operator /=(int v) { if (v == 1) { return *this; } diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index 1e6ae3238..69ee6b30e 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -497,7 +497,7 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) cropgl->cropInit (cropHandler.cropParams->x, cropHandler.cropParams->y, cropHandler.cropParams->w, cropHandler.cropParams->h); } else if (iarea->getToolMode () == TMHand) { if (editSubscriber) { - if ((cropgl && cropgl->inImageArea(iarea->posImage.x, iarea->posImage.y) && editSubscriber->getEditingType() == ET_PIPETTE && (bstate & GDK_CONTROL_MASK))) { + if ((cropgl && cropgl->inImageArea(iarea->posImage.x, iarea->posImage.y) && (editSubscriber->getEditingType() == ET_PIPETTE && (bstate & GDK_CONTROL_MASK))) || editSubscriber->getEditingType() == ET_OBJECTS) { needRedraw = editSubscriber->button1Pressed(bstate); if (editSubscriber->isDragging()) { state = SEditDrag1; @@ -1277,7 +1277,10 @@ void CropWindow::updateCursor (int x, int y) } else if (onArea (CropToolBar, x, y)) { newType = CSMove; } else if (iarea->getObject() > -1 && editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) { - newType = editSubscriber->getCursor(iarea->getObject()); + int cursorX; + int cursorY; + screenCoordToImage (x, y, cursorX, cursorY); + newType = editSubscriber->getCursor(iarea->getObject(), cursorX, cursorY); } else if (onArea (CropResize, x, y)) { newType = CSResizeDiagonal; } else if (tm == TMColorPicker && hoveredPicker) { @@ -1304,7 +1307,10 @@ void CropWindow::updateCursor (int x, int y) } if (objectID > -1) { - newType = editSubscriber->getCursor(objectID); + int cursorX; + int cursorY; + screenCoordToImage (x, y, cursorX, cursorY); + newType = editSubscriber->getCursor(objectID, cursorX, cursorY); } else if (tm == TMHand) { if (onArea (CropObserved, x, y)) { newType = CSMove; @@ -1330,7 +1336,10 @@ void CropWindow::updateCursor (int x, int y) } if (objectID > -1) { - newType = editSubscriber->getCursor(objectID); + int cursorX; + int cursorY; + screenCoordToImage (x, y, cursorX, cursorY); + newType = editSubscriber->getCursor(objectID, cursorX, cursorY); } else { newType = CSArrow; } @@ -1359,6 +1368,16 @@ void CropWindow::updateCursor (int x, int y) newType = CSResizeDiagonal; } else if (state == SDragPicker) { newType = CSMove2D; + } else if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) { + int objectID = iarea->getObject(); + if (objectID > -1) { + int cursorX; + int cursorY; + screenCoordToImage (x, y, cursorX, cursorY); + newType = editSubscriber->getCursor(objectID, cursorX, cursorY); + } else { + newType = CSArrow; + } } if (newType != cursor_type) { diff --git a/rtgui/curveeditor.cc b/rtgui/curveeditor.cc index 528378423..99e371850 100644 --- a/rtgui/curveeditor.cc +++ b/rtgui/curveeditor.cc @@ -490,7 +490,7 @@ bool CurveEditor::drag1(int modifierKey) return false; } -CursorShape CurveEditor::getCursor(int objectID) const +CursorShape CurveEditor::getCursor(int objectID, int xPos, int yPos) const { if (remoteDrag) { return CSResizeHeight; diff --git a/rtgui/curveeditor.h b/rtgui/curveeditor.h index e38d3f205..10963aa1d 100644 --- a/rtgui/curveeditor.h +++ b/rtgui/curveeditor.h @@ -133,7 +133,7 @@ public: bool button1Pressed(int modifierKey) override; bool button1Released() override; bool drag1(int modifierKey) override; - CursorShape getCursor(int objectID) const override; + CursorShape getCursor(int objectID, int xPos, int yPos) const override; }; diff --git a/rtgui/editcallbacks.cc b/rtgui/editcallbacks.cc index d51d672a5..711e56f11 100644 --- a/rtgui/editcallbacks.cc +++ b/rtgui/editcallbacks.cc @@ -172,10 +172,10 @@ void EditDataProvider::setPipetteVal3(float newVal) pipetteVal3 = newVal; } -CursorShape EditDataProvider::getCursor(int objectID) const +CursorShape EditDataProvider::getCursor(int objectID, int xPos, int yPos) const { if (currSubscriber) { - currSubscriber->getCursor(objectID); + currSubscriber->getCursor(objectID, xPos, yPos); } return CSHandOpen; @@ -186,12 +186,12 @@ EditSubscriber* EditDataProvider::getCurrSubscriber() const return currSubscriber; } -EditDataProvider* EditSubscriber::getEditProvider() +EditDataProvider* EditSubscriber::getEditProvider() const { return provider; } -CursorShape EditSubscriber::getCursor(int objectID) const +CursorShape EditSubscriber::getCursor(int objectID, int xPos, int yPos) const { return CSHandOpen; } diff --git a/rtgui/editcallbacks.h b/rtgui/editcallbacks.h index c4003f9ca..0f5f1a0bc 100644 --- a/rtgui/editcallbacks.h +++ b/rtgui/editcallbacks.h @@ -57,7 +57,7 @@ public: virtual ~EditSubscriber () = default; void setEditProvider(EditDataProvider *provider); - EditDataProvider* getEditProvider (); + EditDataProvider* getEditProvider () const; void setEditID(EditUniqueID ID, BufferType buffType); bool isCurrentSubscriber() const; virtual void subscribe(); @@ -70,8 +70,10 @@ public: bool isPicking() const; /// Returns true if something is being picked /** @brief Get the cursor to be displayed when above handles - @param objectID object currently "hovered" */ - virtual CursorShape getCursor (int objectID) const; + @param objectID object currently "hovered" + @param xPos X cursor position in image space + @param yPos Y cursor position in image space */ + virtual CursorShape getCursor (int objectID, int xPos, int yPos) const; /** @brief Triggered when the mouse is moving over an object This method is also triggered when the cursor is moving over the image in ET_PIPETTE mode @@ -188,7 +190,7 @@ public: void setPipetteVal1(float newVal); void setPipetteVal2(float newVal); void setPipetteVal3(float newVal); - virtual CursorShape getCursor(int objectID) const; + virtual CursorShape getCursor(int objectID, int xPos, int yPos) const; int getPipetteRectSize () const; EditSubscriber* getCurrSubscriber() const; virtual void getImageSize (int &w, int&h) = 0; diff --git a/rtgui/editwidgets.cc b/rtgui/editwidgets.cc index 16cd67cd4..1728d1811 100644 --- a/rtgui/editwidgets.cc +++ b/rtgui/editwidgets.cc @@ -20,7 +20,11 @@ #include "editwidgets.h" #include "editbuffer.h" #include "editcallbacks.h" -#include "../rtengine/rt_math.h" + +const std::vector Geometry::dash = {3., 1.5}; + +#define INNERGEOM_OPACITY 1. +#define OUTERGEOM_OPACITY 0.7 RGBColor Geometry::getInnerLineColor () { @@ -65,7 +69,8 @@ RGBColor Geometry::getOuterLineColor () void Circle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { - if ((flags & F_VISIBLE) && state != INSENSITIVE) { + double lineWidth = getOuterLineWidth(); + if ((flags & F_VISIBLE) && state != INSENSITIVE && lineWidth > 0. && innerLineWidth > 0.) { RGBColor color; if (flags & F_AUTO_COLOR) { @@ -74,8 +79,9 @@ void Circle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer color = outerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); - cr->set_line_width( getOuterLineWidth() ); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), OUTERGEOM_OPACITY * rtengine::min(innerLineWidth / 2.f, 1.f)); + cr->set_line_width (lineWidth); + cr->set_line_cap(Cairo::LINE_CAP_ROUND); rtengine::Coord center_ = center; double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius); @@ -105,10 +111,11 @@ void Circle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer color = innerLineColor; } - cr->set_source_rgb(color.getR(), color.getG(), color.getB()); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), INNERGEOM_OPACITY); } - cr->set_line_width( innerLineWidth ); + cr->set_line_width(innerLineWidth); + cr->set_line_cap(flags & F_DASHED ? Cairo::LINE_CAP_BUTT : Cairo::LINE_CAP_ROUND); rtengine::Coord center_ = center; double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius); @@ -121,9 +128,12 @@ void Circle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer center_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; } - if (filled && state != INSENSITIVE) { - cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*rtengine::RT_PI); + if (flags & F_DASHED) { + cr->set_dash(dash, 0.); + } + if (filled) { + cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*rtengine::RT_PI); if (innerLineWidth > 0.) { cr->fill_preserve(); cr->stroke(); @@ -132,28 +142,20 @@ void Circle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer } } else if (innerLineWidth > 0.) { cr->arc(center_.x + 0.5, center_.y + 0.5, radius_, 0., 2.*rtengine::RT_PI); - - if (state == INSENSITIVE) { - std::valarray ds(1); - ds[0] = 4; - cr->set_source_rgba(1.0, 1.0, 1.0, 0.618); - cr->stroke_preserve(); - cr->set_source_rgba(0.0, 0.0, 0.0, 0.618); - cr->set_dash(ds, 0); - cr->stroke(); - ds.resize(0); - cr->set_dash(ds, 0); - } else { - cr->stroke(); - } + cr->stroke(); } - } + + if (flags & F_DASHED) { + cr->unset_dash(); + } +} } void Circle::drawToMOChannel (Cairo::RefPtr &cr, unsigned short id, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { if (flags & F_HOVERABLE) { cr->set_line_width( getMouseOverLineWidth() ); + cr->set_line_cap(Cairo::LINE_CAP_ROUND); rtengine::Coord center_ = center; double radius_ = radiusInImageSpace ? coordSystem.scaleValueToCanvas(double(radius)) : double(radius); @@ -188,7 +190,8 @@ void Circle::drawToMOChannel (Cairo::RefPtr &cr, unsigned short void Line::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { - if ((flags & F_VISIBLE) && state != INSENSITIVE) { + double lineWidth = getOuterLineWidth(); + if ((flags & F_VISIBLE) && state != INSENSITIVE && lineWidth > 0. && innerLineWidth > 0.) { RGBColor color; if (flags & F_AUTO_COLOR) { @@ -197,8 +200,9 @@ void Line::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer * color = outerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); - cr->set_line_width( getOuterLineWidth() ); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), OUTERGEOM_OPACITY * rtengine::min(innerLineWidth / 2.f, 1.f)); + cr->set_line_width (lineWidth); + cr->set_line_cap(Cairo::LINE_CAP_ROUND); rtengine::Coord begin_ = begin; rtengine::Coord end_ = end; @@ -232,10 +236,11 @@ void Line::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer * color = innerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), INNERGEOM_OPACITY); } cr->set_line_width(innerLineWidth); + cr->set_line_cap(flags & F_DASHED ? Cairo::LINE_CAP_BUTT : Cairo::LINE_CAP_ROUND); rtengine::Coord begin_ = begin; rtengine::Coord end_ = end; @@ -251,21 +256,16 @@ void Line::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuffer * end_ += objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; } + if (flags & F_DASHED) { + cr->set_dash(dash, 0.); + } + cr->move_to(begin_.x + 0.5, begin_.y + 0.5); cr->line_to(end_.x + 0.5, end_.y + 0.5); + cr->stroke(); - if (state == INSENSITIVE) { - std::valarray ds(1); - ds[0] = 4; - cr->set_source_rgba(1.0, 1.0, 1.0, 0.618); - cr->stroke_preserve(); - cr->set_source_rgba(0.0, 0.0, 0.0, 0.618); - cr->set_dash(ds, 0); - cr->stroke(); - ds.resize(0); - cr->set_dash(ds, 0); - } else { - cr->stroke(); + if (flags & F_DASHED) { + cr->unset_dash(); } } } @@ -274,6 +274,7 @@ void Line::drawToMOChannel(Cairo::RefPtr &cr, unsigned short id, { if (flags & F_HOVERABLE) { cr->set_line_width( getMouseOverLineWidth() ); + cr->set_line_cap(Cairo::LINE_CAP_ROUND); rtengine::Coord begin_ = begin; rtengine::Coord end_ = end; @@ -302,7 +303,8 @@ void Line::drawToMOChannel(Cairo::RefPtr &cr, unsigned short id, void Polyline::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { - if ((flags & F_VISIBLE) && state != INSENSITIVE && points.size() > 1) { + double lineWidth = getOuterLineWidth(); + if ((flags & F_VISIBLE) && state != INSENSITIVE && points.size() > 1 && lineWidth > 0.) { RGBColor color; if (flags & F_AUTO_COLOR) { @@ -311,8 +313,10 @@ void Polyline::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuff color = outerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); - cr->set_line_width( getOuterLineWidth() ); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), OUTERGEOM_OPACITY * rtengine::min(innerLineWidth / 2.f, 1.f)); + cr->set_line_width (lineWidth); + cr->set_line_cap(Cairo::LINE_CAP_ROUND); + cr->set_line_join(Cairo::LINE_JOIN_ROUND); rtengine::Coord currPos; @@ -355,10 +359,16 @@ void Polyline::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuff color = innerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), INNERGEOM_OPACITY); } - cr->set_line_width( innerLineWidth ); + cr->set_line_width(innerLineWidth); + cr->set_line_cap(flags & F_DASHED ? Cairo::LINE_CAP_BUTT : Cairo::LINE_CAP_ROUND); + cr->set_line_join(Cairo::LINE_JOIN_ROUND); + + if (flags & F_DASHED) { + cr->set_dash(dash, 0.); + } if (filled && state != INSENSITIVE) { rtengine::Coord currPos; @@ -407,20 +417,11 @@ void Polyline::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuff cr->line_to(currPos.x + 0.5, currPos.y + 0.5); } } + cr->stroke(); + } - if (state == INSENSITIVE) { - std::valarray ds(1); - ds[0] = 4; - cr->set_source_rgba(1.0, 1.0, 1.0, 0.618); - cr->stroke_preserve(); - cr->set_source_rgba(0.0, 0.0, 0.0, 0.618); - cr->set_dash(ds, 0); - cr->stroke(); - ds.resize(0); - cr->set_dash(ds, 0); - } else { - cr->stroke(); - } + if (flags & F_DASHED) { + cr->unset_dash(); } } } @@ -437,8 +438,11 @@ void Polyline::drawToMOChannel (Cairo::RefPtr &cr, unsigned shor cr->set_source_rgba (0., 0., 0., (id + 1) / 65535.); } + cr->set_line_width( getMouseOverLineWidth() ); + cr->set_line_cap(Cairo::LINE_CAP_ROUND); + cr->set_line_join(Cairo::LINE_JOIN_ROUND); + for (unsigned int i = 0; i < points.size(); ++i) { - cr->set_line_width( getMouseOverLineWidth() ); currPos = points.at(i); if (datum == IMAGE) { @@ -495,7 +499,8 @@ void Rectangle::setXYXY(rtengine::Coord topLeft, rtengine::Coord bottomRight) void Rectangle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuffer *objectBuffer, EditCoordSystem &coordSystem) { - if ((flags & F_VISIBLE) && state != INSENSITIVE) { + double lineWidth = getOuterLineWidth(); + if ((flags & F_VISIBLE) && state != INSENSITIVE && lineWidth > 0. && innerLineWidth > 0.) { RGBColor color; if (flags & F_AUTO_COLOR) { @@ -504,8 +509,9 @@ void Rectangle::drawOuterGeometry(Cairo::RefPtr &cr, ObjectMOBuf color = outerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); - cr->set_line_width( getOuterLineWidth() ); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), OUTERGEOM_OPACITY * rtengine::min(innerLineWidth / 2.f, 1.f)); + cr->set_line_width (lineWidth); + cr->set_line_join(Cairo::LINE_JOIN_BEVEL); rtengine::Coord tl, br; @@ -548,10 +554,11 @@ void Rectangle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuf color = innerLineColor; } - cr->set_source_rgb (color.getR(), color.getG(), color.getB()); + cr->set_source_rgba (color.getR(), color.getG(), color.getB(), INNERGEOM_OPACITY); } - cr->set_line_width( innerLineWidth ); + cr->set_line_width(innerLineWidth); + cr->set_line_join(Cairo::LINE_JOIN_BEVEL); rtengine::Coord tl, br; @@ -571,7 +578,11 @@ void Rectangle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuf br = bottomRight + objectBuffer->getDataProvider()->posScreen + objectBuffer->getDataProvider()->deltaScreen; } - if (filled && state != INSENSITIVE) { + if (flags & F_DASHED) { + cr->set_dash(dash, 0.); + } + + if (filled) { cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y); if (innerLineWidth > 0.) { @@ -582,20 +593,11 @@ void Rectangle::drawInnerGeometry(Cairo::RefPtr &cr, ObjectMOBuf } } else if (innerLineWidth > 0.) { cr->rectangle(tl.x + 0.5, tl.y + 0.5, br.x - tl.x, br.y - tl.y); + cr->stroke(); + } - if (state == INSENSITIVE) { - std::valarray ds(1); - ds[0] = 4; - cr->set_source_rgba(1.0, 1.0, 1.0, 0.618); - cr->stroke_preserve(); - cr->set_source_rgba(0.0, 0.0, 0.0, 0.618); - cr->set_dash(ds, 0); - cr->stroke(); - ds.resize(0); - cr->set_dash(ds, 0); - } else { - cr->stroke(); - } + if (flags & F_DASHED) { + cr->unset_dash(); } } } @@ -604,6 +606,7 @@ void Rectangle::drawToMOChannel(Cairo::RefPtr &cr, unsigned shor { if (flags & F_HOVERABLE) { cr->set_line_width( getMouseOverLineWidth() ); + cr->set_line_join(Cairo::LINE_JOIN_ROUND); rtengine::Coord tl, br; diff --git a/rtgui/editwidgets.h b/rtgui/editwidgets.h index 1ae185f7a..0282e2bb1 100644 --- a/rtgui/editwidgets.h +++ b/rtgui/editwidgets.h @@ -24,6 +24,7 @@ #include "editbuffer.h" #include "editcoordsys.h" #include "../rtengine/coord.h" +#include "../rtengine/rt_math.h" class ObjectMOBuffer; @@ -208,6 +209,8 @@ public: F_VISIBLE = 1 << 0, /// true if the geometry have to be drawn on the visible layer F_HOVERABLE = 1 << 1, /// true if the geometry have to be drawn on the "mouse over" layer F_AUTO_COLOR = 1 << 2, /// true if the color depend on the state value, not the color field above + F_DASHED = 1 << 3, /// true if the geometry have to be drawn as a dash line + // (TODO: add a F_LARGE_DASH to have two different dash size ?) }; /// @brief Key point of the image's rectangle that is used to locate the icon copy to the target point: @@ -224,6 +227,7 @@ public: }; protected: + static const std::vector dash; RGBColor innerLineColor; RGBColor outerLineColor; short flags; @@ -249,6 +253,8 @@ public: void setVisible (bool visible); bool isHoverable (); void setHoverable (bool visible); + bool isDashed (); + void setDashed (bool dashed); // setActive will enable/disable the visible and hoverable flags in one shot! @@ -427,7 +433,7 @@ inline void Geometry::setOuterLineColor (char r, char g, char b) { } inline double Geometry::getMouseOverLineWidth () { - return getOuterLineWidth () + 2.; + return rtengine::max(double(innerLineWidth), 1.) + 2.; } inline void Geometry::setAutoColor (bool aColor) { @@ -462,6 +468,18 @@ inline void Geometry::setHoverable (bool hoverable) { } } +inline bool Geometry::isDashed () { + return flags & F_DASHED; +} + +inline void Geometry::setDashed (bool dashed) { + if (dashed) { + flags |= F_DASHED; + } else { + flags &= ~F_DASHED; + } +} + inline void Geometry::setActive (bool active) { if (active) { flags |= (F_VISIBLE | F_HOVERABLE); diff --git a/rtgui/filmnegative.cc b/rtgui/filmnegative.cc index 6e93b2364..d490be488 100644 --- a/rtgui/filmnegative.cc +++ b/rtgui/filmnegative.cc @@ -225,7 +225,7 @@ void FilmNegative::setEditProvider(EditDataProvider* provider) EditSubscriber::setEditProvider(provider); } -CursorShape FilmNegative::getCursor(int objectID) const +CursorShape FilmNegative::getCursor(int objectID, int xPos, int yPos) const { return CSSpotWB; } diff --git a/rtgui/filmnegative.h b/rtgui/filmnegative.h index a1efdc455..46993dba5 100644 --- a/rtgui/filmnegative.h +++ b/rtgui/filmnegative.h @@ -59,7 +59,7 @@ public: void setEditProvider(EditDataProvider* provider) override; // EditSubscriber interface - CursorShape getCursor(int objectID) const override; + CursorShape getCursor(int objectID, int xPos, int yPos) const override; bool mouseOver(int modifierKey) override; bool button1Pressed(int modifierKey) override; bool button1Released() override; diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc index 4f389e112..fda961912 100644 --- a/rtgui/gradient.cc +++ b/rtgui/gradient.cc @@ -327,7 +327,7 @@ void Gradient::editToggled () } } -CursorShape Gradient::getCursor(int objectID) const +CursorShape Gradient::getCursor(int objectID, int xPos, int yPos) const { switch (objectID) { case (0): diff --git a/rtgui/gradient.h b/rtgui/gradient.h index 05a267a0d..3b8a18f97 100644 --- a/rtgui/gradient.h +++ b/rtgui/gradient.h @@ -51,7 +51,7 @@ public: void setEditProvider (EditDataProvider* provider) override; // EditSubscriber interface - CursorShape getCursor(int objectID) const override; + CursorShape getCursor(int objectID, int xPos, int yPos) const override; bool mouseOver(int modifierKey) override; bool button1Pressed(int modifierKey) override; bool button1Released() override; diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 6392b95ab..5fb1de8c9 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -32,8 +32,14 @@ using namespace rtengine::procparams; #define STATIC_VISIBLE_OBJ_NBR 6 #define STATIC_MO_OBJ_NBR 6 -Spot::Spot() : FoldableToolPanel (this, "spot", M ("TP_SPOT_LABEL"), true, true), EditSubscriber (ET_OBJECTS), lastObject (-1), activeSpot (-1), - sourceIcon ("spot-normal.png", "spot-active.png", "spot-active.png", "spot-prelight.png", "", Geometry::DP_CENTERCENTER), editedCheckBox (nullptr) +Spot::Spot() : + FoldableToolPanel(this, "spot", M ("TP_SPOT_LABEL"), true, true), + EditSubscriber(ET_OBJECTS), + draggedSide(DraggedSide::NONE), + lastObject(-1), + activeSpot(-1), + sourceIcon("spot-normal.png", "spot-active.png", "spot-prelight.png", "", "", Geometry::DP_CENTERCENTER), + editedCheckBox(nullptr) { countLabel = Gtk::manage (new Gtk::Label (Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), 0))); @@ -61,6 +67,7 @@ Spot::Spot() : FoldableToolPanel (this, "spot", M ("TP_SPOT_LABEL"), true, true) sourceCircle.datum = Geometry::IMAGE; sourceCircle.setActive (false); sourceCircle.radiusInImageSpace = true; + sourceCircle.setDashed(true); sourceMODisc.datum = Geometry::IMAGE; sourceMODisc.setActive (false); sourceMODisc.radiusInImageSpace = true; @@ -77,9 +84,12 @@ Spot::Spot() : FoldableToolPanel (this, "spot", M ("TP_SPOT_LABEL"), true, true) sourceFeatherCircle.datum = Geometry::IMAGE; sourceFeatherCircle.setActive (false); sourceFeatherCircle.radiusInImageSpace = true; + sourceFeatherCircle.setDashed(true); + sourceFeatherCircle.innerLineWidth = 0.7; targetFeatherCircle.datum = Geometry::IMAGE; targetFeatherCircle.setActive (false); targetFeatherCircle.radiusInImageSpace = true; + targetFeatherCircle.innerLineWidth = 0.7; link.datum = Geometry::IMAGE; link.setActive (false); @@ -241,6 +251,10 @@ Geometry* Spot::getVisibleGeometryFromMO (int MOID) return &sourceIcon; } + if (MOID > STATIC_MO_OBJ_NBR) { + return EditSubscriber::visibleGeometry.at(MOID - STATIC_MO_OBJ_NBR); + } + return EditSubscriber::mouseOverGeometry.at (MOID); } @@ -259,10 +273,12 @@ void Spot::createGeometry () delete EditSubscriber::visibleGeometry.at (i); } - size_t i = 0, j = 0; + // mouse over geometry starts with the static geometry, then the spot's icon geometry EditSubscriber::mouseOverGeometry.resize (STATIC_MO_OBJ_NBR + nbrEntry); + // visible geometry starts with the spot's icon geometry, then the static geometry EditSubscriber::visibleGeometry.resize (nbrEntry + STATIC_VISIBLE_OBJ_NBR); + size_t i = 0, j = 0; EditSubscriber::mouseOverGeometry.at (i++) = &targetMODisc; // STATIC_MO_OBJ_NBR + 0 EditSubscriber::mouseOverGeometry.at (i++) = &sourceMODisc; // STATIC_MO_OBJ_NBR + 1 EditSubscriber::mouseOverGeometry.at (i++) = &targetCircle; // STATIC_MO_OBJ_NBR + 2 @@ -351,6 +367,10 @@ void Spot::updateGeometry() } else { link.setActive (false); } + + sourceCircle.setVisible(draggedSide != DraggedSide::SOURCE); + targetCircle.setVisible(draggedSide != DraggedSide::TARGET); + link.setVisible(draggedSide == DraggedSide::NONE); } else { targetCircle.setActive (false); targetMODisc.setActive (false); @@ -432,10 +452,37 @@ void Spot::deleteSelectedEntry() } } -// TODO -CursorShape Spot::getCursor (int objectID) const +CursorShape Spot::getCursor (int objectID, int xPos, int yPos) const { - return CSHandOpen; + const EditDataProvider* editProvider = getEditProvider(); + if (editProvider) { + if (draggedSide != DraggedSide::NONE) { + return CSEmpty; + } + + int object = editProvider->getObject(); + if (object == 0 || object == 1) { + return CSMove2D; + } + if (object >= 2 || object <= 5) { + Coord delta(Coord(xPos, yPos) - ((object == 3 || object == 5) ? spots.at(activeSpot).sourcePos : spots.at(activeSpot).targetPos)); + PolarCoord polarPos(delta); + if (polarPos.angle < 0.) { + polarPos.angle += 180.; + } + if (polarPos.angle < 22.5 || polarPos.angle >= 157.5) { + return CSMove1DH; + } + if (polarPos.angle < 67.5) { + return CSResizeBottomRight; + } + if (polarPos.angle < 112.5) { + return CSMove1DV; + } + return CSResizeBottomLeft; + } + } + return CSCrosshair; } bool Spot::mouseOver (int modifierKey) @@ -494,10 +541,12 @@ bool Spot::button1Pressed (int modifierKey) if (editProvider) { if (lastObject == -1 && (modifierKey & GDK_CONTROL_MASK)) { + draggedSide = DraggedSide::SOURCE; addNewEntry(); EditSubscriber::action = EditSubscriber::Action::DRAGGING; return true; } else if (lastObject > -1) { + draggedSide = lastObject == 0 ? DraggedSide::TARGET : lastObject == 1 ? DraggedSide::SOURCE : DraggedSide::NONE; getVisibleGeometryFromMO (lastObject)->state = Geometry::DRAGGED; EditSubscriber::action = EditSubscriber::Action::DRAGGING; return true; @@ -519,6 +568,7 @@ bool Spot::button1Released() loGeom->state = Geometry::PRELIGHT; EditSubscriber::action = EditSubscriber::Action::NONE; + draggedSide = DraggedSide::NONE; updateGeometry(); return true; } @@ -552,6 +602,7 @@ bool Spot::button3Pressed (int modifierKey) lastObject = 1; // sourceMODisc sourceIcon.state = Geometry::DRAGGED; EditSubscriber::action = EditSubscriber::Action::DRAGGING; + draggedSide = DraggedSide::SOURCE; return true; } else if (! (modifierKey & (GDK_SHIFT_MASK | GDK_SHIFT_MASK))) { EditSubscriber::action = EditSubscriber::Action::PICKING; @@ -571,6 +622,7 @@ bool Spot::button3Released() lastObject = -1; sourceIcon.state = Geometry::ACTIVE; + draggedSide = DraggedSide::NONE; updateGeometry(); EditSubscriber::action = EditSubscriber::Action::NONE; return true; diff --git a/rtgui/spot.h b/rtgui/spot.h index 7604d7846..a29eb582c 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -57,6 +57,13 @@ class Spot : public ToolParamBlock, public FoldableToolPanel, public rtengine::T { private: + enum class DraggedSide { + NONE, + SOURCE, + TARGET + }; + + DraggedSide draggedSide; // tells which of source or target is being dragged int lastObject; // current object that is hovered int activeSpot; // currently active spot, being edited std::vector spots; // list of edited spots @@ -103,7 +110,7 @@ public: void setBatchMode (bool batchMode) override; // EditSubscriber interface - CursorShape getCursor (int objectID) const override; + CursorShape getCursor (int objectID, int xPos, int yPos) const override; bool mouseOver (int modifierKey) override; bool button1Pressed (int modifierKey) override; bool button1Released () override; From 4a9d913c50e027bc2b1ec088e428a77e82c7cff8 Mon Sep 17 00:00:00 2001 From: Hombre Date: Tue, 10 Sep 2019 22:55:20 +0200 Subject: [PATCH 017/135] Slight cleanup + removing dead code --- rtengine/alpha.cc | 6 +- rtengine/alpha.h | 6 +- rtengine/spot.cc | 287 +++------------------------------------------- rtgui/spot.h | 3 - 4 files changed, 20 insertions(+), 282 deletions(-) diff --git a/rtengine/alpha.cc b/rtengine/alpha.cc index 8d1fd6b0e..34132b879 100644 --- a/rtengine/alpha.cc +++ b/rtengine/alpha.cc @@ -54,7 +54,7 @@ void Alpha::setSize (int width, int height) } } -int Alpha::getWidth() +int Alpha::getWidth() const { if (surface) { return surface->get_width(); @@ -63,7 +63,7 @@ int Alpha::getWidth() return -1; } -int Alpha::getHeight() +int Alpha::getHeight() const { if (surface) { return surface->get_height(); @@ -73,7 +73,7 @@ int Alpha::getHeight() } -Cairo::RefPtr Alpha::getSurface () +Cairo::RefPtr Alpha::getSurface () const { return surface; // to be used in bitmap edition } diff --git a/rtengine/alpha.h b/rtengine/alpha.h index 90f32265e..1fe2a7a7c 100644 --- a/rtengine/alpha.h +++ b/rtengine/alpha.h @@ -39,10 +39,10 @@ public: //~Alpha (); void setSize (int width, int height); - int getWidth(); - int getHeight(); + int getWidth() const; + int getHeight() const; - Cairo::RefPtr getSurface (); + Cairo::RefPtr getSurface () const; // TODO: to make the editing faster, we should add an iterator class diff --git a/rtengine/spot.cc b/rtengine/spot.cc index e9d43ef31..9d059ee1c 100644 --- a/rtengine/spot.cc +++ b/rtengine/spot.cc @@ -44,6 +44,14 @@ public: Rectangle() : Rectangle(0, 0, 0, 0) {} Rectangle(int X1, int Y1, int X2, int Y2) : x1(X1), y1(Y1), x2(X2), y2(Y2) {} + int getWidth() { + return x2 - x1 + 1; + } + + int getHeight() { + return y2 - y1 + 1; + } + bool intersects(const Rectangle &other) const { return (other.x1 <= x2 && other.x2 >= x1) && (other.y1 <= y2 && other.y2 >= y1); @@ -175,27 +183,27 @@ public: } int getWidth() { - return spotArea.x2 - spotArea.x1 + 1; + return spotArea.getWidth(); } int getHeight() { - return spotArea.y2 - spotArea.y1 + 1; + return spotArea.getHeight(); } int getImageWidth() { - return imgArea.x2 - imgArea.x1 + 1; + return imgArea.getWidth(); } int getImageHeight() { - return imgArea.y2 - imgArea.y1 + 1; + return imgArea.getHeight(); } int getIntersectionWidth() { - return intersectionArea.x2 - intersectionArea.x1 + 1; + return intersectionArea.getWidth(); } int getIntersectionHeight() { - return intersectionArea.y2 - intersectionArea.y1 + 1; + return intersectionArea.getHeight(); } bool checkImageSize() { @@ -281,9 +289,6 @@ public: return true; } -#define ALGO 1 - -#if ALGO==1 bool processIntersectionWith(SpotBox &destBox) { Imagefloat *dstImg = destBox.image; @@ -327,270 +332,6 @@ public: return true; } -#endif - -#if ALGO==2 - bool processIntersectionWith(SpotBox &destBox) { - /* The following disabled code has been taken from Gimp 2.8.10 and converted - * for RawTherapee by Jean-Christophe FRISCH (aka Hombre) on 02.19.2014. - * It has not been tested, at all, an can (does) contain bugs. Feel free to - * replace the actual working code by this one, if results are better. - */ - - - /* ORIGINAL NOTES - * - * The method used here is similar to the lighting invariant correction - * method but slightly different: we do not divide the RGB components, - * but substract them I2 = I0 - I1, where I0 is the sample image to be - * corrected, I1 is the reference pattern. Then we solve DeltaI=0 - * (Laplace) with I2 Dirichlet conditions at the borders of the - * mask. The solver is a unoptimized red/black checker Gauss-Siedel - * with an over-relaxation factor of 1.8. It can benefit from a - * multi-grid evaluation of an initial solution before the main - * iteration loop. - * - * I reduced the convergence criteria to 0.1% (0.001) as we are - * dealing here with RGB integer components, more is overkill. - * - * Jean-Yves Couleaud cjyves@free.fr - */ - - - /* Original Algorithm Design: - * - * T. Georgiev, "Photoshop Healing Brush: a Tool for Seamless Cloning - * http://www.tgeorgiev.net/Photoshop_Healing.pdf - */ - - // ----------------- Core function ----------------- - - int scaledPPX = pp.getX() / pp.skip; - int scaledPPY = pp.getY() / pp.skip; - int scaledPPW = pp.getWidth() / pp.skip + (pp.getWidth() % pp.getSkip() > 0); - int scaledPPH = pp.getHeight() / pp.skip + (pp.getHeight() % pp.skip > 0); - - int sizeX = dst_XMax - dst_XMin + 1; - int sizeY = dst_YMax - dst_YMin + 1; - - Imagefloat matrix (sizeX, sizeY); - Imagefloat solution (sizeX, sizeY); - - // allocate the mask and draw it - mask.setSize (sizeX, sizeY); - { - Cairo::RefPtr cr = Cairo::Context::create (mask.getSurface()); - - // clear the bitmap - cr->set_source_rgba (0., 0., 0., 0.); - cr->rectangle (0., 0., sizeX, sizeY); - cr->set_line_width (0.); - cr->fill(); - - // draw the mask - cr->set_antialias (Cairo::ANTIALIAS_GRAY); - cr->set_line_width (featherRadius); - double gradientCenterX = double (sizeX) / 2.; - double gradientCenterY = double (sizeY) / 2.; - { - Cairo::RefPtr radialGradient = Cairo::RadialGradient::create ( - gradientCenterX, gradientCenterY, radius, - gradientCenterX, gradientCenterY, featherRadius - ); - radialGradient->add_color_stop_rgb (0., 0., 0., 1.); - radialGradient->add_color_stop_rgb (1., 0., 0., 0.); - cr->set_source_rgba (0., 0., 0., 1.); - cr->mask (radialGradient); - cr->rectangle (0., 0., sizeX, sizeY); - cr->fill(); - } - } - - // copy the src part to a temporary buffer to avoid possible self modified source - Imagefloat *srcBuff = img->copySubRegion (srcX, srcY, sizeX, sizeY); - - - // subtract pattern to image and store the result as a double in matrix - for (int i = 0, i2 = dst_YMin; i2 < sizeY - 1; ++i, ++i2) { - for (int j = 0, j2 = dst_XMin; i2 < sizeX - 1; ++j, ++j2) { - matrix.r (i, j) = img->r (i2, j2) - srcBuff->r (i, j); - matrix.g (i, j) = img->g (i2, j2) - srcBuff->g (i, j); - matrix.b (i, j) = img->b (i2, j2) - srcBuff->b (i, j); - } - } - - - // FIXME: is a faster implementation needed? -#define EPSILON 0.001 -#define MAX_ITER 500 - - // repeat until convergence or max iterations - for (int n = 0; n < MAX_ITER; ++n) { - - // ---------------------------------------------------------------- - - /* Perform one iteration of the Laplace solver for matrix. Store the - * result in solution and get the square of the cumulative error - * of the solution. - */ - int i, j; - double tmp, diff; - double sqr_err_r = 0.0; - double sqr_err_g = 0.0; - double sqr_err_b = 0.0; - const double w = 1.80 * 0.25; /* Over-relaxation = 1.8 */ - - // we use a red/black checker model of the discretization grid - - // do reds - for (i = 0; i < matrix.getHeight(); ++i) { - for (j = i % 2; j < matrix.getWidth(); j += 2) { - if ((0 == mask (i, j)) || (i == 0) || (i == (matrix.getHeight() - 1)) || (j == 0) || (j == (matrix.getWidth() - 1))) { - // do nothing at the boundary or outside mask - solution.r (i, j) = matrix.r (i, j); - solution.g (i, j) = matrix.g (i, j); - solution.b (i, j) = matrix.b (i, j); - } else { - // Use Gauss Siedel to get the correction factor then over-relax it - tmp = solution.r (i, j); - solution.r (i, j) = (matrix.r (i, j) + w * - ( - matrix.r (i, j - 1) + // west - matrix.r (i, j + 1) + // east - matrix.r (i - 1, j) + // north - matrix.r (i + 1, j) - 4.0 * matrix.r (i, j) // south - ) - ); - - diff = solution.r (i, j) - tmp; - sqr_err_r += diff * diff; - - - tmp = solution.g (i, j); - solution.g (i, j) = (matrix.g (i, j) + w * - ( - matrix.g (i, j - 1) + // west - matrix.g (i, j + 1) + // east - matrix.g (i - 1, j) + // north - matrix.g (i + 1, j) - 4.0 * matrix.g (i, j) // south - ) - ); - - diff = solution.g (i, j) - tmp; - sqr_err_g += diff * diff; - - - - tmp = solution.b (i, j); - solution.b (i, j) = (matrix.b (i, j) + w * - ( - matrix.b (i, j - 1) + // west - matrix.b (i, j + 1) + // east - matrix.b (i - 1, j) + // north - matrix.b (i + 1, j) - 4.0 * matrix.b (i, j) // south - ) - ); - - diff = solution.b (i, j) - tmp; - sqr_err_b += diff * diff; - - } - } - } - - - /* Do blacks - * - * As we've done the reds earlier, we can use them right now to - * accelerate the convergence. So we have "solution" in the solver - * instead of "matrix" above - */ - for (i = 0; i < matrix.getHeight(); i++) { - for (j = (i % 2) ? 0 : 1; j < matrix.getWidth(); j += 2) { - if ((0 == mask (i, j)) || (i == 0) || (i == (matrix.getHeight() - 1)) || (j == 0) || (j == (matrix.getWidth() - 1))) { - // do nothing at the boundary or outside mask - solution.r (i, j) = matrix.r (i, j); - solution.g (i, j) = matrix.g (i, j); - solution.b (i, j) = matrix.b (i, j); - } else { - // Use Gauss Siedel to get the correction factor then over-relax it - tmp = solution.r (i, j); - solution.r (i, j) = (matrix.r (i, j) + w * - ( - matrix.r (i, j - 1) + // west - matrix.r (i, j + 1) + // east - matrix.r (i - 1, j) + // north - matrix.r (i + 1, j) - 4.0 * matrix.r (i, j) // south - ) - ); - - diff = solution.r (i, j) - tmp; - sqr_err_r += diff * diff; - - - - tmp = solution.g (i, j); - solution.g (i, j) = (matrix.g (i, j) + w * - ( - matrix.g (i, j - 1) + // west - matrix.g (i, j + 1) + // east - matrix.g (i - 1, j) + // north - matrix.g (i + 1, j) - 4.0 * matrix.g (i, j) // south - ) - ); - - diff = solution.g (i, j) - tmp; - sqr_err_g += diff * diff; - - - - tmp = solution.b (i, j); - solution.b (i, j) = (matrix.b (i, j) + w * - ( - matrix.b (i, j - 1) + // west - matrix.b (i, j + 1) + // east - matrix.b (i - 1, j) + // north - matrix.b (i + 1, j) - 4.0 * matrix.b (i, j) // south - ) - ); - - diff = solution.b (i, j) - tmp; - sqr_err_b += diff * diff; - } - } - } - - // ---------------------------------------------------------------- - - // copy solution to matrix - solution.copyData (&matrix); - - if (sqr_err_r < EPSILON && sqr_err_g < EPSILON && sqr_err_b < EPSILON) { - break; - } - } - - // add solution to original image and store in tempPR - for (int i = 0, i2 = dst_YMin; i2 < dst_YMax - 1; ++i, ++i2) { - if (i2 < 0 || i2 >= img->getHeight()) { - continue; - } - - for (int j = 0, j2 = dst_XMin; j2 < dst_XMax - 1; ++j, ++j2) { - if (j2 < 0 || j2 >= img->getWidth()) { - continue; - } - - float c2 = float (mask (i, j)) / 255.f; - float c1 = 1.f - c2; - resultPR->r(i,j) = (unsigned char) CLAMP0255 ( ROUND( double(first->r(i,j)) + double(secondPR->r(i,j)) ) ); - img->r(i2,j2) = img->r(i2,j2)*c1 + (solution.r(i,j) + srcBuff->r(i,j))*c2; - img->g(i2,j2) = img->g(i2,j2)*c1 + (solution.g(i,j) + srcBuff->g(i,j))*c2; - img->b(i2,j2) = img->b(i2,j2)*c1 + (solution.b(i,j) + srcBuff->b(i,j))*c2; - } - } - } -#endif // Copy the intersecting part bool copyImgTo(SpotBox &destBox) { diff --git a/rtgui/spot.h b/rtgui/spot.h index a29eb582c..bbe70469d 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -130,9 +130,6 @@ public: rtengine::ProcEvent EvSpotEnabledOPA; // used to toggle-on the Spot 'On Preview Adjustment' mode rtengine::ProcEvent EvSpotEntry; rtengine::ProcEvent EvSpotEntryOPA; - - rtengine::ProcEvent evt; - }; #endif From 1935820884927f93402b6fcd417af2284b49e0f6 Mon Sep 17 00:00:00 2001 From: Hombre Date: Sat, 14 Sep 2019 23:03:19 +0200 Subject: [PATCH 018/135] Fix crash in Spot Removal tool when deleting a Spot entry --- rtgui/spot.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 5fb1de8c9..31f5a138e 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -460,12 +460,11 @@ CursorShape Spot::getCursor (int objectID, int xPos, int yPos) const return CSEmpty; } - int object = editProvider->getObject(); - if (object == 0 || object == 1) { + if (objectID == 0 || objectID == 1) { return CSMove2D; } - if (object >= 2 || object <= 5) { - Coord delta(Coord(xPos, yPos) - ((object == 3 || object == 5) ? spots.at(activeSpot).sourcePos : spots.at(activeSpot).targetPos)); + if (objectID >= 2 && objectID <= 5) { + Coord delta(Coord(xPos, yPos) - ((objectID == 3 || objectID == 5) ? spots.at(activeSpot).sourcePos : spots.at(activeSpot).targetPos)); PolarCoord polarPos(delta); if (polarPos.angle < 0.) { polarPos.angle += 180.; From 9bb19eb1a305835d59bf56cdad20cfa7d492128f Mon Sep 17 00:00:00 2001 From: Hombre57 Date: Sun, 8 Dec 2019 02:01:03 +0100 Subject: [PATCH 019/135] Post-merge bugfix --- rtengine/improccoordinator.cc | 2 -- rtengine/improcfun.h | 4 +++- rtengine/spot.cc | 3 +++ rtgui/editwidgets.h | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 684d34e01..d8d9b2d82 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -576,8 +576,6 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) spotprev->copyData(oprevi); } - readyphase++; - if ((todo & M_HDR) && (params->fattal.enabled || params->dehaze.enabled)) { if (fattal_11_dcrop_cache) { delete fattal_11_dcrop_cache; diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 995288e7a..a9f0d4eeb 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -56,6 +56,8 @@ class Image8; class Imagefloat; class LabImage; class wavelet_decomposition; +class ImageSource; +class ColorTemp; namespace procparams { @@ -248,7 +250,7 @@ public: float MadRgb(const float * DataList, int datalen); // spot removal tool - void removeSpots (Imagefloat* img, ImageSource* imgsrc, const std::vector &entries, const PreviewProps &pp, const ColorTemp &currWB, const ColorManagementParams *cmp, int tr); + void removeSpots (rtengine::Imagefloat* img, rtengine::ImageSource* imgsrc, const std::vector &entries, const PreviewProps &pp, const rtengine::ColorTemp &currWB, const procparams::ColorManagementParams *cmp, int tr); // pyramid wavelet void dirpyr_equalizer(const float * const * src, float ** dst, int srcwidth, int srcheight, const float * const * l_a, const float * const * l_b, const double * mult, double dirpyrThreshold, double skinprot, float b_l, float t_l, float t_r, int scale); //Emil's directional pyramid wavelet diff --git a/rtengine/spot.cc b/rtengine/spot.cc index 9d059ee1c..cd19cc62a 100644 --- a/rtengine/spot.cc +++ b/rtengine/spot.cc @@ -21,7 +21,10 @@ #include "alpha.h" #include "procparams.h" #include "imagesource.h" +#include "imagefloat.h" +#include "rt_math.h" #include +#include namespace rtengine { diff --git a/rtgui/editwidgets.h b/rtgui/editwidgets.h index 2dcd5274c..d814f0918 100644 --- a/rtgui/editwidgets.h +++ b/rtgui/editwidgets.h @@ -24,11 +24,11 @@ #include #include "editcoordsys.h" +#include "rtsurface.h" #include "../rtengine/coord.h" #include "../rtengine/rt_math.h" class ObjectMOBuffer; -class RTSurface; /** @file * From 8b60ea4794eaa93860c337fc4ad4bff1c03e375d Mon Sep 17 00:00:00 2001 From: Hombre57 Date: Tue, 17 Dec 2019 21:46:18 +0100 Subject: [PATCH 020/135] Bugfix in SpotRemoval tool GUI (Batch Editor) + Partial Paste handling --- rtdata/languages/Francais | 1 + rtdata/languages/default | 1 + rtgui/partialpastedlg.cc | 9 +++++++++ rtgui/partialpastedlg.h | 3 ++- rtgui/spot.cc | 19 +++++++++++++------ 5 files changed, 26 insertions(+), 7 deletions(-) diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 363feacb9..144837411 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -1022,6 +1022,7 @@ PARTIALPASTE_SHARPENEDGE;Bords PARTIALPASTE_SHARPENING;Netteté PARTIALPASTE_SHARPENMICRO;Microcontraste PARTIALPASTE_SOFTLIGHT;Lumière douce +PARTIALPASTE_SPOT;Retrait de taches PARTIALPASTE_TM_FATTAL;Compression de plage dynamique PARTIALPASTE_VIBRANCE;Vibrance PARTIALPASTE_VIGNETTING;Correction du vignettage diff --git a/rtdata/languages/default b/rtdata/languages/default index e0e65ea0c..8fdfa205c 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1044,6 +1044,7 @@ PARTIALPASTE_SHARPENEDGE;Edges PARTIALPASTE_SHARPENING;Sharpening (USM/RL) PARTIALPASTE_SHARPENMICRO;Microcontrast PARTIALPASTE_SOFTLIGHT;Soft light +PARTIALPASTE_SPOT;Spot removal PARTIALPASTE_TM_FATTAL;Dynamic range compression PARTIALPASTE_VIBRANCE;Vibrance PARTIALPASTE_VIGNETTING;Vignetting correction diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index 22f608ae4..569f39435 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -57,6 +57,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren labcurve = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_LABCURVE"))); // Detail Settings: + spot = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_SPOT"))); sharpen = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_SHARPENING"))); localcontrast = Gtk::manage(new Gtk::CheckButton(M("PARTIALPASTE_LOCALCONTRAST"))); sharpenedge = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_SHARPENEDGE"))); @@ -164,6 +165,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren //DETAIL vboxes[1]->pack_start (*detail, Gtk::PACK_SHRINK, 2); vboxes[1]->pack_start (*hseps[1], Gtk::PACK_SHRINK, 2); + vboxes[1]->pack_start (*spot, Gtk::PACK_SHRINK, 2); vboxes[1]->pack_start (*sharpen, Gtk::PACK_SHRINK, 2); vboxes[1]->pack_start (*localcontrast, Gtk::PACK_SHRINK, 2); vboxes[1]->pack_start (*sharpenedge, Gtk::PACK_SHRINK, 2); @@ -326,6 +328,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren labcurveConn = labcurve->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); // Detail Settings: + spotConn = spot->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true)); sharpenConn = sharpen->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true)); localcontrastConn = localcontrast->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true)); gradsharpenConn = sharpenedge->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true)); @@ -539,6 +542,7 @@ void PartialPasteDlg::basicToggled () void PartialPasteDlg::detailToggled () { + ConnectionBlocker spotBlocker(spotConn); ConnectionBlocker sharpenBlocker(sharpenConn); ConnectionBlocker localcontrastBlocker(localcontrastConn); ConnectionBlocker gradsharpenBlocker(gradsharpenConn); @@ -551,6 +555,7 @@ void PartialPasteDlg::detailToggled () detail->set_inconsistent (false); + spot->set_active (detail->get_active ()); sharpen->set_active (detail->get_active ()); localcontrast->set_active(detail->get_active()); sharpenedge->set_active (detail->get_active ()); @@ -717,6 +722,10 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param filterPE.colorappearance = falsePE.colorappearance; } + if (!spot->get_active ()) { + filterPE.spot = falsePE.spot; + } + if (!sharpen->get_active ()) { filterPE.sharpening = falsePE.sharpening; } diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index 1403e7c1b..8089c0677 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -67,6 +67,7 @@ public: Gtk::CheckButton* colorappearance; // options in detail: + Gtk::CheckButton* spot; Gtk::CheckButton* sharpen; Gtk::CheckButton* sharpenedge; Gtk::CheckButton* sharpenmicro; @@ -146,7 +147,7 @@ public: sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaConn, rawConn, advancedConn; sigc::connection wbConn, exposureConn, localcontrastConn, shConn, pcvignetteConn, gradientConn, labcurveConn, colorappearanceConn; - sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, defringeConn, epdConn, fattalConn, dirpyreqConn, waveletConn, retinexConn, dehazeConn; + sigc::connection spotConn, sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, defringeConn, epdConn, fattalConn, dirpyreqConn, waveletConn, retinexConn, dehazeConn; sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn, chmixerbwConn, colortoningConn, filmSimulationConn, softlightConn; sigc::connection distortionConn, cacorrConn, vignettingConn, lcpConn; sigc::connection coarserotConn, finerotConn, cropConn, resizeConn, prsharpeningConn, perspectiveConn, commonTransConn; diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 31f5a138e..a90c495d0 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -131,11 +131,16 @@ void Spot::read (const ProcParams* pp, const ParamsEdited* pedited) activeSpot = -1; lastObject = -1; - if (spots.size() != oldSize) { - createGeometry(); + if (batchMode) { + editedCheckBox->set_label(Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), spots.size())); } + else { + if (spots.size() != oldSize) { + createGeometry(); + } - updateGeometry(); + updateGeometry(); + } enableListener (); } @@ -147,7 +152,7 @@ void Spot::write (ProcParams* pp, ParamsEdited* pedited) if (pedited) { pedited->spot.enabled = !get_inconsistent(); - pedited->spot.entries = !editedCheckBox->get_active(); + pedited->spot.entries = editedCheckBox->get_active(); } } @@ -160,8 +165,10 @@ void Spot::resetPressed() editedCheckBox->set_active (true); editedConn.block (false); + editedCheckBox->set_label(Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), spots.size())); + if (listener) { - listener->panelChanged (EvSpotEntry, Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), spots.size())); + listener->panelChanged (EvSpotEntry, Glib::ustring::compose (M ("TP_SPOT_COUNTLABEL"), 0)); } } else { if (!spots.empty()) { @@ -783,7 +790,7 @@ void Spot::tweakParams(procparams::ProcParams& pparams) //params->raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST); // -> disabling all transform - //params->coarse = CoarseTransformParams(); + //pparams.coarse = CoarseTransformParams(); pparams.lensProf = LensProfParams(); pparams.cacorrection = CACorrParams(); pparams.distortion = DistortionParams(); From 10b5f65b30b5996b96508b219e466ca0af7fa9cc Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sat, 6 Mar 2021 21:29:56 -0800 Subject: [PATCH 021/135] Fix spot removal enable/disable history message The history panel was showing "HISTORY_MSG_1049". --- rtgui/spot.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index a90c495d0..1f3759c6b 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -95,7 +95,7 @@ Spot::Spot() : auto m = ProcEventMapper::getInstance(); EvSpotEnabled = m->newEvent(ALLNORAW, "TP_SPOT_LABEL"); - EvSpotEnabledOPA = m->newEvent(SPOTADJUST, ""); + EvSpotEnabledOPA = m->newEvent(SPOTADJUST, "TP_SPOT_LABEL"); EvSpotEntry = m->newEvent(SPOTADJUST, "HISTORY_MSG_SPOT_ENTRY"); EvSpotEntryOPA = m->newEvent(SPOTADJUST, "HISTORY_MSG_SPOT_ENTRY"); From f958074d9bd5ece66aeb79a79424c978995940e0 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sun, 7 Mar 2021 11:58:36 -0800 Subject: [PATCH 022/135] Fix crash when deleting spot removal spot Deleting a spot while hovering over one of the circles for adjusting the radius or feathering could trigger a crash. This is because immediately after deleting a geometry object, EditSubscriber::getCursor is given an object ID based on old data, causing the spot tool to attempt to get information about the deleted geometry object. This commit fixes the issue by returning the default cursor if the active spot is -1. It works because the active spot is set to -1 when deleting a spot, and there is no need to use a special cursor when there is no active spot. A better long-term solution would be updating the geometry data before calling EditSubscriber::getCursor. --- rtgui/spot.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 1f3759c6b..6d749838b 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -462,7 +462,7 @@ void Spot::deleteSelectedEntry() CursorShape Spot::getCursor (int objectID, int xPos, int yPos) const { const EditDataProvider* editProvider = getEditProvider(); - if (editProvider) { + if (editProvider && activeSpot > -1) { if (draggedSide != DraggedSide::NONE) { return CSEmpty; } From e98288ab31785b2f97234dd6c2cc8b9ddcfa7955 Mon Sep 17 00:00:00 2001 From: Desmis Date: Tue, 30 Mar 2021 16:49:25 +0200 Subject: [PATCH 023/135] Wavelet levels - enable Toning in some cases --- rtengine/ipwavelet.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index 982557d93..caec5ec22 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -1040,7 +1040,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const } - if (!exblurL && cp.contrast == 0.f && cp.blurres == 0.f && !cp.noiseena && !cp.tonemap && !cp.resena && !cp.chromena && !cp.finena && !cp.edgeena && cp.conres == 0.f && cp.conresH == 0.f && cp.val == 0 && !ref0 && params->wavelet.CLmethod == "all") { // no processing of residual L or edge=> we probably can reduce the number of levels + if (!exblurL && cp.contrast == 0.f && cp.blurres == 0.f && !cp.noiseena && !cp.tonemap && !cp.resena && !cp.chromena && !cp.toningena && !cp.finena && !cp.edgeena && cp.conres == 0.f && cp.conresH == 0.f && cp.val == 0 && !ref0 && params->wavelet.CLmethod == "all") { // no processing of residual L or edge=> we probably can reduce the number of levels while (levwavL > 0 && cp.mul[levwavL - 1] == 0.f) { // cp.mul[level] == 0.f means no changes to level levwavL--; } @@ -1724,7 +1724,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const if (!hhutili) { //always a or b int levwava = levwav; - if (!exblurab && cp.chrores == 0.f && cp.blurcres == 0.f && !cp.noiseena && !cp.tonemap && !cp.resena && !cp.chromena && !cp.finena && !cp.edgeena&& params->wavelet.CLmethod == "all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels + if (!exblurab && cp.chrores == 0.f && cp.blurcres == 0.f && !cp.noiseena && !cp.tonemap && !cp.resena && !cp.chromena && !cp.toningena && !cp.finena && !cp.edgeena && params->wavelet.CLmethod == "all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels while (levwava > 0 && !cp.diag && (((cp.CHmet == 2 && (cp.chro == 0.f || cp.mul[levwava - 1] == 0.f)) || (cp.CHmet != 2 && (levwava == 10 || (!cp.curv || cp.mulC[levwava - 1] == 0.f))))) && (!cp.opaRG || levwava == 10 || (cp.opaRG && cp.mulopaRG[levwava - 1] == 0.f)) && ((levwava == 10 || (cp.CHSLmet == 1 && cp.mulC[levwava - 1] == 0.f)))) { levwava--; } @@ -1777,7 +1777,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const int levwavb = levwav; - if (!exblurab && cp.chrores == 0.f && cp.blurcres == 0.f && !cp.noiseena && !cp.tonemap && !cp.resena && !cp.chromena && !cp.finena && !cp.edgeena && params->wavelet.CLmethod == "all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels + if (!exblurab && cp.chrores == 0.f && cp.blurcres == 0.f && !cp.noiseena && !cp.tonemap && !cp.resena && !cp.chromena && !cp.toningena && !cp.finena && !cp.edgeena && params->wavelet.CLmethod == "all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels while (levwavb > 0 && !cp.diag && (((cp.CHmet == 2 && (cp.chro == 0.f || cp.mul[levwavb - 1] == 0.f)) || (cp.CHmet != 2 && (levwavb == 10 || (!cp.curv || cp.mulC[levwavb - 1] == 0.f))))) && (!cp.opaBY || levwavb == 10 || (cp.opaBY && cp.mulopaBY[levwavb - 1] == 0.f)) && ((levwavb == 10 || (cp.CHSLmet == 1 && cp.mulC[levwavb - 1] == 0.f)))) { levwavb--; } @@ -4532,6 +4532,10 @@ void ImProcFunctions::ContAllAB(LabImage * labco, int maxlvl, float ** varhue, f } if ((useOpacity && level < 9 && mulOpacity != 0.f) && cp.toningena) { //toning + // if (settings->verbose) { + // printf("Toning enabled\n"); + // } + float mea[10]; float effect = cp.sigmaton; float betaab; From 128de03aed60d85252e77df71f060daf28fcec49 Mon Sep 17 00:00:00 2001 From: Desmis Date: Fri, 2 Apr 2021 07:36:42 +0200 Subject: [PATCH 024/135] Local adjustemnts - adapt various parameters to fit labels in right tool panel issue #6153 (#6160) * Various change to fit label in left tool panel * Increase size left panel from 460 to 465 * Various improvment to reduce size left panel * Others changes to reduce left panel labels * Increase default size right panel * Set right panel ajustable to size font * Others small changes to mask * Others small modifications * change a litlle GUI - curveeditorgroup.cc - suppress curves u=in mask and reduce size right panel * Added : to various curves label * Others : labels curves * Some adjustments labels sizefonts * Change 2 forgotten length labels in denoise * Others improvments labels * Others labels change for retinex * Others change labels - thanks to Wayne Sutton * French change label length * Change labels Wavelet levels - LA retinex - LA color and lights - and others * Other change to mask blur * Change box - Flowbox - thanks to Beep6581 * Adapt size box basic..advanced with size font * Restore curveditorgroup : - change some labels and tooltips * Remove some ':' - change and adapt labels tooltip wavelet levels * Change flowbox for complexity under label * Restore right panel and options to default values * Change a label in wavelet level denoise * Change in mask curves L(L) by L C(C) by C * Small change labels denoise to fit in width right panel * Others changes to GUi and labels to fit in right panel * First change tooltips and french * Second change tooltips * Change tooltip mask denoise --- rtdata/languages/Francais | 118 +++++++++--------- rtdata/languages/default | 252 +++++++++++++++++++------------------- rtgui/curveeditorgroup.cc | 9 +- rtgui/curveeditorgroup.h | 2 +- rtgui/editorpanel.cc | 2 + rtgui/locallabtools.cc | 105 +++++++++------- rtgui/locallabtools.h | 2 + rtgui/locallabtools2.cc | 62 +++++----- 8 files changed, 297 insertions(+), 255 deletions(-) diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 6d9a06afb..083bf654a 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -809,7 +809,7 @@ ICCPROFCREATOR_PROF_V2;ICC v2 ICCPROFCREATOR_PROF_V4;ICC v4 ICCPROFCREATOR_SAVEDIALOG_TITLE;Enregistrer le profil ICC sous... ICCPROFCREATOR_SLOPE;Pente -ICCPROFCREATOR_TRC_PRESET;Courbe de réponse tonale: +ICCPROFCREATOR_TRC_PRESET;Courbe de réponse tonale IPTCPANEL_CATEGORY;Catégorie IPTCPANEL_CATEGORYHINT;Identifie le sujet de l'image selon l'opinion du fournisseur. IPTCPANEL_CITY;Ville @@ -1297,8 +1297,8 @@ TP_BWMIX_AUTOCH;Auto TP_BWMIX_CC_ENABLED;Ajuster les couleurs complémentaires TP_BWMIX_CC_TOOLTIP;Activer pour permettre l'ajustage automatique des couleur complémentaire dans le mode ROJVCBPM TP_BWMIX_CHANNEL;Égaliseur de Luminance -TP_BWMIX_CURVEEDITOR1;Courbe 'avant' -TP_BWMIX_CURVEEDITOR2;Courbe 'après' +TP_BWMIX_CURVEEDITOR1;Courbe 'avant': +TP_BWMIX_CURVEEDITOR2;Courbe 'après': TP_BWMIX_CURVEEDITOR_AFTER_TOOLTIP;Courbe tonale, après la conversion en N&B, à la fin du traitement TP_BWMIX_CURVEEDITOR_BEFORE_TOOLTIP;Courbe tonale, juste avant la conversion en N&B\nPeut prendre en compte les composantes couleur TP_BWMIX_CURVEEDITOR_LH_TOOLTIP;Modifie la luminance en fonction de la teinte\nFaites attention aux valeurs extrêmes qui peuvent causer des artefacts @@ -1438,7 +1438,7 @@ TP_COLORTONING_AUTOSAT;Automatique TP_COLORTONING_BALANCE;Balance TP_COLORTONING_BY;o C/L TP_COLORTONING_CHROMAC;Opacité -TP_COLORTONING_COLOR;Couleur +TP_COLORTONING_COLOR;Couleur: TP_COLORTONING_CURVEEDITOR_CL_TOOLTIP;Opacité chroma en fonction de la luminance oC=f(L) TP_COLORTONING_HIGHLIGHT;Hautes lumières TP_COLORTONING_HUE;Teinte @@ -1520,11 +1520,11 @@ TP_DEHAZE_STRENGTH;Force TP_DIRPYRDENOISE_CHROMINANCE_AMZ;Multi-zones auto TP_DIRPYRDENOISE_CHROMINANCE_AUTOGLOBAL;Global automatique TP_DIRPYRDENOISE_CHROMINANCE_BLUEYELLOW;Chrominance - Bleu-Jaune -TP_DIRPYRDENOISE_CHROMINANCE_CURVE;Courbe de chrominance +TP_DIRPYRDENOISE_CHROMINANCE_CURVE;Courbe de chrominance: TP_DIRPYRDENOISE_CHROMINANCE_CURVE_TOOLTIP;Augmente (multiplie) la valeur de tous les curseurs de chrominance.\nCette courbe vous permet d'ajuster la force de la réduction de bruit chromatique en fonction de la chromaticité, par exemple pour augmenter l'action dans les zones faiblement saturées et pour la diminuer dans celles très saturées. TP_DIRPYRDENOISE_CHROMINANCE_FRAME;Chrominance TP_DIRPYRDENOISE_CHROMINANCE_MANUAL;Manuel -TP_DIRPYRDENOISE_CHROMINANCE_MASTER;Chrominance - Maître +TP_DIRPYRDENOISE_CHROMINANCE_MASTER;Chrominance-Maître TP_DIRPYRDENOISE_CHROMINANCE_METHOD;Méthode TP_DIRPYRDENOISE_CHROMINANCE_METHODADVANCED_TOOLTIP;Manuel\nAgit sur l'image entière.\nVous controlez les paramètres de réduction de bruit manuellement.\n\nGlobal automatique\nAgit sur l'image entière.\n9 zones sont utilisées pour calculer un réglage de réduction de bruit de chroma.\n\nAperçu\nAgit sur l'image entière.\nLa partie visible de l'image dans l'aperçu est utilisé pour calculer un réglage de réduction de bruit de chroma. TP_DIRPYRDENOISE_CHROMINANCE_METHOD_TOOLTIP;Manuel\nAgit sur l'image entière.\nVous controlez les paramètres de réduction de bruit manuellement.\n\nGlobal automatique\nAgit sur l'image entière.\n9 zones sont utilisées pour calculer un réglage de réduction de bruit de chroma.\n\nAutomatique multi-zones\nPas d'aperçu - ne fonctionne que lors de l'enregistrement, mais utiliser la méthode "Aperçu" en faisant correspondre la taille et le centre de la tuile à la taille et au centre de l'aperçu, vous permet d'avoir une idée des résultats attendus.\nL'image est divisé en tuiles (entre 10 et 70 en fonction de la taille de l'image) et chaque tuile reçoit son propre réglage de réduction de bruit de chrominance.\n\nAperçu\nAgit sur l'image entière.\nLa partie de l'image visible dans l'aperçu est utilisé pour calculer un réglage de réduction de bruit de chroma. @@ -1538,7 +1538,7 @@ TP_DIRPYRDENOISE_CHROMINANCE_PREVIEW_TILEINFO;Taille des tuiles =%1, Centre: Tx= TP_DIRPYRDENOISE_CHROMINANCE_REDGREEN;Chrominance - Rouge-Vert TP_DIRPYRDENOISE_LABEL;Réduction de Bruit TP_DIRPYRDENOISE_LUMINANCE_CONTROL;Contrôle de luminance -TP_DIRPYRDENOISE_LUMINANCE_CURVE;Courbe de luminance +TP_DIRPYRDENOISE_LUMINANCE_CURVE;Courbe de luminance: TP_DIRPYRDENOISE_LUMINANCE_DETAIL;Niveau de détails de Luminance TP_DIRPYRDENOISE_LUMINANCE_FRAME;Luminance TP_DIRPYRDENOISE_LUMINANCE_SMOOTHING;Luminance @@ -1657,7 +1657,7 @@ TP_HLREC_ENA_TOOLTIP;Peut être activé par le bouton Niveau Auto TP_HLREC_LABEL;Reconstruction des hautes lumières TP_HLREC_LUMINANCE;Récupération de la luminance TP_HLREC_METHOD;Méthode: -TP_HSVEQUALIZER_CHANNEL;Canal +TP_HSVEQUALIZER_CHANNEL;Canal: TP_HSVEQUALIZER_HUE;T TP_HSVEQUALIZER_LABEL;Égaliseur TSV TP_HSVEQUALIZER_SAT;S @@ -1755,7 +1755,7 @@ TP_LOCALCONTRAST_LIGHTNESS;Niveau des hautes-lumières TP_LOCALCONTRAST_RADIUS;Rayon TP_LOCALLAB_ACTIV;Luminosité seulement TP_LOCALLAB_ACTIVSPOT;Activer le Spot -TP_LOCALLAB_ADJ;Egalisateur Bleu-jaune Rouge-vert +TP_LOCALLAB_ADJ;Egalisateur couleur TP_LOCALLAB_ALL;Toutes les rubriques TP_LOCALLAB_AMOUNT;Quantité TP_LOCALLAB_ARTIF;Détection de forme @@ -1771,8 +1771,8 @@ TP_LOCALLAB_BILATERAL;Filtre Bilateral TP_LOCALLAB_BLACK_EV;Noir Ev TP_LOCALLAB_BLCO;Chrominance seulement TP_LOCALLAB_BLENDMASKCOL;Mélange - fusion -TP_LOCALLAB_BLENDMASKMASK;Ajout / soustrait le masque Luminance -TP_LOCALLAB_BLENDMASKMASKAB;Ajout / soustrait le masque Chrominance +TP_LOCALLAB_BLENDMASKMASK;Ajout/soustrait masque Luminance +TP_LOCALLAB_BLENDMASKMASKAB;Ajout/soustrait masque Chro. TP_LOCALLAB_BLENDMASK_TOOLTIP;Si fusion = 0 seule la détection de forme est améliorée.\nSi fusion > 0 le masque est ajouté à l'image. Si fusion < 0 le masque est soustrait à l'image TP_LOCALLAB_BLENDMASKMASK_TOOLTIP;Si ce curseur = 0 pas d'action.\nAjoute ou soustrait le masque de l'image originale TP_LOCALLAB_BLGUID;Filtre guidé @@ -1804,14 +1804,14 @@ TP_LOCALLAB_BUTTON_DEL;Effacer TP_LOCALLAB_BUTTON_DUPL;Dupliquer TP_LOCALLAB_BUTTON_REN;Renommer TP_LOCALLAB_BUTTON_VIS;Montrer/Cacher -TP_LOCALLAB_CBDL;Contraste par niveaux détail +TP_LOCALLAB_CBDL;Contr. par niveaux détail TP_LOCALLAB_CBDLCLARI_TOOLTIP;Ajuste les tons moyens et les réhausse. TP_LOCALLAB_CBDL_ADJ_TOOLTIP;Agit comme un outil ondelettes.\nLe premier niveau (0) agit sur des détails de 2x2.\nLe dernier niveau (5) agit sur des détails de 64x64. TP_LOCALLAB_CBDL_THRES_TOOLTIP;Empêche d'augmenter le bruit TP_LOCALLAB_CBDL_TOOLNAME;Contraste par niveaux de détail - 2 TP_LOCALLAB_CENTER_X;Centre X TP_LOCALLAB_CENTER_Y;Centre Y -TP_LOCALLAB_CH;Courbes CL - LC +TP_LOCALLAB_CH;CL - LC TP_LOCALLAB_CHROMA;Chrominance TP_LOCALLAB_CHROMABLU;Niveaux Chroma TP_LOCALLAB_CHROMABLU_TOOLTIP;Agit comme un amplificateur-reducteur d'action en comparant aux réglages de luma.\nEn dessous de 1 reduit, au dessus de 1 amplifie @@ -1824,7 +1824,7 @@ TP_LOCALLAB_CHRRT;Chroma TP_LOCALLAB_CIRCRADIUS;Taille Spot TP_LOCALLAB_CIRCRAD_TOOLTIP;Contient les références du RT-spot, utile pour la détection de forme (couleur, luma, chroma, Sobel).\nLes faibles valeurs peuvent être utiles pour les feuillages.\nLes valeurs élevées peuvent être utile pour la peau TP_LOCALLAB_CLARICRES;Fusion Chroma -TP_LOCALLAB_CLARIFRA;Clarté & Masque de netteté - Fusion & adoucir images +TP_LOCALLAB_CLARIFRA;Clarté & Masque netteté/Fusion & adoucir TP_LOCALLAB_CLARILRES;Fusion Luma TP_LOCALLAB_CLARISOFT;Rayon adoucir TP_LOCALLAB_CLARISOFT_TOOLTIP;Actif pour Clarté et Masque de netteté si différent de zéro.\n\nActif pour toutes les pyramides ondelettes.\nInactif si rayon = 0 @@ -1832,7 +1832,7 @@ TP_LOCALLAB_CLARITYML;Clarté TP_LOCALLAB_CLARI_TOOLTIP;En dessous ou égal à 4, 'Masque netteté' est actif.\nAu dessus du niveau ondelettes 5 'Clarté' est actif.\nUtilesu=i vous utilisez 'Compression dynamique des niveaux' TP_LOCALLAB_CLIPTM;Clip Recupère données (gain) TP_LOCALLAB_COFR;Couleur & Lumière -TP_LOCALLAB_COLORDE;Couleur prévisualisation sélection ΔE - Intensité +TP_LOCALLAB_COLORDE;Couleur prévis. sélection ΔE - Intensité TP_LOCALLAB_COLORDEPREV_TOOLTIP;Bouton Prévisualisation ΔE a besoin qu'un seul outil soit activé (expander).\nPour pouvoir avoir une Prévisualisation ΔE avec plusieurs outils activés utiliser Masque et modifications - Prévisualisation ΔE TP_LOCALLAB_COLORDE_TOOLTIP;Affiche la prévisualisation ΔE en bleu si négatif et en vert si positif.\n\nMasque et modifications (montre modifications sans masque): montre les modifications réelles si positf, montre les modifications améliorées (luminance seule) en bleu et jaune si négatif. TP_LOCALLAB_COLORSCOPE;Etendue Outils Couleur @@ -1854,8 +1854,8 @@ TP_LOCALLAB_CONTRESID;Contraste TP_LOCALLAB_CONTTHMASK_TOOLTIP;Vous permet de déterminer quelles parties de l'image seront concernées par la texture. TP_LOCALLAB_CONTTHR;Seuil contraste TP_LOCALLAB_CONTWFRA;Contrast Local -TP_LOCALLAB_CSTHRESHOLD;Ψ Ondelettes niveaux -TP_LOCALLAB_CSTHRESHOLDBLUR;Ψ Masque Ondelettes niveau +TP_LOCALLAB_CSTHRESHOLD;Ondelettes niveaux +TP_LOCALLAB_CSTHRESHOLDBLUR;Masque Ondelettes niveau TP_LOCALLAB_CURV;Luminosité - Contraste - Chrominance "Super" TP_LOCALLAB_CURVCURR;Normal TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP;Si la courbe est au sommet, le masque est compétement noir aucune transformation n'est réalisée par le masque sur l'image.\nQuand vous descendez la courbe, progressivement le masque va se colorer et s'éclaicir, l'image change de plus en plus.\n\nIl est recommendé (pas obligatoire) de positionner le sommet des courbes curves sur la ligne de transition grise qui représnte les références (chroma, luma, couleur). @@ -1892,9 +1892,9 @@ TP_LOCALLAB_DENOIEQUALCHRO_TOOLTIP;Equilibre l'action de denoise chrominance ent TP_LOCALLAB_DENOIBILAT_TOOLTIP;Traite le bruit d'impulsion (poivre et sel) TP_LOCALLAB_DEPTH;Profondeur TP_LOCALLAB_DETAIL;Contraste local -TP_LOCALLAB_DETAILFRA;Détection de bord +TP_LOCALLAB_DETAILFRA;Détection bord - DCT TP_LOCALLAB_DETAILSH;Details -TP_LOCALLAB_DETAILTHR;Seuil Detail Luminance Chroma (DCT ƒ) +TP_LOCALLAB_DETAILTHR;Seuil Detail Luma-Chroma TP_LOCALLAB_DUPLSPOTNAME;Copier TP_LOCALLAB_EDGFRA;Netteté des bords TP_LOCALLAB_EDGSHOW;Montre tous les outils @@ -1955,15 +1955,15 @@ TP_LOCALLAB_FATFRA;Compression Dynamique ƒ TP_LOCALLAB_FATFRAME_TOOLTIP;PDE Fattal - utilise Fattal Tone mapping algorithme. TP_LOCALLAB_FATLEVEL;Sigma TP_LOCALLAB_FATRES;Quantité de Residual Image -TP_LOCALLAB_FATSHFRA;Compression Dynamique Masque ƒ +TP_LOCALLAB_FATSHFRA;Compression Dynamique Masque TP_LOCALLAB_FEATH_TOOLTIP;Largeur du Gradient en porcentage de la diagonale du Spot\nUtilisé par tous les Filtres Gradués dans tous les outils.\nPas d'action si les filtres gradués ne sont pas utilisés. -TP_LOCALLAB_FEATVALUE;Adoucissement gradient (Filtres Gradués) +TP_LOCALLAB_FEATVALUE;Adouc. gradient(Filtres Gradués) TP_LOCALLAB_FFTCOL_MASK;FFTW ƒ TP_LOCALLAB_FFTMASK_TOOLTIP;Utilise une transformée de Fourier pour une meilleure qualité (accroit le temps de traitement et le besoin en mémoire) TP_LOCALLAB_FFTW;ƒ - Utilise Fast Fourier Transform TP_LOCALLAB_FFTW2;ƒ - Utilise Fast Fourier Transform (TIF, JPG,..) TP_LOCALLAB_FFTWBLUR;ƒ - Utilise toujours Fast Fourier Transform -TP_LOCALLAB_FULLIMAGE;Calcule les valeurs Noir Ev - Blanc Ev - sur l'image entière +TP_LOCALLAB_FULLIMAGE;Calcule les valeurs NoirEv-blancEv - image entière TP_LOCALLAB_FULLIMAGELOG_TOOLTIP;Calcule les valeurs Ev sur l'image entière. TP_LOCALLAB_GAM;Gamma TP_LOCALLAB_GAMFRA;Courbe Réponse Tonale (TRC) @@ -1999,7 +1999,7 @@ TP_LOCALLAB_GUIDSTRBL_TOOLTIP;Force du filtre guidé TP_LOCALLAB_GUIDEPSBL_TOOLTIP;Détail - agit sur la répartition du filtre guidé, les valeurs négatives simulent un flou gaussien TP_LOCALLAB_HHMASK_TOOLTIP;Ajustements fin de la teinte par exemple pour la peau. TP_LOCALLAB_HIGHMASKCOL;Hautes lumières masque -TP_LOCALLAB_HLH;Courbes H +TP_LOCALLAB_HLH;H TP_LOCALLAB_IND;Independant (souris) TP_LOCALLAB_INDSL;Independant (souris + curseurs) TP_LOCALLAB_INVERS;Inverse @@ -2024,7 +2024,7 @@ TP_LOCALLAB_LC_FFTW_TOOLTIP;FFT améliore la qualité et autorise de grands rayo TP_LOCALLAB_LC_TOOLNAME;Constraste Local & Ondelettes - 7 TP_LOCALLAB_LEVELBLUR;Maximum Flouter TP_LOCALLAB_LEVELLOCCONTRAST_TOOLTIP;En abscisse le contraste local (proche du concept de luminance). En ordonnée, amplification ou reduction du contraste local. -TP_LOCALLAB_LEVELWAV;Ψ Ondelettes Niveaux +TP_LOCALLAB_LEVELWAV;Ondelettes Niveaux TP_LOCALLAB_LEVELWAV_TOOLTIP;Le niveau est automatiquement adapté à la taille du spot et de la prévisualisation.\nDu niveau 9 taille max 512 jusqu'au niveau 1 taille max = 4 TP_LOCALLAB_LEVFRA;Niveaux TP_LOCALLAB_LIGHTNESS;Luminosité @@ -2036,11 +2036,11 @@ TP_LOCALLAB_LIST_TOOLTIP;Vous pouvez choisir 3 niveaux de complexité pour chaqu TP_LOCALLAB_LMASK_LEVEL_TOOLTIP;Donne priorité à l'action sur les tons moyens et hautes lumières en choisissant les niveaux concernés d'ondelettes TP_LOCALLAB_LMASK_LL_TOOLTIP;Vous permet de modifier librement le contraste du masque. Peut amener de artefacts. TP_LOCALLAB_LOCCONT;Masque Flou -TP_LOCALLAB_LOC_CONTRAST;Contraste Local & Ondelettes -TP_LOCALLAB_LOC_CONTRASTPYR;Ψ Pyramide 1: -TP_LOCALLAB_LOC_CONTRASTPYR2;Ψ Pyramide 2: -TP_LOCALLAB_LOC_CONTRASTPYR2LAB; Contr. par niveaux- TM - Cont.Dir. -TP_LOCALLAB_LOC_CONTRASTPYRLAB; Filtre Gradué - Netteté bords - Flou +TP_LOCALLAB_LOC_CONTRAST;Contr. Local & Ondelettes +TP_LOCALLAB_LOC_CONTRASTPYR;Pyramide 1: +TP_LOCALLAB_LOC_CONTRASTPYR2;Pyramide 2: +TP_LOCALLAB_LOC_CONTRASTPYR2LAB; Contr. par niveaux/TM/Cont.Dir. +TP_LOCALLAB_LOC_CONTRASTPYRLAB; Filtre Gradué/Netteté bords/Flou TP_LOCALLAB_LOC_RESIDPYR;Image Residuelle TP_LOCALLAB_LOG;Codage log TP_LOCALLAB_LOG1FRA;Ajustements Image @@ -2077,9 +2077,9 @@ TP_LOCALLAB_LOGSRCGREY_TOOLTIP;Estime la valeur du point gris de l'image, tôt d TP_LOCALLAB_LOGTARGGREY_TOOLTIP;Vous pouvez changer cette valeur pour l'adapter à votre goût. TP_LOCALLAB_LOG_TOOLNAME;Codage log - 0 TP_LOCALLAB_LOGVIEWING_TOOLTIP;Correspond au medium sur lequel l'image finale sera vue (moniteur, TV, projecteur, imprimante,..), ainsi que son environnement. -TP_LOCALLAB_LUM;Courbes LL - CC +TP_LOCALLAB_LUM;LL - CC TP_LOCALLAB_LUMADARKEST;Plus Sombre -TP_LOCALLAB_LUMASK;Maqsue Luminance arrière plan +TP_LOCALLAB_LUMASK;Masque Luminance arrière plan TP_LOCALLAB_LUMASK_TOOLTIP;Ajuste le gris de l'arrière plan du masque dans Montrer Masque (Masque et modifications) TP_LOCALLAB_LUMAWHITESEST;Plus clair TP_LOCALLAB_LUMONLY;Luminance seulement @@ -2093,12 +2093,12 @@ TP_LOCALLAB_MASK;Masque TP_LOCALLAB_MASK2;Courbe de Contraste TP_LOCALLAB_MASKCOL;Masque Courbes TP_LOCALLAB_MASKCURVE_TOOLTIP;Si la courbe est au sommet, le masque est compétement noir aucune transformation n'est réalisée par le masque sur l'image.\nQuand vous descendez la courbe, progressivement le masque va se colorer et s'éclaicir, l'image change de plus en plus.\n\nIl est recommendé (pas obligatoire) de positionner le sommet des courbes curves sur la ligne de transition grise qui représnte les références (chroma, luma, couleur). -TP_LOCALLAB_MASKLCTHRMID;Zones grises de-bruite luminance -TP_LOCALLAB_MASKLCTHRMIDCH;Zones grises de-bruite chrominance +TP_LOCALLAB_MASKLCTHRMID;Zones grises de-bruite lumina +TP_LOCALLAB_MASKLCTHRMIDCH;Zones grises de-bruite chroma TP_LOCALLAB_MASKLC_TOOLTIP;Vous autorise à cibler le de-bruite en se basant sur les informations du masque dans L(L) ou LC(H) (Masque et Modifications).\n Les masques L(L) ou LC(H) doivent être activés pour utiliser cette fonction.\n si le masque est très sombre - sous le seuil 'sombre' - de-bruite sera accru si renforce > 1.\n si le masque est clair - au-dessus du seuil 'clair' - de-bruite sera progressivement réduit.\n entre les deux, de-bruite sera maintenu aux réglages sans masques. TP_LOCALLAB_MASKLCTHR;Seuil luminance zones claires TP_LOCALLAB_MASKLCTHRLOW;Seuil luminance zones sombres -TP_LOCALLAB_MASKLNOISELOW;Renforce de-bruite zones sombres et claires +TP_LOCALLAB_MASKLNOISELOW;Renf. de-bruite sombres/claires TP_LOCALLAB_MASKH;Courbe teinte TP_LOCALLAB_MASKRECOTHRES;Seuil de Récupération TP_LOCALLAB_MASKDE_TOOLTIP;Utilisé pour diriger l'action de de-bruite basé sur les informations des courbes masques L(L) ou LC(H) (Masque et modifications).\n Les masques L(L) ou LC(H) doivent être activés pour utiliser cette fonction.\n Si le masque est en dessous du seuil sombre le De-bruite sera appliqué progressivement.\n Si le masque est au-dessus du seuil 'clair', le De-bruite sera appliqué progressivement.\n Entre les deux, les réglages sans De-bruite seront maintenus, sauf si vous agissez sur les curseurs "Zones grise dé-bruite luminance" or "Zones grise de-bruite chrominance". @@ -2181,7 +2181,7 @@ TP_LOCALLAB_MERTHR;Difference TP_LOCALLAB_MERTWE;Exclusion TP_LOCALLAB_MERTWO;Soustrait TP_LOCALLAB_METHOD_TOOLTIP;'Enhanced + chroma denoise' significantly increases processing times.\nBut reduce artifacts. -TP_LOCALLAB_MLABEL;Récupère les données Min=%1 Max=%2 (Clip - décalage) +TP_LOCALLAB_MLABEL;Réc. données Min=%1 Max=%2 TP_LOCALLAB_MLABEL_TOOLTIP;'Doit être' près de min=0 max=32768 (log mode) mais d'autres valeurs sont possibles.\nVous pouvez agir sur les données récupérées (CLIP) et décalage pour normaliser.\n\nRécupère les données image sans mélange. TP_LOCALLAB_MODE_EXPERT;Avancé TP_LOCALLAB_MODE_NORMAL;Standard @@ -2204,12 +2204,12 @@ TP_LOCALLAB_NLRAD;Taille maximum du rayon TP_LOCALLAB_NOISE_TOOLTIP;Ajoute du bruit de luminance TP_LOCALLAB_NOISECHROCOARSE;Chroma gros (Ond) TP_LOCALLAB_NOISECHROC_TOOLTIP;Si supérieur à zéro, algorithme haute qualité est activé.\nGros est sélectionné si curseur >=0.2 -TP_LOCALLAB_NOISECHRODETAIL;Récupération des détails Chroma (DCT ƒ) +TP_LOCALLAB_NOISECHRODETAIL;Récup. détails Chroma(DCT) TP_LOCALLAB_NOISECHROFINE;Chroma fin (Ond) TP_LOCALLAB_NOISEDETAIL_TOOLTIP;Désactivé si curseur = 100 TP_LOCALLAB_NOISELEQUAL;Egalisateurs blanc-noir TP_LOCALLAB_NOISELUMCOARSE;Luminance gros (ond) -TP_LOCALLAB_NOISELUMDETAIL;Récupération Luminance fin(DCT ƒ) +TP_LOCALLAB_NOISELUMDETAIL;Récup. Luminance détail(DCT) TP_LOCALLAB_NOISELUMFINE;Luminance fin 1 (ond) TP_LOCALLAB_NOISELUMFINETWO;Luminance fin 2 (ond) TP_LOCALLAB_NOISELUMFINEZERO;Luminance fin 0 (ond) @@ -2233,7 +2233,7 @@ TP_LOCALLAB_QUALCURV_METHOD;Types de Courbes TP_LOCALLAB_QUAL_METHOD;Qualité globale TP_LOCALLAB_QUACONSER;Conservatif TP_LOCALLAB_QUAAGRES;Aggressif -TP_LOCALLAB_QUANONEWAV;Débruitage par morceaux - luminance seulement +TP_LOCALLAB_QUANONEWAV;Débruit. par morceaux-luminance seulement TP_LOCALLAB_QUANONEALL;Rien TP_LOCALLAB_RADIUS;Rayon TP_LOCALLAB_RADIUS_TOOLTIP;Au-dessus de Rayon 30 Utilise 'Fast Fourier Transform' @@ -2294,7 +2294,7 @@ TP_LOCALLAB_SH1;Ombres Lumières TP_LOCALLAB_SH2;Egaliseur TP_LOCALLAB_SHADEX;Ombres TP_LOCALLAB_SHADEXCOMP;Compression ombres & profondeur tonale -TP_LOCALLAB_SHADHIGH;Ombres/Lumières-Egaliseur +TP_LOCALLAB_SHADHIGH;Ombres/Lumières&Egaliseur TP_LOCALLAB_SHADOWHIGHLIGHT_TOOLTIP;Peut être utilisé - ou en complement - du module Exposition dans les cas difficiles.\nUtiliser réduction du bruit Denoise peut être nécessaire : éclaicir les ombres.\n\nPeut être utilisé comme un filtre gradué (augmenter Etendue) TP_LOCALLAB_SHAMASKCOL;Ombres TP_LOCALLAB_SHADMASK_TOOLTIP;Relève les ombres du masque de la même manière que l'algorithme "ombres/lumières" @@ -2331,7 +2331,7 @@ TP_LOCALLAB_SHOWMODIF;Montrer modifications sans masque TP_LOCALLAB_SHOWMODIF2;Montrer modifications TP_LOCALLAB_SHOWMODIFMASK;Montrer modifications avec masque TP_LOCALLAB_SHOWNORMAL;Normalise luminance (non) -TP_LOCALLAB_SHOWPLUS;Masque et modifications - Adoucir-flouter & De-bruite +TP_LOCALLAB_SHOWPLUS;Masque et modifications TP_LOCALLAB_SHOWPOISSON;Poisson (pde ƒ) TP_LOCALLAB_SHOWR;Masque et modifications TP_LOCALLAB_SHOWREF;Prévisualisation ΔE @@ -2348,7 +2348,7 @@ TP_LOCALLAB_SIM;Simple TP_LOCALLAB_SLOMASKCOL;Pente (slope) TP_LOCALLAB_SLOMASK_TOOLTIP;Gamma et Pente (Slope) autorise une transformation du masque en douceur et sans artefacts en modifiant progressivement "L" pour éviter les discontinuité. TP_LOCALLAB_SLOSH;Pente -TP_LOCALLAB_SOFT;Lumière douce - Original Retinex +TP_LOCALLAB_SOFT;Lumière douce/Orig. Retinex TP_LOCALLAB_SOFTM;Lumière douce (soft light) TP_LOCALLAB_SOFTMETHOD_TOOLTIP;Applique un mélange Lumière douce. Effectue une émulation de "dodge and burn" en utilisant l'algorithme original de retinex. TP_LOCALLAB_SOFTRADIUSCOL;Rayon adoucir @@ -2388,10 +2388,10 @@ TP_LOCALLAB_THRES;Seuil structure TP_LOCALLAB_THRESDELTAE;Seuil ΔE-Etendue TP_LOCALLAB_THRESRETI;Seuil TP_LOCALLAB_THRESWAV;Balance Seuil -TP_LOCALLAB_TLABEL;TM Datas Min=%1 Max=%2 Mean=%3 Sigma=%4 (Seuil) +TP_LOCALLAB_TLABEL;TM Min=%1 Max=%2 Mea=%3 Sig=%4 TP_LOCALLAB_TLABEL2;TM Effectif Tm=%1 TM=%2 TP_LOCALLAB_TLABEL_TOOLTIP;Transmission map result.\nMin and Max are used by Variance.\nTm=Min TM=Max of Transmission Map.\nYou can act on Threshold to normalize -TP_LOCALLAB_TM;Compression tonale - Texture +TP_LOCALLAB_TM;Compression tonale TP_LOCALLAB_TM_MASK;Utilise transmission map TP_LOCALLAB_TONEMAPESTOP_TOOLTIP;Ce paramètre affecte la sensibilité aux bords.\n Plus grand il est, plus la luminosité change peut être considéré comme un bord.\n Si réglé à zéro 'compression tonale' va avoir un effet similaire à masque flou. TP_LOCALLAB_TONEMAPGAM_TOOLTIP;Gamma déplace l'action de 'compression tonale' des ombres vers les lumières. @@ -2407,7 +2407,7 @@ TP_LOCALLAB_TRANSIT;Transition - Gradient TP_LOCALLAB_TRANSITGRAD;Transition différentiation XY TP_LOCALLAB_TRANSITGRAD_TOOLTIP;Change la transition des abscisses vers les ordonnées TP_LOCALLAB_TRANSITVALUE;Transition valeur -TP_LOCALLAB_TRANSITWEAK;Transition affaiblissement (linéaire-log) +TP_LOCALLAB_TRANSITWEAK;Transition affaiblissement (lin-log) TP_LOCALLAB_TRANSITWEAK_TOOLTIP;Ajuste l'affaiblissement de la transition : change le processus d'affaiblissement - 1 linéaire - 2 parabolique - 3 cubique - ^25.\nPeut être utilisé en conjonction avec de très faibles valeurs de transition pour traiter/réduire les défauts (CBDL, Ondelettes, Couleur et lumière) TP_LOCALLAB_TRANSIT_TOOLTIP;Ajuste la progressions de la transition enttre les zones affectées ou non affectées, comme un pourcentage du "rayon" TP_LOCALLAB_TRANSMISSIONGAIN;Transmission gain @@ -2426,9 +2426,9 @@ TP_LOCALLAB_SHARP_TOOLNAME;Netteté - 8 TP_LOCALLAB_LC_TOOLNAME;Constraste local & Ondelettes (Défauts) - 7 TP_LOCALLAB_CBDL_TOOLNAME;Contraste par Niveau détail - 2 TP_LOCALLAB_LOG_TOOLNAME;Codage log - 0 -TP_LOCALLAB_MASKCOM_TOOLNAME;Masque Commun Couleur - 13 +TP_LOCALLAB_MASKCOM_TOOLNAME;Masque Commun Couleur - 12 TP_LOCALLAB_VIS_TOOLTIP;Click pour montrer/cacher le Spot sélectionné.\nCtrl+click pour montrer/cacher tous les Spot. -TP_LOCALLAB_WAMASKCOL;Ψ Niveau Ondelettes +TP_LOCALLAB_WAMASKCOL;Niveau Ondelettes TP_LOCALLAB_WARM;Chaud - Froid & Artefacts de couleur TP_LOCALLAB_WARM_TOOLTIP;Ce curseur utilise l'algorithme Ciecam et agit comme une Balance des blancs, il prut réchauffer ou refroidir cool la zone concernée.\nIl peut aussi dans certains réduire les artefacts colorés. TP_LOCALLAB_WASDEN_TOOLTIP;De-bruite luminance pour les 3 premiers niveaux (fin).\nLa limite droite de la courbe correspond à gros : niveau 3 et au delà. @@ -2465,18 +2465,18 @@ TP_LOCALLAB_WAVCOMPRE_TOOLTIP;Réalise un 'Tone-mapping' ou une réduction du co TP_LOCALLAB_WAVCOMP_TOOLTIP;Réalise un contrast local en fonction de la direction de la décomposition en ondelettes : horizontal, vertical, diagonal TP_LOCALLAB_WAVCON;Contraste par niveau TP_LOCALLAB_WAVCONTF_TOOLTIP;Similaire à Contrast By Detail Levels : en abscisse niveaux. -TP_LOCALLAB_WAVDEN;de-bruite luminance par niveau (0 1 2 -3 et plus) -TP_LOCALLAB_WAVE;Ψ Ondelette +TP_LOCALLAB_WAVDEN;de-bruite lum. par niveau +TP_LOCALLAB_WAVE;Ondelette TP_LOCALLAB_WAVEDG;Contrast Local TP_LOCALLAB_WAVEEDG_TOOLTIP;Améliore la netteté prenant en compte la notion de "ondelettes bords".\nNécessite au moins que les 4 premiers niveaux sont utilisables TP_LOCALLAB_WAVGRAD_TOOLTIP;Filtre gradué pour Contraste local "luminance" -TP_LOCALLAB_WAVHIGH;Ψ Ondelette haut -TP_LOCALLAB_WAVLEV;Flouter par niveau -TP_LOCALLAB_WAVLOW;Ψ Ondelette bas -TP_LOCALLAB_WAVMASK;Ψ Niveau contraste local +TP_LOCALLAB_WAVHIGH;Ondelette haut +TP_LOCALLAB_WAVLEV;Flou par niveau +TP_LOCALLAB_WAVLOW;Ondelette bas +TP_LOCALLAB_WAVMASK;Contr. local (par niveau) TP_LOCALLAB_WAVEMASK_LEVEL_TOOLTIP;Amplitude des niveaux d'ondelettes utilisés par “Local contrast” TP_LOCALLAB_WAVMASK_TOOLTIP;Autorise un travail fin sur les masques niveaux de contraste (structure) -TP_LOCALLAB_WAVMED;Ψ Ondelette normal +TP_LOCALLAB_WAVMED;Ondelette normal TP_LOCALLAB_WEDIANHI;Median Haut TP_LOCALLAB_WHITE_EV;Blanc Ev TP_METADATA_EDIT;Appliquer les modifications @@ -2604,7 +2604,7 @@ TP_RESIZE_APPLIESTO;S'applique à: TP_RESIZE_CROPPEDAREA;La zone recadrée TP_RESIZE_FITBOX;Boîte englobante TP_RESIZE_FULLIMAGE;L'image entière -TP_RESIZE_H;H: +TP_RESIZE_H;H TP_RESIZE_HEIGHT;Hauteur TP_RESIZE_LABEL;Redimensionnement TP_RESIZE_LANCZOS;Lanczos @@ -2616,7 +2616,7 @@ TP_RESIZE_W;L: TP_RESIZE_WIDTH;Largeur TP_RETINEX_CONTEDIT_HSL;Égaliseur d'histogramme TSV TP_RETINEX_CONTEDIT_LAB;Égaliseur d'histogramme L*a*b* -TP_RETINEX_CONTEDIT_LH;Égaliseur de teinte +TP_RETINEX_CONTEDIT_LH;Égaliseur teinte: TP_RETINEX_CONTEDIT_MAP;Égaliseur TP_RETINEX_CURVEEDITOR_CD;L=f(L) TP_RETINEX_CURVEEDITOR_CD_TOOLTIP;Luminance en fonction de la luminance L=f(L)\nCorrige les données raw pour réduire halos et artéfacts. @@ -2628,7 +2628,7 @@ TP_RETINEX_EQUAL;Égaliseur TP_RETINEX_FREEGAMMA;Gamma manuel TP_RETINEX_GAIN;Gain TP_RETINEX_GAINOFFS;Gain et Décalage (brillance) -TP_RETINEX_GAINTRANSMISSION;Gain sur Transmission +TP_RETINEX_GAINTRANSMISSION;Gain Transmission: TP_RETINEX_GAINTRANSMISSION_TOOLTIP;Amplifie ou réduit le canal transmission pour atteindre la luminance souhaitée.\nAbscisses: transmission ; min = 0, max = valeurs.\nOrdonnées: gain. TP_RETINEX_GAMMA;Gamma TP_RETINEX_GAMMA_FREE;Manuel @@ -2681,7 +2681,7 @@ TP_RETINEX_TLABEL;CT Min=%1 Max=%2 Moyen=%3 Sigma=%4 TP_RETINEX_TLABEL2;CT Tm=%1 TM=%2 TP_RETINEX_TLABEL_TOOLTIP;Résultat du calcul de transmission.\nMin et Max sont utilisés par Variance.\nMoyen et Sigma.\nTm=Min TM=Niveau maximum de transmission. TP_RETINEX_TRANF;Transmission -TP_RETINEX_TRANSMISSION;Modulation du canal 'transmission' +TP_RETINEX_TRANSMISSION;Modulation 'transmission' TP_RETINEX_TRANSMISSION_TOOLTIP;Transmission en fonction de la transmission.\nAbscisses: transmission des valeurs négatives (min), moyennes, et positives (max).\nOrdonnées: amplification ou réduction. TP_RETINEX_UNIFORM;Uniforme TP_RETINEX_VARIANCE;Contraste @@ -2809,7 +2809,7 @@ TP_WAVELET_COMPCONT;Contraste TP_WAVELET_COMPGAMMA;Compression gamma TP_WAVELET_COMPGAMMA_TOOLTIP;Ajuster le gamma de l'image résiduelle vous permet d'équiilibrer les données de l'histogramme. TP_WAVELET_COMPTM;Compression tonale -TP_WAVELET_CONTEDIT;Courbe de contraste 'Après' +TP_WAVELET_CONTEDIT;Courbe contraste 'Après' TP_WAVELET_CONTR;Gamut TP_WAVELET_CONTRA;Contraste TP_WAVELET_CONTRAST_MINUS;Contraste - @@ -2897,7 +2897,7 @@ TP_WAVELET_NPTYPE;Pixels voisins TP_WAVELET_NPTYPE_TOOLTIP;Cet algorithme utilise la proximité d'un pixel et huit de ses voisins. Si moins de différence, les bords sont renforcés. TP_WAVELET_OPACITY;Opacité Bleu-Jaune TP_WAVELET_OPACITYW;Courbe de contraste d/v-h -TP_WAVELET_OPACITYWL;Contraste local final +TP_WAVELET_OPACITYWL;Contraste local TP_WAVELET_OPACITYWL_TOOLTIP;Modifie le contraste local final à la fin du traitement par ondelettes.\n\nLe côté gauche représente les plus faibles contrastes locaaux, progressant jusqu'aux plus grands contrastes locaux vers la droite. TP_WAVELET_PASTEL;Chroma des Pastels TP_WAVELET_PROC;Procédé diff --git a/rtdata/languages/default b/rtdata/languages/default index 15aceb51b..595f03e7e 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1461,7 +1461,7 @@ ICCPROFCREATOR_PROF_V2;ICC v2 ICCPROFCREATOR_PROF_V4;ICC v4 ICCPROFCREATOR_SAVEDIALOG_TITLE;Save ICC profile as... ICCPROFCREATOR_SLOPE;Slope -ICCPROFCREATOR_TRC_PRESET;Tone response curve: +ICCPROFCREATOR_TRC_PRESET;Tone response curve IPTCPANEL_CATEGORY;Category IPTCPANEL_CATEGORYHINT;Identifies the subject of the image in the opinion of the provider. IPTCPANEL_CITY;City @@ -2140,7 +2140,7 @@ TP_COLORTONING_AUTOSAT;Automatic TP_COLORTONING_BALANCE;Balance TP_COLORTONING_BY;o C/L TP_COLORTONING_CHROMAC;Opacity -TP_COLORTONING_COLOR;Color +TP_COLORTONING_COLOR;Color: TP_COLORTONING_CURVEEDITOR_CL_TOOLTIP;Chroma opacity as a function of luminance oC=f(L) TP_COLORTONING_HIGHLIGHT;Highlights TP_COLORTONING_HUE;Hue @@ -2175,7 +2175,7 @@ TP_COLORTONING_METHOD_TOOLTIP;"L*a*b* blending", "RGB sliders" and "RGB curves" TP_COLORTONING_MIDTONES;Midtones TP_COLORTONING_NEUTRAL;Reset sliders TP_COLORTONING_NEUTRAL_TIP;Reset all values (Shadows, Midtones, Highlights) to default. -TP_COLORTONING_OPACITY;Opacity +TP_COLORTONING_OPACITY;Opacity: TP_COLORTONING_RGBCURVES;RGB - Curves TP_COLORTONING_RGBSLIDERS;RGB - Sliders TP_COLORTONING_SA;Saturation Protection @@ -2483,7 +2483,7 @@ TP_LOCALCONTRAST_LIGHTNESS;Lightness level TP_LOCALCONTRAST_RADIUS;Radius TP_LOCALLAB_ACTIV;Luminance only TP_LOCALLAB_ACTIVSPOT;Enable Spot -TP_LOCALLAB_ADJ;Equalizer Blue-Yellow/Red-Green +TP_LOCALLAB_ADJ;Equalizer Color TP_LOCALLAB_ALL;All rubrics TP_LOCALLAB_AMOUNT;Amount TP_LOCALLAB_ARTIF;Shape detection @@ -2501,8 +2501,8 @@ TP_LOCALLAB_BILATERAL;Bilateral filter TP_LOCALLAB_BLACK_EV;Black Ev TP_LOCALLAB_BLCO;Chrominance only TP_LOCALLAB_BLENDMASKCOL;Blend -TP_LOCALLAB_BLENDMASKMASK;Add/subtract luminance mask -TP_LOCALLAB_BLENDMASKMASKAB;Add/subtract chrominance mask +TP_LOCALLAB_BLENDMASKMASK;Add/subtract luma mask +TP_LOCALLAB_BLENDMASKMASKAB;Add/subtract chroma mask TP_LOCALLAB_BLENDMASKMASK_TOOLTIP;If this slider = 0 no action.\nAdd or subtract the mask from the original image TP_LOCALLAB_BLENDMASK_TOOLTIP;If blend = 0 only shape detection is improved.\nIf blend > 0 the mask is added to the image. If blend < 0 the mask is subtracted from the image TP_LOCALLAB_BLGUID;Guided Filter @@ -2510,12 +2510,12 @@ TP_LOCALLAB_BLINV;Inverse TP_LOCALLAB_BLLC;Luminance & Chrominance TP_LOCALLAB_BLLO;Luminance only TP_LOCALLAB_BLMED;Median -TP_LOCALLAB_BLMETHOD_TOOLTIP;Normal - direct blur and noise with all settings.\nInverse blur and noise with all settings. Be careful some results may be curious +TP_LOCALLAB_BLMETHOD_TOOLTIP;Normal: direct blur and noise with all settings.\nInverse: blur and noise with all settings. Warning, some settings may give curious results. TP_LOCALLAB_BLNOI_EXP;Blur & Noise TP_LOCALLAB_BLNORM;Normal TP_LOCALLAB_BLSYM;Symmetric TP_LOCALLAB_BLUFR;Blur/Grain & Denoise -TP_LOCALLAB_BLUMETHOD_TOOLTIP;To blur the background and isolate the foreground:\n-blur the background by completely covering the image with an an RT-spot (high values for scope and transition and ‘Normal’ or ‘Inverse’ in checkbox).\n-Isolate the foreground by using one or more ‘Excluding’ RT-spot(s) and increase the scope.\n\nThis module (including the "median" and "Guided filter") can be used in addition to the main-menu noise reduction. +TP_LOCALLAB_BLUMETHOD_TOOLTIP;To blur the background and isolate the foreground:\n-blur the background by completely covering the image with an an RT-spot (high values for scope and transition and ‘Normal’ or ‘Inverse’ in checkbox).\n-Isolate the foreground by using one or more ‘Excluding’ RT-spot(s) and increase the scope.\n\nThis module (including the ‘median’ and ‘Guided filter’) can be used in addition to the main-menu noise reduction TP_LOCALLAB_BLUR;Gaussian Blur - Noise - Grain TP_LOCALLAB_BLURCBDL;Blur levels 0-1-2-3-4 TP_LOCALLAB_BLURCOL;Radius @@ -2534,7 +2534,7 @@ TP_LOCALLAB_BUTTON_DEL;Delete TP_LOCALLAB_BUTTON_DUPL;Duplicate TP_LOCALLAB_BUTTON_REN;Rename TP_LOCALLAB_BUTTON_VIS;Show/Hide -TP_LOCALLAB_CATAD;Chromatic adaptation - Cat16 +TP_LOCALLAB_CATAD;Chromatic adaptation/Cat16 TP_LOCALLAB_CBDL;Contrast by Detail Levels TP_LOCALLAB_CBDLCLARI_TOOLTIP;Enhances local contrast of the midtones. TP_LOCALLAB_CBDL_ADJ_TOOLTIP;Same as wavelets.\nThe first level (0) acts on 2x2 pixel details.\nThe last level (5) acts on 64x64 pixel details. @@ -2542,7 +2542,7 @@ TP_LOCALLAB_CBDL_THRES_TOOLTIP;Prevents the sharpening of noise TP_LOCALLAB_CBDL_TOOLNAME;Contrast by Detail Levels TP_LOCALLAB_CENTER_X;Center X TP_LOCALLAB_CENTER_Y;Center Y -TP_LOCALLAB_CH;Curves CL - LC +TP_LOCALLAB_CH;CL - LC TP_LOCALLAB_CHROMA;Chrominance TP_LOCALLAB_CHROMABLU;Chroma levels TP_LOCALLAB_CHROMABLU_TOOLTIP;Increases or reduces the effect depending on the luma settings.\nValues under 1 reduce the effect. Values greater than 1 increase the effect. @@ -2555,45 +2555,45 @@ TP_LOCALLAB_CHRRT;Chroma TP_LOCALLAB_CIEC;Use Ciecam environment parameters TP_LOCALLAB_CIECAMLOG_TOOLTIP;This module is based on the CIECAM color appearance model which was designed to better simulate how human vision perceives colors under different lighting conditions.\nThe first Ciecam process 'Scene conditions' is carried out by Log encoding, it also uses 'Absolute luminance' at the time of shooting.\nThe second Ciecam process 'Image adjustments' is simplified and uses only 3 variables (local contrast, contrast J, saturation s).\nThe third Ciecam process 'Viewing conditions' adapts the output to the intended viewing conditions (monitor, TV, projector, printer, etc.) so that the chromatic and contrast appearance is preserved across the display environment. TP_LOCALLAB_CIRCRADIUS;Spot size -TP_LOCALLAB_CIRCRAD_TOOLTIP;Contains the references of the RT-spot, useful for shape detection (hue, luma, chroma, Sobel).\nLow values may be useful for treating foliage.\nHigh values may be useful for treating skin +TP_LOCALLAB_CIRCRAD_TOOLTIP;Contains the references of the RT-spot, useful for shape detection (hue, luma, chroma, Sobel).\nLow values may be useful for processing foliage.\nHigh values may be useful for processing skin. TP_LOCALLAB_CLARICRES;Merge chroma -TP_LOCALLAB_CLARIFRA;Clarity & Sharp mask - Blend & Soften Images +TP_LOCALLAB_CLARIFRA;Clarity & Sharp mask/Blend & Soften Images TP_LOCALLAB_CLARILRES;Merge luma TP_LOCALLAB_CLARISOFT;Soft radius -TP_LOCALLAB_CLARISOFT_TOOLTIP;The "Soft radius" slider (guided filter algorithm) reduces halos and irregularities for both Clarity and Sharp Mask and for all pyramid wavelet processes. To deactivate, set slider to zero. +TP_LOCALLAB_CLARISOFT_TOOLTIP;The ‘Soft radius’ slider (guided filter algorithm) reduces halos and irregularities for both Clarity and Sharp Mask and for all pyramid wavelet processes. To deactivate, set slider to zero. TP_LOCALLAB_CLARITYML;Clarity TP_LOCALLAB_CLARI_TOOLTIP;Levels 0 to 4 (included): ‘Sharp mask’ is enabled\nLevels 5 and above: 'Clarity' is enabled.\nUseful if you use 'Wavelet level tone mapping' TP_LOCALLAB_CLIPTM;Clip restored data (gain) TP_LOCALLAB_COFR;Color & Light TP_LOCALLAB_COLORDE;ΔE preview color - intensity -TP_LOCALLAB_COLORDEPREV_TOOLTIP;Preview ΔE button will only work if you have activated one (and only one) of the tools in "Add tool to current spot" menu.\nTo be able to preview ΔE with several tools enabled, use Mask and modifications - Preview ΔE. -TP_LOCALLAB_COLORDE_TOOLTIP;Show a blue color-preview for ΔE selection if negative and green if positive.\n\nMask and modifications (show modified areas without mask): show actual modifications if positive, show enhanced modifications (luminance only) with blue and yellow if negative. +TP_LOCALLAB_COLORDEPREV_TOOLTIP;Preview ΔE button will only work if you have activated one (and only one) of the tools in ‘Add tool to current spot’ menu.\nTo be able to preview ΔE with several tools enabled, use Mask and modifications - Preview ΔE. +TP_LOCALLAB_COLORDE_TOOLTIP;Show a blue color preview for ΔE selection if negative and green if positive.\n\nMask and modifications (show modified areas without mask): show actual modifications if positive, show enhanced modifications (luminance only) with blue and yellow if negative. TP_LOCALLAB_COLORSCOPE;Scope (color tools) TP_LOCALLAB_COLORSCOPE_TOOLTIP;Common Scope slider for Color and Light, Shadows/Highlights, Vibrance.\nOther tools have their own scope controls. TP_LOCALLAB_COLOR_TOOLNAME;Color & Light TP_LOCALLAB_COL_NAME;Name TP_LOCALLAB_COL_VIS;Status TP_LOCALLAB_COMPFRA;Directional contrast -TP_LOCALLAB_COMPFRAME_TOOLTIP;Allows special effects. You can reduce artifacts with 'Clarity & Sharp mask - Blend & Soften Images".\nUses a lot of resources +TP_LOCALLAB_COMPFRAME_TOOLTIP;Allows you to create special effects. You can reduce artifacts with 'Clarity and Sharp mask - Blend and Soften Images’.\nUses a lot of resources. TP_LOCALLAB_COMPLEX_METHOD;Software Complexity -TP_LOCALLAB_COMPLEX_TOOLTIP; Allow user to select Local adjustments rubrics. +TP_LOCALLAB_COMPLEX_TOOLTIP; Allow user to select Local adjustments complexity. TP_LOCALLAB_COMPREFRA;Wavelet level tone mapping -TP_LOCALLAB_COMPRESS_TOOLTIP;Use if necessary the module 'Clarity & Sharp mask and Blend & Soften Images' by adjusting 'Soft radius' to reduce artifacts. +TP_LOCALLAB_COMPRESS_TOOLTIP;If necessary, use the module 'Clarity and Sharp mask and Blend and Soften Images' by adjusting 'Soft radius' to reduce artifacts. TP_LOCALLAB_CONTCOL;Contrast threshold TP_LOCALLAB_CONTFRA;Contrast by level TP_LOCALLAB_CONTL;Contrast (J) TP_LOCALLAB_CONTRAST;Contrast -TP_LOCALLAB_CONTRASTCURVMASK1_TOOLTIP;Allows you to freely modify the contrast of the mask (gamma and slope), instead of using a continuous and progressive curve. However it can create artifacts that have to be dealt with using the “Smooth radius” or “Laplacian threshold sliders”. +TP_LOCALLAB_CONTRASTCURVMASK1_TOOLTIP;Allows you to freely modify the contrast of the mask (gamma and slope), instead of using a continuous and progressive curve. However it can create artifacts that have to be dealt with using the ‘Smooth radius’ or ‘Laplacian threshold sliders’. TP_LOCALLAB_CONTRASTCURVMASK_TOOLTIP;Allows you to freely change the contrast of the mask.\n Has a similar function to the Gamma and Slope sliders.\n It allows you to target certain parts of the image (usually the lightest parts of the mask by using the curve to exclude the darker parts).May create artifacts. TP_LOCALLAB_CONTRESID;Contrast TP_LOCALLAB_CONTTHMASK_TOOLTIP;Allows you to determine which parts of the image will be impacted based on the texture. TP_LOCALLAB_CONTTHR;Contrast Threshold TP_LOCALLAB_CONTWFRA;Local contrast -TP_LOCALLAB_CSTHRESHOLD;Ψ Wavelet levels -TP_LOCALLAB_CSTHRESHOLDBLUR;Ψ Wavelet level selection +TP_LOCALLAB_CSTHRESHOLD;Wavelet levels +TP_LOCALLAB_CSTHRESHOLDBLUR;Wavelet level selection TP_LOCALLAB_CURV;Lightness - Contrast - Chrominance "Super" TP_LOCALLAB_CURVCURR;Normal -TP_LOCALLAB_CURVEEDITORM_CC_TOOLTIP;If curves at the top, mask is completely black no transformation is made by the mask on the image.\nAs you go down the curve, the mask gradually more colorful and brilliant, the image is changing more and more.\n\nThe gray transition line which represents the references (chroma, luma, hue).\nYou can choose or not to position the top of the curves on this transition. +TP_LOCALLAB_CURVEEDITORM_CC_TOOLTIP;If the curves are at the top, the mask is completely black and no changes are made to the image.\nAs you lower the curve, the mask gradually becomes more colorful and bright, progressively changing the image.\n\nIt is recommended (but not mandatory) to position the top of the curves on the gray boundary line which represents the reference values of chroma, luma, hue for the RT-spot. TP_LOCALLAB_CURVEEDITOR_CC_TOOLTIP;If curves are at the top, the mask is completely black and no changes are made to the image.\nAs you lower the curve, the mask gradually becomes more colorful and bright, progressively changing the image.\n\nIt is recommended (but not mandatory) to position the top of the curves on the gray boundary line which represents the reference values of chroma, luma, hue for the RT-spot. TP_LOCALLAB_CURVEEDITOR_LL_TOOLTIP;To activate the curves, set the ‘Curve type’ combobox to ‘Normal’ TP_LOCALLAB_CURVEEDITOR_TONES_LABEL;Tone curve @@ -2620,16 +2620,16 @@ TP_LOCALLAB_DENOIEQUAL_TOOLTIP;Allows you to carry out more or less noise reduct TP_LOCALLAB_DENOI1_EXP;Denoise based on luminance mask TP_LOCALLAB_DENOI2_EXP;Recovery based on luminance mask TP_LOCALLAB_DENOILUMDETAIL_TOOLTIP;Allows you to recover luminance detail by progressively applying a Fourier transform (DCT). -TP_LOCALLAB_DENOIQUA_TOOLTIP;Conservative mode preserves low frequency detail. Aggressive mode removes low frequency detail.\nConservative and Aggressive use wavelets and DCT, can be used in conjunction with "Non-local Means - Luminance". -TP_LOCALLAB_DENOIS;Ψ Denoise +TP_LOCALLAB_DENOIQUA_TOOLTIP;Conservative mode preserves low frequency detail. Aggressive mode removes low frequency detail.\nConservative and Aggressive modes use wavelets and DCT and can be used in conjunction with ‘Non-local Means – Luminance’. +TP_LOCALLAB_DENOIS;Denoise TP_LOCALLAB_DENOITHR_TOOLTIP;Adjusts edge detection to help reduce noise in uniform, low-contrast areas. TP_LOCALLAB_DENOI_EXP;Denoise TP_LOCALLAB_DENOI_TOOLTIP;This module can be used for noise reduction either on its own (at the end of the processing pipeline) or in addition to the Noise Reduction module in the Detail tab (which works at the beginning of the pipeline).\n Scope allows you to differentiate the action based on color (deltaE). TP_LOCALLAB_DEPTH;Depth TP_LOCALLAB_DETAIL;Local contrast -TP_LOCALLAB_DETAILFRA;Edge detection +TP_LOCALLAB_DETAILFRA;Edge detection - DCT TP_LOCALLAB_DETAILSH;Details -TP_LOCALLAB_DETAILTHR;Luminance & chroma detail threshold (DCT ƒ) +TP_LOCALLAB_DETAILTHR;Luma-chro detail threshold TP_LOCALLAB_DIVGR;Gamma TP_LOCALLAB_DUPLSPOTNAME;Copy TP_LOCALLAB_EDGFRA;Edge sharpness @@ -2638,7 +2638,7 @@ TP_LOCALLAB_ELI;Ellipse TP_LOCALLAB_ENABLE_AFTER_MASK;Use Tone Mapping TP_LOCALLAB_ENABLE_MASK;Enable mask TP_LOCALLAB_ENABLE_MASKAFT;Use all algorithms Exposure -TP_LOCALLAB_ENARETIMASKTMAP_TOOLTIP;If enabled Mask uses Restored Datas after Transmission Map instead of Original datas +TP_LOCALLAB_ENARETIMASKTMAP_TOOLTIP;If enabled the Mask uses Restored Data after Transmission Map instead of Original data. TP_LOCALLAB_ENH;Enhanced TP_LOCALLAB_ENHDEN;Enhanced + chroma denoise TP_LOCALLAB_EPSBL;Detail @@ -2663,9 +2663,9 @@ TP_LOCALLAB_EXPCHROMA_TOOLTIP;Use in association with ‘Exposure compensation f TP_LOCALLAB_EXPCOLOR_TOOLTIP;Adjust color, lightness, contrast and correct small defects such as red-eye, sensor dust etc. TP_LOCALLAB_EXPCOMP;Exposure compensation ƒ TP_LOCALLAB_EXPCOMPINV;Exposure compensation -TP_LOCALLAB_EXPCOMP_TOOLTIP;For portraits or images with a low color gradient. You can change "Shape detection" in "Settings":\n\nIncrease 'ΔE scope threshold'\nReduce 'ΔE decay'\nIncrease 'ab-L balance (ΔE)’ +TP_LOCALLAB_EXPCOMP_TOOLTIP;For portraits or images with a low color gradient. You can change ‘Shape detection’ in "Settings":\n\nIncrease 'ΔE scope threshold'\nReduce 'ΔE decay'\nIncrease 'ab-L balance (ΔE)’ TP_LOCALLAB_EXPCONTRASTPYR_TOOLTIP;See the documentation for Wavelet Levels.\nThere are some differences in the Locallab version: more tools and more possibilities for working on individual detail levels.\ne.g. Wavelet-level tone mapping. -TP_LOCALLAB_EXPCONTRAST_TOOLTIP;Avoid spots that are too small ( < 32x32 pixels).\nUse low ‘Transition value’ and high ‘Transition decay’ and ‘Scope’ to simulate small RT-spots and deal wth defects.\nUse 'Clarity & Sharp mask and Blend & Soften Images' if necessary by adjusting 'Soft radius' to reduce artifacts. +TP_LOCALLAB_EXPCONTRAST_TOOLTIP;Avoid spots that are too small ( < 32x32 pixels).\nUse low ‘Transition value’ and high ‘Transition decay’ and ‘Scope’ to simulate small RT-spots and deal with defects.\nUse 'Clarity and Sharp mask and Blend and Soften Images' if necessary by adjusting 'Soft radius' to reduce artifacts. TP_LOCALLAB_EXPCURV;Curves TP_LOCALLAB_EXPGRAD;Graduated Filter TP_LOCALLAB_EXPGRADCOL_TOOLTIP;A graduated filter is available in Color and Light (luminance, chrominance & hue gradients, and "Merge file") Exposure (luminance grad.), Exposure Mask (luminance grad.), Shadows/Highlights (luminance grad.), Vibrance (luminance, chrominance & hue gradients), Local contrast & wavelet pyramid (local contrast grad.).\nFeather is located in Settings. @@ -2673,13 +2673,13 @@ TP_LOCALLAB_EXPLAPBAL_TOOLTIP;Changes the transformed/original image blend TP_LOCALLAB_EXPLAPGAMM_TOOLTIP;Changes the behaviour for images with too much or too little contrast by adding a gamma curve before and after the Laplace transform TP_LOCALLAB_EXPLAPLIN_TOOLTIP;Changes the behaviour for underexposed images by adding a linear component prior to applying the Laplace transform TP_LOCALLAB_EXPLAP_TOOLTIP;Moving the slider to the right progressively reduces the contrast. -TP_LOCALLAB_EXPMERGEFILE_TOOLTIP;Allows you to use GIMP or Photoshop (c) layer blend modes i.e. Difference, Multiply, Soft Light, Overlay etc., with opacity control.\nOriginal Image : merge current RT-spot with Original.\nPrevious spot : merge current Rt-spot with previous - if there is only one spot previous = original.\nBackground : merge current RT-spot with a color and luminance background (fewer possibilties) +TP_LOCALLAB_EXPMERGEFILE_TOOLTIP;Allows you to use GIMP or Photoshop (c) layer blend modes i.e. Difference, Multiply, Soft Light, Overlay etc., with opacity control.\nOriginal Image : merge current RT-Spot with Original.\nPrevious spot : merge current Rt-Spot with previous - if there is only one spot, previous = original.\nBackground : merge current RT-Spot with a color and luminance background (fewer possibilties). TP_LOCALLAB_EXPMETHOD_TOOLTIP;Standard : use an algorithm similar as main Exposure but in L*a*b* and taking account of deltaE.\n\nContrast attenuator : use another algorithm also with deltaE and with Poisson equation to solve Laplacian in Fourier space.\nContrast attenuator, Dynamic range compression and Standard can be combined.\nFFTW Fourier Transform is optimized in size to reduce processing time.\nReduce artifacts and noise. -TP_LOCALLAB_EXPNOISEMETHOD_TOOLTIP;Applies a median filter before the Laplace transform to prevent artifacts (noise).\nYou can also use the "Denoise" tool. +TP_LOCALLAB_EXPNOISEMETHOD_TOOLTIP;Applies a median filter before the Laplace transform to prevent artifacts (noise).\nYou can also use the ‘Denoise’ tool. TP_LOCALLAB_EXPOSE;Dynamic Range & Exposure TP_LOCALLAB_EXPOSURE_TOOLTIP;Modify exposure in L*a*b space using Laplacian PDE algorithms to take into account dE and minimize artifacts. TP_LOCALLAB_EXPRETITOOLS;Advanced Retinex Tools -TP_LOCALLAB_EXPSHARP_TOOLTIP;RT-Spot minimum 39*39.\nUse low transition values and high ‘Transition decay’ and ‘Scope’ values to simulate smaller RT-spots. +TP_LOCALLAB_EXPSHARP_TOOLTIP;RT-Spot minimum 39*39.\nUse low transition values and high ‘Transition decay’ and ‘Scope’ values to simulate smaller RT-Spots. TP_LOCALLAB_EXPTOOL;Exposure Tools TP_LOCALLAB_EXPTRC;Tone Response Curve - TRC TP_LOCALLAB_EXP_TOOLNAME;Dynamic Range & Exposure @@ -2693,19 +2693,19 @@ TP_LOCALLAB_FATLEVEL;Sigma TP_LOCALLAB_FATRES;Amount Residual Image TP_LOCALLAB_FATSHFRA;Dynamic Range Compression Mask ƒ TP_LOCALLAB_FEATH_TOOLTIP;Gradient width as a percentage of the Spot diagonal\nUsed by all graduated filters in all tools.\nNo action if a graduated filter hasn’t been activated. -TP_LOCALLAB_FEATVALUE;Feather gradient (Graduated Filters) +TP_LOCALLAB_FEATVALUE;Feather gradient (Grad. Filters) TP_LOCALLAB_FFTCOL_MASK;FFTW ƒ TP_LOCALLAB_FFTMASK_TOOLTIP;Use a Fourier transform for better quality (increased processing time and memory requirements) TP_LOCALLAB_FFTW;ƒ - Use Fast Fourier Transform TP_LOCALLAB_FFTW2;ƒ - Use Fast Fourier Transform (TIF, JPG,..) TP_LOCALLAB_FFTWBLUR;ƒ - Always Use Fast Fourier Transform -TP_LOCALLAB_FULLIMAGE;Dark-Ev & white-Ev for the whole image +TP_LOCALLAB_FULLIMAGE;Black-Ev and White-Ev for whole image TP_LOCALLAB_FULLIMAGELOG_TOOLTIP;Calculates the Ev levels for the whole image. TP_LOCALLAB_GAM;Gamma TP_LOCALLAB_GAMFRA;Tone response curve (TRC) TP_LOCALLAB_GAMM;Gamma TP_LOCALLAB_GAMMASKCOL;Gamma -TP_LOCALLAB_GAMMASK_TOOLTIP;Gamma and Slope allow a soft and artifact-free transformation of the mask by progressively modifying “L” to avoid any discontinuities. +TP_LOCALLAB_GAMMASK_TOOLTIP;Adjusting Gamma and Slope can provide a soft and artifact-free transformation of the mask by progressively modifying ‘L’ to avoid any discontinuities. TP_LOCALLAB_GAMSH;Gamma TP_LOCALLAB_GRADANG;Gradient angle TP_LOCALLAB_GRADANG_TOOLTIP;Rotation angle in degrees : -180 0 +180 @@ -2714,18 +2714,17 @@ TP_LOCALLAB_GRADGEN_TOOLTIP;Adjusts luminance gradient strength TP_LOCALLAB_GRADLOGFRA;Graduated Filter Luminance TP_LOCALLAB_GRADSTR;Gradient strength TP_LOCALLAB_GRADSTRAB_TOOLTIP;Adjusts chroma gradient strength -TP_LOCALLAB_GRADSTRCHRO;Chrominance gradient strength +TP_LOCALLAB_GRADSTRCHRO;Chroma gradient strength TP_LOCALLAB_GRADSTRHUE;Hue gradient strength TP_LOCALLAB_GRADSTRHUE2;Hue gradient strength TP_LOCALLAB_GRADSTRHUE_TOOLTIP;Adjusts hue gradient strength -TP_LOCALLAB_GRADSTRLUM;Luminance gradient strength +TP_LOCALLAB_GRADSTRLUM;Luma gradient strength TP_LOCALLAB_GRADSTR_TOOLTIP;Filter strength in stops TP_LOCALLAB_GRAINFRA;Film Grain 1:1 TP_LOCALLAB_GRAINFRA2;Coarseness - TP_LOCALLAB_GRAIN_TOOLTIP;Adds film-like grain to the image TP_LOCALLAB_GRALWFRA;Graduated filter (local contrast) -TP_LOCALLAB_GRIDFRAME_TOOLTIP;You can use this tool as a brush. Use small spot and adapt transition and transition decay\nOnly mode NORMAL and eventually Hue, Saturation, Color, Luminosity are concerned by Merge background (ΔE) +TP_LOCALLAB_GRIDFRAME_TOOLTIP;You can use this tool as a brush. Use a small spot and adapt the ‘Transition value’ and ‘Transition decay’\nOnly 'Normal' mode and possibly Hue, Saturation, Color, Luminosity are concerned by Merge background (ΔE) TP_LOCALLAB_GRIDMETH_TOOLTIP;Color toning: the luminance is taken into account when varying chroma. Equivalent to H=f(H) if the "white dot" on the grid remains at zero and you only vary the "black dot". Equivalent to "Color toning" if you vary the 2 dots.\n\nDirect: acts directly on the chroma TP_LOCALLAB_GRIDONE;Color Toning TP_LOCALLAB_GRIDTWO;Direct @@ -2737,13 +2736,13 @@ TP_LOCALLAB_GUIDFILTER_TOOLTIP;Can reduce or increase artifacts. TP_LOCALLAB_GUIDSTRBL_TOOLTIP;Intensity of the guided filter TP_LOCALLAB_HHMASK_TOOLTIP;Fine hue adjustments for example for the skin. TP_LOCALLAB_HIGHMASKCOL;Highlights -TP_LOCALLAB_HLH;Curves H +TP_LOCALLAB_HLH;H TP_LOCALLAB_IND;Independent (mouse) TP_LOCALLAB_INDSL;Independent (mouse + sliders) TP_LOCALLAB_INVBL;Inverse -TP_LOCALLAB_INVBL_TOOLTIP;Alternative to ‘Inverse’ mode: use two spots\nFirst Spot:\n full image - delimiter outside preview\n RT-spot shape: rectangle. Transition 100\n\nSecond spot : Excluding spot +TP_LOCALLAB_INVBL_TOOLTIP;Alternative to ‘Inverse’ mode: use two spots\nFirst Spot:\n Full Image\n\nSecond spot : Excluding spot TP_LOCALLAB_INVERS;Inverse -TP_LOCALLAB_INVERS_TOOLTIP;Fewer possibilities if selected (Inverse).\n\nAlternative: use two spots\nFirst Spot:\n full image - delimiter outside preview\n RT-spot shape: rectangle. Transition 100\n\nSecond spot: Excluding spot +TP_LOCALLAB_INVERS_TOOLTIP;Fewer possibilities if selected (Inverse).\n\nAlternative: use two spots\nFirst Spot:\n Full Image\n \nSecond spot: Excluding spot TP_LOCALLAB_INVMASK;Inverse algorithm TP_LOCALLAB_ISOGR;Distribution (ISO) TP_LOCALLAB_LABBLURM;Blur Mask @@ -2759,11 +2758,11 @@ TP_LOCALLAB_LAPMASKCOL;Laplacian threshold TP_LOCALLAB_LAPRAD1_TOOLTIP;Increases the contrast of the mask by increasing the luminance values of the lighter areas. Can be used in conjunction with the L(L) and LC(H) curves. TP_LOCALLAB_LAPRAD2_TOOLTIP;Smooth radius uses a guided filter to decrease artifacts and smooth out the transition TP_LOCALLAB_LAPRAD_TOOLTIP;Smooth radius uses a guided filter to decrease artifacts and smooth out the transition -TP_LOCALLAB_LAP_MASK_TOOLTIP;Solve PDE for all Laplacian masks.\nIf enabled Laplacian threshold mask reduce artifacts and smooth result.\nIf disabled linear response. +TP_LOCALLAB_LAP_MASK_TOOLTIP;Solves PDEs for all Laplacian masks.\nIf enabled the Laplacian threshold mask reduces artifacts and smooths the result.\nIf disabled the response is linear. TP_LOCALLAB_LC_FFTW_TOOLTIP;FFT improves quality and allows the use of large radii, but increases processing time (depends on the area to be processed). Preferable to use only for large radii. The size of the area can be reduced by a few pixels to optimize the FFTW. This can reduce the processing time by a factor of 1.5 to 10. TP_LOCALLAB_LC_TOOLNAME;Local Contrast & Wavelets TP_LOCALLAB_LEVELBLUR;Maximum blur levels -TP_LOCALLAB_LEVELWAV;Ψ Wavelet levels +TP_LOCALLAB_LEVELWAV;Wavelet levels TP_LOCALLAB_LEVELWAV_TOOLTIP;The Level is automatically adapted to the size of the spot and the preview.\nFrom level 9 size max 512 to level 1 size max = 4 TP_LOCALLAB_LEVFRA;Levels TP_LOCALLAB_LIGHTNESS;Lightness @@ -2776,20 +2775,20 @@ TP_LOCALLAB_LMASK_LEVEL_TOOLTIP;Allows you to decrease or increase the effect on TP_LOCALLAB_LMASK_LL_TOOLTIP;Allows you to freely change the contrast of the mask.\n Has a similar function to the Gamma and Slope sliders.\n It allows you to target certain parts of the image (usually the lightest parts of the mask by using the curve to exclude the darker parts). May create artifacts. TP_LOCALLAB_LOCCONT;Unsharp Mask TP_LOCALLAB_LOC_CONTRAST;Local Contrast & Wavelets -TP_LOCALLAB_LOC_CONTRASTPYR;Ψ Pyramid 1: -TP_LOCALLAB_LOC_CONTRASTPYR2;Ψ Pyramid 2: -TP_LOCALLAB_LOC_CONTRASTPYR2LAB; Contrast by level - TM - Directional contrast -TP_LOCALLAB_LOC_CONTRASTPYRLAB; Graduated Filter - Edge Sharpness - Blur +TP_LOCALLAB_LOC_CONTRASTPYR;Pyramid 1: +TP_LOCALLAB_LOC_CONTRASTPYR2;Pyramid 2: +TP_LOCALLAB_LOC_CONTRASTPYR2LAB; Contrast by level/TM/Directional contrast +TP_LOCALLAB_LOC_CONTRASTPYRLAB; Graduated Filter/Edge Sharpness/Blur TP_LOCALLAB_LOC_RESIDPYR;Residual image (Main) TP_LOCALLAB_LOG;Log Encoding TP_LOCALLAB_LOG1FRA;Image Adjustments TP_LOCALLAB_LOG2FRA;Viewing Conditions TP_LOCALLAB_LOGAUTO;Automatic -TP_LOCALLAB_LOGAUTOGRAY_TOOLTIP;Automatically calculates the 'mean luminance' for the scene conditons when the ‘Automatic’ button in Relative Exposure Levels is pressed. -TP_LOCALLAB_LOGAUTO_TOOLTIP;Pressing this button will calculate the 'dynamic range' and 'mean luminance' for the scene conditions if the "Auto mean luminance (Yb%)” is checked).\nAlso calculates the absolute luminance at the time of shooting.\nPress the button again to adjust the automatically calculated values. +TP_LOCALLAB_LOGAUTOGRAY_TOOLTIP;Automatically calculates the 'Mean luminance' for the scene conditions when the ‘Automatic’ button in Relative Exposure Levels is pressed. +TP_LOCALLAB_LOGAUTO_TOOLTIP;Pressing this button will calculate the dynamic range and 'Mean luminance' for the scene conditions if the "Auto mean luminance (Yb%)” is checked).\nAlso calculates the absolute luminance at the time of shooting.\nPress the button again to adjust the automatically calculated values. TP_LOCALLAB_LOGBASE_TOOLTIP;Default = 2.\nValues less than 2 reduce the action of the algorithm making the shadows darker and the highlights brighter.\nWith values greater than 2, the shadows are grayer and the highlights become more washed out. -TP_LOCALLAB_LOGBLACKWHEV_TOOLTIP;Estimated values of Dynamic Range i.e. Black Ev and White Ev -TP_LOCALLAB_LOGCATAD_TOOLTIP;The chromatic adaptation allows us to interpret a color according to its spatio-temporal environment.\nUseful when the white balance is far from reference D50.\nAdapts colors to the illuminant of the output device. +TP_LOCALLAB_LOGBLACKWHEV_TOOLTIP;Estimated values of dynamic range i.e. Black Ev and White Ev +TP_LOCALLAB_LOGCATAD_TOOLTIP;The chromatic adaptation allows us to interpret a color according to its spatio-temporal environment.\nUseful when the white balance deviates significantly from the D50 reference.\nAdapts colors to the illuminant of the output device. TP_LOCALLAB_LOGCOLORFL;Colorfulness (M) TP_LOCALLAB_LOGCOLORF_TOOLTIP;Perceived amount of hue in relation to gray.\nIndicator that a stimulus appears more or less colored. TP_LOCALLAB_LOGCONQL;Contrast (Q) @@ -2803,7 +2802,7 @@ TP_LOCALLAB_LOGENCOD_TOOLTIP;Tone Mapping with Logarithmic encoding (ACES).\nUse TP_LOCALLAB_LOGEXP;All tools TP_LOCALLAB_LOGFRA;Scene Conditions TP_LOCALLAB_LOGFRAME_TOOLTIP;Allows you to calculate and adjust the Ev levels and the 'Mean luminance Yb%' (source gray point) for the spot area. The resulting values will be used by all Lab operations and most RGB operations in the pipeline.\nTakes into account exposure compensation in the main-menu Exposure tab.\nAlso calculates the absolute luminance at the time of shooting. -TP_LOCALLAB_LOGIMAGE_TOOLTIP;Takes into account corresponding Ciecam variables (mainly Contrast 'J' and Saturation 's', and also 'advanced' Contrast 'Q' , Brightness 'Q', Lightness (J), Colorfulness (M)). +TP_LOCALLAB_LOGIMAGE_TOOLTIP;Takes into account corresponding Ciecam variables (mainly Contrast 'J' and Saturation 's', and also Contrast (Q) , Brightness (Q), Lightness (J), Colorfulness (M) in Advanced mode). TP_LOCALLAB_LOGLIGHTL;Lightness (J) TP_LOCALLAB_LOGLIGHTL_TOOLTIP;Close to lightness (L*a*b*), takes into account the increase in perceived coloration. TP_LOCALLAB_LOGLIGHTQ;Brightness (Q) @@ -2815,22 +2814,22 @@ TP_LOCALLAB_LOGREPART_TOOLTIP;Allows you to adjust the relative strength of the TP_LOCALLAB_LOGSATURL_TOOLTIP;Saturation (s) in CIECAM16 corresponds to the color of a stimulus in relation to its own brightness.\nActs mainly on medium and highlights tones TP_LOCALLAB_LOGSCENE_TOOLTIP;Corresponds to the shooting conditions. TP_LOCALLAB_LOGSRCGREY_TOOLTIP;Estimated gray point value of the image. -TP_LOCALLAB_LOGSURSOUR_TOOLTIP;Changes tones and colors to take into account the Scene conditions.\n\nAverage: Average light environment (standard). The image will not change.\n\nDim: Dim environment. The image will become slightly bright. +TP_LOCALLAB_LOGSURSOUR_TOOLTIP;Changes tones and colors to take into account the Scene conditions.\n\nAverage: Average light environment (standard). The image will not change.\n\nDim: Dim environment. The image will become slightly brighter. TP_LOCALLAB_LOGTARGGREY_TOOLTIP;You can adjust this value to suit. TP_LOCALLAB_LOGVIEWING_TOOLTIP;Corresponds to the medium on which the final image will be viewed (monitor, TV, projector, printer,..), as well as its environment. TP_LOCALLAB_LOG_TOOLNAME;Log Encoding -TP_LOCALLAB_LUM;Curves LL - CC +TP_LOCALLAB_LUM;LL - CC TP_LOCALLAB_LUMADARKEST;Darkest -TP_LOCALLAB_LUMASK;Background color for luminance mask +TP_LOCALLAB_LUMASK;Background color/luma mask TP_LOCALLAB_LUMASK_TOOLTIP;Adjusts the shade of gray or color of the mask background in Show Mask (Mask and modifications) TP_LOCALLAB_LUMAWHITESEST;Lightest TP_LOCALLAB_LUMFRA;L*a*b* standard TP_LOCALLAB_LUMONLY;Luminance only TP_LOCALLAB_MASFRAME;Mask and Merge -TP_LOCALLAB_MASFRAME_TOOLTIP;For all masks.\nTakes into account the deltaE image to avoid modifying the selection area when the following Mask Tools are used: Gamma , Slope , Chroma, Contrast curve , Local contrast (by wavelet level), Blur Mask and Structure Mask (if enabled ) .\nDisabled when Inverse mode is used -TP_LOCALLAB_MASK;Contrast +TP_LOCALLAB_MASFRAME_TOOLTIP;For all masks.\nTakes into account the deltaE image to avoid modifying the selection area when the following Mask Tools are used: Gamma, Slope, Chroma, Contrast curve, Local contrast (by wavelet level), Blur Mask and Structure Mask (if enabled ).\nDisabled when Inverse mode is used. +TP_LOCALLAB_MASK;Curves TP_LOCALLAB_MASK2;Contrast curve -TP_LOCALLAB_MASKCOL;Mask Curves +TP_LOCALLAB_MASKCOL; TP_LOCALLAB_MASKCOM;Common Color Mask TP_LOCALLAB_MASKCOM_TOOLNAME;Common Color Mask TP_LOCALLAB_MASKCOM_TOOLTIP;A tool in its own right.\nCan be used to adjust the image appearance (chrominance, luminance, contrast) and texture as a function of Scope. @@ -2838,7 +2837,7 @@ TP_LOCALLAB_MASKCURVE_TOOLTIP;The 3 curves are set to 1 (maximum) by default:\nC TP_LOCALLAB_MASKDDECAY;Decay strength TP_LOCALLAB_MASKDECAY_TOOLTIP;Manages the rate of decay for the gray levels in the mask.\n Decay = 1 linear, Decay > 1 sharper parabolic transitions, Decay < 1 more gradual transitions TP_LOCALLAB_MASKH;Hue curve -TP_LOCALLAB_MASKLC_TOOLTIP;This allows you to target the denoise based on the image luminance information contained in the L(L) or LC(H) mask (Mask and Modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n 'Dark area luminance threshold'. If 'Reinforce denoise in dark and light areas' > 1 the denoise is progressively increased from 0% at the threshold settings to 100% at the maximum black value (determined by mask).\n 'Light area luminance threshold' .The denoise is progressively decreased from 100% at the threshold setting to 0% at the maximum white value (determined by mask).\n In the area between the two thresholds, the denoise settings are not affected by the mask. +TP_LOCALLAB_MASKLC_TOOLTIP;This allows you to target the denoise based on the image luminance information contained in the L(L) or LC(H) mask (Mask and Modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n 'Dark area luminance threshold'. If 'Reinforce denoise in dark and light areas' > 1 the denoise is progressively increased from 0% at the threshold setting to 100% at the maximum black value (determined by mask).\n 'Light area luminance threshold'. The denoise is progressively decreased from 100% at the threshold setting to 0% at the maximum white value (determined by mask).\n In the area between the two thresholds, the denoise settings are not affected by the mask. TP_LOCALLAB_MASKDE_TOOLTIP;Used to target the denoise as a function of the image luminance information contained in the L(L) or LC(H) masks (Mask and modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n If the mask is below the ‘dark’ threshold, then the Denoise will be applied progressively.\n if the mask is above the ‘light’ threshold, then the Denoise will be applied progressively.\n Between the two, the image settings without the Denoise will be maintained, unless you adjust the sliders "Gray area luminance denoise" or "Gray area chrominance denoise". TP_LOCALLAB_MASKGF_TOOLTIP;Used to target the Guided Filter as a function of the image luminance information contained in the L(L) or LC(H) masks (Mask and modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n If the mask is below the ‘dark’ threshold, then the GF will be applied progressively.\n if the mask is above the ‘light’ threshold, then the GF will be applied progressively.\n Between the two, the image settings without the GF will be maintained. TP_LOCALLAB_MASKRECOL_TOOLTIP;Used to modulate the effect of the Color and Light settings based on the image luminance information contained in the L(L) or LC(H) masks (Mask and modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n The ‘dark’ and ‘light’ areas below the dark threshold and above the light threshold will be restored progressively to their original values prior to being modified by the Color and Light settings \n In between these two areas, the full value of the Color and Light settings will be applied @@ -2851,33 +2850,35 @@ TP_LOCALLAB_MASKRESVIB_TOOLTIP;Used to modulate the effect of the Vibrance and W TP_LOCALLAB_MASKRESWAV_TOOLTIP;Used to modulate the effect of the Local contrast and Wavelet settings based on the image luminance information contained in the L(L) or LC(H) masks (Mask and modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n The ‘dark’ and ‘light’ areas below the dark threshold and above the light threshold will be restored progressively to their original values prior to being modified by the Local contrast and Wavelet settings \n In between these two areas, the full value of the Local contrast and Wavelet settings will be applied TP_LOCALLAB_MASKRELOG_TOOLTIP;Used to modulate the effect of the Log encoding settings based on the image luminance information contained in the L(L) or LC(H) masks (Mask and modifications).\n The L(L) mask or the LC(H) mask must be enabled to use this function.\n The ‘dark’ and ‘light’ areas below the dark threshold and above the light threshold will be restored progressively to their original values prior to being modified by the Log encoding settings - can be used to restore highlights reconstructed by Color propagation \n In between these two areas, the full value of the Log encoding settings will be applied TP_LOCALLAB_MASKDEINV_TOOLTIP;Reverses the way the algorithm interprets the mask.\nIf checked black and very light areas will be decreased. -TP_LOCALLAB_MASKHIGTHRESC_TOOLTIP;Light-tone limit above which Color and Light will be restored progressively to their original values prior to being modified by the Color and Light settings .\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘structure mask’, 'Blur mask', ‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’, ‘Local contrast wavelet’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKHIGTHRESS_TOOLTIP;Light-tone limit above which Shadows Highlights will be restored progressively to their original values prior to being modified by the Shadows Highlights settings .\n You can use certain tools in ‘Mask and modifications’ to change the gray levels:‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKHIGTHRESCB_TOOLTIP;Light-tone limit above which CBDL (Luminance only) will be restored progressively to their original values prior to being modified by the CBDL settings .\n You can use certain tools in ‘Mask and modifications’ to change the gray levels:‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKHIGTHRESRETI_TOOLTIP;Light-tone limit above which Retinex (Luminance only) will be restored progressively to their original values prior to being modified by the Retinex settings .\n You can use certain tools in ‘Mask and modifications’ to change the gray levels:‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKHIGTHRESTM_TOOLTIP;Light-tone limit above which Tone Mapping will be restored progressively to their original values prior to being modified by the Tone Mapping settings .\n You can use certain tools in ‘Mask and modifications’ to change the gray levels:‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKHIGTHRESVIB_TOOLTIP;Light-tone limit above which Vibrance and Warm Cool will be restored progressively to their original values prior to being modified by the Vibrance and Warm Cool settings .\n You can use certain tools in ‘Mask and modifications’ to change the gray levels:‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKHIGTHRESWAV_TOOLTIP;Light-tone limit above which Local contrast and Wavelet will be restored progressively to their original values prior to being modified by the Local contrast and Wavelet settings .\n You can use certain tools in ‘Mask and modifications’ to change the gray levels:‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKHIGTHRESE_TOOLTIP;Light-tone limit above which 'Dynamic range and Exposure' will be restored progressively to their original values prior to being modified by the 'Dynamic range and Exposure' settings .\n You can use certain tools in ‘Mask and modifications’ to change the gray levels:‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKHIGTHRESL_TOOLTIP;Light-tone limit above which Log encoding will be restored progressively to their original values prior to being modified by the Log encoding settings .\n You can use certain tools in ‘Mask and modifications’ to change the gray levels:‘Smooth radius’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKHIGTHRESD_TOOLTIP; The denoise is progressively decreased from 100% at the threshold setting to 0% at the maximum white value (as determined by the mask).\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘structure mask’, ‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’, ‘Local contrast wavelet’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 +TP_LOCALLAB_MASKHIGTHRESC_TOOLTIP;Lighter-tone limit above which the parameters will be restored progressively to their original values prior to being modified by the Color and Light settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Structure mask’, 'Blur mask', ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’, ‘Local contrast’ (wavelets).\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKHIGTHRESS_TOOLTIP;Lighter-tone limit above which the parameters will be restored progressively to their original values prior to being modified by the Shadows Highlights settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKHIGTHRESCB_TOOLTIP;Lighter-tone limit above which CBDL (Luminance only) parameters will be restored progressively to their original values prior to being modified by the CBDL settings .\n You can use certain tools in ‘Mask and modifications’ to change the gray levels:‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKHIGTHRESRETI_TOOLTIP;Lighter-tone limit above which Retinex (Luminance only) parameters will be restored progressively to their original values prior to being modified by the Retinex settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKHIGTHRESTM_TOOLTIP;Lighter-tone limit above which the parameters will be restored progressively to their original values prior to being modified by the Tone Mapping settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKHIGTHRESVIB_TOOLTIP;Lighter-tone limit above which the parameters will be restored progressively to their original values prior to being modified by the Vibrance and Warm Cool settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels:‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKHIGTHRESWAV_TOOLTIP;Lighter-tone limit above which the parameters will be restored progressively to their original values prior to being modified by the Local contrast and Wavelet settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKHIGTHRESE_TOOLTIP;Lighter-tone limit above which the parameters will be restored progressively to their original values prior to being modified by the 'Dynamic range and Exposure' settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable colorpicker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKHIGTHRESL_TOOLTIP;Lighter-tone limit above which the parameters will be restored progressively to their original values prior to being modified by the Log encoding settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels:‘Smooth radius’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKHIGTHRESD_TOOLTIP; The denoise is progressively decreased from 100% at the threshold setting to 0% at the maximum white value (as determined by the mask).\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Structure mask’, ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’, ‘Local contrast’ (wavelets).\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask'=0 in Settings. TP_LOCALLAB_MASKHIGTHRES_TOOLTIP; The Guided Filter is progressively decreased from 100% at the threshold setting to 0% at the maximum white value (as determined by the mask).\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘structure mask’, ‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’, ‘Local contrast wavelet’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 TP_LOCALLAB_MASKLCTHR;Light area luminance threshold +TP_LOCALLAB_MASKLCTHR2;Light area luma threshold TP_LOCALLAB_MASKLCTHRLOW;Dark area luminance threshold -TP_LOCALLAB_MASKLNOISELOW;Reinforce denoise in dark and light areas -TP_LOCALLAB_MASKLOWTHRES_TOOLTIP;The Guided Filter is progressively increased from 0% at the threshold setting to 100% at the maximum black value (as determined by the mask).\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘structure mask’, ‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’, ‘Local contrast wavelet’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKLOWTHRESD_TOOLTIP;The denoise is progressively increased from 0% at the threshold setting to 100% at the maximum black value (as determined by the mask).\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘structure mask’, ‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’, ‘Local contrast wavelet’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKLOWTHRESC_TOOLTIP;Dark-tone limit below which Color and Light will be restored progressively to their original values prior to being modified by the Color and Light settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘structure mask’, 'blur mask', ‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’, ‘Local contrast wavelet’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKLOWTHRESL_TOOLTIP;Dark-tone limit below which Log encoding will be restored progressively to their original values prior to being modified by the Log encoding settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels:‘Smooth radius’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKLOWTHRESE_TOOLTIP;Dark-tone limit below which 'Dynamic range and Exposure' will be restored progressively to their original values prior to being modified by the 'Dynamic range and Exposure' settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKLOWTHRESS_TOOLTIP;Dark-tone limit below which Shadows Highligts will be restored progressively to their original values prior to being modified by the Shadows Highlights settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKLOWTHRESCB_TOOLTIP;Dark-tone limit below which CBDL (Luminance only) will be restored progressively to their original values prior to being modified by the CBDL settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKLOWTHRESRETI_TOOLTIP;Dark-tone limit below which Retinex (Luminance only) will be restored progressively to their original values prior to being modified by the Retinex settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKLOWTHRESTM_TOOLTIP;Dark-tone limit below which Tone Mapping will be restored progressively to their original values prior to being modified by the Tone Mapping settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKLOWTHRESVIB_TOOLTIP;Dark-tone limit below which Vibrance and Warm Cool will be restored progressively to their original values prior to being modified by the Vibrance and Warm Cool settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKLOWTHRESWAV_TOOLTIP;Dark-tone limit below which Local contrast and Wavelet will be restored progressively to their original values prior to being modified by the Local contrast and Wavelet settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, ‘Gamma and slope’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Be carefull in 'settings' to Background color mask = 0 -TP_LOCALLAB_MASKLCTHRMID;Gray area luminance denoise -TP_LOCALLAB_MASKLCTHRMIDCH;Gray area chrominance denoise +TP_LOCALLAB_MASKLCTHRLOW2;Dark area luma threshold +TP_LOCALLAB_MASKLNOISELOW;Reinforce dark/light areas +TP_LOCALLAB_MASKLOWTHRES_TOOLTIP;The Guided Filter is progressively increased from 0% at the threshold setting to 100% at the maximum black value (as determined by the mask).\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Structure mask’, ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’, ‘Local contrast’ (wavelets).\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKLOWTHRESD_TOOLTIP;The denoise is progressively increased from 0% at the threshold setting to 100% at the maximum black value (as determined by the mask).\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Structure mask’, ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’, ‘Local contrast’ (wavelets).\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKLOWTHRESC_TOOLTIP;Dark-tone limit below which the parameters will be restored progressively to their original values prior to being modified by the Color and Light settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Structure mask’, 'blur mask', ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’, ‘Local contrast’ (wavelets).\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKLOWTHRESL_TOOLTIP;Dark-tone limit below which the parameters will be restored progressively to their original values prior to being modified by the Log encoding settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels:‘Smooth radius’, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKLOWTHRESE_TOOLTIP;Dark-tone limit below which the parameters will be restored progressively to their original values prior to being modified by the 'Dynamic range and Exposure' settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKLOWTHRESS_TOOLTIP;Dark-tone limit below which the parameters will be restored progressively to their original values prior to being modified by the Shadows Highlights settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKLOWTHRESCB_TOOLTIP;Dark-tone limit below which the CBDL parameters (Luminance only) will be restored progressively to their original values prior to being modified by the CBDL settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKLOWTHRESRETI_TOOLTIP;Dark-tone limit below which the Retinex (Luminance only) parameters will be restored progressively to their original values prior to being modified by the Retinex settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKLOWTHRESTM_TOOLTIP;Dark-tone limit below which the parameters will be restored progressively to their original values prior to being modified by the Tone Mapping settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKLOWTHRESVIB_TOOLTIP;Dark-tone limit below which the parameters will be restored progressively to their original values prior to being modified by the Vibrance and Warm Cool settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKLOWTHRESWAV_TOOLTIP;Dark-tone limit below which the parameters will be restored progressively to their original values prior to being modified by the Local contrast and Wavelet settings.\n You can use certain tools in ‘Mask and modifications’ to change the gray levels: ‘Smooth radius’, Gamma and Slope, ‘Contrast curve’.\n Use a ‘lockable color picker’ on the mask to see which areas will be affected. Make sure you set ‘Background color mask’ = 0 in Settings. +TP_LOCALLAB_MASKLCTHRMID;Gray area luma denoise +TP_LOCALLAB_MASKLCTHRMIDCH;Gray area chroma denoise TP_LOCALLAB_MASKUSABLE;Mask enabled (Mask & modifications) TP_LOCALLAB_MASKUNUSABLE;Mask disabled (Mask & modifications) TP_LOCALLAB_MASKRECOTHRES;Recovery threshold @@ -2893,19 +2894,19 @@ TP_LOCALLAB_MERELE;Lighten only TP_LOCALLAB_MERFIV;Addition TP_LOCALLAB_MERFOR;Color Dodge TP_LOCALLAB_MERFOU;Multiply -TP_LOCALLAB_MERGE1COLFRA;Merge with Original or Previous or Background -TP_LOCALLAB_MERGECOLFRA;Mask: LCH & Structure -TP_LOCALLAB_MERGECOLFRMASK_TOOLTIP;Allows you to create masks based on the 3 LCH curves and/or a structure-detection algorithm -TP_LOCALLAB_MERGEFIV;Previous Spot(Mask 7) + Mask LCH +TP_LOCALLAB_MERGE1COLFRA;Merge with Original/Previous/Background +TP_LOCALLAB_MERGECOLFRA;Mask: LCh & Structure +TP_LOCALLAB_MERGECOLFRMASK_TOOLTIP;Allows you to create masks based on the 3 LCh curves and/or a structure-detection algorithm +TP_LOCALLAB_MERGEFIV;Previous Spot(Mask 7) + Mask LCh TP_LOCALLAB_MERGEFOU;Previous Spot(Mask 7) TP_LOCALLAB_MERGEMER_TOOLTIP;Takes ΔE into account when merging files (equivalent of scope in this case) TP_LOCALLAB_MERGENONE;None TP_LOCALLAB_MERGEONE;Short Curves 'L' Mask TP_LOCALLAB_MERGEOPA_TOOLTIP;Opacity = % of current spot to be merged with original or previous Spot.\nContrast threshold : adjusts result as a function of contrast in original image. -TP_LOCALLAB_MERGETHR;Original(Mask 7) + Mask LCH -TP_LOCALLAB_MERGETWO;Original(Mask 7) +TP_LOCALLAB_MERGETHR;Original + Mask LCh +TP_LOCALLAB_MERGETWO;Original TP_LOCALLAB_MERGETYPE;Merge image and mask -TP_LOCALLAB_MERGETYPE_TOOLTIP;None, use all mask in LCH mode.\nShort curves 'L' mask, use a short circuit for mask 2, 3, 4, 6, 7.\nOriginal mask 8, blend current image with original +TP_LOCALLAB_MERGETYPE_TOOLTIP;None, use all mask in LCh mode.\nShort curves 'L' mask, use a short circuit for mask 2, 3, 4, 6, 7.\nOriginal mask 8, blend current image with original TP_LOCALLAB_MERHEI;Overlay TP_LOCALLAB_MERHUE;Hue TP_LOCALLAB_MERLUCOL;Luminance @@ -2924,7 +2925,7 @@ TP_LOCALLAB_MERTHR;Difference TP_LOCALLAB_MERTWE;Exclusion TP_LOCALLAB_MERTWO;Subtract TP_LOCALLAB_METHOD_TOOLTIP;'Enhanced + chroma denoise' significantly increases processing times.\nBut reduce artifacts. -TP_LOCALLAB_MLABEL;Restored data Min=%1 Max=%2 (Clip - Offset) +TP_LOCALLAB_MLABEL;Restored data Min=%1 Max=%2 TP_LOCALLAB_MLABEL_TOOLTIP;The values should be close to Min=0 Max=32768 (log mode) but other values are possible.You can adjust ‘Clip restored data (gain)’ and ‘Offset’ to normalize.\nRecovers image data without blending. TP_LOCALLAB_MODE_EXPERT;Advanced TP_LOCALLAB_MODE_NORMAL;Standard @@ -2949,12 +2950,12 @@ TP_LOCALLAB_NLPAT;Maximum patch size TP_LOCALLAB_NLRAD;Maximum radius size TP_LOCALLAB_NOISECHROCOARSE;Coarse chroma (Wav) TP_LOCALLAB_NOISECHROC_TOOLTIP;If superior to zero, high quality algorithm is enabled.\nCoarse is for slider >=0.02 -TP_LOCALLAB_NOISECHRODETAIL;Chroma detail recovery (DCT ƒ) +TP_LOCALLAB_NOISECHRODETAIL;Chroma detail recovery TP_LOCALLAB_NOISECHROFINE;Fine chroma (Wav) TP_LOCALLAB_NOISEDETAIL_TOOLTIP;Disabled if slider = 100 TP_LOCALLAB_NOISELEQUAL;Equalizer white-black TP_LOCALLAB_NOISELUMCOARSE;Luminance coarse (Wav) -TP_LOCALLAB_NOISELUMDETAIL;Luminance detail recovery (DCT ƒ) +TP_LOCALLAB_NOISELUMDETAIL;Luma detail recovery TP_LOCALLAB_NOISELUMFINE;Luminance fine 1 (Wav) TP_LOCALLAB_NOISELUMFINETWO;Luminance fine 2 (Wav) TP_LOCALLAB_NOISELUMFINEZERO;Luminance fine 0 (Wav) @@ -3035,8 +3036,8 @@ TP_LOCALLAB_SETTINGS;Settings TP_LOCALLAB_SH1;Shadows Highlights TP_LOCALLAB_SH2;Equalizer TP_LOCALLAB_SHADEX;Shadows -TP_LOCALLAB_SHADEXCOMP;Shadow compression & tonal width -TP_LOCALLAB_SHADHIGH;Shadows/Highlights-Equalizer +TP_LOCALLAB_SHADEXCOMP;Shadow compression +TP_LOCALLAB_SHADHIGH;Shadows/Highlights & Tone Equalizer TP_LOCALLAB_SHADHMASK_TOOLTIP;Lowers the highlights of the mask in the same way as the shadows/highlights algorithm TP_LOCALLAB_SHADMASK_TOOLTIP;Lifts the shadows of the mask in the same way as the shadows/highlights algorithm TP_LOCALLAB_SHADOWHIGHLIGHT_TOOLTIP;Adjust shadows and highlights either with shadows & highlights sliders or with a tone equalizer.\nCan be used instead of, or in conjunction with the Exposure module.\nCan also be used as a graduated filter. @@ -3067,7 +3068,8 @@ TP_LOCALLAB_SHOWMASKSOFT_TOOLTIP;Allows you to visualize the different stages of TP_LOCALLAB_SHOWMASKTYP1;Blur & Noise TP_LOCALLAB_SHOWMASKTYP2;Denoise TP_LOCALLAB_SHOWMASKTYP3;Blur & Noise + Denoise -TP_LOCALLAB_SHOWMASKTYP_TOOLTIP;Mask and modifications can be chosen.\nBlur and noise : in this case it is not used for 'denoise'.\nDenoise : in this case it is not used for 'blur and noise'.\n\nBlur and noise + denoise : mask is shared, be carefull to 'show modifications' and 'scope' +//TP_LOCALLAB_SHOWMASKTYP_TOOLTIP;Mask and modifications can be chosen.\nBlur and noise : in this case it is not used for 'denoise'.\nDenoise : in this case it is not used for 'blur and noise'.\n\nBlur and noise + denoise : mask is shared, be carefull to 'show modifications' and 'scope' +TP_LOCALLAB_SHOWMASKTYP_TOOLTIP;Can be used with ‘Mask and modifications’.\nIf ‘Blur and noise’ is selected, the mask cannot be used for Denoise.\nIf Denoise is selected, the mask cannot be used for ‘Blur and noise’.\nIf ‘Blur and noise + Denoise’ is selected, the mask is shared. Note that in this case, the Scope sliders for both ‘Blur and noise’ and Denoise will be active so it is advisable to use the option ‘Show modifications with mask’ when making any adjustments. TP_LOCALLAB_SHOWMNONE;Show modified image TP_LOCALLAB_SHOWMODIF;Show modified areas without mask TP_LOCALLAB_SHOWMODIF2;Show modified areas @@ -3078,8 +3080,8 @@ TP_LOCALLAB_SHOWPOISSON;Poisson (pde ƒ) TP_LOCALLAB_SHOWR;Mask and modifications TP_LOCALLAB_SHOWREF;Preview ΔE TP_LOCALLAB_SHOWS;Mask and modifications -TP_LOCALLAB_SHOWSTRUC;Show spot structure(advanced) -TP_LOCALLAB_SHOWSTRUCEX;Show spot structure(advanced) +TP_LOCALLAB_SHOWSTRUC;Show spot structure(Advanced) +TP_LOCALLAB_SHOWSTRUCEX;Show spot structure(Advanced) TP_LOCALLAB_SHOWT;Mask and modifications TP_LOCALLAB_SHOWVI;Mask and modifications TP_LOCALLAB_SHRESFRA;Shadows/Highlights @@ -3088,7 +3090,7 @@ TP_LOCALLAB_SH_TOOLNAME;Shadows/Highlights & Tone Equalizer TP_LOCALLAB_SIGMAWAV;Attenuation response TP_LOCALLAB_SIM;Simple TP_LOCALLAB_SLOMASKCOL;Slope -TP_LOCALLAB_SLOMASK_TOOLTIP;Gamma and Slope allow a soft and artifact-free transformation of the mask by progressively modifying “L” to avoid any discontinuities. +TP_LOCALLAB_SLOMASK_TOOLTIP;Adjusting Gamma and Slope can provide a soft and artifact-free transformation of the mask by progressively modifying ‘L’ to avoid any discontinuities. TP_LOCALLAB_SLOSH;Slope TP_LOCALLAB_SOFT;Soft Light & Original Retinex TP_LOCALLAB_SOFTM;Soft Light @@ -3102,7 +3104,7 @@ TP_LOCALLAB_SOURCE_ABS;Absolute luminance TP_LOCALLAB_SOURCE_GRAY;Mean luminance (Yb%) TP_LOCALLAB_SPECCASE;Specific cases TP_LOCALLAB_SPECIAL;Special use of RGB curves -TP_LOCALLAB_SPECIAL_TOOLTIP;The checkbox allows you to remove all other actions i.e. “Scope”, masks, sliders etc., (except for transitions) and use just the effect of the RGB tone-curve. +TP_LOCALLAB_SPECIAL_TOOLTIP;The checkbox allows you to remove all other actions i.e. ‘Scope’, masks, sliders etc., (except for transitions) and use just the effect of the RGB tone-curve. TP_LOCALLAB_SPOTNAME;New Spot TP_LOCALLAB_STD;Standard TP_LOCALLAB_STR;Strength @@ -3117,9 +3119,9 @@ TP_LOCALLAB_STRRETI_TOOLTIP;if Strength Retinex < 0.2 only Dehaze is enabled.\ni TP_LOCALLAB_STRUC;Structure TP_LOCALLAB_STRUCCOL;Spot structure TP_LOCALLAB_STRUCCOL1;Spot structure -TP_LOCALLAB_STRUCT_TOOLTIP;Uses the Sobel algorithm to take into account structure for shape detection.\nActivate "Mask and modifications” > “Show spot structure" (advanced mode) to see a preview of the mask (without modifications).\n\nCan be used in conjunction with the Structure Mask, Blur Mask and “Local contrast (by wavelet level)” to improve edge detection.\n\nEffects of adjustments using Lightness, Contrast, Chrominance, Exposure or other non-mask-related tools visible using either ‘Show modified image” or “Show modified areas with mask ”. +TP_LOCALLAB_STRUCT_TOOLTIP;Uses the Sobel algorithm to take into account structure for shape detection.\nActivate ‘Mask and modifications’ > ‘Show spot structure’ (Advanced mode) to see a preview of the mask (without modifications).\n\nCan be used in conjunction with the Structure Mask, Blur Mask and ‘Local contrast’ (by wavelet level) to improve edge detection.\n\nEffects of adjustments using Lightness, Contrast, Chrominance, Exposure or other non-mask-related tools visible using either ‘Show modified image’ or ‘Show modified areas with mask’. TP_LOCALLAB_STRUMASKCOL;Structure mask strength -TP_LOCALLAB_STRUMASK_TOOLTIP;Structure mask (slider) with the checkbox "Structure mask as tool" unchecked: In this case a mask showing the structure will be generated even if none of the 3 curves is activated. Structure masks are available for mask 1 (Blur and denoise") and mask 7 (Color & Light). +TP_LOCALLAB_STRUMASK_TOOLTIP;Structure mask (slider) with the checkbox 'Structure mask as tool' unchecked: In this case a mask showing the structure will be generated even if none of the 3 curves is activated. Structure masks are available for mask (Blur and denoise") and mask(Color & Light). TP_LOCALLAB_STRUSTRMASK_TOOLTIP;Moderate use of this slider is recommended! TP_LOCALLAB_STYPE;Shape method TP_LOCALLAB_STYPE_TOOLTIP;You can choose between:\nSymmetrical - left handle linked to right, top handle linked to bottom.\nIndependent - all handles are independent. @@ -3130,7 +3132,7 @@ TP_LOCALLAB_THRES;Threshold structure TP_LOCALLAB_THRESDELTAE;ΔE scope threshold TP_LOCALLAB_THRESRETI;Threshold TP_LOCALLAB_THRESWAV;Balance threshold -TP_LOCALLAB_TLABEL;TM Data Min=%1 Max=%2 Mean=%3 Sigma=%4 (Threshold) +TP_LOCALLAB_TLABEL;TM Min=%1 Max=%2 Mean=%3 Sig=%4 TP_LOCALLAB_TLABEL2;TM Effective Tm=%1 TM=%2 TP_LOCALLAB_TLABEL_TOOLTIP;Transmission map result.\nMin and Max are used by Variance.\nTm=Min TM=Max of Transmission Map.\nYou can normalize the results with the threshold slider. TP_LOCALLAB_TM;Tone Mapping @@ -3144,7 +3146,8 @@ TP_LOCALLAB_TONE_TOOLNAME;Tone Mapping TP_LOCALLAB_TOOLCOL;Structure mask as tool TP_LOCALLAB_TOOLCOLFRMASK_TOOLTIP;Allows you to modify the mask, if one exists TP_LOCALLAB_TOOLMASK;Mask Tools -TP_LOCALLAB_TOOLMASK_TOOLTIP;Structure mask (slider) with the checkbox "Structure mask as tool" checked: in this case a mask showing the structure will be generated after one or more of the 2 curves L(L) or LC(H) has been modified.\n Here, the "Structure mask" behaves like the other Mask tools : Gamma, Slope, etc.\n It allows you to vary the action on the mask according to the structure of the image. +TP_LOCALLAB_TOOLMASK_2;Wavelets +TP_LOCALLAB_TOOLMASK_TOOLTIP;Structure mask (slider) with the checkbox ‘Structure mask as tool’ checked: in this case a mask showing the structure will be generated after one or more of the 2 curves L(L) or LC(H) has been modified.\n Here, the ‘Structure mask’ behaves like the other Mask tools : Gamma, Slope, etc.\n It allows you to vary the action on the mask according to the structure of the image. TP_LOCALLAB_TRANSIT;Transition Gradient TP_LOCALLAB_TRANSITGRAD;Transition differentiation XY TP_LOCALLAB_TRANSITGRAD_TOOLTIP;Allows you to vary the y-axis transition @@ -3161,7 +3164,7 @@ TP_LOCALLAB_VIBRANCE;Vibrance & Warm/Cool TP_LOCALLAB_VIBRA_TOOLTIP;Adjusts vibrance (essentially the same as the global adjustment).\nCarries out the equivalent of a white-balance adjustment using a CIECAM algorithm. TP_LOCALLAB_VIB_TOOLNAME;Vibrance & Warm/Cool TP_LOCALLAB_VIS_TOOLTIP;Click to show/hide selected Control Spot.\nCtrl+click to show/hide all Control Spot. -TP_LOCALLAB_WAMASKCOL;Ψ Mask Wavelet level +TP_LOCALLAB_WAMASKCOL;Mask Wavelet level TP_LOCALLAB_WARM;Warm/Cool & Color artifacts TP_LOCALLAB_WARM_TOOLTIP;This slider uses the CIECAM algorithm and acts as a White Balance control to make the color temperature of the selected area warmer or cooler.\nIt can also reduce color artifacts in some cases. TP_LOCALLAB_WASDEN_TOOLTIP;Luminance noise reduction: the left-hand side of the curve including the dark-gray/light-gray boundary corresponds to the first 3 levels 0, 1, 2 (fine detail). The right hand side of the curve corresponds to the coarser details (level 3, 4, 5, 6). @@ -3169,24 +3172,24 @@ TP_LOCALLAB_WAT_BALTHRES_TOOLTIP;Balances the action within each level. TP_LOCALLAB_WAT_BLURLC_TOOLTIP;The default blur setting affects all 3 L*a* b* components (luminance and colour).\nWhen checked, only luminance is blurred. TP_LOCALLAB_WAT_CLARIC_TOOLTIP;“Merge chroma” is used to select the intensity of the desired effect on chrominance. TP_LOCALLAB_WAT_CLARIL_TOOLTIP;“Merge luma” is used to select the intensity of the desired effect on luminance. -TP_LOCALLAB_WAT_CONTCHROMALEV_TOOLTIP;“Chroma levels”: adjusts the “a” and “b” components of Lab* as a proportion of the luminance value. -TP_LOCALLAB_WAT_CONTOFFSET_TOOLTIP;Offset modifies the balance between low-contrast and high-contrast details.\nHigh values will amplify contrast changes to the higher-contrast details, whereas low values will amplify contrast changes to low-contrast details.\nBy using a low “Attenuation response” value you can select which contrast values will be enhanced. +TP_LOCALLAB_WAT_CONTCHROMALEV_TOOLTIP;‘Chroma levels’: adjusts the “a” and “b” components of Lab* as a proportion of the luminance value. +TP_LOCALLAB_WAT_CONTOFFSET_TOOLTIP;Offset modifies the balance between low-contrast and high-contrast details.\nHigh values will amplify contrast changes to the higher-contrast details, whereas low values will amplify contrast changes to low-contrast details.\nBy using a low ‘Attenuation response’ value you can select which contrast values will be enhanced. TP_LOCALLAB_WAT_DELTABAL_TOOLTIP;By moving the slider to the left, the lower levels are accentuated. To the right, the lower levels are reduced and the higher levels accentuated. TP_LOCALLAB_WAT_EXPRESID_TOOLTIP;The residual image behaves in the same way as the main image when making adjustments to contrast, chroma etc. TP_LOCALLAB_WAT_GRADW_TOOLTIP;The more you move the slider to the right, the more effective the detection algorithm will be and the less noticeable the effects of local contrast. TP_LOCALLAB_WAT_LEVELLOCCONTRAST_TOOLTIP;Low to high local contrast from left to right on the x-axis.\nIncrease or decrease local contrast on the y-axis. TP_LOCALLAB_WAT_LOCCONTRASTEDG_TOOLTIP;You can adjust the distribution of local contrast by wavelet level based on the initial intensity of the contrast. This will modify the effects of perspective and relief in the image, and/or reduce the contrast values for very low initial contrast levels. -TP_LOCALLAB_WAT_ORIGLC_TOOLTIP;“Merge only with original image”, prevents the “Wavelet Pyramid” settings from interfering with “Clarity” and “Sharp mask”. +TP_LOCALLAB_WAT_ORIGLC_TOOLTIP;‘Merge only with original image’, prevents the ‘Wavelet Pyramid’ settings from interfering with ‘Clarity’ and ‘Sharp mask’. TP_LOCALLAB_WAT_RESIDBLUR_TOOLTIP;Blurs the residual image, independent of the levels. TP_LOCALLAB_WAT_RESIDCOMP_TOOLTIP;Compresses the residual image to increase or reduce contrast. TP_LOCALLAB_WAT_SIGMALC_TOOLTIP;The effect of the local contrast adjustment is stronger for medium-contrast details, and weaker for high and low-contrast details.\n This slider controls how quickly the effect dampens towards the extreme contrasts.\nThe higher the value of the slider, the wider the range of contrasts that will receive the full effect of the local contrast adjustment, and the higher the risk of generating artifacts.\nThe lower the value, the more the effect will be pinpointed towards a narrow range of contrast values. TP_LOCALLAB_WAT_STRENGTHW_TOOLTIP;Intensity of edge-effect detection. TP_LOCALLAB_WAT_STRWAV_TOOLTIP;Allows the local contrast to be varied according to a chosen gradient and angle. The variation of the luminance signal is taken into account and not the luminance. -TP_LOCALLAB_WAT_THRESHOLDWAV_TOOLTIP;Range of wavelet levels used throughout the "Wavelets" module. +TP_LOCALLAB_WAT_THRESHOLDWAV_TOOLTIP;Range of wavelet levels used throughout the ‘Wavelets’ module. TP_LOCALLAB_WAT_WAVBLURCURV_TOOLTIP;Allows you to blur each level of decomposition.\nThe finest to coarsest levels of decomposition are from left to right. TP_LOCALLAB_WAT_WAVCBDL_TOOLTIP;Similar to Contrast By Detail Levels. Fine to coarse detail levels from left to right on the x-axis. TP_LOCALLAB_WAT_WAVDELTABAL_TOOLTIP;Acts on the balance of the three directions (horizontal, vertical and diagonal) based on the luminance of the image.\nBy default the shadows or highlights are reduced to avoid artifacts. -TP_LOCALLAB_WAT_WAVESHOW_TOOLTIP;Shows all of the "Edge sharpness" tools. It is advisable to read the Wavelet Levels documentation. +TP_LOCALLAB_WAT_WAVESHOW_TOOLTIP;Shows all of the ‘Edge sharpness’ tools. It is advisable to read the Wavelet Levels documentation. TP_LOCALLAB_WAT_WAVLEVELBLUR_TOOLTIP;Allows you to adjust the maximum effect of blurring on the levels. TP_LOCALLAB_WAT_WAVSHAPE_TOOLTIP;Low to high local contrast from left to right on the x-axis\nIncrease or decrease local contrast on the y-axis. TP_LOCALLAB_WAT_WAVTM_TOOLTIP;The lower (negative) part compresses each level of decomposition creating a tone mapping effect.\nThe upper (positive) part attenuates the contrast by level.\nThe finest to coarsest levels of decomposition are from left to right on the x-axis. @@ -3198,19 +3201,20 @@ TP_LOCALLAB_WAVCOMPRE_TOOLTIP;Allows you to apply tone mapping or reduce local c TP_LOCALLAB_WAVCOMP_TOOLTIP;Allows you to apply local contrast based on the direction of the wavelet decomposition : horizontal, vertical, diagonal TP_LOCALLAB_WAVCON;Contrast by level TP_LOCALLAB_WAVCONTF_TOOLTIP;Similar to Contrast By Detail Levels. Fine to coarse detail levels from left to right on the x-axis. -TP_LOCALLAB_WAVDEN;Luminance denoise by level -TP_LOCALLAB_WAVE;Ψ Wavelets +TP_LOCALLAB_WAVDEN;Luminance denoise +TP_LOCALLAB_WAVE;Wavelets TP_LOCALLAB_WAVEDG;Local contrast TP_LOCALLAB_WAVEEDG_TOOLTIP;Improves sharpness by targeting the action of local contrast on the edges. It has the same functions as the corresponding module in Wavelet Levels and uses the same settings. -TP_LOCALLAB_WAVEMASK_LEVEL_TOOLTIP;Range of wavelet levels used in “Local contrast (by wavelet level)” +TP_LOCALLAB_WAVEMASK_LEVEL_TOOLTIP;Range of wavelet levels used in ‘Local contrast’ (by wavelet level). TP_LOCALLAB_WAVGRAD_TOOLTIP;Allows the local contrast to be varied according to a chosen gradient and angle. The variation of the luminance signal is taken into account and not the luminance. -TP_LOCALLAB_WAVHIGH;Ψ Wavelet high +TP_LOCALLAB_WAVHIGH;Wavelet high TP_LOCALLAB_WAVHUE_TOOLTIP;Allows you to reduce or increase the denoise based on hue. TP_LOCALLAB_WAVLEV;Blur by level -TP_LOCALLAB_WAVLOW;Ψ Wavelet low -TP_LOCALLAB_WAVMASK;Ψ Local contrast (by wavelet level) +TP_LOCALLAB_WAVLOW;Wavelet low +TP_LOCALLAB_WAVMASK;Local contrast TP_LOCALLAB_WAVMASK_TOOLTIP;Uses wavelets to modify the local contrast of the mask and reinforce or reduce the structure (skin, buildings...) -TP_LOCALLAB_WAVMED;Ψ Wavelet normal +//TP_LOCALLAB_WAVMED;Ψ Wavelet normal +TP_LOCALLAB_WAVMED;Wavelet normal TP_LOCALLAB_WEDIANHI;Median Hi TP_LOCALLAB_WHITE_EV;White Ev TP_LOCAL_HEIGHT;Bottom @@ -3555,7 +3559,7 @@ TP_WAVELET_BACUR;Curve TP_WAVELET_BALANCE;Contrast balance d/v-h TP_WAVELET_BALANCE_TOOLTIP;Alters the balance between the wavelet directions: vertical-horizontal and diagonal.\nIf contrast, chroma or residual tone mapping are activated, the effect due to balance is amplified. TP_WAVELET_BALCHRO;Chroma balance -TP_WAVELET_BALCHROM;Denoise equalizer Blue-Yellow/Red-Green +TP_WAVELET_BALCHROM;Equalizer Color TP_WAVELET_BALCHRO_TOOLTIP;If enabled, the 'Contrast balance' curve or slider also modifies chroma balance. TP_WAVELET_BALLUM;Denoise equalizer White-Black TP_WAVELET_BANONE;None @@ -3630,9 +3634,9 @@ TP_WAVELET_DENCURV;Curve TP_WAVELET_DENEQUAL;1 2 3 4 Equal TP_WAVELET_DENH;Threshold TP_WAVELET_DENL;Correction structure -TP_WAVELET_DENLH;Guided threshold by detail levels 1-4 +TP_WAVELET_DENLH;Guided threshold levels 1-4 TP_WAVELET_DENLOCAL_TOOLTIP;Use a curve in order to guide the denoising according to the local contrast.\nThe areas are denoised, the structures are maintained -TP_WAVELET_DENMIX_TOOLTIP;Balances the action of the guide taking into account the original image and the denoised image +TP_WAVELET_DENMIX_TOOLTIP;The local-contrast reference value used by the guided filter.\nDepending on the image, results can vary depending on whether the noise is measured before or after the noise reduction. These four choices allow you to take into account various combinations of the original and modified (denoised) images to find the best compromise. TP_WAVELET_DENOISE;Guide curve based on Local contrast TP_WAVELET_DENOISEGUID;Guided threshold based on hue TP_WAVELET_DENOISEH;High levels Curve Local contrast @@ -3715,7 +3719,7 @@ TP_WAVELET_MEDILEV;Edge detection TP_WAVELET_MEDILEV_TOOLTIP;When you enable Edge Detection, it is recommanded:\n- to disabled low contrast levels to avoid artifacts,\n- to use high values of gradient sensitivity.\n\nYou can modulate the strength with 'refine' from Denoise and Refine. TP_WAVELET_MERGEC;Merge chroma TP_WAVELET_MERGEL;Merge luma -TP_WAVELET_MIXCONTRAST;Reference local contrast +TP_WAVELET_MIXCONTRAST;Reference TP_WAVELET_MIXDENOISE;Denoise TP_WAVELET_MIXMIX;Mixed 50% noise - 50% denoise TP_WAVELET_MIXMIX70;Mixed 30% noise - 70% denoise @@ -3772,7 +3776,7 @@ TP_WAVELET_STREND;Strength TP_WAVELET_STRENGTH;Strength TP_WAVELET_SUPE;Extra TP_WAVELET_THR;Shadows threshold -TP_WAVELET_THRDEN_TOOLTIP;Generates a stepped curve in order to guide the denoising according to the local contrast.\nThe areas are denoised, the structures are maintained +TP_WAVELET_THRDEN_TOOLTIP;Generates a stepped curve used to guide the noise reduction as a function of local contrast. The denoise will be applied to uniform low local-contrast areas. Areas with detail (higher local contrast) will be preserved. TP_WAVELET_THREND;Local contrast threshold TP_WAVELET_THRESHOLD;Finer levels TP_WAVELET_THRESHOLD2;Coarser levels @@ -3862,4 +3866,4 @@ ZOOMPANEL_ZOOMOUT;Zoom Out\nShortcut: - //TP_LOCALLAB_CIECAMLOG_TOOLTIP;This module is based on the CIECAM color appearance model which was designed to better simulate how human vision perceives colors under different lighting conditions.\nOnly the third Ciecam process (Viewing conditions - Target) is taken into account, as well as part of the second (contrast J, saturation s) , as well as some data from the first process (Scene conditions - Source) which is used for the Log encoding.\nIt also adapts the output to the intended viewing conditions (monitor, TV, projector, printer, etc.) so that the chromatic and contrast appearance is preserved across the display environment. //TP_WAVELET_DENH;Low levels (1234)- Finest details //TP_WAVELET_DENL;High levels - Coarsest details -//TP_WAVELET_DENLH;Guided threshold by detail levels 1-4 +//TP_WAVELET_DENLH;Guided threshold for detail levels 1-4 diff --git a/rtgui/curveeditorgroup.cc b/rtgui/curveeditorgroup.cc index 5c120f7e4..d099e1a99 100644 --- a/rtgui/curveeditorgroup.cc +++ b/rtgui/curveeditorgroup.cc @@ -29,12 +29,17 @@ #include "options.h" #include "pathutils.h" -CurveEditorGroup::CurveEditorGroup (Glib::ustring& curveDir, Glib::ustring groupLabel) : curveDir(curveDir), line(0), curve_reset(nullptr), +CurveEditorGroup::CurveEditorGroup (Glib::ustring& curveDir, Glib::ustring groupLabel, int blank) : curveDir(curveDir), line(0), curve_reset(nullptr), displayedCurve(nullptr), flatSubGroup(nullptr), diagonalSubGroup(nullptr), cl(nullptr), numberOfPackedCurve(0) { // We set the label to the one provided as parameter, even if it's an empty string - curveGroupLabel = Gtk::manage (new Gtk::Label (groupLabel + ":", Gtk::ALIGN_START)); + if(blank == 0) { + curveGroupLabel = Gtk::manage (new Gtk::Label (groupLabel + ":", Gtk::ALIGN_START)); + } else if(blank == 1){ + curveGroupLabel = Gtk::manage (new Gtk::Label (groupLabel, Gtk::ALIGN_START)); + } + setExpandAlignProperties(curveGroupLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); set_row_spacing(RTScalable::getScale()); } diff --git a/rtgui/curveeditorgroup.h b/rtgui/curveeditorgroup.h index 0f7c01a32..55d438b2d 100644 --- a/rtgui/curveeditorgroup.h +++ b/rtgui/curveeditorgroup.h @@ -71,7 +71,7 @@ public: * dialogs. */ - explicit CurveEditorGroup(Glib::ustring& curveDir, Glib::ustring groupLabel = ""); + explicit CurveEditorGroup(Glib::ustring& curveDir, Glib::ustring groupLabel = "", int blank = 0); ~CurveEditorGroup() override; void newLine(); void curveListComplete(); diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 7553a7353..1ec19e616 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -637,6 +637,8 @@ EditorPanel::EditorPanel (FilePanel* filePanel) vboxright = new Gtk::Paned (Gtk::ORIENTATION_VERTICAL); vsubboxright = new Gtk::Box (Gtk::ORIENTATION_VERTICAL, 0); +// int rightsize = options.fontSize * 44; +// vsubboxright->set_size_request (rightsize, rightsize - 50); vsubboxright->set_size_request (300, 250); vsubboxright->pack_start (*ppframe, Gtk::PACK_SHRINK, 2); diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc index c0988ca37..2edb7db82 100644 --- a/rtgui/locallabtools.cc +++ b/rtgui/locallabtools.cc @@ -132,28 +132,29 @@ LocallabTool::LocallabTool(Gtk::Box* content, Glib::ustring toolName, Glib::ustr complexity(Gtk::manage(new MyComboBoxText())) { // Create expander title bar + Gtk::Box *titVBox; + titVBox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); + titVBox->set_spacing(2); + Gtk::Box* const titleBox = Gtk::manage(new Gtk::Box()); Gtk::Label* const titleLabel = Gtk::manage(new Gtk::Label()); titleLabel->set_markup(Glib::ustring("") + escapeHtmlChars(UILabel) + Glib::ustring("")); titleLabel->set_alignment(Gtk::ALIGN_START, Gtk::ALIGN_CENTER); titleBox->pack_start(*titleLabel, Gtk::PACK_EXPAND_WIDGET, 0); - + Gtk::EventBox* const removeEvBox = Gtk::manage(new Gtk::EventBox()); // Glue to manage mouse clicking event on remove image removeEvBox->set_can_focus(false); removeEvBox->set_above_child(false); // To have priority over expander title bar when mouse clicking on remove image removeEvBox->signal_button_release_event().connect(sigc::mem_fun(this, &LocallabTool::on_remove_change)); RTImage* const removeImage = Gtk::manage(new RTImage("cancel-small.png")); removeEvBox->add(*removeImage); - titleBox->pack_end(*removeEvBox, Gtk::PACK_SHRINK, 4); - + titleBox->pack_end(*removeEvBox, Gtk::PACK_SHRINK, 1); if (needMode) { complexity->append(M("TP_LOCALLAB_MODE_EXPERT")); complexity->append(M("TP_LOCALLAB_MODE_NORMAL")); complexity->append(M("TP_LOCALLAB_MODE_SIMPLE")); complexity->set_active(2); - complexity->setPreferredWidth(100, -1); complexityConn = complexity->signal_changed().connect(sigc::mem_fun(*this, &LocallabTool::complexityModeChanged)); - titleBox->pack_end(*complexity, Gtk::PACK_SHRINK, 2); } Gtk::Separator* const separator = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)); @@ -164,8 +165,10 @@ LocallabTool::LocallabTool(Gtk::Box* content, Glib::ustring toolName, Glib::ustr titleImage->set_tooltip_text(M("TP_GENERAL_11SCALE_TOOLTIP")); titleBox->pack_end(*titleImage, Gtk::PACK_SHRINK, 0); } + titVBox->pack_start(*titleBox, Gtk::PACK_SHRINK, 1); + titVBox->pack_start(*complexity, Gtk::PACK_SHRINK, 1); - exp = Gtk::manage(new MyExpander(true, titleBox)); + exp = Gtk::manage(new MyExpander(true, titVBox)); exp->signal_button_release_event().connect_notify(sigc::mem_fun(this, &LocallabTool::foldThemAll)); enaExpConn = exp->signal_enabled_toggled().connect(sigc::mem_fun(*this, &LocallabTool::enabledChanged)); @@ -448,11 +451,11 @@ LocallabColor::LocallabColor(): clshape(static_cast(clCurveEditorG->addCurve(CT_Diagonal, "C(L)"))), lcshape(static_cast(clCurveEditorG->addCurve(CT_Diagonal, "L(C)"))), HCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_HLH"))), - LHshape(static_cast(HCurveEditorG->addCurve(CT_Flat, "L(H)", nullptr, false, true))), + LHshape(static_cast(HCurveEditorG->addCurve(CT_Flat, "L(h)", nullptr, false, true))), H3CurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_HLH"))), - CHshape(static_cast(H3CurveEditorG->addCurve(CT_Flat, "C(H)", nullptr, false, true))), + CHshape(static_cast(H3CurveEditorG->addCurve(CT_Flat, "C(h)", nullptr, false, true))), H2CurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_HLH"))), - HHshape(static_cast(H2CurveEditorG->addCurve(CT_Flat, "H(H)", nullptr, false, true))), + HHshape(static_cast(H2CurveEditorG->addCurve(CT_Flat, "h(h)", nullptr, false, true))), rgbCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_RGB"))), toneMethod(Gtk::manage(new MyComboBoxText())), rgbshape(static_cast(rgbCurveEditorG->addCurve(CT_Diagonal, "", toneMethod))), @@ -472,10 +475,11 @@ LocallabColor::LocallabColor(): showmaskcolMethod(Gtk::manage(new MyComboBoxText())), showmaskcolMethodinv(Gtk::manage(new MyComboBoxText())), enaColorMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), - maskCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKCOL"))), - CCmaskshape(static_cast(maskCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), - LLmaskshape(static_cast(maskCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), - HHmaskshape(static_cast(maskCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), +// maskCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKCOL"))), + maskCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir,"", 1)), + CCmaskshape(static_cast(maskCurveEditorG->addCurve(CT_Flat, "C", nullptr, false, false))), + LLmaskshape(static_cast(maskCurveEditorG->addCurve(CT_Flat, "L", nullptr, false, false))), + HHmaskshape(static_cast(maskCurveEditorG->addCurve(CT_Flat, "LC(h)", nullptr, false, true))), struFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LABSTRUM")))), strumaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRUMASKCOL"), 0., 200., 0.1, 0.))), toolcol(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_TOOLCOL")))), @@ -485,14 +489,16 @@ LocallabColor::LocallabColor(): blurcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLURCOL"), 0.2, 100., 0.5, 0.2))), blendmaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), toolcolFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_TOOLMASK")))), + toolcolFrame2(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_TOOLMASK_2")))), radmaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.0, 0.1, 0.))), lapmaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), chromaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), gammaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAMMASKCOL"), 0.25, 4.0, 0.01, 1.))), slomaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SLOMASKCOL"), 0.0, 15.0, 0.1, 0.))), shadmaskcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SHAMASKCOL"), 0, 100, 1, 0))), - maskHCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKH"))), - HHhmaskshape(static_cast(maskHCurveEditorG->addCurve(CT_Flat, "H(H)", nullptr, false, true))), + // maskHCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKH"))), + maskHCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, "")), + HHhmaskshape(static_cast(maskHCurveEditorG->addCurve(CT_Flat, "h(h)", nullptr, false, true))), mask2CurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK2"))), Lmaskshape(static_cast(mask2CurveEditorG->addCurve(CT_Diagonal, "L(L)"))), mask2CurveEditorGwav(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_WAVMASK"))), @@ -879,6 +885,7 @@ LocallabColor::LocallabColor(): maskcolBox->pack_start(*blendmaskcol, Gtk::PACK_SHRINK, 0); // Gtk::Frame* const toolcolFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_TOOLMASK"))); toolcolFrame->set_label_align(0.025, 0.5); + toolcolFrame2->set_label_align(0.025, 0.5); ToolParamBlock* const toolcolBox = Gtk::manage(new ToolParamBlock()); toolcolBox->pack_start(*radmaskcol, Gtk::PACK_SHRINK, 0); toolcolBox->pack_start(*lapmaskcol, Gtk::PACK_SHRINK, 0); @@ -888,8 +895,11 @@ LocallabColor::LocallabColor(): toolcolBox->pack_start(*shadmaskcol, Gtk::PACK_SHRINK, 0); toolcolBox->pack_start(*maskHCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor toolcolBox->pack_start(*mask2CurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor - toolcolBox->pack_start(*mask2CurveEditorGwav, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor - toolcolBox->pack_start(*csThresholdcol, Gtk::PACK_SHRINK, 0); + ToolParamBlock* const toolcolBox2 = Gtk::manage(new ToolParamBlock()); + toolcolBox2->pack_start(*mask2CurveEditorGwav, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + toolcolBox2->pack_start(*csThresholdcol, Gtk::PACK_SHRINK, 0); + toolcolFrame2->add(*toolcolBox2); + toolcolBox->pack_start(*toolcolFrame2); toolcolFrame->add(*toolcolBox); maskcolBox->pack_start(*toolcolFrame); mergecolFrame->add(*maskcolBox); @@ -2041,6 +2051,7 @@ void LocallabColor::updateGUIToMode(const modeType new_type) maskHCurveEditorG->hide(); mask2CurveEditorGwav->hide(); csThresholdcol->hide(); + toolcolFrame2->hide(); // Specific Simple mode widgets are shown in Normal mode softradiuscol->show(); if (enaColorMask->get_active()) { @@ -2113,6 +2124,7 @@ void LocallabColor::updateGUIToMode(const modeType new_type) maskHCurveEditorG->show(); mask2CurveEditorGwav->show(); csThresholdcol->show(); + toolcolFrame2->show(); } } @@ -2518,10 +2530,11 @@ LocallabExposure::LocallabExposure(): showmaskexpMethodinv(Gtk::manage(new MyComboBoxText())), enaExpMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), enaExpMaskaft(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASKAFT")))), - maskexpCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), - CCmaskexpshape(static_cast(maskexpCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), - LLmaskexpshape(static_cast(maskexpCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), - HHmaskexpshape(static_cast(maskexpCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + // maskexpCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + maskexpCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, "", 1)), + CCmaskexpshape(static_cast(maskexpCurveEditorG->addCurve(CT_Flat, "C", nullptr, false, false))), + LLmaskexpshape(static_cast(maskexpCurveEditorG->addCurve(CT_Flat, "L", nullptr, false, false))), + HHmaskexpshape(static_cast(maskexpCurveEditorG->addCurve(CT_Flat, "LC(h)", nullptr, false, true))), blendmaskexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), radmaskexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.0, 0.1, 0.))), lapmaskexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), @@ -3850,10 +3863,11 @@ LocallabShadow::LocallabShadow(): showmaskSHMethod(Gtk::manage(new MyComboBoxText())), showmaskSHMethodinv(Gtk::manage(new MyComboBoxText())), enaSHMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), - maskSHCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), - CCmaskSHshape(static_cast(maskSHCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), - LLmaskSHshape(static_cast(maskSHCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), - HHmaskSHshape(static_cast(maskSHCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), +// maskSHCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + maskSHCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, "", 1)), + CCmaskSHshape(static_cast(maskSHCurveEditorG->addCurve(CT_Flat, "C", nullptr, false, false))), + LLmaskSHshape(static_cast(maskSHCurveEditorG->addCurve(CT_Flat, "L", nullptr, false, false))), + HHmaskSHshape(static_cast(maskSHCurveEditorG->addCurve(CT_Flat, "LC(h)", nullptr, false, true))), blendmaskSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), radmaskSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.0, 0.1, 0.))), lapmaskSH(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), @@ -4924,10 +4938,11 @@ LocallabVibrance::LocallabVibrance(): expmaskvib(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWVI")))), showmaskvibMethod(Gtk::manage(new MyComboBoxText())), enavibMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), - maskvibCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), - CCmaskvibshape(static_cast(maskvibCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), - LLmaskvibshape(static_cast(maskvibCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), - HHmaskvibshape(static_cast(maskvibCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + // maskvibCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + maskvibCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, "", 1)), + CCmaskvibshape(static_cast(maskvibCurveEditorG->addCurve(CT_Flat, "C", nullptr, false, false))), + LLmaskvibshape(static_cast(maskvibCurveEditorG->addCurve(CT_Flat, "L", nullptr, false, false))), + HHmaskvibshape(static_cast(maskvibCurveEditorG->addCurve(CT_Flat, "LC(h)", nullptr, false, true))), blendmaskvib(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), radmaskvib(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.0, 0.1, 0.))), lapmaskvib(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), @@ -6269,8 +6284,8 @@ LocallabBlur::LocallabBlur(): epsbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_EPSBL"), -10, 10, 1, 0))), expdenoise2(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_DENOI2_EXP")))), recothres(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKRECOTHRES"), 1., 2., 0.01, 1.))), - lowthres(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHRLOW"), 1., 80., 0.5, 12.))), - higthres(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHR"), 20., 99., 0.5, 85.))), + lowthres(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHRLOW2"), 1., 80., 0.5, 12.))), + higthres(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHR2"), 20., 99., 0.5, 85.))), sensibn(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 0, 100, 1, 40))), blurMethod(Gtk::manage(new MyComboBoxText())), invbl(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVBL")))), @@ -6289,8 +6304,8 @@ LocallabBlur::LocallabBlur(): maskunusable3(Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_MASKUNUSABLE")))), usemask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_USEMASK")))), lnoiselow(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLNOISELOW"), 0.7, 2., 0.01, 1.))), - levelthr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHR"), 20., 99., 0.5, 85.))), - levelthrlow(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHRLOW"), 1., 80., 0.5, 12.))), + levelthr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHR2"), 20., 99., 0.5, 85.))), + levelthrlow(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHRLOW2"), 1., 80., 0.5, 12.))), noiselumf0(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISELUMFINEZERO"), MINCHRO, MAXCHRO, 0.01, 0.))), noiselumf(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISELUMFINE"), MINCHRO, MAXCHRO, 0.01, 0.))), noiselumf2(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISELUMFINETWO"), MINCHRO, MAXCHRO, 0.01, 0.))), @@ -6307,10 +6322,10 @@ LocallabBlur::LocallabBlur(): adjblur(Gtk::manage(new Adjuster(M("TP_LOCALLAB_ADJ"), -100., 100., 1., 0., Gtk::manage(new RTImage("circle-blue-yellow-small.png")), Gtk::manage(new RTImage("circle-red-green-small.png"))))), expdenoise3(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_DENOI2_EXP")))), recothresd(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKRECOTHRES"), 1., 2., 0.01, 1.))), - lowthresd(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHRLOW"), 1., 80., 0.5, 12.))), + lowthresd(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHRLOW2"), 1., 80., 0.5, 12.))), midthresd(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHRMID"), 0., 100., 0.5, 0.))), midthresdch(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHRMIDCH"), 0., 100., 0.5, 0.))), - higthresd(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHR"), 20., 99., 0.5, 85.))), + higthresd(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHR2"), 20., 99., 0.5, 85.))), decayd(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKDDECAY"), 0.5, 4., 0.1, 2.))), invmaskd(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVMASK")))), invmask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_INVMASK")))), @@ -6327,13 +6342,15 @@ LocallabBlur::LocallabBlur(): showmaskblMethod(Gtk::manage(new MyComboBoxText())), showmaskblMethodtyp(Gtk::manage(new MyComboBoxText())), enablMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), - maskblCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), - CCmaskblshape(static_cast(maskblCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), - LLmaskblshape(static_cast(maskblCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), - HHmaskblshape(static_cast(maskblCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), +// maskblCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + maskblCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, "", 1)), + CCmaskblshape(static_cast(maskblCurveEditorG->addCurve(CT_Flat, "C", nullptr, false, false))), + LLmaskblshape(static_cast(maskblCurveEditorG->addCurve(CT_Flat, "L", nullptr, false, false))), + HHmaskblshape(static_cast(maskblCurveEditorG->addCurve(CT_Flat, "LC(h)", nullptr, false, true))), strumaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRUMASKCOL"), 0., 200., 0.1, 0.))), toolbl(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_TOOLCOL")))), toolblFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_TOOLMASK")))), + toolblFrame2(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_TOOLMASK_2")))), blendmaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), radmaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.0, 0.1, 0.))), lapmaskbl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), @@ -6698,6 +6715,7 @@ LocallabBlur::LocallabBlur(): maskblBox->pack_start(*separatorstrubl, Gtk::PACK_SHRINK, 2); maskblBox->pack_start(*blendmaskbl, Gtk::PACK_SHRINK, 0); toolblFrame->set_label_align(0.025, 0.5); + toolblFrame2->set_label_align(0.025, 0.5); ToolParamBlock* const toolblBox = Gtk::manage(new ToolParamBlock()); toolblBox->pack_start(*radmaskbl, Gtk::PACK_SHRINK, 0); toolblBox->pack_start(*lapmaskbl, Gtk::PACK_SHRINK, 0); @@ -6707,8 +6725,11 @@ LocallabBlur::LocallabBlur(): toolblBox->pack_start(*shadmaskblsha, Gtk::PACK_SHRINK, 0); toolblBox->pack_start(*shadmaskbl, Gtk::PACK_SHRINK, 0); toolblBox->pack_start(*mask2blCurveEditorG, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor - toolblBox->pack_start(*mask2blCurveEditorGwav, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor - toolblBox->pack_start(*csThresholdblur, Gtk::PACK_SHRINK, 0); + ToolParamBlock* const toolblBox2 = Gtk::manage(new ToolParamBlock()); + toolblBox2->pack_start(*mask2blCurveEditorGwav, Gtk::PACK_SHRINK, 4); // Padding is mandatory to correct behavior of curve editor + toolblBox2->pack_start(*csThresholdblur, Gtk::PACK_SHRINK, 0); + toolblFrame2->add(*toolblBox2); + toolblBox->pack_start(*toolblFrame2); toolblFrame->add(*toolblBox); maskblBox->pack_start(*toolblFrame); expmaskbl->add(*maskblBox, false); @@ -7900,6 +7921,7 @@ void LocallabBlur::updateGUIToMode(const modeType new_type) shadmaskblsha->hide(); mask2blCurveEditorGwav->hide(); csThresholdblur->hide(); + toolblFrame2->hide(); // Specific Simple mode widgets are shown in Normal mode expmaskbl->show(); expdenoise1->hide(); @@ -7987,6 +8009,7 @@ void LocallabBlur::updateGUIToMode(const modeType new_type) shadmaskblsha->show(); mask2blCurveEditorGwav->show(); csThresholdblur->show(); + toolblFrame2->show(); nlpat->show(); nlrad->show(); nlgam->show(); diff --git a/rtgui/locallabtools.h b/rtgui/locallabtools.h index 5b80706f5..53eafd6f8 100644 --- a/rtgui/locallabtools.h +++ b/rtgui/locallabtools.h @@ -249,6 +249,7 @@ private: Adjuster* const blurcol; Adjuster* const blendmaskcol; Gtk::Frame* const toolcolFrame; + Gtk::Frame* const toolcolFrame2; Adjuster* const radmaskcol; Adjuster* const lapmaskcol; Adjuster* const chromaskcol; @@ -756,6 +757,7 @@ private: Adjuster* const strumaskbl; Gtk::CheckButton* const toolbl; Gtk::Frame* const toolblFrame; + Gtk::Frame* const toolblFrame2; Adjuster* const blendmaskbl; Adjuster* const radmaskbl; Adjuster* const lapmaskbl; diff --git a/rtgui/locallabtools2.cc b/rtgui/locallabtools2.cc index 33e006baa..d0ed30a8a 100644 --- a/rtgui/locallabtools2.cc +++ b/rtgui/locallabtools2.cc @@ -139,10 +139,11 @@ LocallabTone::LocallabTone(): showmasktmMethod(Gtk::manage(new MyComboBoxText())), enatmMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), enatmMaskaft(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_AFTER_MASK")))), - masktmCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), - CCmasktmshape(static_cast(masktmCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), - LLmasktmshape(static_cast(masktmCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), - HHmasktmshape(static_cast(masktmCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + // masktmCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + masktmCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, "", 1)), + CCmasktmshape(static_cast(masktmCurveEditorG->addCurve(CT_Flat, "C", nullptr, false, false))), + LLmasktmshape(static_cast(masktmCurveEditorG->addCurve(CT_Flat, "L", nullptr, false, false))), + HHmasktmshape(static_cast(masktmCurveEditorG->addCurve(CT_Flat, "LC(h)", nullptr, false, true))), blendmasktm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), lapmasktm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), radmasktm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.0, 0.1, 0.))), @@ -809,17 +810,18 @@ LocallabRetinex::LocallabRetinex(): maskusabler(Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_MASKUSABLE")))), maskunusabler(Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_MASKUNUSABLE")))), recothresr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKRECOTHRES"), 1., 2., 0.01, 1.))), - lowthresr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHRLOW"), 1., 80., 0.5, 12.))), - higthresr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHR"), 20., 99., 0.5, 85.))), + lowthresr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHRLOW2"), 1., 80., 0.5, 12.))), + higthresr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHR2"), 20., 99., 0.5, 85.))), decayr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKDDECAY"), 0.5, 4., 0.1, 2.))), expmaskreti(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWR")))), showmaskretiMethod(Gtk::manage(new MyComboBoxText())), enaretiMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), enaretiMasktmap(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_TM_MASK")))), - maskretiCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), - CCmaskretishape(static_cast(maskretiCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), - LLmaskretishape(static_cast(maskretiCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), - HHmaskretishape(static_cast(maskretiCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + // maskretiCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + maskretiCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, "", 1)), + CCmaskretishape(static_cast(maskretiCurveEditorG->addCurve(CT_Flat, "C", nullptr, false, false))), + LLmaskretishape(static_cast(maskretiCurveEditorG->addCurve(CT_Flat, "L", nullptr, false, false))), + HHmaskretishape(static_cast(maskretiCurveEditorG->addCurve(CT_Flat, "LC(h)", nullptr, false, true))), blendmaskreti(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), radmaskreti(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.0, 0.1, 10.))), lapmaskreti(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), @@ -2396,10 +2398,11 @@ LocallabContrast::LocallabContrast(): expmasklc(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWLC")))), showmasklcMethod(Gtk::manage(new MyComboBoxText())), enalcMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), - masklcCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), - CCmasklcshape(static_cast(masklcCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), - LLmasklcshape(static_cast(masklcCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), - HHmasklcshape(static_cast(masklcCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), +// masklcCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + masklcCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, "", 1)), + CCmasklcshape(static_cast(masklcCurveEditorG->addCurve(CT_Flat, "C", nullptr, false, false))), + LLmasklcshape(static_cast(masklcCurveEditorG->addCurve(CT_Flat, "L", nullptr, false, false))), + HHmasklcshape(static_cast(masklcCurveEditorG->addCurve(CT_Flat, "LC(h)", nullptr, false, true))), blendmasklc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), radmasklc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.0, 0.1, 0.))), chromasklc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), @@ -4343,10 +4346,11 @@ LocallabCBDL::LocallabCBDL(): expmaskcb(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWCB")))), showmaskcbMethod(Gtk::manage(new MyComboBoxText())), enacbMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), - maskcbCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), - CCmaskcbshape(static_cast(maskcbCurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), - LLmaskcbshape(static_cast(maskcbCurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), - HHmaskcbshape(static_cast(maskcbCurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + // maskcbCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK"))), + maskcbCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, "", 1)), + CCmaskcbshape(static_cast(maskcbCurveEditorG->addCurve(CT_Flat, "C", nullptr, false, false))), + LLmaskcbshape(static_cast(maskcbCurveEditorG->addCurve(CT_Flat, "L", nullptr, false, false))), + HHmaskcbshape(static_cast(maskcbCurveEditorG->addCurve(CT_Flat, "LC(h)", nullptr, false, true))), blendmaskcb(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), radmaskcb(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.0, 0.1, 0.))), lapmaskcb(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPMASKCOL"), 0.0, 100.0, 0.1, 0.))), @@ -4446,7 +4450,7 @@ LocallabCBDL::LocallabCBDL(): // Add CBDL specific widgets to GUI ToolParamBlock* const levBox = Gtk::manage(new ToolParamBlock()); Gtk::Box* buttonBox = Gtk::manage(new Gtk::Box()); - buttonBox->set_spacing(10); + buttonBox->set_spacing(2); buttonBox->set_homogeneous(true); buttonBox->pack_start(*lumacontrastMinusButton); buttonBox->pack_start(*lumaneutralButton); @@ -5151,10 +5155,11 @@ LocallabLog::LocallabLog(): expmaskL(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWC")))), showmaskLMethod(Gtk::manage(new MyComboBoxText())), enaLMask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), - maskCurveEditorL(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKCOL"))), - CCmaskshapeL(static_cast(maskCurveEditorL->addCurve(CT_Flat, "C(C)", nullptr, false, false))), - LLmaskshapeL(static_cast(maskCurveEditorL->addCurve(CT_Flat, "L(L)", nullptr, false, false))), - HHmaskshapeL(static_cast(maskCurveEditorL->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), + // maskCurveEditorL(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKCOL"))), + maskCurveEditorL(new CurveEditorGroup(options.lastlocalCurvesDir, "", 1)), + CCmaskshapeL(static_cast(maskCurveEditorL->addCurve(CT_Flat, "C", nullptr, false, false))), + LLmaskshapeL(static_cast(maskCurveEditorL->addCurve(CT_Flat, "L", nullptr, false, false))), + HHmaskshapeL(static_cast(maskCurveEditorL->addCurve(CT_Flat, "LC(h)", nullptr, false, true))), blendmaskL(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLENDMASKCOL"), -100, 100, 1, 0))), radmaskL(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RADMASKCOL"), 0.0, 100.0, 0.1, 0.))), chromaskL(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMASKCOL"), -100.0, 100.0, 0.1, 0.))), @@ -6408,10 +6413,11 @@ LocallabMask::LocallabMask(): softradiusmask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SOFTRADIUSCOL"), 0.0, 100.0, 0.5, 1.))), showmask_Method(Gtk::manage(new MyComboBoxText())), enamask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ENABLE_MASK")))), - mask_CurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKCOL"))), - CCmask_shape(static_cast(mask_CurveEditorG->addCurve(CT_Flat, "C(C)", nullptr, false, false))), - LLmask_shape(static_cast(mask_CurveEditorG->addCurve(CT_Flat, "L(L)", nullptr, false, false))), - HHmask_shape(static_cast(mask_CurveEditorG->addCurve(CT_Flat, "LC(H)", nullptr, false, true))), +// mask_CurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKCOL"))), + mask_CurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, "", 1)), + CCmask_shape(static_cast(mask_CurveEditorG->addCurve(CT_Flat, "C", nullptr, false, false))), + LLmask_shape(static_cast(mask_CurveEditorG->addCurve(CT_Flat, "L", nullptr, false, false))), + HHmask_shape(static_cast(mask_CurveEditorG->addCurve(CT_Flat, "LC(h)", nullptr, false, true))), struFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LABSTRUM")))), strumaskmask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRUMASKCOL"), 0., 200., 0.1, 0.))), toolmask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_TOOLCOL")))), @@ -6427,7 +6433,7 @@ LocallabMask::LocallabMask(): slopmask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SLOMASKCOL"), 0.0, 15.0, 0.1, 0.))), shadmask(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SHAMASKCOL"), 0, 100, 1, 0))), mask_HCurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASKH"))), - HHhmask_shape(static_cast(mask_HCurveEditorG->addCurve(CT_Flat, "H(H)", nullptr, false, true))), + HHhmask_shape(static_cast(mask_HCurveEditorG->addCurve(CT_Flat, "h(h)", nullptr, false, true))), mask2CurveEditorG(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_MASK2"))), Lmask_shape(static_cast(mask2CurveEditorG->addCurve(CT_Diagonal, "L(L)"))), mask2CurveEditorGwav(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_WAVMASK"))), From a0993b624d7a63136ab7cc713e6c5f33362d5d76 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <> Date: Sat, 3 Apr 2021 11:56:22 -0700 Subject: [PATCH 025/135] Enable neutral colors for LA merge file --- rtengine/iplocallab.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index ca1319052..b2102fd6a 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -15089,7 +15089,6 @@ void ImProcFunctions::Lab_Local( const float a_basemerg = lp.lowAmerg / scaling; const float b_scalemerg = (lp.highBmerg - lp.lowBmerg) / factor / scaling; const float b_basemerg = lp.lowBmerg / scaling; - const bool ctoningmerg = (a_scalemerg != 0.f || b_scalemerg != 0.f || a_basemerg != 0.f || b_basemerg != 0.f); if (!lp.inv && (lp.chro != 0 || lp.ligh != 0.f || lp.cont != 0 || ctoning || lp.mergemet > 0 || lp.strcol != 0.f || lp.strcolab != 0.f || lp.qualcurvemet != 0 || lp.showmaskcolmet == 2 || lp.enaColorMask || lp.showmaskcolmet == 3 || lp.showmaskcolmet == 4 || lp.showmaskcolmet == 5 || lp.prevdE) && lp.colorena) { // || lllocalcurve)) { //interior ellipse renforced lightness and chroma //locallutili int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); @@ -15564,7 +15563,7 @@ void ImProcFunctions::Lab_Local( bufcolreserv->L[y][x] = lastorig->L[y + ystart][x + xstart]; bufcolreserv->a[y][x] = lastorig->a[y + ystart][x + xstart]; bufcolreserv->b[y][x] = lastorig->b[y + ystart][x + xstart]; - } else if (lp.mergemet == 4 && ctoningmerg) { + } else if (lp.mergemet == 4) { bufcolreserv->L[y][x] = merlucol * 327.68f; bufcolreserv->a[y][x] = 9.f * scaledirect * a_scalemerg; bufcolreserv->b[y][x] = 9.f * scaledirect * b_scalemerg; From c14a43355fd41d5098b204dc988bcb02e91c314d Mon Sep 17 00:00:00 2001 From: Desmis Date: Sun, 4 Apr 2021 08:15:01 +0200 Subject: [PATCH 026/135] Remove unused variables a_basemerg and b_basemerg --- rtengine/iplocallab.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index b2102fd6a..2d0edb1b8 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -15086,9 +15086,7 @@ void ImProcFunctions::Lab_Local( const float b_base = lp.lowB / scaling; const bool ctoning = (a_scale != 0.f || b_scale != 0.f || a_base != 0.f || b_base != 0.f); const float a_scalemerg = (lp.highAmerg - lp.lowAmerg) / factor / scaling; - const float a_basemerg = lp.lowAmerg / scaling; const float b_scalemerg = (lp.highBmerg - lp.lowBmerg) / factor / scaling; - const float b_basemerg = lp.lowBmerg / scaling; if (!lp.inv && (lp.chro != 0 || lp.ligh != 0.f || lp.cont != 0 || ctoning || lp.mergemet > 0 || lp.strcol != 0.f || lp.strcolab != 0.f || lp.qualcurvemet != 0 || lp.showmaskcolmet == 2 || lp.enaColorMask || lp.showmaskcolmet == 3 || lp.showmaskcolmet == 4 || lp.showmaskcolmet == 5 || lp.prevdE) && lp.colorena) { // || lllocalcurve)) { //interior ellipse renforced lightness and chroma //locallutili int ystart = rtengine::max(static_cast(lp.yc - lp.lyT) - cy, 0); From cfda519894de58801b6ae54cc31045576d5e0336 Mon Sep 17 00:00:00 2001 From: Desmis Date: Sun, 4 Apr 2021 08:35:45 +0200 Subject: [PATCH 027/135] Fixed LA shape detection adjusters range mismatch issue 6198 - thanks to Lawrence37 --- rtengine/iplocallab.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index ca1319052..e790dd259 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -785,9 +785,10 @@ static void calcLocalParams(int sp, int oW, int oH, const LocallabParams& locall float laplac = ((float)locallab.spots.at(sp).laplace); float thre = locallab.spots.at(sp).thresh; - if (thre > 8.f || thre < 0.f) {//to avoid artifacts if user does not clear cache with new settings. Can be suppressed after - thre = 2.f; - } +// if (thre > 8.f || thre < 0.f) {//to avoid artifacts if user does not clear cache with new settings. Can be suppressed after +// thre = 2.f; +// } + thre = LIM(thre, 0.f, 10.0f); double local_x = locallab.spots.at(sp).loc.at(0) / 2000.0; double local_y = locallab.spots.at(sp).loc.at(2) / 2000.0; @@ -800,9 +801,10 @@ static void calcLocalParams(int sp, int oW, int oH, const LocallabParams& locall float balanch = (float) locallab.spots.at(sp).balanh; int colorde = (int) locallab.spots.at(sp).colorde; - if (iterati > 4.f || iterati < 0.2f) {//to avoid artifacts if user does not clear cache with new settings Can be suppressed after - iterati = 2.f; - } +// if (iterati > 4.f || iterati < 0.2f) {//to avoid artifacts if user does not clear cache with new settings Can be suppressed after +// iterati = 2.f; +// } + iterati = LIM(iterati, 0.2f, 10.0f); float neigh = float (locallab.spots.at(sp).neigh); float chromaPastel = float (locallab.spots.at(sp).pastels) / 100.0f; From 4d7b6406dd892c0f8c957826b77af39d1f0ad849 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Thu, 8 Apr 2021 19:38:10 +0200 Subject: [PATCH 028/135] Missing copyright statements and Boost license text for files forked from SLEEF, fixes #6202 --- licenses/sleef_LICENSE.txt | 30 ++++++++++++++++++++++++++++++ rtengine/helperavx.h | 5 +++++ rtengine/helpersse2.h | 5 +++++ rtengine/sleef.h | 5 +++++ rtengine/sleefsseavx.h | 5 +++++ 5 files changed, 50 insertions(+) create mode 100644 licenses/sleef_LICENSE.txt diff --git a/licenses/sleef_LICENSE.txt b/licenses/sleef_LICENSE.txt new file mode 100644 index 000000000..8170d3224 --- /dev/null +++ b/licenses/sleef_LICENSE.txt @@ -0,0 +1,30 @@ +============================================================================= +Boost Software License - Version 1.0 + +This license applies to selected portions of the software derived from SLEEF +(https://sleef.org/), as noted in the applicable source file headers. +============================================================================= + +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/rtengine/helperavx.h b/rtengine/helperavx.h index 528760a92..de4ecf880 100644 --- a/rtengine/helperavx.h +++ b/rtengine/helperavx.h @@ -3,6 +3,11 @@ // this code was taken from http://shibatch.sourceforge.net/ // Many thanks to the author: Naoki Shibata // +// Copyright Naoki Shibata and contributors 2010 - 2021. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file sleef_LICENSE.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// //////////////////////////////////////////////////////////////// #ifndef __AVX__ #error Please specify -mavx. diff --git a/rtengine/helpersse2.h b/rtengine/helpersse2.h index e8c489b04..8e87032f0 100644 --- a/rtengine/helpersse2.h +++ b/rtengine/helpersse2.h @@ -3,6 +3,11 @@ // this code was taken from http://shibatch.sourceforge.net/ // Many thanks to the author of original version: Naoki Shibata // +// Copyright Naoki Shibata and contributors 2010 - 2021. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file sleef_LICENSE.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// // This version contains modifications made by Ingo Weyrich // //////////////////////////////////////////////////////////////// diff --git a/rtengine/sleef.h b/rtengine/sleef.h index fc23cbad9..8611e2fc7 100644 --- a/rtengine/sleef.h +++ b/rtengine/sleef.h @@ -3,6 +3,11 @@ // this code was taken from http://shibatch.sourceforge.net/ // Many thanks to the author of original version: Naoki Shibata // +// Copyright Naoki Shibata and contributors 2010 - 2021. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file sleef_LICENSE.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// // This version contains modifications made by Ingo Weyrich // //////////////////////////////////////////////////////////////// diff --git a/rtengine/sleefsseavx.h b/rtengine/sleefsseavx.h index c10f4a0c2..374823316 100644 --- a/rtengine/sleefsseavx.h +++ b/rtengine/sleefsseavx.h @@ -3,6 +3,11 @@ // this code was taken from http://shibatch.sourceforge.net/ // Many thanks to the author of original version: Naoki Shibata // +// Copyright Naoki Shibata and contributors 2010 - 2021. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file sleef_LICENSE.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// // This version contains modifications made by Ingo Weyrich // //////////////////////////////////////////////////////////////// From cfbc8a632deaadc9aca438b283c41246ead13ec3 Mon Sep 17 00:00:00 2001 From: Simon Segerblom Rex Date: Sun, 18 Apr 2021 08:03:53 +0200 Subject: [PATCH 029/135] lj92: Fix decoding of 16 bit diff values (#6190) This is a port of the fix discussed here: https://github.com/ilia3101/MLV-App/pull/221 --- rtengine/lj92.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/rtengine/lj92.c b/rtengine/lj92.c index d72075a62..1e0e8cb80 100644 --- a/rtengine/lj92.c +++ b/rtengine/lj92.c @@ -313,6 +313,9 @@ static int decode(ljp* self) { } static int receive(ljp* self,int ssss) { + if (ssss == 16) { + return 1 << 15; + } int i = 0; int v = 0; while (i != ssss) { @@ -365,24 +368,29 @@ inline static int nextdiff(ljp* self, int Px) { cnt -= usedbits; int keepbitsmask = (1 << cnt)-1; b &= keepbitsmask; - while (cnt < t) { - next = *(u16*)&self->data[ix]; - int one = next&0xFF; - int two = next>>8; - b = (b<<16)|(one<<8)|two; - cnt += 16; - ix += 2; - if (one==0xFF) { - b >>= 8; - cnt -= 8; - } else if (two==0xFF) ix++; - } - cnt -= t; - int diff = b >> cnt; - int vt = 1<<(t-1); - if (diff < vt) { - vt = (-1 << t) + 1; - diff += vt; + int diff; + if (t == 16) { + diff = 1 << 15; + } else { + while (cnt < t) { + next = *(u16*)&self->data[ix]; + int one = next&0xFF; + int two = next>>8; + b = (b<<16)|(one<<8)|two; + cnt += 16; + ix += 2; + if (one==0xFF) { + b >>= 8; + cnt -= 8; + } else if (two==0xFF) ix++; + } + cnt -= t; + diff = b >> cnt; + int vt = 1<<(t-1); + if (diff < vt) { + vt = (-1 << t) + 1; + diff += vt; + } } keepbitsmask = (1 << cnt)-1; self->b = b & keepbitsmask; @@ -424,6 +432,7 @@ static int parsePred6(ljp* self) { diff = nextdiff(self,0); Px = 1 << (self->bits-1); left = Px + diff; + left = (u16) (left % 65536); if (self->linearize) linear = self->linearize[left]; else @@ -437,6 +446,7 @@ static int parsePred6(ljp* self) { diff = nextdiff(self,0); Px = left; left = Px + diff; + left = (u16) (left % 65536); if (self->linearize) linear = self->linearize[left]; else @@ -460,6 +470,7 @@ static int parsePred6(ljp* self) { diff = nextdiff(self,0); Px = lastrow[col]; // Use value above for first pixel in row left = Px + diff; + left = (u16) (left % 65536); if (self->linearize) { if (left>self->linlen) return LJ92_ERROR_CORRUPT; linear = self->linearize[left]; @@ -478,6 +489,7 @@ static int parsePred6(ljp* self) { diff = nextdiff(self,0); Px = lastrow[col] + ((left - lastrow[col-1])>>1); left = Px + diff; + left = (u16) (left % 65536); //printf("%d %d %d %d %d %x\n",col,diff,left,lastrow[col],lastrow[col-1],&lastrow[col]); if (self->linearize) { if (left>self->linlen) return LJ92_ERROR_CORRUPT; @@ -556,6 +568,7 @@ static int parseScan(ljp* self) { } diff = nextdiff(self,Px); left = Px + diff; + left = (u16) (left % 65536); //printf("%d %d %d\n",c,diff,left); int linear; if (self->linearize) { From 1d075175f4c10cc90974d785aedc7c26696f5ed2 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Sun, 18 Apr 2021 13:40:44 +0200 Subject: [PATCH 030/135] Apply patch to support 16-bit Fujifilm + support for GFX100S --- rtengine/camconst.json | 4 ++-- rtengine/dcraw.cc | 2 +- rtengine/fujicompressed.cc | 36 ++++++++++++++++++++---------------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index d0947cc69..68a282c6a 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1308,8 +1308,8 @@ Camera constants: }, { // Quality C - "make_model": "FUJIFILM GFX 100", - "dcraw_matrix" : [16212, -8423, -1583, -4336, 12583, 1937, -195, 726, 6199], // taken from ART + "make_model": [ "FUJIFILM GFX 100", "FUJIFILM GFX100S" ], + "dcraw_matrix" : [ 16212, -8423, -1583, -4336, 12583, 1937, -195, 726, 6199 ], // taken from ART "raw_crop": [ 0, 2, 11664, 8734 ] }, diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index bd2e8546c..275b35d81 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -9568,7 +9568,7 @@ void CLASS identify() apply_tiff(); if (!strcmp(model, "X-T3")) { height = raw_height - 2; - } else if (!strcmp(model, "GFX 100")) { + } else if (!strcmp(model, "GFX 100") || !strcmp(model, "GFX100S")) { load_flags = 0; } if (!load_raw) { diff --git a/rtengine/fujicompressed.cc b/rtengine/fujicompressed.cc index 45622eb7f..c1c620657 100644 --- a/rtengine/fujicompressed.cc +++ b/rtengine/fujicompressed.cc @@ -25,7 +25,7 @@ int bitDiff (int value1, int value2) int decBits = 0; if ( value2 < value1 ) - while (decBits <= 12 && (value2 << ++decBits) < value1) + while (decBits <= 14 && (value2 << ++decBits) < value1) ; return decBits; @@ -42,7 +42,7 @@ void CLASS init_fuji_compr (struct fuji_compressed_params* info) derror(); } - info->q_table = (char *) malloc (32768); + info->q_table = (char *) malloc (2 << fuji_bits); merror (info->q_table, "init_fuji_compr()"); if (fuji_raw_type == 16) { @@ -83,19 +83,23 @@ void CLASS init_fuji_compr (struct fuji_compressed_params* info) } // populting gradients - if (info->q_point[4] == 0x3FFF) { - info->total_values = 0x4000; - info->raw_bits = 14; - info->max_bits = 56; - info->maxDiff = 256; - } else if (info->q_point[4] == 0xFFF) { - info->total_values = 4096; - info->raw_bits = 12; - info->max_bits = 48; - info->maxDiff = 64; - } else { - derror(); - } + //if (info->q_point[4] == 0x3FFF) { + // info->total_values = 0x4000; + // info->raw_bits = 14; + // info->max_bits = 56; + // info->maxDiff = 256; + //} else if (info->q_point[4] == 0xFFF) { + // info->total_values = 4096; + // info->raw_bits = 12; + // info->max_bits = 48; + // info->maxDiff = 64; + //} else { + // derror(); + //} + info->total_values = (1 << fuji_bits); + info->raw_bits = fuji_bits; + info->max_bits = 4 * info->raw_bits; + info->maxDiff = info->total_values >> 6; } #define FUJI_BUF_SIZE 0x10000u @@ -1017,7 +1021,7 @@ void CLASS parse_fuji_compressed_header() || h_total_lines > 0x800 || h_total_lines == 0 || h_total_lines != h_raw_height / 6 - || (h_raw_bits != 12 && h_raw_bits != 14) + || (h_raw_bits != 12 && h_raw_bits != 14 && h_raw_bits != 16) || (h_raw_type != 16 && h_raw_type != 0)) { xtransCompressed = false; return; From f47f23a4dc04750ee8baee83724cf094a771ecb9 Mon Sep 17 00:00:00 2001 From: Desmis Date: Wed, 21 Apr 2021 10:32:51 +0200 Subject: [PATCH 031/135] LA - Duplicate full image size whole image - issue 6200 --- rtgui/locallab.cc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc index e1eca81c5..71e55202d 100644 --- a/rtgui/locallab.cc +++ b/rtgui/locallab.cc @@ -759,10 +759,18 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited } } - r->locX = newSpot->loc.at(0); - r->locXL = newSpot->loc.at(1); - r->locY = newSpot->loc.at(2); - r->locYT = newSpot->loc.at(3); + if(r->spotMethod != 2) { + r->locX = newSpot->loc.at(0); + r->locXL = newSpot->loc.at(1); + r->locY = newSpot->loc.at(2); + r->locYT = newSpot->loc.at(3); + } else { + r->locX = 3000.; + r->locXL = 3000.; + r->locY = 3000.; + r->locYT = 3000.; + } + r->centerX = newSpot->centerX; r->centerY = newSpot->centerY; From aea1d805f78ddcc005c88d666d6af9dcbc879e2b Mon Sep 17 00:00:00 2001 From: rom9 <4711834+rom9@users.noreply.github.com> Date: Wed, 21 Apr 2021 21:53:37 +0200 Subject: [PATCH 032/135] Fixes #6213 : when both fattal and filmNegative tools are enabled, copy data from `baseCrop`, to avoid using the fresh buffer from `getImage` (un-doing the previous negative inversion). This minimal change might not be the most correct solution, but it cannot be harmful: at worst, it can only break when both filmNeg and fattal are enabled (a situation wich is already broken). --- rtengine/dcrop.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 790a2bf0d..852ba0ba7 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -720,7 +720,7 @@ void Crop::update(int todo) parent->imgsrc->getImage(parent->currWB, tr, f, pp, params.toneCurve, params.raw); parent->imgsrc->convertColorSpace(f, params.icm, parent->currWB); - if (params.dirpyrDenoise.enabled) { + if (params.dirpyrDenoise.enabled || params.filmNegative.enabled) { // copy the denoised crop int oy = trafy / skip; int ox = trafx / skip; From ca9f373ab805e79ac7fb5fef7b2e8363d684812c Mon Sep 17 00:00:00 2001 From: rom9 <4711834+rom9@users.noreply.github.com> Date: Wed, 21 Apr 2021 22:52:37 +0200 Subject: [PATCH 033/135] Film negative: added new bundled profile for black and white film. #6201 Simply sets both exponent ratios to 1.0, and enables the B&W tool. This is a temporary solution waiting for more specific handling of B&W negatives in the tool. --- .../Film Negative - Black and White.pp3 | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 rtdata/profiles/Film Negative - Black and White.pp3 diff --git a/rtdata/profiles/Film Negative - Black and White.pp3 b/rtdata/profiles/Film Negative - Black and White.pp3 new file mode 100644 index 000000000..ad2a38e1e --- /dev/null +++ b/rtdata/profiles/Film Negative - Black and White.pp3 @@ -0,0 +1,41 @@ +[Exposure] +Auto=false +Compensation=0 +HistogramMatching=false +CurveFromHistogramMatching=false +ClampOOG=false +CurveMode=Standard +CurveMode2=Standard +Curve=1;0;0;0.88544601940051371;1; +Curve2=1;0;0;0.0397505754145333;0.020171771436200074;0.54669745433149319;0.69419974733677647;1;1; + +[HLRecovery] +Enabled=false +Method=Blend + +[Black & White] +Enabled=true + +[Crop] +FixedRatio=false + +[Color Management] +InputProfile=(camera) +ToneCurve=false +ApplyLookTable=false +ApplyHueSatMap=false +WorkingProfile=Rec2020 +WorkingTRC=none + +[RAW Bayer] +Method=rcd + +[Film Negative] +Enabled=true +RedRatio=1.0 +GreenExponent=1.5 +BlueRatio=1.0 +ColorSpace=1 +RefInput=0;0;0; +RefOutput=0;0;0; +BackCompat=0 From 53bb6e41bb1f4052bb85048fe72499cabcdcb1ec Mon Sep 17 00:00:00 2001 From: Desmis Date: Thu, 22 Apr 2021 07:15:28 +0200 Subject: [PATCH 034/135] LA other bad behavior Duplicate spot when spot outside preview --- rtgui/locallab.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc index 71e55202d..6f59d3b0f 100644 --- a/rtgui/locallab.cc +++ b/rtgui/locallab.cc @@ -740,6 +740,7 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited } else { r->shapeMethod = 3; } + //printf("n0=%f n1=%f n2=%f n3=%f\n", (double) newSpot->loc.at(0), (double) newSpot->loc.at(1), (double) newSpot->loc.at(2), (double) newSpot->loc.at(3)); // Calculate spot size and center position according to preview area if (provider && !batchMode) { @@ -752,10 +753,12 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited newSpot->centerX = rtengine::LIM(int(int((double)prX - (double)imW / 2.) * 2000. / (double)imW), -1000, 1000); newSpot->centerY = rtengine::LIM(int(int((double)prY - (double)imH / 2.) * 2000. / (double)imH), -1000, 1000); // Ellipse/rectangle size computation + /* newSpot->loc.at(0) = rtengine::LIM(int(((double)prW / 2. - 5.) * 2000. / (double)imW), 2, newSpot->loc.at(0)); newSpot->loc.at(1) = rtengine::LIM(int(((double)prW / 2. - 5.) * 2000. / (double)imW), 2, newSpot->loc.at(1)); newSpot->loc.at(2) = rtengine::LIM(int(((double)prH / 2. - 5.) * 2000. / (double)imH), 2, newSpot->loc.at(2)); newSpot->loc.at(3) = rtengine::LIM(int(((double)prH / 2. - 5.) * 2000. / (double)imH), 2, newSpot->loc.at(3)); + */ } } From 2061cfc54e6ba856708290a46b7ef9710b307591 Mon Sep 17 00:00:00 2001 From: Simon Segerblom Rex Date: Thu, 22 Apr 2021 14:35:32 +0200 Subject: [PATCH 035/135] Fix predictor modes 2-7 for lossless JPEG Predictor modes 2-7 were broken. I just copy-pasted this line from dcraw.c After this fix it should be possible to remove lj92 (the lib + lossless_dnglj92_load_raw) and always use lossless_dng_load_raw. --- rtengine/dcraw.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 275b35d81..144fcd0ee 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -923,7 +923,7 @@ ushort * CLASS ljpeg_row (int jrow, struct jhead *jh) } getbits(-1); } - FORC3 row[c] = (jh->row + ((jrow & 1) + 1) * (jh->wide*jh->clrs*((jrow+c) & 1))); + FORC3 row[c] = jh->row + jh->wide*jh->clrs*((jrow+c) & 1); for (col=0; col < jh->wide; col++) FORC(jh->clrs) { diff = ljpeg_diff (jh->huff[c]); @@ -9078,7 +9078,7 @@ void CLASS adobe_coeff (const char *make, const char *model) RT_matrix_from_constant = ThreeValBool::T; } // -- RT -------------------------------------------------------------------- - + for (i=0; i < sizeof table / sizeof *table; i++) if (!strncmp (name, table[i].prefix, strlen(table[i].prefix))) { if (RT_blacklevel_from_constant == ThreeValBool::T && table[i].black) black = (ushort) table[i].black; From 58995a052db23009db3c8341a0f189163d0f3f7a Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 25 Apr 2021 15:44:49 -0700 Subject: [PATCH 036/135] Properly enable inspector window for film strip --- rtgui/filebrowserentry.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc index 432296f38..5e8c730aa 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -294,7 +294,7 @@ bool FileBrowserEntry::motionNotify (int x, int y) Inspector* inspector = parent->getInspector(); - if (inspector && inspector->isActive() && !parent->isInTabMode()) { + if (inspector && inspector->isActive() && (!parent->isInTabMode() || options.inspectorWindow)) { const rtengine::Coord2D coord(getPosInImgSpace(x, y)); if (coord.x != -1.) { From 61aba8ad08f17f7fe3091725ca8c790518266c61 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 25 Apr 2021 15:48:29 -0700 Subject: [PATCH 037/135] Set inspector window title from language files --- rtdata/languages/default | 1 + rtgui/inspector.cc | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 595f03e7e..abc5f1609 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1462,6 +1462,7 @@ ICCPROFCREATOR_PROF_V4;ICC v4 ICCPROFCREATOR_SAVEDIALOG_TITLE;Save ICC profile as... ICCPROFCREATOR_SLOPE;Slope ICCPROFCREATOR_TRC_PRESET;Tone response curve +INSPECTOR_WINDOW_TITLE;Inspector IPTCPANEL_CATEGORY;Category IPTCPANEL_CATEGORYHINT;Identifies the subject of the image in the opinion of the provider. IPTCPANEL_CITY;City diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 37ed20207..711a96615 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -21,6 +21,7 @@ #include #include "cursormanager.h" #include "guiutils.h" +#include "multilangmgr.h" #include "options.h" #include "pathutils.h" #include "rtscalable.h" @@ -91,7 +92,7 @@ Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomSca } else { window = new Gtk::Window(); - window->set_title("RawTherapee Inspector"); + window->set_title("RawTherapee " + M("INSPECTOR_WINDOW_TITLE")); window->set_visible(false); window->add_events(Gdk::KEY_PRESS_MASK); window->signal_key_release_event().connect(sigc::mem_fun(*this, &Inspector::on_key_release)); From 67e18b5c53fc24de2fec155d59623937f80328e1 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 25 Apr 2021 17:05:02 -0700 Subject: [PATCH 038/135] Fix inspector window sometimes not hiding When the f shortcut is quickly pressed, the inspector window will sometimes open and remain open even though it should automatically close. This commit ensures the window closes by capturing the f key release event from the main window in addition to the inspector window. --- rtgui/filecatalog.cc | 15 +++++++++++++++ rtgui/filecatalog.h | 1 + rtgui/filepanel.cc | 9 +++++++++ rtgui/filepanel.h | 1 + rtgui/inspector.cc | 5 +++++ rtgui/inspector.h | 5 +++++ rtgui/rtwindow.cc | 9 +++++++++ rtgui/rtwindow.h | 1 + 8 files changed, 46 insertions(+) diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index dbea4ade9..cdcb00195 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -2524,6 +2524,21 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) return fileBrowser->keyPressed(event); } +bool FileCatalog::handleShortcutKeyRelease(GdkEventKey* event) +{ + bool ctrl = event->state & GDK_CONTROL_MASK; + bool alt = event->state & GDK_MOD1_MASK; + + if (!ctrl && !alt) { + switch (event->keyval) { + case GDK_KEY_f: + case GDK_KEY_F: + fileBrowser->getInspector()->hideWindow(); + return true; + } + } +} + void FileCatalog::showToolBar() { if (hbToolBar1STB) { diff --git a/rtgui/filecatalog.h b/rtgui/filecatalog.h index c7c4f3155..23d56af73 100644 --- a/rtgui/filecatalog.h +++ b/rtgui/filecatalog.h @@ -276,6 +276,7 @@ public: void openNextPreviousEditorImage (Glib::ustring fname, bool clearFilters, eRTNav nextPrevious); bool handleShortcutKey (GdkEventKey* event); + bool handleShortcutKeyRelease(GdkEventKey *event); bool CheckSidePanelsVisibility(); void toggleSidePanels(); diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc index a09a82597..974482f41 100644 --- a/rtgui/filepanel.cc +++ b/rtgui/filepanel.cc @@ -412,6 +412,15 @@ bool FilePanel::handleShortcutKey (GdkEventKey* event) return false; } +bool FilePanel::handleShortcutKeyRelease(GdkEventKey *event) +{ + if(fileCatalog->handleShortcutKeyRelease(event)) { + return true; + } + + return false; +} + void FilePanel::loadingThumbs(Glib::ustring str, double rate) { GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected diff --git a/rtgui/filepanel.h b/rtgui/filepanel.h index 65e1ea548..ba5dfa7c9 100644 --- a/rtgui/filepanel.h +++ b/rtgui/filepanel.h @@ -81,6 +81,7 @@ public: bool imageLoaded( Thumbnail* thm, ProgressConnector * ); bool handleShortcutKey (GdkEventKey* event); + bool handleShortcutKeyRelease(GdkEventKey *event); void updateTPVScrollbar (bool hide); private: diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 711a96615..7ca0b92d0 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -144,6 +144,11 @@ void Inspector::showWindow(bool scaled, bool fullscreen) mouseMove(next_image_pos, 0); } +void Inspector::hideWindow() +{ + window->set_visible(false); +} + bool Inspector::on_key_release(GdkEventKey *event) { if (!window) diff --git a/rtgui/inspector.h b/rtgui/inspector.h index 726bc947c..52c95d14c 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -91,6 +91,11 @@ public: */ void showWindow(bool scaled, bool fullscreen = true); + /** + * Hide the window. + */ + void hideWindow(); + /** @brief Mouse movement to a new position * @param pos Location of the mouse, in percentage (i.e. [0;1] range) relative to the full size image ; -1,-1 == out of the image * @param transform H/V flip and coarse rotation transformation diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index c0042f949..cf77374ce 100644 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -285,6 +285,7 @@ RTWindow::RTWindow () property_destroy_with_parent().set_value (false); signal_window_state_event().connect ( sigc::mem_fun (*this, &RTWindow::on_window_state_event) ); signal_key_press_event().connect ( sigc::mem_fun (*this, &RTWindow::keyPressed) ); + signal_key_release_event().connect(sigc::mem_fun(*this, &RTWindow::keyReleased)); if (simpleEditor) { epanel = Gtk::manage ( new EditorPanel (nullptr) ); @@ -756,6 +757,14 @@ bool RTWindow::keyPressed (GdkEventKey* event) return false; } +bool RTWindow::keyReleased(GdkEventKey *event) +{ + if (mainNB->get_current_page() == mainNB->page_num(*fpanel)) { + return fpanel->handleShortcutKeyRelease(event); + } + return false; +} + void RTWindow::addBatchQueueJob (BatchQueueEntry* bqe, bool head) { diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h index e5e180747..aa1830d89 100644 --- a/rtgui/rtwindow.h +++ b/rtgui/rtwindow.h @@ -85,6 +85,7 @@ public: void addBatchQueueJobs (const std::vector& entries); bool keyPressed (GdkEventKey* event); + bool keyReleased(GdkEventKey *event); bool on_configure_event (GdkEventConfigure* event) override; bool on_delete_event (GdkEventAny* event) override; bool on_window_state_event (GdkEventWindowState* event) override; From d4bceb5c06b256debf76051a5e2da4108bc253ca Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 25 Apr 2021 17:27:57 -0700 Subject: [PATCH 039/135] Pin inspector window if opened with context menu --- rtgui/filebrowser.cc | 2 +- rtgui/inspector.cc | 4 ++-- rtgui/inspector.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 0d2451b59..0246520ee 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -2100,5 +2100,5 @@ void FileBrowser::openRequested( std::vector mselected) void FileBrowser::inspectRequested(std::vector mselected) { - getInspector()->showWindow(false, false); + getInspector()->showWindow(false, false, true); } diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 7ca0b92d0..242ebac24 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -117,7 +117,7 @@ Inspector::~Inspector() delete window; } -void Inspector::showWindow(bool scaled, bool fullscreen) +void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) { if (!window) return; @@ -137,7 +137,7 @@ void Inspector::showWindow(bool scaled, bool fullscreen) window->unfullscreen(); this->fullscreen = fullscreen; window->set_visible(true); - pinned = false; + this->pinned = pinned; // update content when becoming visible switchImage(next_image_path); diff --git a/rtgui/inspector.h b/rtgui/inspector.h index 52c95d14c..62bcef471 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -89,7 +89,7 @@ public: /** @brief Show or hide window * @param scaled fit image into window */ - void showWindow(bool scaled, bool fullscreen = true); + void showWindow(bool scaled, bool fullscreen = true, bool pinned = false); /** * Hide the window. From 900af7aeb7c9e9ba71c0a2e4d489f7b853790cd3 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 25 Apr 2021 18:11:47 -0700 Subject: [PATCH 040/135] Remove drawn background in inspector window Add "InspectorWindow" CSS ID so that the background color can be changed through CSS. --- rtgui/inspector.cc | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 242ebac24..c43e3863e 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -92,6 +92,7 @@ Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomSca } else { window = new Gtk::Window(); + window->set_name("InspectorWindow"); window->set_title("RawTherapee " + M("INSPECTOR_WINDOW_TITLE")); window->set_visible(false); window->add_events(Gdk::KEY_PRESS_MASK); @@ -450,15 +451,6 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) // draw the background style->render_background(cr, 0, 0, get_width(), get_height()); } - else { - ///* --- old method (the new method does not seem to work) - c = style->get_background_color (Gtk::STATE_FLAG_NORMAL); - cr->set_source_rgb (c.get_red(), c.get_green(), c.get_blue()); - cr->set_line_width (0); - cr->rectangle (0, 0, availableSize.x, availableSize.y); - cr->fill (); - //*/ - } bool scaledImage = scale != 1.0; if (!window || (deviceScale == 1 && !scaledImage)) { From 8c477ffb8b813012a5a8de1ce0e47b43dd93d799 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Fri, 30 Apr 2021 10:21:04 +0200 Subject: [PATCH 041/135] Fix bug in `DFManager::addFileInfo()` This was caught by GCC 11.1. --- rtengine/dfmanager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/dfmanager.cc b/rtengine/dfmanager.cc index 6961a4b54..7dde668eb 100644 --- a/rtengine/dfmanager.cc +++ b/rtengine/dfmanager.cc @@ -367,7 +367,7 @@ dfInfo* DFManager::addFileInfo (const Glib::ustring& filename, bool pool) auto info = file->query_info("standard::name,standard::type,standard::is-hidden"); - if (!info && info->get_file_type() == Gio::FILE_TYPE_DIRECTORY) { + if (!info || info->get_file_type() == Gio::FILE_TYPE_DIRECTORY) { return nullptr; } From 5decec540542a9769f410a6ab50265a59a771b81 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 1 May 2021 15:48:50 -0700 Subject: [PATCH 042/135] Fix inspector window zoom centering Use floating point coordinates instead of integers to avoid rounding errors. --- rtgui/inspector.cc | 59 +++++++++++++++++++++++++++++----------------- rtgui/inspector.h | 5 ++-- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index c43e3863e..d212787df 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -333,8 +333,17 @@ void Inspector::beginZoom(double x, double y) moveCenter(0, 0, imW, imH, deviceScale); // store center and current position for zooming - dcenterBegin.x = (x - window->get_width()/2) / scale * deviceScale; - dcenterBegin.y = (y - window->get_height()/2) / scale * deviceScale; + double cur_scale = zoomScale; + if (scaled) { + Glib::RefPtr win = get_window(); + double winW = win->get_width() * deviceScale; + double winH = win->get_height() * deviceScale; + int imW = rtengine::max(currImage->imgBuffer.getWidth(), 1); + int imH = rtengine::max(currImage->imgBuffer.getHeight(), 1); + cur_scale *= rtengine::min(winW / imW, winH / imH); + } + dcenterBegin.x = (x - window->get_width() / 2.) / cur_scale * deviceScale; + dcenterBegin.y = (y - window->get_height() / 2.) / cur_scale * deviceScale; centerBegin = center; zoomScaleBegin = zoomScale; @@ -385,15 +394,16 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) // this will eventually create/update the off-screen pixmap // compute the displayed area - rtengine::Coord availableSize; - rtengine::Coord topLeft; - rtengine::Coord dest(0, 0); + rtengine::Coord2D availableSize; + rtengine::Coord2D topLeft; + rtengine::Coord topLeftInt; + rtengine::Coord2D dest(0, 0); int deviceScale = window? get_scale_factor(): 1; availableSize.x = win->get_width() * deviceScale; availableSize.y = win->get_height() * deviceScale; int imW = rtengine::max(currImage->imgBuffer.getWidth(), 1); int imH = rtengine::max(currImage->imgBuffer.getHeight(), 1); - scale = rtengine::min((double)availableSize.x / imW, (double)availableSize.y / imH); + scale = rtengine::min(availableSize.x / imW, availableSize.y / imH); if (scaled) { // reduce size of image to fit into window, no further zoom down zoomScale = rtengine::max(zoomScale, 1.0); @@ -410,33 +420,36 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) if (imW < availableSize.x) { // center the image in the available space along X topLeft.x = 0; - dest.x = (availableSize.x - imW) / 2; + dest.x = (availableSize.x - imW) / 2.; } else { // partial image display // double clamp - topLeft.x = center.x + availableSize.x / 2; - topLeft.x = rtengine::min(topLeft.x, imW); + topLeft.x = center.x + availableSize.x / 2.; + topLeft.x = rtengine::min(topLeft.x, imW); topLeft.x -= availableSize.x; - topLeft.x = rtengine::max(topLeft.x, 0); + topLeft.x = rtengine::max(topLeft.x, 0); } if (imH < availableSize.y) { // center the image in the available space along Y topLeft.y = 0; - dest.y = (availableSize.y - imH) / 2; + dest.y = (availableSize.y - imH) / 2.; } else { // partial image display // double clamp - topLeft.y = center.y + availableSize.y / 2; - topLeft.y = rtengine::min(topLeft.y, imH); + topLeft.y = center.y + availableSize.y / 2.; + topLeft.y = rtengine::min(topLeft.y, imH); topLeft.y -= availableSize.y; - topLeft.y = rtengine::max(topLeft.y, 0); + topLeft.y = rtengine::max(topLeft.y, 0); } //printf("center: %d, %d (img: %d, %d) (availableSize: %d, %d) (topLeft: %d, %d)\n", center.x, center.y, imW, imH, availableSize.x, availableSize.y, topLeft.x, topLeft.y); + topLeftInt.x = floor(topLeft.x); + topLeftInt.y = floor(topLeft.y); + // define the destination area - currImage->imgBuffer.setDrawRectangle(win, dest.x, dest.y, rtengine::min(availableSize.x - dest.x, imW), rtengine::min(availableSize.y - dest.y, imH), false); - currImage->imgBuffer.setSrcOffset(topLeft.x, topLeft.y); + currImage->imgBuffer.setDrawRectangle(win, dest.x, dest.y, rtengine::min(ceil(availableSize.x + (topLeft.x - topLeftInt.x) - 2 * dest.x), imW), rtengine::min(ceil(availableSize.y + (topLeft.y - topLeftInt.y) - 2 * dest.y), imH), false); + currImage->imgBuffer.setSrcOffset(topLeftInt.x, topLeftInt.y); if (!currImage->imgBuffer.surfaceCreated()) { return false; @@ -464,16 +477,18 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) cairo_surface_set_device_scale(cr->get_target()->cobj(), scale, scale); scaledImage = false; } - int viewW = rtengine::min(imW, availableSize.x); - int viewH = rtengine::min(imH, availableSize.y); - Glib::RefPtr crop = Gdk::Pixbuf::create(currImage->imgBuffer.getSurface(), topLeft.x, topLeft.y, viewW, viewH); + int viewW = rtengine::min(imW, ceil(availableSize.x + (topLeft.x - topLeftInt.x))); + int viewH = rtengine::min(imH, ceil(availableSize.y + (topLeft.y - topLeftInt.y))); + Glib::RefPtr crop = Gdk::Pixbuf::create(currImage->imgBuffer.getSurface(), topLeftInt.x, topLeftInt.y, viewW, viewH); if (!scaledImage) { Gdk::Cairo::set_source_pixbuf(cr, crop, dest.x, dest.y); } else { + double dx = scale * (dest.x + topLeftInt.x - topLeft.x); + double dy = scale * (dest.y + topLeftInt.y - topLeft.y); // scale crop as the device does not seem to support it (Linux) - crop = crop->scale_simple(viewW*scale, viewH*scale, Gdk::INTERP_BILINEAR); - Gdk::Cairo::set_source_pixbuf(cr, crop, dest.x*scale, dest.y*scale); + crop = crop->scale_simple(round(viewW*scale), round(viewH*scale), Gdk::INTERP_BILINEAR); + Gdk::Cairo::set_source_pixbuf(cr, crop, dx, dy); } cr->paint(); } @@ -504,7 +519,7 @@ void Inspector::mouseMove (rtengine::Coord2D pos, int transform) return; if (currImage) { - center.set(int(rtengine::LIM01(pos.x)*double(currImage->imgBuffer.getWidth())), int(rtengine::LIM01(pos.y)*double(currImage->imgBuffer.getHeight()))); + center.set(rtengine::LIM01(pos.x)*double(currImage->imgBuffer.getWidth()), rtengine::LIM01(pos.y)*double(currImage->imgBuffer.getHeight())); } else { center.set(0, 0); } diff --git a/rtgui/inspector.h b/rtgui/inspector.h index 62bcef471..b17d199bf 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -22,7 +22,6 @@ #include "guiutils.h" -#include "../rtengine/coord.h" #include "../rtengine/coord2d.h" class InspectorBuffer @@ -44,13 +43,13 @@ class Inspector final : public Gtk::DrawingArea { private: - rtengine::Coord center; + rtengine::Coord2D center; std::vector images; InspectorBuffer* currImage; bool scaled; // fit image into window double scale; // current scale double zoomScale, zoomScaleBegin; // scale during zoom - rtengine::Coord centerBegin, dcenterBegin; // center during zoom + rtengine::Coord2D centerBegin, dcenterBegin; // center during zoom bool active; bool pinned; bool dirty; From e25cb3fde0665f1060e9fa6d8dba2414671002d3 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 1 May 2021 15:52:45 -0700 Subject: [PATCH 043/135] Fix inspector window panning speed Consistently use integers for mouse movement and compensate for image scale. --- rtgui/inspector.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index d212787df..59378b9d2 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -227,13 +227,15 @@ bool Inspector::on_motion_notify_event(GdkEventMotion *event) return false; int deviceScale = get_scale_factor(); - int delta_x = (button_pos.x - event->x)*deviceScale; - int delta_y = (button_pos.y - event->y)*deviceScale; + int event_x = round(event->x); + int event_y = round(event->y); + int delta_x = (button_pos.x - event_x) * deviceScale; + int delta_y = (button_pos.y - event_y) * deviceScale; int imW = currImage->imgBuffer.getWidth(); int imH = currImage->imgBuffer.getHeight(); moveCenter(delta_x, delta_y, imW, imH, deviceScale); - button_pos.set(event->x, event->y); + button_pos.set(event_x, event_y); if (!dirty) { dirty = true; @@ -316,8 +318,8 @@ void Inspector::moveCenter(int delta_x, int delta_y, int imW, int imH, int devic rtengine::Coord margin; // limit to image size margin.x = rtengine::min(window->get_width() * deviceScale / scale, imW) / 2; margin.y = rtengine::min(window->get_height() * deviceScale / scale, imH) / 2; - center.set(rtengine::LIM(center.x + delta_x, margin.x, imW - margin.x), - rtengine::LIM(center.y + delta_y, margin.y, imH - margin.y)); + center.set(rtengine::LIM(center.x + delta_x / scale, margin.x, imW - margin.x), + rtengine::LIM(center.y + delta_y / scale, margin.y, imH - margin.y)); } void Inspector::beginZoom(double x, double y) From b99b9302cce5a8e175fc7faf87edc6c745f22fd3 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 2 May 2021 12:31:33 -0700 Subject: [PATCH 044/135] Fix inspector window scaling with caps lock When launched with the accelerator key, the inspector window initially scales the image without respecting the state of the caps lock. This commit fixes the bug. --- rtgui/filecatalog.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index cdcb00195..d0316a2d4 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -2515,8 +2515,10 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) if (!ctrl && !alt) { switch (event->keyval) { case GDK_KEY_f: + fileBrowser->getInspector()->showWindow(true); + return true; case GDK_KEY_F: - fileBrowser->getInspector()->showWindow(!shift); + fileBrowser->getInspector()->showWindow(false); return true; } } From 4811f92c399a5941175591c578f30baffe9cb8ec Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 2 May 2021 12:35:05 -0700 Subject: [PATCH 045/135] Add missing return statement --- rtgui/filecatalog.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index d0316a2d4..a685bebe9 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -2539,6 +2539,8 @@ bool FileCatalog::handleShortcutKeyRelease(GdkEventKey* event) return true; } } + + return false; } void FileCatalog::showToolBar() From de9403f9fe27c9d36cb48cbac4663952301e581c Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 2 May 2021 12:52:15 -0700 Subject: [PATCH 046/135] Ignore key down repeat events in inspector window Ignore key press events that happen when a key is held down. --- rtgui/inspector.cc | 12 +++++++++++- rtgui/inspector.h | 1 + 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 59378b9d2..e0da8378e 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -83,7 +83,7 @@ InspectorBuffer::~InspectorBuffer() { // return deg; //} -Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false) +Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false), keyDown(false) { set_name("Inspector"); @@ -152,6 +152,8 @@ void Inspector::hideWindow() bool Inspector::on_key_release(GdkEventKey *event) { + keyDown = false; + if (!window) return false; @@ -172,6 +174,12 @@ bool Inspector::on_key_press(GdkEventKey *event) if (!window) return false; + if (keyDown) { + return true; + } + + keyDown = true; + switch (event->keyval) { case GDK_KEY_z: case GDK_KEY_F: @@ -203,6 +211,8 @@ bool Inspector::on_key_press(GdkEventKey *event) return true; } + keyDown = false; + return false; } diff --git a/rtgui/inspector.h b/rtgui/inspector.h index b17d199bf..4d5e5e835 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -55,6 +55,7 @@ private: bool dirty; bool initialized; bool fullscreen; // window is shown in fullscreen mode + bool keyDown; sigc::connection delayconn; Glib::ustring next_image_path; From bce88478c47731eca702d65fc0baaf88d44855ce Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 2 May 2021 15:50:55 -0700 Subject: [PATCH 047/135] Fix inspector window rendering with device scaling --- rtgui/inspector.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index e0da8378e..c8d9c8bd2 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -485,9 +485,13 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) else { // consider device scale and image scale if (deviceScale > 1) { +#ifdef __APPLE__ // use full device resolution and let it scale the image (macOS) cairo_surface_set_device_scale(cr->get_target()->cobj(), scale, scale); scaledImage = false; +#else + cr->scale(1. / deviceScale, 1. / deviceScale); +#endif } int viewW = rtengine::min(imW, ceil(availableSize.x + (topLeft.x - topLeftInt.x))); int viewH = rtengine::min(imH, ceil(availableSize.y + (topLeft.y - topLeftInt.y))); From 70d30a5050e6784f8b118eb088704df068fc30ea Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 2 May 2021 15:57:34 -0700 Subject: [PATCH 048/135] Fix crash after pressing `f` key in file browser Check that the inspector window exists before trying to close it. --- rtgui/inspector.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index c8d9c8bd2..2de324b29 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -147,6 +147,9 @@ void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) void Inspector::hideWindow() { + if (!window) { + return; + } window->set_visible(false); } From 87869e2bb1b7c9a451d1f0324b005c4567372f10 Mon Sep 17 00:00:00 2001 From: Simon Segerblom Rex Date: Fri, 30 Apr 2021 08:09:16 +0200 Subject: [PATCH 049/135] Remove lj92 library and use dcraw instead dcraw works fine for decoding DNGs using any predictor mode for the lossless JPEG compression. No need to maintain two different implemenations. --- rtengine/CMakeLists.txt | 1 - rtengine/dcraw.cc | 58 +--- rtengine/dcraw.h | 1 - rtengine/lj92.c | 711 ---------------------------------------- rtengine/lj92.h | 68 ---- 5 files changed, 1 insertion(+), 838 deletions(-) delete mode 100644 rtengine/lj92.c delete mode 100644 rtengine/lj92.h diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index ee575ae47..d87bcca0f 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -139,7 +139,6 @@ set(RTENGINESOURCEFILES jpeg_ijg/jpeg_memsrc.cc labimage.cc lcp.cc - lj92.c lmmse_demosaic.cc loadinitial.cc munselllch.cc diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 144fcd0ee..ea15cefbe 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -21,7 +21,6 @@ /*RT*/#define LOCALTIME /*RT*/#define DJGPP /*RT*/#include "jpeg.h" -/*RT*/#include "lj92.h" /*RT*/#ifdef _OPENMP /*RT*/#include /*RT*/#endif @@ -1126,61 +1125,6 @@ void CLASS ljpeg_idct (struct jhead *jh) FORC(64) jh->idct[c] = CLIP(((float *)work[2])[c]+0.5); } -void CLASS lossless_dnglj92_load_raw() -{ - BENCHFUN - - tiff_bps = 16; - - int save = ifp->pos; - uint16_t *lincurve = !strncmp(make,"Blackmagic",10) ? curve : nullptr; - tile_width = tile_length < INT_MAX ? tile_width : raw_width; - size_t tileCount = raw_width / tile_width; - - size_t dataOffset[tileCount]; - if(tile_length < INT_MAX) { - for (size_t t = 0; t < tileCount; ++t) { - dataOffset[t] = get4(); - } - } else { - dataOffset[0] = ifp->pos; - } - const int data_length = ifp->size; - const std::unique_ptr data(new uint8_t[data_length]); - fseek(ifp, 0, SEEK_SET); - // read whole file - fread(data.get(), 1, data_length, ifp); - lj92 lj; - int newwidth, newheight, newbps; - lj92_open(&lj, &data[dataOffset[0]], data_length, &newwidth, &newheight, &newbps); - lj92_close(lj); - if (newwidth * newheight * tileCount != raw_width * raw_height) { - // not a lj92 file - fseek(ifp, save, SEEK_SET); - lossless_dng_load_raw(); - return; - } - -#ifdef _OPENMP - #pragma omp parallel for num_threads(std::min(tileCount, omp_get_max_threads())) -#endif - for (size_t t = 0; t < tileCount; ++t) { - size_t tcol = t * tile_width; - lj92 lj; - int newwidth, newheight, newbps; - lj92_open(&lj, &data[dataOffset[t]], data_length, &newwidth, &newheight, &newbps); - - const std::unique_ptr target(new uint16_t[newwidth * newheight]); - lj92_decode(lj, target.get(), tile_width, 0, lincurve, 0x1000); - for (int y = 0; y < height; ++y) { - for(int x = 0; x < tile_width; ++x) { - RAW(y, x + tcol) = target[y * tile_width + x]; - } - } - lj92_close(lj); - } -} - void CLASS lossless_dng_load_raw() { unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col, i, j; @@ -9768,7 +9712,7 @@ void CLASS identify() switch (tiff_compress) { case 0: case 1: load_raw = &CLASS packed_dng_load_raw; break; - case 7: load_raw = (!strncmp(make,"Blackmagic",10) || !strncmp(make,"Canon",5)) ? &CLASS lossless_dnglj92_load_raw : &CLASS lossless_dng_load_raw; break; + case 7: load_raw = &CLASS lossless_dng_load_raw; break; case 8: load_raw = &CLASS deflate_dng_load_raw; break; case 34892: load_raw = &CLASS lossy_dng_load_raw; break; default: load_raw = 0; diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index 89c1fcaff..10c7b9ba6 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -329,7 +329,6 @@ void ljpeg_idct (struct jhead *jh); void canon_sraw_load_raw(); void adobe_copy_pixel (unsigned row, unsigned col, ushort **rp); void lossless_dng_load_raw(); -void lossless_dnglj92_load_raw(); void packed_dng_load_raw(); void deflate_dng_load_raw(); void init_fuji_compr(struct fuji_compressed_params* info); diff --git a/rtengine/lj92.c b/rtengine/lj92.c deleted file mode 100644 index 1e0e8cb80..000000000 --- a/rtengine/lj92.c +++ /dev/null @@ -1,711 +0,0 @@ -/* -lj92.c -(c) Andrew Baldwin 2014 - -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 -#include -#include -#include - -#include "lj92.h" - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; - -//#define SLOW_HUFF -//#define DEBUG - -typedef struct _ljp { - u8* data; - u8* dataend; - int datalen; - int scanstart; - int ix; - int x; // Width - int y; // Height - int bits; // Bit depth - int writelen; // Write rows this long - int skiplen; // Skip this many values after each row - u16* linearize; // Linearization table - int linlen; - int sssshist[16]; - - // Huffman table - only one supported, and probably needed -#ifdef SLOW_HUFF - int* maxcode; - int* mincode; - int* valptr; - u8* huffval; - int* huffsize; - int* huffcode; -#else - u16* hufflut; - int huffbits; -#endif - // Parse state - int cnt; - u32 b; - u16* image; - u16* rowcache; - u16* outrow[2]; -} ljp; - -static int find(ljp* self) { - int ix = self->ix; - u8* data = self->data; - while (data[ix] != 0xFF && ix<(self->datalen-1)) { - ix += 1; - } - ix += 2; - if (ix>=self->datalen) return -1; - self->ix = ix; - return data[ix-1]; -} - -#define BEH(ptr) ((((int)(*&ptr))<<8)|(*(&ptr+1))) - -static int parseHuff(ljp* self) { - int ret = LJ92_ERROR_CORRUPT; - u8* huffhead = &self->data[self->ix]; // xstruct.unpack('>HB16B',self.data[self.ix:self.ix+19]) - u8* bits = &huffhead[2]; - bits[0] = 0; // Because table starts from 1 - unsigned int hufflen = BEH(huffhead[0]); - if ((self->ix + hufflen) >= self->datalen) return ret; -#ifdef SLOW_HUFF - u8* huffval = calloc(hufflen - 19,sizeof(u8)); - if (huffval == NULL) return LJ92_ERROR_NO_MEMORY; - self->huffval = huffval; - for (int hix=0;hix<(hufflen-19);hix++) { - huffval[hix] = self->data[self->ix+19+hix]; -#ifdef DEBUG - printf("huffval[%d]=%d\n",hix,huffval[hix]); -#endif - } - self->ix += hufflen; - // Generate huffman table - int k = 0; - int i = 1; - int j = 1; - int huffsize_needed = 1; - // First calculate how long huffsize needs to be - while (i<=16) { - while (j<=bits[i]) { - huffsize_needed++; - k = k+1; - j = j+1; - } - i = i+1; - j = 1; - } - // Now allocate and do it - int* huffsize = calloc(huffsize_needed,sizeof(int)); - if (huffsize == NULL) return LJ92_ERROR_NO_MEMORY; - self->huffsize = huffsize; - k = 0; - i = 1; - j = 1; - // First calculate how long huffsize needs to be - int hsix = 0; - while (i<=16) { - while (j<=bits[i]) { - huffsize[hsix++] = i; - k = k+1; - j = j+1; - } - i = i+1; - j = 1; - } - huffsize[hsix++] = 0; - - // Calculate the size of huffcode array - int huffcode_needed = 0; - k = 0; - int code = 0; - int si = huffsize[0]; - while (1) { - while (huffsize[k] == si) { - huffcode_needed++; - code = code+1; - k = k+1; - } - if (huffsize[k] == 0) - break; - while (huffsize[k] != si) { - code = code << 1; - si = si + 1; - } - } - // Now fill it - int* huffcode = calloc(huffcode_needed,sizeof(int)); - if (huffcode == NULL) return LJ92_ERROR_NO_MEMORY; - self->huffcode = huffcode; - int hcix = 0; - k = 0; - code = 0; - si = huffsize[0]; - while (1) { - while (huffsize[k] == si) { - huffcode[hcix++] = code; - code = code+1; - k = k+1; - } - if (huffsize[k] == 0) - break; - while (huffsize[k] != si) { - code = code << 1; - si = si + 1; - } - } - - i = 0; - j = 0; - - int* maxcode = calloc(17,sizeof(int)); - if (maxcode == NULL) return LJ92_ERROR_NO_MEMORY; - self->maxcode = maxcode; - int* mincode = calloc(17,sizeof(int)); - if (mincode == NULL) return LJ92_ERROR_NO_MEMORY; - self->mincode = mincode; - int* valptr = calloc(17,sizeof(int)); - if (valptr == NULL) return LJ92_ERROR_NO_MEMORY; - self->valptr = valptr; - - while (1) { - while (1) { - i++; - if (i>16) - break; - if (bits[i]!=0) - break; - maxcode[i] = -1; - } - if (i>16) - break; - valptr[i] = j; - mincode[i] = huffcode[j]; - j = j+bits[i]-1; - maxcode[i] = huffcode[j]; - j++; - } - free(huffsize); - self->huffsize = NULL; - free(huffcode); - self->huffcode = NULL; - ret = LJ92_ERROR_NONE; -#else - /* Calculate huffman direct lut */ - // How many bits in the table - find highest entry - u8* huffvals = &self->data[self->ix+19]; - int maxbits = 16; - while (maxbits>0) { - if (bits[maxbits]) break; - maxbits--; - } - self->huffbits = maxbits; - /* Now fill the lut */ - u16* hufflut = (u16*)malloc((1<hufflut = hufflut; - int i = 0; - int hv = 0; - int rv = 0; - int vl = 0; // i - int hcode; - int bitsused = 1; -#ifdef DEBUG - printf("%04x:%x:%d:%x\n",i,huffvals[hv],bitsused,1<<(maxbits-bitsused)); -#endif - while (i<1<maxbits) { - break; // Done. Should never get here! - } - if (vl >= bits[bitsused]) { - bitsused++; - vl = 0; - continue; - } - if (rv == 1 << (maxbits-bitsused)) { - rv = 0; - vl++; - hv++; -#ifdef DEBUG - printf("%04x:%x:%d:%x\n",i,huffvals[hv],bitsused,1<<(maxbits-bitsused)); -#endif - continue; - } - hcode = huffvals[hv]; - hufflut[i] = hcode<<8 | bitsused; - //printf("%d %d %d\n",i,bitsused,hcode); - i++; - rv++; - } - ret = LJ92_ERROR_NONE; -#endif - return ret; -} - -static int parseSof3(ljp* self) { - if (self->ix+6 >= self->datalen) return LJ92_ERROR_CORRUPT; - self->y = BEH(self->data[self->ix+3]); - self->x = BEH(self->data[self->ix+5]); - self->bits = self->data[self->ix+2]; - self->ix += BEH(self->data[self->ix]); - return LJ92_ERROR_NONE; -} - -static int parseBlock(ljp* self,int marker) { - self->ix += BEH(self->data[self->ix]); - if (self->ix >= self->datalen) return LJ92_ERROR_CORRUPT; - return LJ92_ERROR_NONE; -} - -#ifdef SLOW_HUFF -static int nextbit(ljp* self) { - u32 b = self->b; - if (self->cnt == 0) { - u8* data = &self->data[self->ix]; - u32 next = *data++; - b = next; - if (next == 0xff) { - data++; - self->ix++; - } - self->ix++; - self->cnt = 8; - } - int bit = b >> 7; - self->cnt--; - self->b = (b << 1)&0xFF; - return bit; -} - -static int decode(ljp* self) { - int i = 1; - int code = nextbit(self); - while (code > self->maxcode[i]) { - i++; - code = (code << 1) + nextbit(self); - } - int j = self->valptr[i]; - j = j + code - self->mincode[i]; - int value = self->huffval[j]; - return value; -} - -static int receive(ljp* self,int ssss) { - if (ssss == 16) { - return 1 << 15; - } - int i = 0; - int v = 0; - while (i != ssss) { - i++; - v = (v<<1) + nextbit(self); - } - return v; -} - -static int extend(ljp* self,int v,int t) { - int vt = 1<<(t-1); - if (v < vt) { - vt = (-1 << t) + 1; - v = v + vt; - } - return v; -} -#endif - -inline static int nextdiff(ljp* self, int Px) { -#ifdef SLOW_HUFF - int t = decode(self); - int diff = receive(self,t); - diff = extend(self,diff,t); - //printf("%d %d %d %x\n",Px+diff,Px,diff,t);//,index,usedbits); -#else - u32 b = self->b; - int cnt = self->cnt; - int huffbits = self->huffbits; - int ix = self->ix; - int next; - while (cnt < huffbits) { - next = *(u16*)&self->data[ix]; - int one = next&0xFF; - int two = next>>8; - b = (b<<16)|(one<<8)|two; - cnt += 16; - ix += 2; - if (one==0xFF) { - //printf("%x %x %x %x %d\n",one,two,b,b>>8,cnt); - b >>= 8; - cnt -= 8; - } else if (two==0xFF) ix++; - } - int index = b >> (cnt - huffbits); - u16 ssssused = self->hufflut[index]; - int usedbits = ssssused&0xFF; - int t = ssssused>>8; - self->sssshist[t]++; - cnt -= usedbits; - int keepbitsmask = (1 << cnt)-1; - b &= keepbitsmask; - int diff; - if (t == 16) { - diff = 1 << 15; - } else { - while (cnt < t) { - next = *(u16*)&self->data[ix]; - int one = next&0xFF; - int two = next>>8; - b = (b<<16)|(one<<8)|two; - cnt += 16; - ix += 2; - if (one==0xFF) { - b >>= 8; - cnt -= 8; - } else if (two==0xFF) ix++; - } - cnt -= t; - diff = b >> cnt; - int vt = 1<<(t-1); - if (diff < vt) { - vt = (-1 << t) + 1; - diff += vt; - } - } - keepbitsmask = (1 << cnt)-1; - self->b = b & keepbitsmask; - self->cnt = cnt; - self->ix = ix; - //printf("%d %d\n",t,diff); - //printf("%d %d %d %x %x %d\n",Px+diff,Px,diff,t,index,usedbits); -#ifdef DEBUG -#endif -#endif - return diff; -} - -static int parsePred6(ljp* self) { - int ret = LJ92_ERROR_CORRUPT; - self->ix = self->scanstart; - //int compcount = self->data[self->ix+2]; - self->ix += BEH(self->data[self->ix]); - self->cnt = 0; - self->b = 0; - int write = self->writelen; - // Now need to decode huffman coded values - int c = 0; - int pixels = self->y * self->x; - u16* out = self->image; - u16* temprow; - u16* thisrow = self->outrow[0]; - u16* lastrow = self->outrow[1]; - - // First pixel predicted from base value - int diff; - int Px; - int col = 0; - int row = 0; - int left = 0; - int linear; - - // First pixel - diff = nextdiff(self,0); - Px = 1 << (self->bits-1); - left = Px + diff; - left = (u16) (left % 65536); - if (self->linearize) - linear = self->linearize[left]; - else - linear = left; - thisrow[col++] = left; - out[c++] = linear; - if (self->ix >= self->datalen) return ret; - --write; - int rowcount = self->x-1; - while (rowcount--) { - diff = nextdiff(self,0); - Px = left; - left = Px + diff; - left = (u16) (left % 65536); - if (self->linearize) - linear = self->linearize[left]; - else - linear = left; - thisrow[col++] = left; - out[c++] = linear; - //printf("%d %d %d %d %x\n",col-1,diff,left,thisrow[col-1],&thisrow[col-1]); - if (self->ix >= self->datalen) return ret; - if (--write==0) { - out += self->skiplen; - write = self->writelen; - } - } - temprow = lastrow; - lastrow = thisrow; - thisrow = temprow; - row++; - //printf("%x %x\n",thisrow,lastrow); - while (clinearize) { - if (left>self->linlen) return LJ92_ERROR_CORRUPT; - linear = self->linearize[left]; - } else - linear = left; - thisrow[col++] = left; - //printf("%d %d %d %d\n",col,diff,left,lastrow[col]); - out[c++] = linear; - if (self->ix >= self->datalen) break; - rowcount = self->x-1; - if (--write==0) { - out += self->skiplen; - write = self->writelen; - } - while (rowcount--) { - diff = nextdiff(self,0); - Px = lastrow[col] + ((left - lastrow[col-1])>>1); - left = Px + diff; - left = (u16) (left % 65536); - //printf("%d %d %d %d %d %x\n",col,diff,left,lastrow[col],lastrow[col-1],&lastrow[col]); - if (self->linearize) { - if (left>self->linlen) return LJ92_ERROR_CORRUPT; - linear = self->linearize[left]; - } else - linear = left; - thisrow[col++] = left; - out[c++] = linear; - if (--write==0) { - out += self->skiplen; - write = self->writelen; - } - } - temprow = lastrow; - lastrow = thisrow; - thisrow = temprow; - if (self->ix >= self->datalen) break; - } - if (c >= pixels) ret = LJ92_ERROR_NONE; - return ret; -} - -static int parseScan(ljp* self) { - int ret = LJ92_ERROR_CORRUPT; - memset(self->sssshist,0,sizeof(self->sssshist)); - self->ix = self->scanstart; - int compcount = self->data[self->ix+2]; - int pred = self->data[self->ix+3+2*compcount]; - if (pred<0 || pred>7) return ret; - if (pred==6) return parsePred6(self); // Fast path - self->ix += BEH(self->data[self->ix]); - self->cnt = 0; - self->b = 0; - int write = self->writelen; - // Now need to decode huffman coded values - int c = 0; - int pixels = self->y * self->x; - u16* out = self->image; - u16* thisrow = self->outrow[0]; - u16* lastrow = self->outrow[1]; - - // First pixel predicted from base value - int diff; - int Px = 0; - int col = 0; - int row = 0; - int left = 0; - while (cbits-1); - } else if (row==0) { - Px = left; - } else if (col==0) { - Px = lastrow[col]; // Use value above for first pixel in row - } else { - switch (pred) { - case 0: - Px = 0; break; // No prediction... should not be used - case 1: - Px = left; break; - case 2: - Px = lastrow[col]; break; - case 3: - Px = lastrow[col-1];break; - case 4: - Px = left + lastrow[col] - lastrow[col-1];break; - case 5: - Px = left + ((lastrow[col] - lastrow[col-1])>>1);break; - /* case 6 has a shortcut above - case 6: - Px = lastrow[col] + ((left - lastrow[col-1])>>1);break; - */ - case 7: - Px = (left + lastrow[col])>>1;break; - } - } - diff = nextdiff(self,Px); - left = Px + diff; - left = (u16) (left % 65536); - //printf("%d %d %d\n",c,diff,left); - int linear; - if (self->linearize) { - if (left>self->linlen) return LJ92_ERROR_CORRUPT; - linear = self->linearize[left]; - } else - linear = left; - thisrow[col] = left; - out[c++] = linear; - if (++col==self->x) { - col = 0; - row++; - u16* temprow = lastrow; - lastrow = thisrow; - thisrow = temprow; - } - if (--write==0) { - out += self->skiplen; - write = self->writelen; - } - if (self->ix >= self->datalen+2) break; - } - if (c >= pixels) ret = LJ92_ERROR_NONE; - /*for (int h=0;h<17;h++) { - printf("ssss:%d=%d (%f)\n",h,self->sssshist[h],(float)self->sssshist[h]/(float)(pixels)); - }*/ - return ret; -} - -static int parseImage(ljp* self) { - int ret = LJ92_ERROR_NONE; - while (1) { - int nextMarker = find(self); - if (nextMarker == 0xc4) - ret = parseHuff(self); - else if (nextMarker == 0xc3) - ret = parseSof3(self); - else if (nextMarker == 0xfe)// Comment - ret = parseBlock(self,nextMarker); - else if (nextMarker == 0xd9) // End of image - break; - else if (nextMarker == 0xda) { - self->scanstart = self->ix; - ret = LJ92_ERROR_NONE; - break; - } else if (nextMarker == -1) { - ret = LJ92_ERROR_CORRUPT; - break; - } else - ret = parseBlock(self,nextMarker); - if (ret != LJ92_ERROR_NONE) break; - } - return ret; -} - -static int findSoI(ljp* self) { - int ret = LJ92_ERROR_CORRUPT; - if (find(self)==0xd8) - ret = parseImage(self); - return ret; -} - -static void free_memory(ljp* self) { -#ifdef SLOW_HUFF - free(self->maxcode); - self->maxcode = NULL; - free(self->mincode); - self->mincode = NULL; - free(self->valptr); - self->valptr = NULL; - free(self->huffval); - self->huffval = NULL; - free(self->huffsize); - self->huffsize = NULL; - free(self->huffcode); - self->huffcode = NULL; -#else - free(self->hufflut); - self->hufflut = NULL; -#endif - free(self->rowcache); - self->rowcache = NULL; -} - -int lj92_open(lj92* lj, - uint8_t* data, int datalen, - int* width,int* height, int* bitdepth) { - ljp* self = (ljp*)calloc(sizeof(ljp),1); - if (self==NULL) return LJ92_ERROR_NO_MEMORY; - - self->data = (u8*)data; - self->dataend = self->data + datalen; - self->datalen = datalen; - - int ret = findSoI(self); - - if (ret == LJ92_ERROR_NONE) { - u16* rowcache = (u16*)calloc(self->x * 2,sizeof(u16)); - if (rowcache == NULL) ret = LJ92_ERROR_NO_MEMORY; - else { - self->rowcache = rowcache; - self->outrow[0] = rowcache; - self->outrow[1] = &rowcache[self->x]; - } - } - - if (ret != LJ92_ERROR_NONE) { // Failed, clean up - *lj = NULL; - free_memory(self); - free(self); - } else { - *width = self->x; - *height = self->y; - *bitdepth = self->bits; - *lj = self; - } - return ret; -} - -int lj92_decode(lj92 lj, - uint16_t* target,int writeLength, int skipLength, - uint16_t* linearize,int linearizeLength) { - int ret = LJ92_ERROR_NONE; - ljp* self = lj; - if (self == NULL) return LJ92_ERROR_BAD_HANDLE; - self->image = target; - self->writelen = writeLength; - self->skiplen = skipLength; - self->linearize = linearize; - self->linlen = linearizeLength; - ret = parseScan(self); - return ret; -} - -void lj92_close(lj92 lj) { - ljp* self = lj; - if (self != NULL) - free_memory(self); - free(self); -} diff --git a/rtengine/lj92.h b/rtengine/lj92.h deleted file mode 100644 index bc8bf7604..000000000 --- a/rtengine/lj92.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -lj92.h -(c) Andrew Baldwin 2014 - -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. -*/ - -#ifndef LJ92_H -#define LJ92_H - -#ifdef __cplusplus -extern "C" -{ -#endif -enum LJ92_ERRORS { - LJ92_ERROR_NONE = 0, - LJ92_ERROR_CORRUPT = -1, - LJ92_ERROR_NO_MEMORY = -2, - LJ92_ERROR_BAD_HANDLE = -3, - LJ92_ERROR_TOO_WIDE = -4, -}; - -typedef struct _ljp* lj92; - -/* Parse a lossless JPEG (1992) structure returning - * - a handle that can be used to decode the data - * - width/height/bitdepth of the data - * Returns status code. - * If status == LJ92_ERROR_NONE, handle must be closed with lj92_close - */ -int lj92_open(lj92* lj, // Return handle here - uint8_t* data,int datalen, // The encoded data - int* width,int* height,int* bitdepth); // Width, height and bitdepth - -/* Release a decoder object */ -void lj92_close(lj92 lj); - -/* - * Decode previously opened lossless JPEG (1992) into a 2D tile of memory - * Starting at target, write writeLength 16bit values, then skip 16bit skipLength value before writing again - * If linearize is not NULL, use table at linearize to convert data values from output value to target value - * Data is only correct if LJ92_ERROR_NONE is returned - */ -int lj92_decode(lj92 lj, - uint16_t* target, int writeLength, int skipLength, // The image is written to target as a tile - uint16_t* linearize, int linearizeLength); // If not null, linearize the data using this table - -#endif - -#ifdef __cplusplus -} -#endif From f22482c204f6f2bb9757fdb084ea444a89e23e1b Mon Sep 17 00:00:00 2001 From: Desmis Date: Tue, 4 May 2021 07:27:55 +0200 Subject: [PATCH 050/135] Local adjustments - Strength control on Spot - tools - issue 6221 (#6223) * Add strength to local contrast and wavelet * Added strength to Color and Light * Added strength to Denoise * Added strength to shadows highlight Tone equalizer * Added strength to Dynamic Range and exposure * Added strength to Tone mapping * Small improvment to Dynamic Range --- rtdata/languages/default | 12 ++++ rtengine/iplocallab.cc | 133 +++++++++++++++++++++++++++++++++++---- rtengine/procevents.h | 6 ++ rtengine/procparams.cc | 26 +++++++- rtengine/procparams.h | 6 ++ rtengine/refreshmap.cc | 8 ++- rtgui/locallabtools.cc | 82 +++++++++++++++++++++--- rtgui/locallabtools.h | 6 ++ rtgui/locallabtools2.cc | 29 +++++++++ rtgui/paramsedited.cc | 45 ++++++++++++- rtgui/paramsedited.h | 6 ++ 11 files changed, 334 insertions(+), 25 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 595f03e7e..ba2d13d4f 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1288,6 +1288,12 @@ HISTORY_MSG_1040;Local - Spot - soft radius HISTORY_MSG_1041;Local - Spot - Munsell HISTORY_MSG_1042;Local - Log encoding - threshold HISTORY_MSG_1043;Local - Exp - normalize +HISTORY_MSG_1044;Local - Local contrast strength +HISTORY_MSG_1045;Local - Color and Light strength +HISTORY_MSG_1046;Local - Denoise strength +HISTORY_MSG_1047;Local - SH and Tone Equalizer strength +HISTORY_MSG_1048;Local - DR and Exposure strength +HISTORY_MSG_1049;Local - TM strength HISTORY_MSG_BLSHAPE;Blur by level HISTORY_MSG_BLURCWAV;Blur chroma HISTORY_MSG_BLURWAV;Blur luminance @@ -2992,6 +2998,12 @@ TP_LOCALLAB_RECURS_TOOLTIP;Forces the algorithm to recalculate the references af TP_LOCALLAB_REFLABEL;Ref. (0..1) Chroma=%1 Luma=%2 Hue=%3 TP_LOCALLAB_REN_DIALOG_LAB;Enter the new Control Spot name TP_LOCALLAB_REN_DIALOG_NAME;Renaming Control Spot +TP_LOCALLAB_REPARW_TOOLTIP;Allows you to adjust the relative strength of the local contrast and wavelet image with respect to the original image. +TP_LOCALLAB_REPARCOL_TOOLTIP;Allows you to adjust the relative strength of the Color and Light image with respect to the original image. +TP_LOCALLAB_REPARDEN_TOOLTIP;Allows you to adjust the relative strength of the Denoise image with respect to the original image. +TP_LOCALLAB_REPARSH_TOOLTIP;Allows you to adjust the relative strength of the Shadows/Highlights and Tone Equalizer image with respect to the original image. +TP_LOCALLAB_REPAREXP_TOOLTIP;Allows you to adjust the relative strength of the Dynamic Range and Exposure image with respect to the original image. +TP_LOCALLAB_REPARTM_TOOLTIP;Allows you to adjust the relative strength of the Tone mapping image with respect to the original image. TP_LOCALLAB_RESETSHOW;Reset All Show Modifications TP_LOCALLAB_RESID;Residual Image TP_LOCALLAB_RESIDBLUR;Blur residual image diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 7ff84b632..11887b10c 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -439,6 +439,8 @@ struct local_params { float thr; float stru; int chro, cont, sens, sensh, senscb, sensbn, senstm, sensex, sensexclu, sensden, senslc, senssf, senshs, senscolor; + float reparden; + float repartm; float clarityml; float contresid; bool deltaem; @@ -1124,6 +1126,8 @@ static void calcLocalParams(int sp, int oW, int oH, const LocallabParams& locall int local_noiselequal = locallab.spots.at(sp).noiselequal; float local_noisechrodetail = (float)locallab.spots.at(sp).noisechrodetail; int local_sensiden = locallab.spots.at(sp).sensiden; + float local_reparden = locallab.spots.at(sp).reparden; + float local_repartm = locallab.spots.at(sp).repartm; float local_detailthr = (float)locallab.spots.at(sp).detailthr; float local_recothr = (float)locallab.spots.at(sp).recothres; float local_lowthr = (float)locallab.spots.at(sp).lowthres; @@ -1582,6 +1586,8 @@ static void calcLocalParams(int sp, int oW, int oH, const LocallabParams& locall lp.noisecf = local_noisecf; lp.noisecc = local_noisecc; lp.sensden = local_sensiden; + lp.reparden = local_reparden; + lp.repartm = local_repartm; lp.bilat = locallab.spots.at(sp).bilateral; lp.nldet = locallab.spots.at(sp).nldet; lp.nlstr = locallab.spots.at(sp).nlstr; @@ -3263,6 +3269,11 @@ void ImProcFunctions::DeNoise_Local(int call, const struct local_params& lp, Lab difa = tmp1.a[loy - begy][lox - begx] - original->a[y][x]; difb = tmp1.b[loy - begy][lox - begx] - original->b[y][x]; } else { //dcrop + const float repart = 1.0f - 0.01f * lp.reparden; + tmp1.L[y][x] = intp(repart, original->L[y][x], tmp1.L[y][x]); + tmp1.a[y][x] = intp(repart, original->a[y][x], tmp1.a[y][x]); + tmp1.b[y][x] = intp(repart, original->b[y][x], tmp1.b[y][x]); + difL = tmp1.L[y][x] - original->L[y][x]; difa = tmp1.a[y][x] - original->a[y][x]; difb = tmp1.b[y][x] - original->b[y][x]; @@ -3409,16 +3420,14 @@ void ImProcFunctions::DeNoise_Local2(const struct local_params& lp, LabImage* or float difL, difa, difb; - // if (call == 2 /*|| call == 1 || call == 3 */) { //simpleprocess - // difL = tmp1.L[loy - begy][lox - begx] - original->L[y][x]; - // difa = tmp1.a[loy - begy][lox - begx] - original->a[y][x]; - // difb = tmp1.b[loy - begy][lox - begx] - original->b[y][x]; - // } else { //dcrop + const float repart = 1.0f - 0.01f * lp.reparden; + tmp1.L[y-ystart][x-xstart] = intp(repart, original->L[y][x], tmp1.L[y-ystart][x-xstart]); + tmp1.a[y-ystart][x-xstart] = intp(repart, original->a[y][x], tmp1.a[y-ystart][x-xstart]); + tmp1.b[y-ystart][x-xstart] = intp(repart, original->b[y][x], tmp1.b[y-ystart][x-xstart]); - difL = tmp1.L[y-ystart][x-xstart] - original->L[y][x]; - difa = tmp1.a[y-ystart][x-xstart] - original->a[y][x]; - difb = tmp1.b[y-ystart][x-xstart] - original->b[y][x]; - // } + difL = tmp1.L[y-ystart][x-xstart] - original->L[y][x]; + difa = tmp1.a[y-ystart][x-xstart] - original->a[y][x]; + difb = tmp1.b[y-ystart][x-xstart] - original->b[y][x]; difL *= localFactor * reducdEL; difa *= localFactor * reducdEa; @@ -6937,6 +6946,8 @@ void ImProcFunctions::transit_shapedetect2(int sp, float meantm, float stdtm, in } } + + if (lp.equtm && senstype == 8) { //normalize luminance for Tone mapping , at this place we can use for others senstype! float *datain = new float[bfh * bfw]; float *data = new float[bfh * bfw]; @@ -6976,6 +6987,24 @@ void ImProcFunctions::transit_shapedetect2(int sp, float meantm, float stdtm, in delete [] data; } + + if (senstype == 8) {//strength Tone mapping + const float repart = 1.0f - 0.01f * lp.repartm; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if(multiThread) +#endif + + for (int y = ystart; y < yend; y++){ + for (int x = xstart; x < xend; x++) { + bufexpfin->L[y - ystart][x - xstart]= intp(repart, original->L[y][x], bufexpfin->L[y - ystart][x - xstart]); + bufexpfin->a[y - ystart][x - xstart]= intp(repart, original->a[y][x], bufexpfin->a[y - ystart][x - xstart]); + bufexpfin->b[y - ystart][x - xstart]= intp(repart, original->b[y][x], bufexpfin->b[y - ystart][x - xstart]); + } + } + } + + #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif @@ -7078,6 +7107,7 @@ void ImProcFunctions::transit_shapedetect2(int sp, float meantm, float stdtm, in } } + //deltaE float abdelta2 = SQR(refa - maskptr->a[y][x]) + SQR(refb - maskptr->b[y][x]); float chrodelta2 = SQR(std::sqrt(SQR(maskptr->a[y][x]) + SQR(maskptr->b[y][x])) - (chromaref * 327.68f)); @@ -12567,6 +12597,8 @@ void ImProcFunctions::Lab_Local( } // transit_shapedetect_retinex(call, 4, bufgb.get(),bufmaskorigtm.get(), originalmasktm.get(), buflight, bufchro, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); + + transit_shapedetect2(sp, meantm, stdtm, call, 8, bufgb.get(), tmp1.get(), originalmasktm.get(), hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); // transit_shapedetect(8, tmp1.get(), originalmasktm.get(), bufchro, false, hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); @@ -13942,6 +13974,21 @@ void ImProcFunctions::Lab_Local( maskrecov(bufexpfin.get(), original, bufmaskorigSH.get(), bfh, bfw, ystart, xstart, hig, low, recoth, decay, invmask, sk, multiThread); } + const float repart = 1.0 - 0.01 * params->locallab.spots.at(sp).reparsh; + int bw = bufexporig->W; + int bh = bufexporig->H; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if(multiThread) +#endif + for (int x = 0; x < bh; x++) { + for (int y = 0; y < bw; y++) { + bufexpfin->L[x][y] = intp(repart, bufexporig->L[x][y], bufexpfin->L[x][y]); + bufexpfin->a[x][y] = intp(repart, bufexporig->a[x][y], bufexpfin->a[x][y]); + bufexpfin->b[x][y] = intp(repart, bufexporig->b[x][y], bufexpfin->b[x][y]); + } + } + transit_shapedetect2(sp, 0.f, 0.f, call, 9, bufexporig.get(), bufexpfin.get(), originalmaskSH.get(), hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); if (lp.recur) { @@ -14567,6 +14614,20 @@ void ImProcFunctions::Lab_Local( bool invmask = false; maskrecov(tmp1.get(), original, bufmaskoriglc.get(), bfh, bfw, ystart, xstart, hig, low, recoth, decay, invmask, sk, multiThread); } + const float repart = 1.0 - 0.01 * params->locallab.spots.at(sp).reparw; + int bw = bufgb->W; + int bh = bufgb->H; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if(multiThread) +#endif + for (int x = 0; x < bh; x++) { + for (int y = 0; y < bw; y++) { + tmp1->L[x][y] = intp(repart, bufgb->L[x][y], tmp1->L[x][y]); + tmp1->a[x][y] = intp(repart, bufgb->a[x][y], tmp1->a[x][y]); + tmp1->b[x][y] = intp(repart, bufgb->b[x][y], tmp1->b[x][y]); + } + } transit_shapedetect2(sp, 0.f, 0.f, call, 10, bufgb.get(), tmp1.get(), originalmasklc.get(), hueref, chromaref, lumaref, sobelref, 0.f, nullptr, lp, original, transformed, cx, cy, sk); tmp1.reset(); @@ -14865,12 +14926,16 @@ void ImProcFunctions::Lab_Local( fatParams.enabled = true; fatParams.threshold = params->locallab.spots.at(sp).fatdetail; fatParams.amount = params->locallab.spots.at(sp).fatamount; - fatParams.anchor = 50.f; //params->locallab.spots.at(sp).fatanchor; + fatParams.anchor = params->locallab.spots.at(sp).fatanchor; //const float sigm = 1.f; //params->locallab.spots.at(sp).fatlevel; //const float mean = 1.f;// params->locallab.spots.at(sp).fatanchor; const std::unique_ptr tmpImagefat(new Imagefloat(bfwr, bfhr)); lab2rgb(*bufexpfin, *(tmpImagefat.get()), params->icm.workingProfile); - ToneMapFattal02(tmpImagefat.get(), fatParams, 3, 0, nullptr, 0, 0, 1);//last parameter = 1 ==>ART algorithm + int alg = 0; + if(fatParams.anchor == 50.f) { + alg = 1; + } + ToneMapFattal02(tmpImagefat.get(), fatParams, 3, 0, nullptr, 0, 0, alg);//last parameter = 1 ==>ART algorithm rgb2lab(*(tmpImagefat.get()), *bufexpfin, params->icm.workingProfile); } @@ -14982,6 +15047,22 @@ void ImProcFunctions::Lab_Local( } float meansob = 0.f; + + const float repart = 1.0 - 0.01 * params->locallab.spots.at(sp).reparexp; + int bw = bufexporig->W; + int bh = bufexporig->H; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if(multiThread) +#endif + for (int x = 0; x < bh; x++) { + for (int y = 0; y < bw; y++) { + bufexpfin->L[x][y] = intp(repart, bufexporig->L[x][y], bufexpfin->L[x][y]); + bufexpfin->a[x][y] = intp(repart, bufexporig->a[x][y], bufexpfin->a[x][y]); + bufexpfin->b[x][y] = intp(repart, bufexporig->b[x][y], bufexpfin->b[x][y]); + } + } + transit_shapedetect2(sp, 0.f, 0.f, call, 1, bufexporig.get(), bufexpfin.get(), originalmaskexp.get(), hueref, chromaref, lumaref, sobelref, meansob, blend2, lp, original, transformed, cx, cy, sk); } @@ -16042,6 +16123,21 @@ void ImProcFunctions::Lab_Local( softproc(bufcolreserv.get(), bufcolfin.get(), lp.softradiuscol, bfh, bfw, 0.001, 0.00001, 0.5f, sk, multiThread, 1); } float meansob = 0.f; + const float repart = 1.0 - 0.01 * params->locallab.spots.at(sp).reparcol; + int bw = bufcolreserv->W; + int bh = bufcolreserv->H; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if(multiThread) +#endif + for (int x = 0; x < bh; x++) { + for (int y = 0; y < bw; y++) { + bufcolfin->L[x][y] = intp(repart, bufcolreserv->L[x][y], bufcolfin->L[x][y]); + bufcolfin->a[x][y] = intp(repart, bufcolreserv->a[x][y], bufcolfin->a[x][y]); + bufcolfin->b[x][y] = intp(repart, bufcolreserv->b[x][y], bufcolfin->b[x][y]); + } + } + transit_shapedetect2(sp, 0.f, 0.f, call, 0, bufcolreserv.get(), bufcolfin.get(), originalmaskcol.get(), hueref, chromaref, lumaref, sobelref, meansob, blend2, lp, original, transformed, cx, cy, sk); } @@ -16124,6 +16220,21 @@ void ImProcFunctions::Lab_Local( bool invmask = false; maskrecov(bufcolfin.get(), original, bufmaskblurcol.get(), bfh, bfw, ystart, xstart, hig, low, recoth, decay, invmask, sk, multiThread); } + const float repart = 1.0 - 0.01 * params->locallab.spots.at(sp).reparcol; + int bw = bufcolorig->W; + int bh = bufcolorig->H; + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) if(multiThread) +#endif + for (int x = 0; x < bh; x++) { + for (int y = 0; y < bw; y++) { + bufcolfin->L[x][y] = intp(repart, bufcolorig->L[x][y], bufcolfin->L[x][y]); + bufcolfin->a[x][y] = intp(repart, bufcolorig->a[x][y], bufcolfin->a[x][y]); + bufcolfin->b[x][y] = intp(repart, bufcolorig->b[x][y], bufcolfin->b[x][y]); + } + } + float meansob = 0.f; transit_shapedetect2(sp, 0.f, 0.f, call, 0, bufcolorig.get(), bufcolfin.get(), originalmaskcol.get(), hueref, chromaref, lumaref, sobelref, meansob, blend2, lp, original, transformed, cx, cy, sk); } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 863fbd6e2..890f3bf4a 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -1066,6 +1066,12 @@ enum ProcEventCode { EvLocallabSpotavoidmun = 1040, Evlocallabcontthres = 1041, Evlocallabnorm = 1042, + Evlocallabreparw = 1043, + Evlocallabreparcol = 1044, + Evlocallabreparden = 1045, + Evlocallabreparsh = 1046, + Evlocallabreparexp = 1047, + Evlocallabrepartm = 1048, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 9b371a1c8..e01247471 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2795,6 +2795,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : complexcolor(2), curvactiv(false), lightness(0), + reparcol(100.), contrast(0), chroma(0), labgridALow(0.0), @@ -3127,12 +3128,13 @@ LocallabParams::LocallabSpot::LocallabSpot() : expMethod("std"), exnoiseMethod("none"), laplacexp(0.0), + reparexp(100.0), balanexp(1.0), linear(0.05), gamm(0.4), fatamount(1.0), fatdetail(40.0), - fatanchor(1.0), + fatanchor(50.0), fatlevel(1.), recothrese(1.), lowthrese(12.), @@ -3207,6 +3209,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : slomaskSH(0.0), lapmaskSH(0.0), detailSH(0), + reparsh(100.), LmaskSHcurve{ static_cast(DCT_NURBS), 0.0, @@ -3365,6 +3368,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : nlrad(5), nlgam(3.), sensiden(60), + reparden(100.), detailthr(50), locwavcurveden{ static_cast(FCT_MinMaxCPoints), @@ -3494,6 +3498,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : gamma(1.0), estop(1.4), scaltm(1.0), + repartm(100.0), rewei(0), satur(0.), sensitm(60), @@ -3739,6 +3744,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : edgw(60.0), basew(10.0), sensilc(60), + reparw(100.), fftwlc(false), blurlc(true), wavblur(false), @@ -4219,6 +4225,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && complexcolor == other.complexcolor && curvactiv == other.curvactiv && lightness == other.lightness + && reparcol == other.reparcol && contrast == other.contrast && chroma == other.chroma && labgridALow == other.labgridALow @@ -4318,6 +4325,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && expMethod == other.expMethod && exnoiseMethod == other.exnoiseMethod && laplacexp == other.laplacexp + && reparexp == other.reparexp && balanexp == other.balanexp && linear == other.linear && gamm == other.gamm @@ -4364,6 +4372,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && slomaskSH == other.slomaskSH && lapmaskSH == other.lapmaskSH && detailSH == other.detailSH + && reparsh == other.reparsh && LmaskSHcurve == other.LmaskSHcurve && fatamountSH == other.fatamountSH && fatanchorSH == other.fatanchorSH @@ -4466,6 +4475,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && nlrad == other.nlrad && nlgam == other.nlgam && sensiden == other.sensiden + && reparden == other.reparden && detailthr == other.detailthr && locwavcurveden == other.locwavcurveden && locwavcurvehue == other.locwavcurvehue @@ -4497,6 +4507,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && gamma == other.gamma && estop == other.estop && scaltm == other.scaltm + && repartm == other.repartm && rewei == other.rewei && satur == other.satur && sensitm == other.sensitm @@ -4618,6 +4629,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && edgw == other.edgw && basew == other.basew && sensilc == other.sensilc + && reparw == other.reparw && fftwlc == other.fftwlc && blurlc == other.blurlc && wavblur == other.wavblur @@ -5864,6 +5876,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || spot_edited->complexcolor, "Locallab", "Complexcolor_" + index_str, spot.complexcolor, keyFile); saveToKeyfile(!pedited || spot_edited->curvactiv, "Locallab", "Curvactiv_" + index_str, spot.curvactiv, keyFile); saveToKeyfile(!pedited || spot_edited->lightness, "Locallab", "Lightness_" + index_str, spot.lightness, keyFile); + saveToKeyfile(!pedited || spot_edited->reparcol, "Locallab", "Reparcol_" + index_str, spot.reparcol, keyFile); saveToKeyfile(!pedited || spot_edited->contrast, "Locallab", "Contrast_" + index_str, spot.contrast, keyFile); saveToKeyfile(!pedited || spot_edited->chroma, "Locallab", "Chroma_" + index_str, spot.chroma, keyFile); saveToKeyfile(!pedited || spot_edited->labgridALow, "Locallab", "labgridALow_" + index_str, spot.labgridALow, keyFile); @@ -5964,6 +5977,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || spot_edited->expMethod, "Locallab", "ExpMethod_" + index_str, spot.expMethod, keyFile); saveToKeyfile(!pedited || spot_edited->exnoiseMethod, "Locallab", "ExnoiseMethod_" + index_str, spot.exnoiseMethod, keyFile); saveToKeyfile(!pedited || spot_edited->laplacexp, "Locallab", "Laplacexp_" + index_str, spot.laplacexp, keyFile); + saveToKeyfile(!pedited || spot_edited->reparexp, "Locallab", "Reparexp_" + index_str, spot.reparexp, keyFile); saveToKeyfile(!pedited || spot_edited->balanexp, "Locallab", "Balanexp_" + index_str, spot.balanexp, keyFile); saveToKeyfile(!pedited || spot_edited->linear, "Locallab", "Linearexp_" + index_str, spot.linear, keyFile); saveToKeyfile(!pedited || spot_edited->gamm, "Locallab", "Gamm_" + index_str, spot.gamm, keyFile); @@ -6006,6 +6020,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || spot_edited->gammaskSH, "Locallab", "GammaskSH_" + index_str, spot.gammaskSH, keyFile); saveToKeyfile(!pedited || spot_edited->slomaskSH, "Locallab", "SlomaskSH_" + index_str, spot.slomaskSH, keyFile); saveToKeyfile(!pedited || spot_edited->detailSH, "Locallab", "DetailSH_" + index_str, spot.detailSH, keyFile); + saveToKeyfile(!pedited || spot_edited->reparsh, "Locallab", "Reparsh_" + index_str, spot.reparsh, keyFile); saveToKeyfile(!pedited || spot_edited->LmaskSHcurve, "Locallab", "LmaskSHCurve_" + index_str, spot.LmaskSHcurve, keyFile); saveToKeyfile(!pedited || spot_edited->fatamountSH, "Locallab", "FatamountSH_" + index_str, spot.fatamountSH, keyFile); saveToKeyfile(!pedited || spot_edited->fatanchorSH, "Locallab", "FatanchorSH_" + index_str, spot.fatanchorSH, keyFile); @@ -6111,6 +6126,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || spot_edited->nlrad, "Locallab", "Nlrad_" + index_str, spot.nlrad, keyFile); saveToKeyfile(!pedited || spot_edited->nlgam, "Locallab", "Nlgam_" + index_str, spot.nlgam, keyFile); saveToKeyfile(!pedited || spot_edited->sensiden, "Locallab", "Sensiden_" + index_str, spot.sensiden, keyFile); + saveToKeyfile(!pedited || spot_edited->reparden, "Locallab", "Reparden_" + index_str, spot.reparden, keyFile); saveToKeyfile(!pedited || spot_edited->detailthr, "Locallab", "Detailthr_" + index_str, spot.detailthr, keyFile); saveToKeyfile(!pedited || spot_edited->locwavcurveden, "Locallab", "LocwavCurveden_" + index_str, spot.locwavcurveden, keyFile); saveToKeyfile(!pedited || spot_edited->locwavcurvehue, "Locallab", "LocwavCurvehue_" + index_str, spot.locwavcurvehue, keyFile); @@ -6143,6 +6159,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || spot_edited->gamma, "Locallab", "Gamma_" + index_str, spot.gamma, keyFile); saveToKeyfile(!pedited || spot_edited->estop, "Locallab", "Estop_" + index_str, spot.estop, keyFile); saveToKeyfile(!pedited || spot_edited->scaltm, "Locallab", "Scaltm_" + index_str, spot.scaltm, keyFile); + saveToKeyfile(!pedited || spot_edited->repartm, "Locallab", "Repartm_" + index_str, spot.repartm, keyFile); saveToKeyfile(!pedited || spot_edited->rewei, "Locallab", "Rewei_" + index_str, spot.rewei, keyFile); saveToKeyfile(!pedited || spot_edited->satur, "Locallab", "Satur_" + index_str, spot.satur, keyFile); saveToKeyfile(!pedited || spot_edited->sensitm, "Locallab", "Sensitm_" + index_str, spot.sensitm, keyFile); @@ -6267,6 +6284,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || spot_edited->edgw, "Locallab", "Edgw_" + index_str, spot.edgw, keyFile); saveToKeyfile(!pedited || spot_edited->basew, "Locallab", "Basew_" + index_str, spot.basew, keyFile); saveToKeyfile(!pedited || spot_edited->sensilc, "Locallab", "Sensilc_" + index_str, spot.sensilc, keyFile); + saveToKeyfile(!pedited || spot_edited->reparw, "Locallab", "Reparw_" + index_str, spot.reparw, keyFile); saveToKeyfile(!pedited || spot_edited->fftwlc, "Locallab", "Fftwlc_" + index_str, spot.fftwlc, keyFile); saveToKeyfile(!pedited || spot_edited->blurlc, "Locallab", "Blurlc_" + index_str, spot.blurlc, keyFile); saveToKeyfile(!pedited || spot_edited->wavblur, "Locallab", "Wavblur_" + index_str, spot.wavblur, keyFile); @@ -7688,6 +7706,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "Complexcolor_" + index_str, pedited, spot.complexcolor, spotEdited.complexcolor); assignFromKeyfile(keyFile, "Locallab", "Curvactiv_" + index_str, pedited, spot.curvactiv, spotEdited.curvactiv); assignFromKeyfile(keyFile, "Locallab", "Lightness_" + index_str, pedited, spot.lightness, spotEdited.lightness); + assignFromKeyfile(keyFile, "Locallab", "Reparcol_" + index_str, pedited, spot.reparcol, spotEdited.reparcol); assignFromKeyfile(keyFile, "Locallab", "Contrast_" + index_str, pedited, spot.contrast, spotEdited.contrast); assignFromKeyfile(keyFile, "Locallab", "Chroma_" + index_str, pedited, spot.chroma, spotEdited.chroma); assignFromKeyfile(keyFile, "Locallab", "labgridALow_" + index_str, pedited, spot.labgridALow, spotEdited.labgridALow); @@ -7801,6 +7820,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "ExpMethod_" + index_str, pedited, spot.expMethod, spotEdited.expMethod); assignFromKeyfile(keyFile, "Locallab", "ExnoiseMethod_" + index_str, pedited, spot.exnoiseMethod, spotEdited.exnoiseMethod); assignFromKeyfile(keyFile, "Locallab", "Laplacexp_" + index_str, pedited, spot.laplacexp, spotEdited.laplacexp); + assignFromKeyfile(keyFile, "Locallab", "Reparexp_" + index_str, pedited, spot.reparexp, spotEdited.reparexp); assignFromKeyfile(keyFile, "Locallab", "Balanexp_" + index_str, pedited, spot.balanexp, spotEdited.balanexp); assignFromKeyfile(keyFile, "Locallab", "Linearexp_" + index_str, pedited, spot.linear, spotEdited.linear); assignFromKeyfile(keyFile, "Locallab", "Gamm_" + index_str, pedited, spot.gamm, spotEdited.gamm); @@ -7848,6 +7868,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "SlomaskSH_" + index_str, pedited, spot.slomaskSH, spotEdited.slomaskSH); assignFromKeyfile(keyFile, "Locallab", "LapmaskSH_" + index_str, pedited, spot.lapmaskSH, spotEdited.lapmaskSH); assignFromKeyfile(keyFile, "Locallab", "DetailSH_" + index_str, pedited, spot.detailSH, spotEdited.detailSH); + assignFromKeyfile(keyFile, "Locallab", "Reparsh_" + index_str, pedited, spot.reparsh, spotEdited.reparsh); assignFromKeyfile(keyFile, "Locallab", "LmaskSHCurve_" + index_str, pedited, spot.LmaskSHcurve, spotEdited.LmaskSHcurve); assignFromKeyfile(keyFile, "Locallab", "FatamountSH_" + index_str, pedited, spot.fatamountSH, spotEdited.fatamountSH); assignFromKeyfile(keyFile, "Locallab", "FatanchorSH_" + index_str, pedited, spot.fatanchorSH, spotEdited.fatanchorSH); @@ -7972,6 +7993,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "Nlrad_" + index_str, pedited, spot.nlrad, spotEdited.nlrad); assignFromKeyfile(keyFile, "Locallab", "Nlgam_" + index_str, pedited, spot.nlgam, spotEdited.nlgam); assignFromKeyfile(keyFile, "Locallab", "Sensiden_" + index_str, pedited, spot.sensiden, spotEdited.sensiden); + assignFromKeyfile(keyFile, "Locallab", "Reparden_" + index_str, pedited, spot.reparden, spotEdited.reparden); assignFromKeyfile(keyFile, "Locallab", "Detailthr_" + index_str, pedited, spot.detailthr, spotEdited.detailthr); assignFromKeyfile(keyFile, "Locallab", "LocwavCurveden_" + index_str, pedited, spot.locwavcurveden, spotEdited.locwavcurveden); assignFromKeyfile(keyFile, "Locallab", "LocwavCurvehue_" + index_str, pedited, spot.locwavcurvehue, spotEdited.locwavcurvehue); @@ -8016,6 +8038,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "Gamma_" + index_str, pedited, spot.gamma, spotEdited.gamma); assignFromKeyfile(keyFile, "Locallab", "Estop_" + index_str, pedited, spot.estop, spotEdited.estop); assignFromKeyfile(keyFile, "Locallab", "Scaltm_" + index_str, pedited, spot.scaltm, spotEdited.scaltm); + assignFromKeyfile(keyFile, "Locallab", "Repartm_" + index_str, pedited, spot.repartm, spotEdited.repartm); assignFromKeyfile(keyFile, "Locallab", "Rewei_" + index_str, pedited, spot.rewei, spotEdited.rewei); assignFromKeyfile(keyFile, "Locallab", "Satur_" + index_str, pedited, spot.satur, spotEdited.satur); assignFromKeyfile(keyFile, "Locallab", "Sensitm_" + index_str, pedited, spot.sensitm, spotEdited.sensitm); @@ -8149,6 +8172,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "Edgw_" + index_str, pedited, spot.edgw, spotEdited.edgw); assignFromKeyfile(keyFile, "Locallab", "Basew_" + index_str, pedited, spot.basew, spotEdited.basew); assignFromKeyfile(keyFile, "Locallab", "Sensilc_" + index_str, pedited, spot.sensilc, spotEdited.sensilc); + assignFromKeyfile(keyFile, "Locallab", "Reparw_" + index_str, pedited, spot.reparw, spotEdited.reparw); assignFromKeyfile(keyFile, "Locallab", "Fftwlc_" + index_str, pedited, spot.fftwlc, spotEdited.fftwlc); assignFromKeyfile(keyFile, "Locallab", "Blurlc_" + index_str, pedited, spot.blurlc, spotEdited.blurlc); assignFromKeyfile(keyFile, "Locallab", "Wavblur_" + index_str, pedited, spot.wavblur, spotEdited.wavblur); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 0df63b2fa..ea6b94d73 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1030,6 +1030,7 @@ struct LocallabParams { int complexcolor; bool curvactiv; int lightness; + double reparcol; int contrast; int chroma; double labgridALow; @@ -1129,6 +1130,7 @@ struct LocallabParams { Glib::ustring expMethod; // std, pde Glib::ustring exnoiseMethod; // none, med, medhi double laplacexp; + double reparexp; double balanexp; double linear; double gamm; @@ -1167,6 +1169,7 @@ struct LocallabParams { double slomaskSH; double lapmaskSH; int detailSH; + double reparsh; std::vector LmaskSHcurve; double fatamountSH; double fatanchorSH; @@ -1269,6 +1272,7 @@ struct LocallabParams { int nlrad; double nlgam; int sensiden; + double reparden; int detailthr; std::vector locwavcurveden; std::vector locwavcurvehue; @@ -1300,6 +1304,7 @@ struct LocallabParams { double gamma; double estop; double scaltm; + double repartm; int rewei; double satur; int sensitm; @@ -1421,6 +1426,7 @@ struct LocallabParams { double edgw; double basew; int sensilc; + double reparw; bool fftwlc; bool blurlc; bool wavblur; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index cb5353054..e5446dfb1 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -1069,7 +1069,13 @@ int refreshmap[rtengine::NUMOFEVENTS] = { AUTOEXP, // EvLocallabSpotavoidrad AUTOEXP, // EvLocallabSpotavoidmun AUTOEXP, // Evlocallabcontthres - AUTOEXP // Evlocallabnorm + AUTOEXP, // Evlocallabnorm + AUTOEXP, // Evlocallabreparw + AUTOEXP, // Evlocallabreparcol + AUTOEXP, // Evlocallabreparden + AUTOEXP, // Evlocallabreparsh + AUTOEXP, // Evlocallabreparexp + AUTOEXP // Evlocallabrepartm }; diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc index 2edb7db82..6f8ccea7a 100644 --- a/rtgui/locallabtools.cc +++ b/rtgui/locallabtools.cc @@ -416,6 +416,7 @@ LocallabColor::LocallabColor(): // Color & Light specific widgets lumFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LUMFRA")))), + reparcol(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGREPART"), 1.0, 100.0, 1., 100.0))), lightness(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LIGHTNESS"), -100, 500, 1, 0))), contrast(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CONTRAST"), -100, 100, 1, 0))), chroma(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMA"), -100, 150, 1, 0))), @@ -525,6 +526,8 @@ LocallabColor::LocallabColor(): lightness->setAdjusterListener(this); + reparcol->setAdjusterListener(this); + contrast->setAdjusterListener(this); chroma->setAdjusterListener(this); @@ -787,6 +790,7 @@ LocallabColor::LocallabColor(): csThresholdcol->setAdjusterListener(this); // Add Color & Light specific widgets to GUI + pack_start(*reparcol); ToolParamBlock* const lumBox = Gtk::manage(new ToolParamBlock()); lumBox->pack_start(*lightness); lumBox->pack_start(*contrast); @@ -957,6 +961,7 @@ void LocallabColor::updateAdviceTooltips(const bool showTooltips) if (showTooltips) { lumFrame->set_tooltip_text(M("TP_LOCALLAB_EXPCOLOR_TOOLTIP")); lightness->set_tooltip_text(M("TP_LOCALLAB_LIGHTN_TOOLTIP")); + reparcol->set_tooltip_text(M("TP_LOCALLAB_REPARCOL_TOOLTIP")); gridMethod->set_tooltip_text(M("TP_LOCALLAB_GRIDMETH_TOOLTIP")); strengthgrid->set_tooltip_text(M("TP_LOCALLAB_STRENGRID_TOOLTIP")); blurcolde->set_tooltip_text(M("TP_LOCALLAB_BLURCOLDE_TOOLTIP")); @@ -1008,6 +1013,7 @@ void LocallabColor::updateAdviceTooltips(const bool showTooltips) } else { lumFrame->set_tooltip_text(""); lightness->set_tooltip_text(""); + reparcol->set_tooltip_text(""); gridMethod->set_tooltip_text(""); strengthgrid->set_tooltip_text(""); blurcolde->set_tooltip_text(""); @@ -1124,6 +1130,7 @@ void LocallabColor::read(const rtengine::procparams::ProcParams* pp, const Param complexity->set_active(spot.complexcolor); lightness->setValue(spot.lightness); + reparcol->setValue(spot.reparcol); contrast->setValue(spot.contrast); chroma->setValue(spot.chroma); curvactiv->set_active(spot.curvactiv); @@ -1298,6 +1305,7 @@ void LocallabColor::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pe spot.complexcolor = complexity->get_active_row_number(); spot.lightness = lightness->getIntValue(); + spot.reparcol = reparcol->getValue(); spot.contrast = contrast->getIntValue(); spot.chroma = chroma->getIntValue(); spot.curvactiv = curvactiv->get_active(); @@ -1461,6 +1469,7 @@ void LocallabColor::setDefaults(const rtengine::procparams::ProcParams* defParam // Set default value for adjuster, labgrid and threshold adjuster widgets lightness->setDefault((double)defSpot.lightness); + reparcol->setDefault(defSpot.reparcol); contrast->setDefault((double)defSpot.contrast); chroma->setDefault((double)defSpot.chroma); labgrid->setDefault(defSpot.labgridALow / LocallabParams::LABGRIDL_CORR_MAX, @@ -1515,6 +1524,13 @@ void LocallabColor::adjusterChanged(Adjuster* a, double newval) } } + if (a == reparcol) { + if (listener) { + listener->panelChanged(Evlocallabreparcol, + reparcol->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + if (a == contrast) { if (listener) { listener->panelChanged(Evlocallabcontrast, @@ -2376,6 +2392,7 @@ void LocallabColor::updateColorGUI1() showmaskcolMethodinv->show(); contcol->hide(); blurcol->hide(); + reparcol->hide(); } else { gridFrame->show(); @@ -2407,6 +2424,7 @@ void LocallabColor::updateColorGUI1() showmaskcolMethodConninv.block(false); contcol->show(); blurcol->show(); + reparcol->show(); } } @@ -2488,6 +2506,7 @@ LocallabExposure::LocallabExposure(): // pdeFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_PDEFRA")))), exppde(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_PDEFRA")))), laplacexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LAPLACEXP"), 0.0, 100.0, 0.1, 0.))), + reparexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGREPART"), 1.0, 100.0, 1., 100.0))), linear(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LINEAR"), 0.01, 1., 0.01, 0.05))), balanexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BALANEXP"), 0.5, 1.5, 0.01, 1.0))), gamm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_GAMM"), 0.2, 1.3, 0.01, 0.4))), @@ -2499,7 +2518,7 @@ LocallabExposure::LocallabExposure(): fatdetail(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATDETAIL"), -100., 300., 1., 0.))), norm(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_EQUIL")))), fatlevel(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATLEVEL"), 0.5, 2.0, 0.01, 1.))), - fatanchor(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATANCHORA"), 0.5, 2.0, 0.01, 1.))), + fatanchor(Gtk::manage(new Adjuster(M("TP_LOCALLAB_FATANCHOR"), 0.1, 100.0, 0.01, 50., Gtk::manage(new RTImage("circle-black-small.png")), Gtk::manage(new RTImage("circle-white-small.png"))))), sensiex(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 0, 100, 1, 60))), structexp(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRUCCOL"), 0, 100, 1, 0))), blurexpde(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BLURDE"), 2, 100, 1, 5))), @@ -2562,6 +2581,7 @@ LocallabExposure::LocallabExposure(): setExpandAlignProperties(expfat, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); laplacexp->setAdjusterListener(this); + reparexp->setAdjusterListener(this); linear->setAdjusterListener(this); @@ -2701,7 +2721,8 @@ LocallabExposure::LocallabExposure(): mask2expCurveEditorG->curveListComplete(); // Add Color & Light specific widgets to GUI -// pack_start(*expMethod); + pack_start(*sensiex); + pack_start(*reparexp); ToolParamBlock* const pdeBox = Gtk::manage(new ToolParamBlock()); pdeBox->pack_start(*laplacexp); pdeBox->pack_start(*linear); @@ -2721,13 +2742,12 @@ LocallabExposure::LocallabExposure(): fatBox->pack_start(*fatdetail); // fatBox->pack_start(*norm); // fatBox->pack_start(*fatlevel); -// fatBox->pack_start(*fatanchor); + fatBox->pack_start(*fatanchor); // fatFrame->add(*fatBox); expfat->add(*fatBox, false); // pack_start(*fatFrame); pack_start(*expfat); pack_start(*expcomp); - pack_start(*sensiex); pack_start(*structexp); pack_start(*blurexpde); ToolParamBlock* const toolBox = Gtk::manage(new ToolParamBlock()); @@ -2822,6 +2842,7 @@ void LocallabExposure::updateAdviceTooltips(const bool showTooltips) higthrese->set_tooltip_text(M("TP_LOCALLAB_MASKHIGTHRESE_TOOLTIP")); blurexpde->set_tooltip_text(M("TP_LOCALLAB_BLURCOLDE_TOOLTIP")); laplacexp->set_tooltip_text(M("TP_LOCALLAB_EXPLAP_TOOLTIP")); + reparexp->set_tooltip_text(M("TP_LOCALLAB_REPAREXP_TOOLTIP")); linear->set_tooltip_text(M("TP_LOCALLAB_EXPLAPLIN_TOOLTIP")); balanexp->set_tooltip_text(M("TP_LOCALLAB_EXPLAPBAL_TOOLTIP")); gamm->set_tooltip_text(M("TP_LOCALLAB_EXPLAPGAMM_TOOLTIP")); @@ -2856,6 +2877,7 @@ void LocallabExposure::updateAdviceTooltips(const bool showTooltips) blurexpde->set_tooltip_text(""); exprecove->set_tooltip_markup(""); laplacexp->set_tooltip_text(""); + reparexp->set_tooltip_text(""); linear->set_tooltip_text(""); balanexp->set_tooltip_text(""); gamm->set_tooltip_text(""); @@ -2946,6 +2968,7 @@ void LocallabExposure::read(const rtengine::procparams::ProcParams* pp, const Pa } */ laplacexp->setValue(spot.laplacexp); + reparexp->setValue(spot.reparexp); linear->setValue(spot.linear); balanexp->setValue(spot.balanexp); gamm->setValue(spot.gamm); @@ -3037,6 +3060,7 @@ void LocallabExposure::write(rtengine::procparams::ProcParams* pp, ParamsEdited* } */ spot.laplacexp = laplacexp->getValue(); + spot.reparexp = reparexp->getValue(); spot.linear = linear->getValue(); spot.balanexp = balanexp->getValue(); spot.gamm = gamm->getValue(); @@ -3101,6 +3125,7 @@ void LocallabExposure::setDefaults(const rtengine::procparams::ProcParams* defPa // Set default values for adjuster widgets laplacexp->setDefault(defSpot.laplacexp); + reparexp->setDefault(defSpot.reparexp); linear->setDefault(defSpot.linear); balanexp->setDefault(defSpot.balanexp); gamm->setDefault(defSpot.gamm); @@ -3153,6 +3178,13 @@ void LocallabExposure::adjusterChanged(Adjuster* a, double newval) } } + if (a == reparexp) { + if (listener) { + listener->panelChanged(Evlocallabreparexp, + reparexp->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + if (a == linear) { if (listener) { listener->panelChanged(Evlocallablinear, @@ -3449,12 +3481,9 @@ void LocallabExposure::convertParamToNormal() slomaskexp->setValue(defSpot.slomaskexp); strmaskexp->setValue(defSpot.strmaskexp); angmaskexp->setValue(defSpot.angmaskexp); -// fatlevel->setValue(defSpot.fatlevel); -// fatanchor->setValue(defSpot.fatanchor); decaye->setValue(defSpot.decaye); // norm->set_active(defSpot.enaExpMask); fatlevel->setValue(defSpot.fatlevel); - fatanchor->setValue(defSpot.fatanchor); // Enable all listeners enableListener(); @@ -3530,7 +3559,7 @@ void LocallabExposure::updateGUIToMode(const modeType new_type) } norm->show(); fatlevel->hide(); - fatanchor->hide(); + fatanchor->show(); // Specific Simple mode widgets are shown in Normal mode if (!inversex->get_active()) { // Keep widget hidden when invers is toggled @@ -3774,6 +3803,7 @@ void LocallabExposure::updateExposureGUI3() expMethod->hide(); expcomp->setLabel(M("TP_LOCALLAB_EXPCOMPINV")); exprecove->hide(); + reparexp->hide(); // Manage specific case where expMethod is different from 0 if (expMethod->get_active_row_number() > 0) { @@ -3802,6 +3832,7 @@ void LocallabExposure::updateExposureGUI3() expgradexp->show(); exprecove->show(); } + reparexp->show(); showmaskexpMethodinv->hide(); // Reset hidden mask combobox @@ -3818,6 +3849,7 @@ LocallabShadow::LocallabShadow(): // Shadow highlight specific widgets shMethod(Gtk::manage(new MyComboBoxText())), + reparsh(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGREPART"), 1.0, 100.0, 1., 100.0))), multipliersh([]() -> std::array { std::array res = {}; @@ -3895,6 +3927,7 @@ LocallabShadow::LocallabShadow(): } detailSH->setAdjusterListener(this); + reparsh->setAdjusterListener(this); highlights->setAdjusterListener(this); @@ -3995,6 +4028,7 @@ LocallabShadow::LocallabShadow(): fatanchorSH->setAdjusterListener(this); // Add Shadow highlight specific widgets to GUI + pack_start(*reparsh); pack_start(*shMethod); for (const auto multiplier : multipliersh) { @@ -4091,6 +4125,7 @@ void LocallabShadow::updateAdviceTooltips(const bool showTooltips) } gamSH->set_tooltip_text(M("TP_LOCALLAB_SHTRC_TOOLTIP")); + reparsh->set_tooltip_text(M("TP_LOCALLAB_REPARSH_TOOLTIP")); sloSH->set_tooltip_text(M("TP_LOCALLAB_SHTRC_TOOLTIP")); strSH->set_tooltip_text(M("TP_LOCALLAB_GRADGEN_TOOLTIP")); exprecovs->set_tooltip_markup(M("TP_LOCALLAB_MASKRESH_TOOLTIP")); @@ -4131,6 +4166,7 @@ void LocallabShadow::updateAdviceTooltips(const bool showTooltips) multiplier->set_tooltip_text(""); } gamSH->set_tooltip_text(""); + reparsh->set_tooltip_text(""); sloSH->set_tooltip_text(""); strSH->set_tooltip_text(""); blurSHde->set_tooltip_text(""); @@ -4221,6 +4257,7 @@ void LocallabShadow::read(const rtengine::procparams::ProcParams* pp, const Para decays->setValue((double)spot.decays); detailSH->setValue((double)spot.detailSH); + reparsh->setValue(spot.reparsh); highlights->setValue((double)spot.highlights); h_tonalwidth->setValue((double)spot.h_tonalwidth); shadows->setValue(spot.shadows); @@ -4285,6 +4322,7 @@ void LocallabShadow::write(rtengine::procparams::ProcParams* pp, ParamsEdited* p } spot.detailSH = detailSH->getIntValue(); + spot.reparsh = reparsh->getValue(); spot.highlights = highlights->getIntValue(); spot.h_tonalwidth = h_tonalwidth->getIntValue(); spot.shadows = shadows->getIntValue(); @@ -4332,6 +4370,7 @@ void LocallabShadow::setDefaults(const rtengine::procparams::ProcParams* defPara } detailSH->setDefault((double)defSpot.detailSH); + reparsh->setDefault(defSpot.reparsh); highlights->setDefault((double)defSpot.highlights); h_tonalwidth->setDefault((double)defSpot.h_tonalwidth); shadows->setDefault((double)defSpot.shadows); @@ -4382,6 +4421,13 @@ void LocallabShadow::adjusterChanged(Adjuster* a, double newval) } } + if (a == reparsh) { + if (listener) { + listener->panelChanged(Evlocallabreparsh, + reparsh->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + if (a == highlights) { if (listener) { listener->panelChanged(Evlocallabhighlights, @@ -4858,11 +4904,13 @@ void LocallabShadow::updateShadowGUI1() showmaskSHMethodConn.block(false); showmaskSHMethodinv->show(); exprecovs->hide(); + reparsh->hide(); } else { if (mode == Expert || mode == Normal) { // Keep widget hidden in Simple mode expgradsh->show(); exprecovs->show(); } + reparsh->show(); showmaskSHMethod->show(); showmaskSHMethodinv->hide(); @@ -6337,6 +6385,7 @@ LocallabBlur::LocallabBlur(): nlgam(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NLGAM"), 2., 5., 0.1, 3.))), bilateral(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BILATERAL"), 0, 100, 1, 0))), sensiden(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 0, 100, 1, 60))), + reparden(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGREPART"), 1.0, 100.0, 1., 100.0))), neutral(Gtk::manage (new Gtk::Button (M ("TP_RETINEX_NEUTRAL")))), expmaskbl(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_SHOWPLUS")))), showmaskblMethod(Gtk::manage(new MyComboBoxText())), @@ -6522,6 +6571,7 @@ LocallabBlur::LocallabBlur(): nlgam->setAdjusterListener(this); sensiden->setAdjusterListener(this); + reparden->setAdjusterListener(this); setExpandAlignProperties (neutral, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); @@ -6670,7 +6720,8 @@ LocallabBlur::LocallabBlur(): detailFrame->add(*detailBox); wavBox->pack_start(*detailFrame); denoisebox->pack_start(*sensiden); - + denoisebox->pack_start(*reparden); + ToolParamBlock* const nlbox = Gtk::manage(new ToolParamBlock()); nlbox->pack_start(*nlstr); nlbox->pack_start(*nldet); @@ -6770,6 +6821,7 @@ void LocallabBlur::updateAdviceTooltips(const bool showTooltips) strength->set_tooltip_text(M("TP_LOCALLAB_NOISE_TOOLTIP")); grainFrame->set_tooltip_text(M("TP_LOCALLAB_GRAIN_TOOLTIP")); sensibn->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); + reparden->set_tooltip_text(M("TP_LOCALLAB_REPARDEN_TOOLTIP")); medMethod->set_tooltip_text(M("TP_LOCALLAB_MEDIAN_TOOLTIP")); itera->set_tooltip_text(M("TP_LOCALLAB_MEDIANITER_TOOLTIP")); fftwbl->set_tooltip_text(M("TP_LOCALLAB_FFTMASK_TOOLTIP")); @@ -6838,6 +6890,7 @@ void LocallabBlur::updateAdviceTooltips(const bool showTooltips) strength->set_tooltip_text(""); grainFrame->set_tooltip_text(""); sensibn->set_tooltip_text(""); + reparden->set_tooltip_text(""); medMethod->set_tooltip_text(""); itera->set_tooltip_text(""); fftwbl->set_tooltip_text(""); @@ -6867,7 +6920,6 @@ void LocallabBlur::updateAdviceTooltips(const bool showTooltips) nlpat->set_tooltip_text(""); nlrad->set_tooltip_text(""); nlgam->set_tooltip_text(""); - sensibn->set_tooltip_text(""); blurMethod->set_tooltip_markup(""); expdenoise->set_tooltip_markup(""); wavshapeden->setTooltip(""); @@ -7052,6 +7104,7 @@ void LocallabBlur::read(const rtengine::procparams::ProcParams* pp, const Params higthres->setValue((double)spot.higthres); epsbl->setValue((double)spot.epsbl); sensibn->setValue((double)spot.sensibn); + reparden->setValue(spot.reparden); recothresd->setValue((double)spot.recothresd); lowthresd->setValue((double)spot.lowthresd); midthresd->setValue((double)spot.midthresd); @@ -7198,6 +7251,7 @@ void LocallabBlur::write(rtengine::procparams::ProcParams* pp, ParamsEdited* ped spot.higthres = higthres->getValue(); spot.epsbl = epsbl->getIntValue(); spot.sensibn = sensibn->getIntValue(); + spot.reparden = reparden->getValue(); spot.recothresd = recothresd->getValue(); spot.lowthresd = lowthresd->getValue(); spot.midthresd = midthresd->getValue(); @@ -7307,6 +7361,7 @@ void LocallabBlur::setDefaults(const rtengine::procparams::ProcParams* defParams higthres->setDefault((double)defSpot.higthres); epsbl->setDefault((double)defSpot.epsbl); sensibn->setDefault((double)defSpot.sensibn); + reparden->setDefault(defSpot.reparden); recothresd->setDefault((double)defSpot.recothresd); lowthresd->setDefault((double)defSpot.lowthresd); midthresd->setDefault((double)defSpot.midthresd); @@ -7656,6 +7711,13 @@ void LocallabBlur::adjusterChanged(Adjuster* a, double newval) } } + if (a == reparden) { + if (listener) { + listener->panelChanged(Evlocallabreparden, + reparden->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + if (a == strumaskbl) { if (listener) { listener->panelChanged(Evlocallabstrumaskbl, diff --git a/rtgui/locallabtools.h b/rtgui/locallabtools.h index 53eafd6f8..d9d3a11f8 100644 --- a/rtgui/locallabtools.h +++ b/rtgui/locallabtools.h @@ -177,6 +177,7 @@ class LocallabColor: private: // Color & Light specific widgets Gtk::Frame* const lumFrame; + Adjuster* const reparcol; Adjuster* const lightness; Adjuster* const contrast; Adjuster* const chroma; @@ -331,6 +332,7 @@ private: // Gtk::Frame* const pdeFrame; MyExpander* const exppde; Adjuster* const laplacexp; + Adjuster* const reparexp; Adjuster* const linear; Adjuster* const balanexp; Adjuster* const gamm; @@ -442,6 +444,7 @@ class LocallabShadow: private: // Shadow highlight specific widgets MyComboBoxText* const shMethod; + Adjuster* const reparsh; const std::array multipliersh; Adjuster* const detailSH; Adjuster* const highlights; @@ -745,6 +748,7 @@ private: Adjuster* const nlgam; Adjuster* const bilateral; Adjuster* const sensiden; + Adjuster* const reparden; Gtk::Button* neutral; MyExpander* const expmaskbl; MyComboBoxText* const showmaskblMethod; @@ -835,6 +839,7 @@ class LocallabTone: { private: // Tone Mapping specific widgets + Adjuster* const repartm; Adjuster* const amount; Adjuster* const stren; Gtk::CheckButton* const equiltm; @@ -1083,6 +1088,7 @@ private: Adjuster* const residhi; Adjuster* const residhithr; Adjuster* const sensilc; + Adjuster* const reparw; Gtk::Frame* const clariFrame; Adjuster* const clarilres; Adjuster* const claricres; diff --git a/rtgui/locallabtools2.cc b/rtgui/locallabtools2.cc index d0ed30a8a..f7d68e5a1 100644 --- a/rtgui/locallabtools2.cc +++ b/rtgui/locallabtools2.cc @@ -118,6 +118,7 @@ LocallabTone::LocallabTone(): LocallabTool(this, M("TP_LOCALLAB_TONE_TOOLNAME"), M("TP_LOCALLAB_TM"), true), // Tone mapping specific widgets + repartm(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGREPART"), 1.0, 100.0, 1., 100.0))), amount(Gtk::manage(new Adjuster(M("TP_LOCALLAB_AMOUNT"), 50., 100.0, 0.5, 95.))), stren(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STREN"), -0.5, 2.0, 0.01, 0.5))), equiltm(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_EQUIL")))), @@ -160,6 +161,8 @@ LocallabTone::LocallabTone(): // Parameter Tone Mapping specific widgets amount->setAdjusterListener(this); + repartm->setAdjusterListener(this); + stren->setAdjusterListener(this); equiltmConn = equiltm->signal_toggled().connect(sigc::mem_fun(*this, &LocallabTone::equiltmChanged)); @@ -235,10 +238,13 @@ LocallabTone::LocallabTone(): Lmasktmshape->setLeftBarBgGradient({{0., 0., 0., 0.}, {1., 1., 1., 1.}}); mask2tmCurveEditorG->curveListComplete(); + Gtk::Separator* const separatortm = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); // Add Tone Mapping specific widgets to GUI // pack_start(*amount); // To use if we change transit_shapedetect parameters pack_start(*sensitm); + pack_start(*repartm); + pack_start(*separatortm); pack_start(*stren); pack_start(*equiltm); pack_start(*gamma); @@ -304,6 +310,7 @@ void LocallabTone::updateAdviceTooltips(const bool showTooltips) exp->set_tooltip_text(M("TP_LOCALLAB_TONEMAP_TOOLTIP")); exprecovt->set_tooltip_markup(M("TP_LOCALLAB_MASKRESTM_TOOLTIP")); equiltm->set_tooltip_text(M("TP_LOCALLAB_EQUILTM_TOOLTIP")); + repartm->set_tooltip_text(M("TP_LOCALLAB_REPARTM_TOOLTIP")); gamma->set_tooltip_text(M("TP_LOCALLAB_TONEMAPGAM_TOOLTIP")); estop->set_tooltip_text(M("TP_LOCALLAB_TONEMAPESTOP_TOOLTIP")); scaltm->set_tooltip_text(M("TP_LOCALLAB_TONEMASCALE_TOOLTIP")); @@ -329,6 +336,7 @@ void LocallabTone::updateAdviceTooltips(const bool showTooltips) } else { exp->set_tooltip_text(""); equiltm->set_tooltip_text(""); + repartm->set_tooltip_text(""); gamma->set_tooltip_text(""); estop->set_tooltip_text(""); scaltm->set_tooltip_text(""); @@ -401,6 +409,7 @@ void LocallabTone::read(const rtengine::procparams::ProcParams* pp, const Params amount->setValue(spot.amount); stren->setValue(spot.stren); + repartm->setValue(spot.repartm); equiltm->set_active(spot.equiltm); gamma->setValue(spot.gamma); satur->setValue(spot.satur); @@ -449,6 +458,7 @@ void LocallabTone::write(rtengine::procparams::ProcParams* pp, ParamsEdited* ped spot.amount = amount->getValue(); spot.stren = stren->getValue(); + spot.repartm = repartm->getValue(); spot.equiltm = equiltm->get_active(); spot.gamma = gamma->getValue(); spot.satur = satur->getValue(); @@ -492,6 +502,7 @@ void LocallabTone::setDefaults(const rtengine::procparams::ProcParams* defParams satur->setDefault(defSpot.satur); estop->setDefault(defSpot.estop); scaltm->setDefault(defSpot.scaltm); + repartm->setDefault(defSpot.repartm); rewei->setDefault((double)defSpot.rewei); softradiustm->setDefault(defSpot.softradiustm); sensitm->setDefault((double)defSpot.sensitm); @@ -527,6 +538,8 @@ void LocallabTone::adjusterChanged(Adjuster* a, double newval) listener->panelChanged(Evlocallabestop, estop->getTextValue() + spName); } else if (a == scaltm) { listener->panelChanged(Evlocallabscaltm, scaltm->getTextValue() + spName); + } else if (a == repartm) { + listener->panelChanged(Evlocallabrepartm, repartm->getTextValue() + spName); } else if (a == rewei) { listener->panelChanged(Evlocallabrewei, rewei->getTextValue() + spName); } else if (a == softradiustm) { @@ -2333,6 +2346,7 @@ LocallabContrast::LocallabContrast(): residhi(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RESIDHI"), -100., 100., 1., 0.))), residhithr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_RESIDHITHR"), 0., 100., 1., 70.))), sensilc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 0, 100, 1, 60))), + reparw(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGREPART"), 1.0, 100.0, 1., 100.0))), clariFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_CLARIFRA")))), clarilres(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CLARILRES"), -20., 100., 0.5, 0.))), claricres(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CLARICRES"), -20., 100., 0.5, 0.))), @@ -2465,6 +2479,8 @@ LocallabContrast::LocallabContrast(): sensilc->setAdjusterListener(this); + reparw->setAdjusterListener(this); + clariFrame->set_label_align(0.025, 0.5); clarilres->setAdjusterListener(this); @@ -2689,6 +2705,7 @@ LocallabContrast::LocallabContrast(): // Add Local contrast specific widgets to GUI pack_start(*sensilc); + pack_start(*reparw); pack_start(*localcontMethod); pack_start(*lcradius); pack_start(*lcamount); @@ -2945,6 +2962,7 @@ void LocallabContrast::updateAdviceTooltips(const bool showTooltips) masklcCurveEditorG->set_tooltip_markup(M("TP_LOCALLAB_MASKCURVE_TOOLTIP")); chromasklc->set_tooltip_text(M("TP_LOCALLAB_CHROMASK_TOOLTIP")); sensilc->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); + reparw->set_tooltip_text(M("TP_LOCALLAB_REPARW_TOOLTIP")); decayw->set_tooltip_text(M("TP_LOCALLAB_MASKDECAY_TOOLTIP")); lowthresw->set_tooltip_text(M("TP_LOCALLAB_MASKLOWTHRESWAV_TOOLTIP")); higthresw->set_tooltip_text(M("TP_LOCALLAB_MASKHIGTHRESWAV_TOOLTIP")); @@ -2977,6 +2995,7 @@ void LocallabContrast::updateAdviceTooltips(const bool showTooltips) masklcCurveEditorG->set_tooltip_markup(""); chromasklc->set_tooltip_text(""); sensilc->set_tooltip_text(""); + reparw->set_tooltip_text(""); wavshape->setTooltip(""); clarilres->set_tooltip_text(""); @@ -3113,6 +3132,7 @@ void LocallabContrast::read(const rtengine::procparams::ProcParams* pp, const Pa residhi->setValue(spot.residhi); residhithr->setValue(spot.residhithr); sensilc->setValue((double)spot.sensilc); + reparw->setValue(spot.reparw); clarilres->setValue(spot.clarilres); claricres->setValue(spot.claricres); clarisoft->setValue(spot.clarisoft); @@ -3234,6 +3254,7 @@ void LocallabContrast::write(rtengine::procparams::ProcParams* pp, ParamsEdited* spot.residhi = residhi->getValue(); spot.residhithr = residhithr->getValue(); spot.sensilc = sensilc->getIntValue(); + spot.reparw = reparw->getValue(); spot.clarilres = clarilres->getValue(); spot.claricres = claricres->getValue(); spot.clarisoft = clarisoft->getValue(); @@ -3334,6 +3355,7 @@ void LocallabContrast::setDefaults(const rtengine::procparams::ProcParams* defPa residhi->setDefault(defSpot.residhi); residhithr->setDefault(defSpot.residhithr); sensilc->setDefault((double)defSpot.sensilc); + reparw->setDefault(defSpot.reparw); clarilres->setDefault(defSpot.clarilres); claricres->setDefault(defSpot.claricres); clarisoft->setDefault(defSpot.clarisoft); @@ -3468,6 +3490,13 @@ void LocallabContrast::adjusterChanged(Adjuster* a, double newval) } } + if (a == reparw) { + if (listener) { + listener->panelChanged(Evlocallabreparw, + reparw->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + if (a == clarilres) { if (listener) { listener->panelChanged(Evlocallabclarilres, diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 1fdefc0a3..8fdd44bb6 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -1198,6 +1198,7 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).expMethod = locallab.spots.at(j).expMethod && pSpot.expMethod == otherSpot.expMethod; locallab.spots.at(j).exnoiseMethod = locallab.spots.at(j).exnoiseMethod && pSpot.exnoiseMethod == otherSpot.exnoiseMethod; locallab.spots.at(j).laplacexp = locallab.spots.at(j).laplacexp && pSpot.laplacexp == otherSpot.laplacexp; + locallab.spots.at(j).reparexp = locallab.spots.at(j).reparexp && pSpot.reparexp == otherSpot.reparexp; locallab.spots.at(j).balanexp = locallab.spots.at(j).balanexp && pSpot.balanexp == otherSpot.balanexp; locallab.spots.at(j).linear = locallab.spots.at(j).linear && pSpot.linear == otherSpot.linear; locallab.spots.at(j).gamm = locallab.spots.at(j).gamm && pSpot.gamm == otherSpot.gamm; @@ -1240,6 +1241,7 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).slomaskSH = locallab.spots.at(j).slomaskSH && pSpot.slomaskSH == otherSpot.slomaskSH; locallab.spots.at(j).lapmaskSH = locallab.spots.at(j).lapmaskSH && pSpot.lapmaskSH == otherSpot.lapmaskSH; locallab.spots.at(j).detailSH = locallab.spots.at(j).detailSH && pSpot.detailSH == otherSpot.detailSH; + locallab.spots.at(j).reparsh = locallab.spots.at(j).reparsh && pSpot.reparsh == otherSpot.reparsh; locallab.spots.at(j).LmaskSHcurve = locallab.spots.at(j).LmaskSHcurve && pSpot.LmaskSHcurve == otherSpot.LmaskSHcurve; locallab.spots.at(j).fatamountSH = locallab.spots.at(j).fatamountSH && pSpot.fatamountSH == otherSpot.fatamountSH; locallab.spots.at(j).fatanchorSH = locallab.spots.at(j).fatanchorSH && pSpot.fatanchorSH == otherSpot.fatanchorSH; @@ -1342,6 +1344,7 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).nlrad = locallab.spots.at(j).nlrad && pSpot.nlrad == otherSpot.nlrad; locallab.spots.at(j).nlgam = locallab.spots.at(j).nlgam && pSpot.nlgam == otherSpot.nlgam; locallab.spots.at(j).sensiden = locallab.spots.at(j).sensiden && pSpot.sensiden == otherSpot.sensiden; + locallab.spots.at(j).reparden = locallab.spots.at(j).reparden && pSpot.reparden == otherSpot.reparden; locallab.spots.at(j).detailthr = locallab.spots.at(j).detailthr && pSpot.detailthr == otherSpot.detailthr; locallab.spots.at(j).locwavcurveden = locallab.spots.at(j).locwavcurveden && pSpot.locwavcurveden == otherSpot.locwavcurveden; locallab.spots.at(j).locwavcurvehue = locallab.spots.at(j).locwavcurvehue && pSpot.locwavcurvehue == otherSpot.locwavcurvehue; @@ -1373,6 +1376,7 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).gamma = locallab.spots.at(j).gamma && pSpot.gamma == otherSpot.gamma; locallab.spots.at(j).estop = locallab.spots.at(j).estop && pSpot.estop == otherSpot.estop; locallab.spots.at(j).scaltm = locallab.spots.at(j).scaltm && pSpot.scaltm == otherSpot.scaltm; + locallab.spots.at(j).repartm = locallab.spots.at(j).repartm && pSpot.repartm == otherSpot.repartm; locallab.spots.at(j).rewei = locallab.spots.at(j).rewei && pSpot.rewei == otherSpot.rewei; locallab.spots.at(j).satur = locallab.spots.at(j).satur && pSpot.satur == otherSpot.satur; locallab.spots.at(j).sensitm = locallab.spots.at(j).sensitm && pSpot.sensitm == otherSpot.sensitm; @@ -1494,6 +1498,7 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).edgw = locallab.spots.at(j).edgw && pSpot.edgw == otherSpot.edgw; locallab.spots.at(j).basew = locallab.spots.at(j).basew && pSpot.basew == otherSpot.basew; locallab.spots.at(j).sensilc = locallab.spots.at(j).sensilc && pSpot.sensilc == otherSpot.sensilc; + locallab.spots.at(j).reparw = locallab.spots.at(j).reparw && pSpot.reparw == otherSpot.reparw; locallab.spots.at(j).fftwlc = locallab.spots.at(j).fftwlc && pSpot.fftwlc == otherSpot.fftwlc; locallab.spots.at(j).blurlc = locallab.spots.at(j).blurlc && pSpot.blurlc == otherSpot.blurlc; locallab.spots.at(j).wavblur = locallab.spots.at(j).wavblur && pSpot.wavblur == otherSpot.wavblur; @@ -3398,6 +3403,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).lightness = mods.locallab.spots.at(i).lightness; } + if (locallab.spots.at(i).reparcol) { + toEdit.locallab.spots.at(i).reparcol = mods.locallab.spots.at(i).reparcol; + } + if (locallab.spots.at(i).contrast) { toEdit.locallab.spots.at(i).contrast = mods.locallab.spots.at(i).contrast; } @@ -3791,8 +3800,12 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).laplacexp = mods.locallab.spots.at(i).laplacexp; } - if (locallab.spots.at(i).balanexp) { - toEdit.locallab.spots.at(i).balanexp = mods.locallab.spots.at(i).balanexp; + if (locallab.spots.at(i).laplacexp) { + toEdit.locallab.spots.at(i).laplacexp = mods.locallab.spots.at(i).laplacexp; + } + + if (locallab.spots.at(i).reparexp) { + toEdit.locallab.spots.at(i).reparexp = mods.locallab.spots.at(i).reparexp; } if (locallab.spots.at(i).linear) { @@ -3942,6 +3955,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).detailSH = mods.locallab.spots.at(i).detailSH; } + if (locallab.spots.at(i).reparsh) { + toEdit.locallab.spots.at(i).reparsh = mods.locallab.spots.at(i).reparsh; + } + if (locallab.spots.at(i).LmaskSHcurve) { toEdit.locallab.spots.at(i).LmaskSHcurve = mods.locallab.spots.at(i).LmaskSHcurve; } @@ -4341,6 +4358,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).sensiden = mods.locallab.spots.at(i).sensiden; } + if (locallab.spots.at(i).reparden) { + toEdit.locallab.spots.at(i).reparden = mods.locallab.spots.at(i).reparden; + } + if (locallab.spots.at(i).detailthr) { toEdit.locallab.spots.at(i).detailthr = mods.locallab.spots.at(i).detailthr; } @@ -4463,6 +4484,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).scaltm = mods.locallab.spots.at(i).scaltm; } + if (locallab.spots.at(i).repartm) { + toEdit.locallab.spots.at(i).repartm = mods.locallab.spots.at(i).repartm; + } + if (locallab.spots.at(i).rewei) { toEdit.locallab.spots.at(i).rewei = mods.locallab.spots.at(i).rewei; } @@ -4939,6 +4964,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).sensilc = mods.locallab.spots.at(i).sensilc; } + if (locallab.spots.at(i).reparw) { + toEdit.locallab.spots.at(i).reparw = mods.locallab.spots.at(i).reparw; + } + if (locallab.spots.at(i).fftwlc) { toEdit.locallab.spots.at(i).fftwlc = mods.locallab.spots.at(i).fftwlc; } @@ -6700,6 +6729,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : complexcolor(v), curvactiv(v), lightness(v), + reparcol(v), contrast(v), chroma(v), labgridALow(v), @@ -6799,6 +6829,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : expMethod(v), exnoiseMethod(v), laplacexp(v), + reparexp(v), balanexp(v), linear(v), gamm(v), @@ -6837,6 +6868,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : slomaskSH(v), lapmaskSH(v), detailSH(v), + reparsh(v), LmaskSHcurve(v), fatamountSH(v), fatanchorSH(v), @@ -6939,6 +6971,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : nlrad(v), nlgam(v), sensiden(v), + reparden(v), detailthr(v), locwavcurveden(v), locwavcurvehue(v), @@ -6970,6 +7003,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : gamma(v), estop(v), scaltm(v), + repartm(v), rewei(v), satur(v), sensitm(v), @@ -7091,6 +7125,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : edgw(v), basew(v), sensilc(v), + reparw(v), fftwlc(v), blurlc(v), wavblur(v), @@ -7272,6 +7307,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) complexcolor = v; curvactiv = v; lightness = v; + reparcol = v; contrast = v; chroma = v; labgridALow = v; @@ -7371,6 +7407,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) expMethod = v; exnoiseMethod = v; laplacexp = v; + reparexp = v; balanexp = v; linear = v; gamm = v; @@ -7413,6 +7450,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) slomaskSH = v; lapmaskSH = v; detailSH = v; + reparsh = v; LmaskSHcurve = v; fatamountSH = v; fatanchorSH = v; @@ -7515,6 +7553,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) nlrad = v; nlgam = v; sensiden = v; + reparden = v; detailthr = v; locwavcurveden = v; showmaskblMethodtyp = v; @@ -7545,6 +7584,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) gamma = v; estop = v; scaltm = v; + repartm = v; rewei = v; satur = v; sensitm = v; @@ -7666,6 +7706,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) edgw = v; basew = v; sensilc = v; + reparw = v; fftwlc = v; blurlc = v; wavblur = v; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 95fc76407..ff3702c7e 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -438,6 +438,7 @@ public: bool complexcolor; bool curvactiv; bool lightness; + bool reparcol; bool contrast; bool chroma; bool labgridALow; @@ -537,6 +538,7 @@ public: bool expMethod; bool exnoiseMethod; bool laplacexp; + bool reparexp; bool balanexp; bool linear; bool gamm; @@ -575,6 +577,7 @@ public: bool slomaskSH; bool lapmaskSH; bool detailSH; + bool reparsh; bool LmaskSHcurve; bool fatamountSH; bool fatanchorSH; @@ -677,6 +680,7 @@ public: bool nlrad; bool nlgam; bool sensiden; + bool reparden; bool detailthr; bool locwavcurveden; bool locwavcurvehue; @@ -708,6 +712,7 @@ public: bool gamma; bool estop; bool scaltm; + bool repartm; bool rewei; bool satur; bool sensitm; @@ -829,6 +834,7 @@ public: bool edgw; bool basew; bool sensilc; + bool reparw; bool fftwlc; bool blurlc; bool wavblur; From 980a16abb0834b0138d7d99e6dc94e05aa8ead89 Mon Sep 17 00:00:00 2001 From: Desmis Date: Tue, 4 May 2021 13:54:12 +0200 Subject: [PATCH 051/135] Improve ciecam16 Log encoding (#6228) --- rtdata/languages/default | 4 +++- rtengine/iplocallab.cc | 15 +++++++++++++-- rtengine/procevents.h | 1 + rtengine/procparams.cc | 4 ++++ rtengine/procparams.h | 1 + rtengine/refreshmap.cc | 3 ++- rtgui/locallabtools.h | 1 + rtgui/locallabtools2.cc | 27 ++++++++++++++++++++++++++- rtgui/paramsedited.cc | 7 +++++++ rtgui/paramsedited.h | 1 + 10 files changed, 59 insertions(+), 5 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index ba2d13d4f..7fc3a6f40 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1294,6 +1294,7 @@ HISTORY_MSG_1046;Local - Denoise strength HISTORY_MSG_1047;Local - SH and Tone Equalizer strength HISTORY_MSG_1048;Local - DR and Exposure strength HISTORY_MSG_1049;Local - TM strength +HISTORY_MSG_1050;Local - Log encoding chroma HISTORY_MSG_BLSHAPE;Blur by level HISTORY_MSG_BLURCWAV;Blur chroma HISTORY_MSG_BLURWAV;Blur luminance @@ -2557,6 +2558,7 @@ TP_LOCALLAB_CHROMACB_TOOLTIP;Increases or reduces the effect depending on the lu TP_LOCALLAB_CHROMALEV;Chroma levels TP_LOCALLAB_CHROMASKCOL;Chroma TP_LOCALLAB_CHROMASK_TOOLTIP;Changes the chroma of the mask if one exists (i.e. C(C) or LC(H) is activated). +TP_LOCALLAB_CHROML;Chroma (C) TP_LOCALLAB_CHRRT;Chroma TP_LOCALLAB_CIEC;Use Ciecam environment parameters TP_LOCALLAB_CIECAMLOG_TOOLTIP;This module is based on the CIECAM color appearance model which was designed to better simulate how human vision perceives colors under different lighting conditions.\nThe first Ciecam process 'Scene conditions' is carried out by Log encoding, it also uses 'Absolute luminance' at the time of shooting.\nThe second Ciecam process 'Image adjustments' is simplified and uses only 3 variables (local contrast, contrast J, saturation s).\nThe third Ciecam process 'Viewing conditions' adapts the output to the intended viewing conditions (monitor, TV, projector, printer, etc.) so that the chromatic and contrast appearance is preserved across the display environment. @@ -2820,7 +2822,7 @@ TP_LOCALLAB_LOGREPART_TOOLTIP;Allows you to adjust the relative strength of the TP_LOCALLAB_LOGSATURL_TOOLTIP;Saturation (s) in CIECAM16 corresponds to the color of a stimulus in relation to its own brightness.\nActs mainly on medium and highlights tones TP_LOCALLAB_LOGSCENE_TOOLTIP;Corresponds to the shooting conditions. TP_LOCALLAB_LOGSRCGREY_TOOLTIP;Estimated gray point value of the image. -TP_LOCALLAB_LOGSURSOUR_TOOLTIP;Changes tones and colors to take into account the Scene conditions.\n\nAverage: Average light environment (standard). The image will not change.\n\nDim: Dim environment. The image will become slightly brighter. +TP_LOCALLAB_LOGSURSOUR_TOOLTIP;Changes tones and colors to take into account the Scene conditions.\n\nAverage: Average light environment (standard). The image will not change.\n\nDim: Dim environment. The image will become slightly brighter.\n\nDark: Dark environment. The image will become more bright. TP_LOCALLAB_LOGTARGGREY_TOOLTIP;You can adjust this value to suit. TP_LOCALLAB_LOGVIEWING_TOOLTIP;Corresponds to the medium on which the final image will be viewed (monitor, TV, projector, printer,..), as well as its environment. TP_LOCALLAB_LOG_TOOLNAME;Log Encoding diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 11887b10c..35df6d350 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -2565,6 +2565,10 @@ void ImProcFunctions::ciecamloc_02float(int sp, LabImage* lab, int call) f = 0.9f; c = 0.59f; nc = 0.9f; + } else if (params->locallab.spots.at(sp).sursour == "Dark") { + f = 0.8f; + c = 0.525f; + nc = 0.8f; } //viewing condition for surround @@ -2617,8 +2621,15 @@ void ImProcFunctions::ciecamloc_02float(int sp, LabImage* lab, int call) float schr = 0.f; float mchr = 0.f; + float cchr = 0.f; if (ciec) { + + cchr = params->locallab.spots.at(sp).chroml; + if (cchr == -100.0f) { + cchr = -99.8f; + } + schr = params->locallab.spots.at(sp).saturl; if (schr > 0.f) { @@ -2773,7 +2784,7 @@ void ImProcFunctions::ciecamloc_02float(int sp, LabImage* lab, int call) if(ciec) { Qpro = CAMBrightCurveQ[(float)(Qpro * coefQ)] / coefQ; //brightness and contrast float rstprotection = 50.f;//default value to avoid 1 slider - float chr = 0.f;//no use of chroma + // float chr = 0.f;//no use of chroma float Mp, sres; Mp = Mpro / 100.0f; Ciecam02::curvecolorfloat(mchr, Mp, sres, 2.5f); @@ -2801,7 +2812,7 @@ void ImProcFunctions::ciecamloc_02float(int sp, LabImage* lab, int call) Qpro = QproFactor * sqrtf(Jpro); float Cp = (spro * spro * Qpro) / (1000000.f); Cpro = Cp * 100.f; - Ciecam02::curvecolorfloat(chr, Cp, sres, 1.8f); + Ciecam02::curvecolorfloat(cchr, Cp, sres, 1.8f); Color::skinredfloat(Jpro, hpro, sres, Cp, 55.f, 30.f, 1, rstprotection, 100.f, Cpro); } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 890f3bf4a..0bb673f1e 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -1072,6 +1072,7 @@ enum ProcEventCode { Evlocallabreparsh = 1046, Evlocallabreparexp = 1047, Evlocallabrepartm = 1048, + Evlocallabchroml = 1049, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index e01247471..35ba742f3 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -3985,6 +3985,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : targetGray(18.), catad(0.), saturl(0.), + chroml(0.), lightl(0.), lightq(0.), contl(0.), @@ -4707,6 +4708,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && targetGray == other.targetGray && catad == other.catad && saturl == other.saturl + && chroml == other.chroml && lightl == other.lightl && lightq == other.lightq && contl == other.contl @@ -6360,6 +6362,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || spot_edited->targetGray, "Locallab", "TargetGray_" + index_str, spot.targetGray, keyFile); saveToKeyfile(!pedited || spot_edited->catad, "Locallab", "Catad_" + index_str, spot.catad, keyFile); saveToKeyfile(!pedited || spot_edited->saturl, "Locallab", "Saturl_" + index_str, spot.saturl, keyFile); + saveToKeyfile(!pedited || spot_edited->saturl, "Locallab", "Chroml_" + index_str, spot.chroml, keyFile); saveToKeyfile(!pedited || spot_edited->LcurveL, "Locallab", "LCurveL_" + index_str, spot.LcurveL, keyFile); saveToKeyfile(!pedited || spot_edited->lightl, "Locallab", "Lightl_" + index_str, spot.lightl, keyFile); saveToKeyfile(!pedited || spot_edited->lightq, "Locallab", "Brightq_" + index_str, spot.lightq, keyFile); @@ -8265,6 +8268,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "TargetGray_" + index_str, pedited, spot.targetGray, spotEdited.targetGray); assignFromKeyfile(keyFile, "Locallab", "Catad_" + index_str, pedited, spot.catad, spotEdited.catad); assignFromKeyfile(keyFile, "Locallab", "Saturl_" + index_str, pedited, spot.saturl, spotEdited.saturl); + assignFromKeyfile(keyFile, "Locallab", "Chroml_" + index_str, pedited, spot.chroml, spotEdited.chroml); assignFromKeyfile(keyFile, "Locallab", "Lightl_" + index_str, pedited, spot.lightl, spotEdited.lightl); assignFromKeyfile(keyFile, "Locallab", "Brightq_" + index_str, pedited, spot.lightq, spotEdited.lightq); assignFromKeyfile(keyFile, "Locallab", "Contl_" + index_str, pedited, spot.contl, spotEdited.contl); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index ea6b94d73..07db23a32 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1496,6 +1496,7 @@ struct LocallabParams { double targetGray; double catad; double saturl; + double chroml; double lightl; double lightq; double contl; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index e5446dfb1..225cef180 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -1075,7 +1075,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { AUTOEXP, // Evlocallabreparden AUTOEXP, // Evlocallabreparsh AUTOEXP, // Evlocallabreparexp - AUTOEXP // Evlocallabrepartm + AUTOEXP, // Evlocallabrepartm + AUTOEXP // Evlocallabchroml }; diff --git a/rtgui/locallabtools.h b/rtgui/locallabtools.h index d9d3a11f8..2acafa826 100644 --- a/rtgui/locallabtools.h +++ b/rtgui/locallabtools.h @@ -1330,6 +1330,7 @@ private: Adjuster* const contthres; Adjuster* const colorfl; Adjuster* const saturl; + Adjuster* const chroml; MyExpander* const expL; CurveEditorGroup* const CurveEditorL; DiagonalCurveEditor* const LshapeL; diff --git a/rtgui/locallabtools2.cc b/rtgui/locallabtools2.cc index f7d68e5a1..0518cc4b6 100644 --- a/rtgui/locallabtools2.cc +++ b/rtgui/locallabtools2.cc @@ -5162,6 +5162,7 @@ LocallabLog::LocallabLog(): contthres(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGCONTHRES"), -1., 1., 0.01, 0.))), colorfl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LOGCOLORFL"), -100., 100., 0.5, 0.))), saturl(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SATURV"), -100., 100., 0.5, 0.))), + chroml(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROML"), -100., 100., 0.5, 0.))), expL(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_LOGEXP")))), CurveEditorL(new CurveEditorGroup(options.lastlocalCurvesDir, M("TP_LOCALLAB_LOGCONTQ"))), LshapeL(static_cast(CurveEditorL->addCurve(CT_Diagonal, "Q(Q)"))), @@ -5231,6 +5232,8 @@ LocallabLog::LocallabLog(): saturl->setAdjusterListener(this); + chroml->setAdjusterListener(this); + lightl->setAdjusterListener(this); lightq->setAdjusterListener(this); @@ -5272,7 +5275,7 @@ LocallabLog::LocallabLog(): surHBox->pack_start (*surLabel, Gtk::PACK_SHRINK); sursour->append (M ("TP_COLORAPP_SURROUND_AVER")); sursour->append (M ("TP_COLORAPP_SURROUND_DIM")); -// sursour->append (M ("TP_COLORAPP_SURROUND_DARK")); + sursour->append (M ("TP_COLORAPP_SURROUND_DARK")); sursour->set_active (0); surHBox->pack_start (*sursour); sursourconn = sursour->signal_changed().connect ( sigc::mem_fun (*this, &LocallabLog::sursourChanged) ); @@ -5362,10 +5365,13 @@ LocallabLog::LocallabLog(): logP1Box->pack_start(*contl); logP1Box->pack_start(*contthres); logP1Box->pack_start(*saturl); + Gtk::Separator* const separatorchro = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); ToolParamBlock* const logP11Box = Gtk::manage(new ToolParamBlock()); logP11Box->pack_start(*lightl); logP11Box->pack_start(*lightq); logP11Box->pack_start(*contq); + logP11Box->pack_start(*separatorchro); + logP11Box->pack_start(*chroml); logP11Box->pack_start(*colorfl); expL->add(*logP11Box, false); logP1Box->pack_start(*expL, false, false); @@ -5463,6 +5469,7 @@ void LocallabLog::updateAdviceTooltips(const bool showTooltips) lightl->set_tooltip_text(M("TP_LOCALLAB_LOGLIGHTL_TOOLTIP")); lightq->set_tooltip_text(M("TP_LOCALLAB_LOGLIGHTQ_TOOLTIP")); saturl->set_tooltip_text(M("TP_LOCALLAB_LOGSATURL_TOOLTIP")); + chroml->set_tooltip_text(M("TP_COLORAPP_CHROMA_TOOLTIP")); detail->set_tooltip_text(M("TP_LOCALLAB_LOGDETAIL_TOOLTIP")); catad->set_tooltip_text(M("TP_LOCALLAB_LOGCATAD_TOOLTIP")); sensilog->set_tooltip_text(M("TP_LOCALLAB_SENSI_TOOLTIP")); @@ -5512,6 +5519,7 @@ void LocallabLog::updateAdviceTooltips(const bool showTooltips) contthres->set_tooltip_text(""); colorfl->set_tooltip_text(""); saturl->set_tooltip_text(""); + chroml->set_tooltip_text(""); catad->set_tooltip_text(""); expmaskL->set_tooltip_markup(""); CCmaskshapeL->setTooltip(""); @@ -5607,6 +5615,8 @@ void LocallabLog::read(const rtengine::procparams::ProcParams* pp, const ParamsE sursour->set_active (0); } else if (spot.sursour == "Dim") { sursour->set_active (1); + } else if (spot.sursour == "Dark") { + sursour->set_active (2); } @@ -5631,6 +5641,7 @@ void LocallabLog::read(const rtengine::procparams::ProcParams* pp, const ParamsE sourceabs->setValue(spot.sourceabs); catad->setValue(spot.catad); saturl->setValue(spot.saturl); + chroml->setValue(spot.chroml); lightl->setValue(spot.lightl); lightq->setValue(spot.lightq); contl->setValue(spot.contl); @@ -5694,6 +5705,7 @@ void LocallabLog::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedi spot.targetGray = targetGray->getValue(); spot.catad = catad->getValue(); spot.saturl = saturl->getValue(); + spot.chroml = chroml->getValue(); spot.lightl = lightl->getValue(); spot.lightq = lightq->getValue(); spot.contl = contl->getValue(); @@ -5724,6 +5736,8 @@ void LocallabLog::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedi spot.sursour = "Average"; } else if (sursour->get_active_row_number() == 1) { spot.sursour = "Dim"; + } else if (sursour->get_active_row_number() == 2) { + spot.sursour = "Dark"; } if (surround->get_active_row_number() == 0) { @@ -5778,6 +5792,7 @@ void LocallabLog::updateGUIToMode(const modeType new_type) sourceabs->hide(); targabs->hide(); saturl->hide(); + chroml->hide(); contl->hide(); contthres->hide(); lightl->hide(); @@ -5805,6 +5820,7 @@ void LocallabLog::updateGUIToMode(const modeType new_type) targabs->show(); catad->show(); saturl->show(); + chroml->show(); lightl->show(); lightq->show(); contl->show(); @@ -5838,6 +5854,7 @@ void LocallabLog::updateGUIToMode(const modeType new_type) targabs->show(); catad->show(); saturl->show(); + chroml->show(); lightl->show(); lightq->show(); contl->show(); @@ -5984,6 +6001,7 @@ void LocallabLog::setDefaults(const rtengine::procparams::ProcParams* defParams, targetGray->setDefault(defSpot.targetGray); catad->setDefault(defSpot.catad); saturl->setDefault(defSpot.saturl); + chroml->setDefault(defSpot.chroml); lightl->setDefault(defSpot.lightl); lightq->setDefault(defSpot.lightq); contl->setDefault(defSpot.contl); @@ -6075,6 +6093,13 @@ void LocallabLog::adjusterChanged(Adjuster* a, double newval) } } + if (a == chroml) { + if (listener) { + listener->panelChanged(Evlocallabchroml, + chroml->getTextValue() + " (" + escapeHtmlChars(spotName) + ")"); + } + } + if (a == lightl) { if (listener) { listener->panelChanged(Evlocallablightl, diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 8fdd44bb6..7570c0047 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -1572,6 +1572,7 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).targetGray = locallab.spots.at(j).targetGray && pSpot.targetGray == otherSpot.targetGray; locallab.spots.at(j).catad = locallab.spots.at(j).catad && pSpot.catad == otherSpot.catad; locallab.spots.at(j).saturl = locallab.spots.at(j).saturl && pSpot.saturl == otherSpot.saturl; + locallab.spots.at(j).chroml = locallab.spots.at(j).chroml && pSpot.chroml == otherSpot.chroml; locallab.spots.at(j).lightl = locallab.spots.at(j).lightl && pSpot.lightl == otherSpot.lightl; locallab.spots.at(j).lightq = locallab.spots.at(j).lightq && pSpot.lightq == otherSpot.lightq; locallab.spots.at(j).contl = locallab.spots.at(j).contl && pSpot.contl == otherSpot.contl; @@ -5240,6 +5241,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).saturl = mods.locallab.spots.at(i).saturl; } + if (locallab.spots.at(i).chroml) { + toEdit.locallab.spots.at(i).chroml = mods.locallab.spots.at(i).chroml; + } + if (locallab.spots.at(i).lightl) { toEdit.locallab.spots.at(i).lightl = mods.locallab.spots.at(i).lightl; } @@ -7195,6 +7200,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : targetGray(v), catad(v), saturl(v), + chroml(v), lightl(v), lightq(v), contl(v), @@ -7780,6 +7786,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) targetGray = v; catad = v; saturl = v; + chroml = v; lightl = v; lightq = v; contl = v; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index ff3702c7e..7094f5492 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -904,6 +904,7 @@ public: bool targetGray; bool catad; bool saturl; + bool chroml; bool lightl; bool lightq; bool contl; From 9495c049c49b73b129ee329546af84db173753c7 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Thu, 6 May 2021 21:39:01 -0700 Subject: [PATCH 052/135] Fix inspector not opening full-screen at first --- rtgui/inspector.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 2de324b29..cf4ae3207 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -126,7 +126,6 @@ void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) // initialize when shown first if (!initialized) { window->show_all(); - window->set_visible(false); initialized = true; } From 75b6b274bb31a15d7e72ad752cc816dc04526dec Mon Sep 17 00:00:00 2001 From: Beep6581 Date: Fri, 7 May 2021 07:44:39 +0200 Subject: [PATCH 053/135] Update CONTRIBUTING.md --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f94454b63..041b273df 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,6 +16,7 @@ The most useful feedback is based on the latest development code, and in the cas - Announce and discuss your plans in GitHub before starting work. - Work in a new branch. Fork if necessary. - Keep branches small so that completed and working features can be merged into the "dev" branch often, and so that they can be abandoned if they head in the wrong direction. +- Documentation for your work must be provided in order for your branch to be merged if it changes or adds anything the user should know about. The documentation can be provided in plain-text or markdown form as a comment in the issue or pull request. - Use C++11. - To break header dependencies use forward declarations as much as possible. See [#5197](https://github.com/Beep6581/RawTherapee/pull/5197#issuecomment-468938190) for some tips. - The naming isn't homogeneous throughout the code but here is a rough guideline: From 1c9d1f522cbdec406f0086e027ee6a31949e2fec Mon Sep 17 00:00:00 2001 From: Pandagrapher Date: Fri, 7 May 2021 18:47:14 +0200 Subject: [PATCH 054/135] Locallab - Fix bad syntax in LocallabParamsEdited vector resize --- rtgui/editorpanel.cc | 2 +- rtgui/filebrowser.cc | 2 +- rtgui/history.cc | 4 ++-- rtgui/paramsedited.cc | 4 ++-- rtgui/profilepanel.cc | 20 ++++++++++---------- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 1ec19e616..7f2352b5a 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -1757,7 +1757,7 @@ void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt) PartialProfile pp (true); pp.set (true); * (pp.pparams) = openThm->getProcParams(); - pp.pedited->locallab.spots.resize(pp.pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + pp.pedited->locallab.spots.resize(pp.pparams->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); tpc->profileChange (&pp, rtengine::EvProfileChangeNotification, M ("PROGRESSDLG_PROFILECHANGEDINBROWSER")); pp.deleteInstance(); } diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 0d2451b59..c3b4a6353 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -1431,7 +1431,7 @@ void FileBrowser::applyPartialMenuItemActivated (ProfileStoreLabel *label) rtengine::procparams::PartialProfile dstProfile(true); *dstProfile.pparams = (static_cast(selected[i]))->thumbnail->getProcParams (); dstProfile.set(true); - dstProfile.pedited->locallab.spots.resize(dstProfile.pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + dstProfile.pedited->locallab.spots.resize(dstProfile.pparams->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); partialPasteDlg.applyPaste (dstProfile.pparams, dstProfile.pedited, srcProfiles->pparams, srcProfiles->pedited); (static_cast(selected[i]))->thumbnail->setProcParams (*dstProfile.pparams, dstProfile.pedited, FILEBROWSER); dstProfile.deleteInstance(); diff --git a/rtgui/history.cc b/rtgui/history.cc index dfc74af24..4d6940e9b 100644 --- a/rtgui/history.cc +++ b/rtgui/history.cc @@ -180,7 +180,7 @@ void History::historySelectionChanged () if (row && tpc) { ProcParams pparams = row[historyColumns.params]; ParamsEdited pe (true); - pe.locallab.spots.resize(pparams.locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + pe.locallab.spots.resize(pparams.locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); PartialProfile pp (&pparams, &pe); ParamsEdited paramsEdited = row[historyColumns.paramsEdited]; @@ -215,7 +215,7 @@ void History::bookmarkSelectionChanged () if (row && tpc) { ProcParams pparams = row[bookmarkColumns.params]; ParamsEdited pe (true); - pe.locallab.spots.resize(pparams.locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + pe.locallab.spots.resize(pparams.locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); PartialProfile pp (&pparams, &pe); ParamsEdited paramsEdited = row[bookmarkColumns.paramsEdited]; tpc->profileChange (&pp, EvBookmarkSelected, row[bookmarkColumns.text], ¶msEdited); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 7570c0047..d6808cf38 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -704,7 +704,7 @@ void ParamsEdited::initFrom(const std::vector& // Resize LocallabSpotEdited according to src[0] locallab.spots.clear(); - locallab.spots.resize(p.locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + locallab.spots.resize(p.locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); // Variable used to determined if Locallab spots number is equal and so spots can be combined bool isSpotNumberEqual = true; @@ -1642,7 +1642,7 @@ void ParamsEdited::initFrom(const std::vector& if (!isSpotNumberEqual) { // All LocallabSpotEdited are set to false because cannot be combined locallab.spots.clear(); - locallab.spots.resize(p.locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(false)); + locallab.spots.resize(p.locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(false)); } pcvignette.enabled = pcvignette.enabled && p.pcvignette.enabled == other.pcvignette.enabled; diff --git a/rtgui/profilepanel.cc b/rtgui/profilepanel.cc index a13c6421d..05e5bbab1 100644 --- a/rtgui/profilepanel.cc +++ b/rtgui/profilepanel.cc @@ -573,7 +573,7 @@ void ProfilePanel::paste_clicked (GdkEventButton* event) // Setting LocallabSpotEdited number coherent with spots number in lastsaved->pparams custom->pedited->locallab.spots.clear(); - custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(false)); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(false)); } else { const ProfileStoreEntry* entry = profiles->getSelectedEntry(); @@ -583,7 +583,7 @@ void ProfilePanel::paste_clicked (GdkEventButton* event) // Setting LocallabSpotEdited number coherent with spots number in partProfile->pparams custom->pedited->locallab.spots.clear(); - custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(false)); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(false)); } } @@ -601,7 +601,7 @@ void ProfilePanel::paste_clicked (GdkEventButton* event) // Setting LocallabSpotEdited number coherent with spots number in lastsaved->pparams custom->pedited->locallab.spots.clear(); - custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); } else { const ProfileStoreEntry* entry = profiles->getSelectedEntry(); @@ -611,7 +611,7 @@ void ProfilePanel::paste_clicked (GdkEventButton* event) // Setting LocallabSpotEdited number coherent with spots number in partProfile->pparams custom->pedited->locallab.spots.clear(); - custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); } } } @@ -658,7 +658,7 @@ void ProfilePanel::paste_clicked (GdkEventButton* event) } else { // Setting LocallabSpotEdited number coherent with spots number in custom->pparams custom->pedited->locallab.spots.clear(); - custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); } } } else { @@ -682,14 +682,14 @@ void ProfilePanel::paste_clicked (GdkEventButton* event) // Setting LocallabSpotEdited number coherent with spots number in custom->pparams custom->pedited->locallab.spots.clear(); - custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); } else { // custom.pparams = clipboard.pparams non filtered *custom->pparams = pp; // Setting LocallabSpotEdited number coherent with spots number in custom->pparams custom->pedited->locallab.spots.clear(); - custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + custom->pedited->locallab.spots.resize(custom->pparams->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); } } @@ -739,7 +739,7 @@ void ProfilePanel::selection_changed () ParamsEdited pe(true); // Setting LocallabSpotEdited number coherent with spots number in s->pparams - pe.locallab.spots.resize(s->pparams->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + pe.locallab.spots.resize(s->pparams->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); PartialProfile s2(s->pparams, &pe, false); changeTo (&s2, pse->label + "+"); @@ -782,7 +782,7 @@ void ProfilePanel::procParamsChanged( // Setting LocallabSpotEdited number coherent with spots number in p custom->pedited->locallab.spots.clear(); - custom->pedited->locallab.spots.resize(p->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + custom->pedited->locallab.spots.resize(p->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); } void ProfilePanel::clearParamChanges() @@ -819,7 +819,7 @@ void ProfilePanel::initProfile (const Glib::ustring& profileFullPath, ProcParams if (lastSaved) { ParamsEdited* pe = new ParamsEdited(true); // Setting LocallabSpotEdited number coherent with lastSaved->locallab spots number (initialized at true such as pe) - pe->locallab.spots.resize(lastSaved->locallab.spots.size(), new LocallabParamsEdited::LocallabSpotEdited(true)); + pe->locallab.spots.resize(lastSaved->locallab.spots.size(), LocallabParamsEdited::LocallabSpotEdited(true)); // copying the provided last saved profile to ProfilePanel::lastsaved lastsaved = new PartialProfile(lastSaved, pe); } From b2988ddbb32e0bd77805daa4f3e36284cfb91fea Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 7 May 2021 22:26:28 -0700 Subject: [PATCH 055/135] Avoid reopening inspector window when being opened --- rtgui/inspector.cc | 11 +++++++++-- rtgui/inspector.h | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index cf4ae3207..1534618e4 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -83,7 +83,7 @@ InspectorBuffer::~InspectorBuffer() { // return deg; //} -Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false), keyDown(false) +Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false), keyDown(false), windowShowing(false) { set_name("Inspector"); @@ -98,6 +98,7 @@ Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomSca window->add_events(Gdk::KEY_PRESS_MASK); window->signal_key_release_event().connect(sigc::mem_fun(*this, &Inspector::on_key_release)); window->signal_key_press_event().connect(sigc::mem_fun(*this, &Inspector::on_key_press)); + window->signal_hide().connect(sigc::mem_fun(*this, &Inspector::on_window_hide)); add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_MOTION_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); gestureZoom = Gtk::GestureZoom::create(*this); @@ -120,7 +121,7 @@ Inspector::~Inspector() void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) { - if (!window) + if (!window || windowShowing) return; // initialize when shown first @@ -138,6 +139,7 @@ void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) this->fullscreen = fullscreen; window->set_visible(true); this->pinned = pinned; + windowShowing = true; // update content when becoming visible switchImage(next_image_path); @@ -218,6 +220,11 @@ bool Inspector::on_key_press(GdkEventKey *event) return false; } +void Inspector::on_window_hide() +{ + windowShowing = false; +} + bool Inspector::on_button_press_event(GdkEventButton *event) { if (!window) diff --git a/rtgui/inspector.h b/rtgui/inspector.h index 4d5e5e835..9ff03f96e 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -56,6 +56,7 @@ private: bool initialized; bool fullscreen; // window is shown in fullscreen mode bool keyDown; + bool windowShowing; sigc::connection delayconn; Glib::ustring next_image_path; @@ -65,6 +66,8 @@ private: bool on_key_release(GdkEventKey *event); bool on_key_press(GdkEventKey *event); + void on_window_hide(); + rtengine::Coord button_pos; bool on_button_press_event(GdkEventButton *event) override; bool on_motion_notify_event(GdkEventMotion *event) override; From 36cb32b31be5702574bcc32e97a82296e465a2be Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 8 May 2021 11:15:41 -0700 Subject: [PATCH 056/135] Make inspector window size consistent --- rtgui/filebrowser.cc | 2 +- rtgui/filecatalog.cc | 4 ++-- rtgui/inspector.cc | 22 +++++++++++++++------- rtgui/inspector.h | 4 +++- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 0246520ee..304e75a5c 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -2100,5 +2100,5 @@ void FileBrowser::openRequested( std::vector mselected) void FileBrowser::inspectRequested(std::vector mselected) { - getInspector()->showWindow(false, false, true); + getInspector()->showWindow(true); } diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index a685bebe9..c45fc154f 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -2515,10 +2515,10 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) if (!ctrl && !alt) { switch (event->keyval) { case GDK_KEY_f: - fileBrowser->getInspector()->showWindow(true); + fileBrowser->getInspector()->showWindow(false, true); return true; case GDK_KEY_F: - fileBrowser->getInspector()->showWindow(false); + fileBrowser->getInspector()->showWindow(false, false); return true; } } diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 1534618e4..9fa1b8773 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -83,7 +83,7 @@ InspectorBuffer::~InspectorBuffer() { // return deg; //} -Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false), keyDown(false), windowShowing(false) +Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomScale(1.0), zoomScaleBegin(1.0), active(false), pinned(false), dirty(false), fullscreen(true), keyDown(false), windowShowing(false) { set_name("Inspector"); @@ -99,6 +99,7 @@ Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomSca window->signal_key_release_event().connect(sigc::mem_fun(*this, &Inspector::on_key_release)); window->signal_key_press_event().connect(sigc::mem_fun(*this, &Inspector::on_key_press)); window->signal_hide().connect(sigc::mem_fun(*this, &Inspector::on_window_hide)); + window->signal_window_state_event().connect(sigc::mem_fun(*this, &Inspector::on_inspector_window_state_event)); add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_MOTION_MASK | Gdk::SCROLL_MASK | Gdk::SMOOTH_SCROLL_MASK); gestureZoom = Gtk::GestureZoom::create(*this); @@ -107,6 +108,7 @@ Inspector::Inspector () : currImage(nullptr), scaled(false), scale(1.0), zoomSca window->add(*this); window->set_size_request(500, 500); + window->fullscreen(); initialized = false; // delay init to avoid flickering on some systems active = true; // always track inspected thumbnails } @@ -119,7 +121,7 @@ Inspector::~Inspector() delete window; } -void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) +void Inspector::showWindow(bool pinned, bool scaled) { if (!window || windowShowing) return; @@ -132,11 +134,6 @@ void Inspector::showWindow(bool scaled, bool fullscreen, bool pinned) // show inspector window this->scaled = scaled; - if (fullscreen) - window->fullscreen(); - else - window->unfullscreen(); - this->fullscreen = fullscreen; window->set_visible(true); this->pinned = pinned; windowShowing = true; @@ -225,6 +222,17 @@ void Inspector::on_window_hide() windowShowing = false; } +bool Inspector::on_inspector_window_state_event(GdkEventWindowState *event) +{ + if (!window->get_window() || window->get_window()->gobj() != event->window) { + return false; + } + + fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN; + + return true; +} + bool Inspector::on_button_press_event(GdkEventButton *event) { if (!window) diff --git a/rtgui/inspector.h b/rtgui/inspector.h index 9ff03f96e..5577bfb45 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -67,6 +67,7 @@ private: bool on_key_press(GdkEventKey *event); void on_window_hide(); + bool on_inspector_window_state_event(GdkEventWindowState *event); rtengine::Coord button_pos; bool on_button_press_event(GdkEventButton *event) override; @@ -90,9 +91,10 @@ public: ~Inspector() override; /** @brief Show or hide window + * @param pinned pin window * @param scaled fit image into window */ - void showWindow(bool scaled, bool fullscreen = true, bool pinned = false); + void showWindow(bool pinned, bool scaled = true); /** * Hide the window. From 9df34be6cbf5ed791aa78f3f1761c719208aea09 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 8 May 2021 12:15:58 -0700 Subject: [PATCH 057/135] Hide inspector accelerator in film strip Only show the accelerator key in the context menu when opening the menu from the full file browser but not the film strip. --- rtgui/filebrowser.cc | 15 ++++++++++++++- rtgui/filebrowser.h | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 304e75a5c..37ff6da62 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -411,7 +411,7 @@ FileBrowser::FileBrowser () : untrash->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_Delete, Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); open->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_Return, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); if (options.inspectorWindow) - inspect->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_F, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); + inspect->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_f, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); develop->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_B, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); developfast->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_B, Gdk::CONTROL_MASK | Gdk::SHIFT_MASK, Gtk::ACCEL_VISIBLE); copyprof->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_C, Gdk::CONTROL_MASK, Gtk::ACCEL_VISIBLE); @@ -1374,6 +1374,19 @@ int FileBrowser::getThumbnailHeight () } } +void FileBrowser::enableTabMode(bool enable) +{ + ThumbBrowserBase::enableTabMode(enable); + if (options.inspectorWindow) { + if (enable) { + inspect->remove_accelerator(pmenu->get_accel_group(), GDK_KEY_f, (Gdk::ModifierType)0); + } + else { + inspect->add_accelerator ("activate", pmenu->get_accel_group(), GDK_KEY_f, (Gdk::ModifierType)0, Gtk::ACCEL_VISIBLE); + } + } +} + void FileBrowser::applyMenuItemActivated (ProfileStoreLabel *label) { MYREADERLOCK(l, entryRW); diff --git a/rtgui/filebrowser.h b/rtgui/filebrowser.h index 03a8636e5..4602ba9bb 100644 --- a/rtgui/filebrowser.h +++ b/rtgui/filebrowser.h @@ -182,6 +182,8 @@ public: void saveThumbnailHeight (int height) override; int getThumbnailHeight () override; + + void enableTabMode(bool enable); bool isInTabMode() override { return tbl ? tbl->isInTabMode() : false; From 6535cb4a9454b86164f0017df958b691965ae4d1 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 9 May 2021 12:18:06 -0700 Subject: [PATCH 058/135] Make inspector never upscale in fit-to-window mode When zoomed completely out, don't upscale images. --- rtgui/inspector.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 9fa1b8773..0453564f9 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -432,7 +432,7 @@ bool Inspector::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) availableSize.y = win->get_height() * deviceScale; int imW = rtengine::max(currImage->imgBuffer.getWidth(), 1); int imH = rtengine::max(currImage->imgBuffer.getHeight(), 1); - scale = rtengine::min(availableSize.x / imW, availableSize.y / imH); + scale = rtengine::min(1., rtengine::min(availableSize.x / imW, availableSize.y / imH)); if (scaled) { // reduce size of image to fit into window, no further zoom down zoomScale = rtengine::max(zoomScale, 1.0); From 77ea6d92cbfadc1a1c90cee5064dc78501c4d031 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 9 May 2021 12:31:26 -0700 Subject: [PATCH 059/135] Pin inspector whenever scrolling or zooming --- rtgui/inspector.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 0453564f9..675da51c6 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -277,6 +277,8 @@ bool Inspector::on_scroll_event(GdkEventScroll *event) if (!currImage || !window) return false; + pinned = true; + bool alt = event->state & GDK_MOD1_MASK; int deviceScale = get_scale_factor(); int imW = currImage->imgBuffer.getWidth(); @@ -381,6 +383,7 @@ void Inspector::beginZoom(double x, double y) void Inspector::on_zoom_begin(GdkEventSequence *s) { double x, y; + pinned = true; if (gestureZoom->get_point(s, x, y)) beginZoom(x, y); } From 62996e16b1c2cbbb64adf54612419132491173fc Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Mon, 10 May 2021 22:02:49 -0700 Subject: [PATCH 060/135] Fix NR luminance detail recovery calculation Add back parentheses removed in 806c086fbcc92c6a11bb714d1bce37b13d41c34b. Closes #6235. --- rtengine/FTblockDN.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index 474196843..400dea05b 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -667,7 +667,7 @@ BENCHFUN const float gain = std::pow(2.0, expcomp); const double params_Ldetail = std::min(dnparams.Ldetail, 99.9); // max out to avoid div by zero when using noisevar_Ldetail as divisor - const float noisevar_Ldetail = SQR(SQR(100. - params_Ldetail) + 50.0 * (100.0 - params_Ldetail) * TS * 0.5); + const float noisevar_Ldetail = SQR((SQR(100. - params_Ldetail) + 50.0 * (100.0 - params_Ldetail)) * TS * 0.5); array2D tilemask_in(TS, TS); array2D tilemask_out(TS, TS); From 4426f85bf929786f752ddfd243df0c4f2dc14fcb Mon Sep 17 00:00:00 2001 From: Simon Segerblom Rex Date: Tue, 11 May 2021 11:37:39 +0200 Subject: [PATCH 061/135] Update AUTHORS.txt --- AUTHORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index ec40f75e1..b880db000 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -33,6 +33,7 @@ Development contributors, in last name alphabetical order: Jan Rinze Alberto Romei Ben S. + Simon Segerblom Rex Andrey Skvortsov Fabio Suprani Anders Torger From 3cb6e88ea4bcd2ab069f21c45dfcee5c3d769d8d Mon Sep 17 00:00:00 2001 From: Desmis Date: Tue, 11 May 2021 13:27:04 +0200 Subject: [PATCH 062/135] Harmonize GUI for Scope - Retinex and Dehaze --- rtgui/locallabtools2.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rtgui/locallabtools2.cc b/rtgui/locallabtools2.cc index 0518cc4b6..f49667ff8 100644 --- a/rtgui/locallabtools2.cc +++ b/rtgui/locallabtools2.cc @@ -980,6 +980,7 @@ LocallabRetinex::LocallabRetinex(): inversretConn = inversret->signal_toggled().connect(sigc::mem_fun(*this, &LocallabRetinex::inversretChanged)); // Add Retinex specific widgets to GUI + pack_start(*sensih); ToolParamBlock* const auxBox = Gtk::manage(new ToolParamBlock()); // Gtk::Frame* const dehaFrame = Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_DEHAFRA"))); dehaFrame->set_label_align(0.025, 0.5); @@ -994,9 +995,9 @@ LocallabRetinex::LocallabRetinex(): deharetiBox->pack_start(*loglin); retiFrame->add(*deharetiBox); auxBox->add(*retiFrame); - ToolParamBlock* const scopeBox = Gtk::manage(new ToolParamBlock()); - scopeBox->pack_start(*sensih); - auxBox->add(*scopeBox); + // ToolParamBlock* const scopeBox = Gtk::manage(new ToolParamBlock()); + // scopeBox->pack_start(*sensih); + // auxBox->add(*scopeBox); pack_start(*auxBox); ToolParamBlock* const retiBox = Gtk::manage(new ToolParamBlock()); retiBox->pack_start(*retinexMethod); From aa7d635f29ed9e50b7c24b1ed8f4abb4f849a98d Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Thu, 13 May 2021 12:32:56 +0200 Subject: [PATCH 063/135] Fix https in license text refreshmap.h --- rtengine/refreshmap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h index 39c80feef..05a8f7f44 100644 --- a/rtengine/refreshmap.h +++ b/rtengine/refreshmap.h @@ -14,7 +14,7 @@ * 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 . + * along with RawTherapee. If not, see . */ #pragma once From bb623d3a02ddd20ebbace4ab8a8c18c3adf75f77 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Thu, 13 May 2021 12:34:27 +0200 Subject: [PATCH 064/135] Fix instance of deprecated HBox --- rtgui/spot.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 6d749838b..10ff99767 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -54,7 +54,7 @@ Spot::Spot() : reset->set_border_width (0); reset->signal_clicked().connect ( sigc::mem_fun (*this, &Spot::resetPressed) ); - labelBox = Gtk::manage (new Gtk::HBox()); + labelBox = Gtk::manage (new Gtk::Box()); labelBox->set_spacing (2); labelBox->pack_start (*countLabel, false, false, 0); labelBox->pack_end (*edit, false, false, 0); From fa2776c7327eb8c69f8f386339d38a6aa379c068 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Thu, 13 May 2021 12:41:01 +0200 Subject: [PATCH 065/135] Remove double include --- rtgui/labgrid.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/rtgui/labgrid.cc b/rtgui/labgrid.cc index b4c4a5c9d..d8a22b1d9 100644 --- a/rtgui/labgrid.cc +++ b/rtgui/labgrid.cc @@ -37,7 +37,6 @@ */ #include "labgrid.h" -#include "options.h" #include "../rtengine/color.h" #include "options.h" From eb8f121709c37b38ada6cee9eb6f27b9b4767027 Mon Sep 17 00:00:00 2001 From: Desmis Date: Thu, 13 May 2021 12:41:22 +0200 Subject: [PATCH 066/135] Add ability to export to an external editor within the same folder as the original file - issue 6195 (#6232) * import and change the art code -thanks to Alberto * Possible fixed for white space in folder * Added verbose when white-space * Replace WS only if windows and Gimp * Fixed Windows and Gimp bug for external editor - thanks to Lawrence37 * Fix LGTM alert for reused variable name Co-authored-by: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> --- rtdata/languages/default | 6 ++++ rtengine/procparams.cc | 2 +- rtengine/procparams.h | 1 + rtgui/editorpanel.cc | 35 +++++++++++++++++----- rtgui/extprog.cc | 4 +-- rtgui/options.cc | 30 +++++++++++++++++++ rtgui/options.h | 10 +++++++ rtgui/preferences.cc | 65 +++++++++++++++++++++++++++++++++++++++- rtgui/preferences.h | 8 +++++ 9 files changed, 149 insertions(+), 12 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 7fc3a6f40..150d16705 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1762,6 +1762,12 @@ PREFERENCES_DIRSOFTWARE;Installation directory PREFERENCES_EDITORCMDLINE;Custom command line PREFERENCES_EDITORLAYOUT;Editor layout PREFERENCES_EXTERNALEDITOR;External Editor +PREFERENCES_EXTEDITOR_DIR;Output directory +PREFERENCES_EXTEDITOR_DIR_TEMP;OS temp dir +PREFERENCES_EXTEDITOR_DIR_CURRENT;Same as input image +PREFERENCES_EXTEDITOR_DIR_CUSTOM;Custom +PREFERENCES_EXTEDITOR_FLOAT32;32-bit float TIFF output +PREFERENCES_EXTEDITOR_BYPASS_OUTPUT_PROFILE;Bypass output profile PREFERENCES_FBROWSEROPTS;File Browser / Thumbnail Options PREFERENCES_FILEBROWSERTOOLBARSINGLEROW;Compact toolbars in File Browser PREFERENCES_FLATFIELDFOUND;Found diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 35ba742f3..5768f9c3e 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2206,6 +2206,7 @@ bool ResizeParams::operator !=(const ResizeParams& other) const } const Glib::ustring ColorManagementParams::NoICMString = Glib::ustring("No ICM: sRGB output"); +const Glib::ustring ColorManagementParams::NoProfileString = Glib::ustring("(none)"); ColorManagementParams::ColorManagementParams() : inputProfile("(cameraICC)"), @@ -6505,7 +6506,6 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo {RI_RELATIVE, "Relative"}, {RI_SATURATION, "Saturation"}, {RI_ABSOLUTE, "Absolute"} - }, icm.outputIntent, keyFile diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 07db23a32..ef14a6e05 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1718,6 +1718,7 @@ struct ColorManagementParams { bool outputBPC; static const Glib::ustring NoICMString; + static const Glib::ustring NoProfileString; ColorManagementParams(); diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 7f2352b5a..a365a8599 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -1972,6 +1972,9 @@ void EditorPanel::sendToGimpPressed () // develop image rtengine::procparams::ProcParams pparams; ipc->getParams (&pparams); + if (options.editor_bypass_output_profile) { + pparams.icm.outputProfile = rtengine::procparams::ColorManagementParams::NoProfileString; + } rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); ProgressConnector *ld = new ProgressConnector(); ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ), @@ -2045,24 +2048,40 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector *p if (img) { // get file name base - const Glib::ustring shortname = removeExtension (Glib::path_get_basename (fname)); - const Glib::ustring dirname = Glib::get_tmp_dir (); - const Glib::ustring lfname = Glib::build_filename (dirname, shortname); + Glib::ustring shortname = removeExtension(Glib::path_get_basename(fname)); + Glib::ustring dirname; + switch (options.editor_out_dir) { + case Options::EDITOR_OUT_DIR_CURRENT: + dirname = Glib::path_get_dirname(fname); + break; + case Options::EDITOR_OUT_DIR_CUSTOM: + dirname = options.editor_custom_out_dir; + break; + default: // Options::EDITOR_OUT_DIR_TEMP + dirname = Glib::get_tmp_dir(); + break; + } + Glib::ustring fullFileName = Glib::build_filename(dirname, shortname); SaveFormat sf; sf.format = "tif"; - sf.tiffBits = 16; - sf.tiffFloat = false; + if (options.editor_float32) { + sf.tiffBits = 32; + sf.tiffFloat = true; + } else { + sf.tiffBits = 16; + sf.tiffFloat = false; + } + sf.tiffUncompressed = true; sf.saveParams = true; - Glib::ustring fileName = Glib::ustring::compose ("%1.%2", lfname, sf.format); + Glib::ustring fileName = Glib::ustring::compose ("%1.%2", fullFileName, sf.format); // TODO: Just list all file with a suitable name instead of brute force... int tries = 1; - while (Glib::file_test (fileName, Glib::FILE_TEST_EXISTS) && tries < 1000) { - fileName = Glib::ustring::compose ("%1-%2.%3", lfname, tries, sf.format); + fileName = Glib::ustring::compose ("%1-%2.%3", fullFileName, tries, sf.format); tries++; } diff --git a/rtgui/extprog.cc b/rtgui/extprog.cc index 57d57ecd8..34dd35e54 100644 --- a/rtgui/extprog.cc +++ b/rtgui/extprog.cc @@ -276,8 +276,8 @@ bool ExtProgStore::openInGimp (const Glib::ustring& fileName) for (auto ver = 12; ver >= 0; --ver) { executable = Glib::build_filename (options.gimpDir, "bin", Glib::ustring::compose (Glib::ustring("gimp-2.%1.exe"), ver)); - auto lsuccess = ShellExecute( NULL, "open", executable.c_str(), fileName.c_str(), NULL, SW_SHOWNORMAL ); - + Glib::ustring escapedFileName = Glib::ustring::compose ("\"%1\"", fileName); + auto lsuccess = ShellExecute( NULL, "open", executable.c_str(), escapedFileName.c_str(), NULL, SW_SHOWNORMAL ); if (reinterpret_cast(lsuccess) > 32) { return true; } diff --git a/rtgui/options.cc b/rtgui/options.cc index ce03db434..e17b2f074 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -415,6 +415,10 @@ void Options::setDefaults() customEditorProg = ""; CPBKeys = CPBKT_TID; editorToSendTo = 1; + editor_out_dir = EDITOR_OUT_DIR_TEMP; + editor_custom_out_dir = ""; + editor_float32 = false; + editor_bypass_output_profile = false; favoriteDirs.clear(); tpOpen.clear(); autoSaveTpOpen = true; @@ -824,6 +828,28 @@ void Options::readFromFile(Glib::ustring fname) if (keyFile.has_key("External Editor", "CustomEditor")) { customEditorProg = keyFile.get_string("External Editor", "CustomEditor"); } + + if (keyFile.has_key("External Editor", "OutputDir")) { + int v = keyFile.get_integer("External Editor", "OutputDir"); + if (v < int(EDITOR_OUT_DIR_TEMP) || v > int(EDITOR_OUT_DIR_CUSTOM)) { + editor_out_dir = EDITOR_OUT_DIR_TEMP; + } else { + editor_out_dir = EditorOutDir(v); + } + } + + if (keyFile.has_key("External Editor", "CustomOutputDir")) { + editor_custom_out_dir = keyFile.get_string("External Editor", "CustomOutputDir"); + } + + if (keyFile.has_key("External Editor", "Float32")) { + editor_float32 = keyFile.get_boolean("External Editor", "Float32"); + } + + if (keyFile.has_key("External Editor", "BypassOutputProfile")) { + editor_bypass_output_profile = keyFile.get_boolean("External Editor", "BypassOutputProfile"); + } + } if (keyFile.has_group("Output")) { @@ -2115,6 +2141,10 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_string("External Editor", "GimpDir", gimpDir); keyFile.set_string("External Editor", "PhotoshopDir", psDir); keyFile.set_string("External Editor", "CustomEditor", customEditorProg); + keyFile.set_integer("External Editor", "OutputDir", int(editor_out_dir)); + keyFile.set_string("External Editor", "CustomOutputDir", editor_custom_out_dir); + keyFile.set_boolean("External Editor", "Float32", editor_float32); + keyFile.set_boolean("External Editor", "BypassOutputProfile", editor_bypass_output_profile); keyFile.set_boolean("File Browser", "BrowseOnlyRaw", fbOnlyRaw); keyFile.set_boolean("File Browser", "BrowserShowsDate", fbShowDateTime); diff --git a/rtgui/options.h b/rtgui/options.h index 03b551efe..52e1c0270 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -280,6 +280,16 @@ public: Glib::ustring CPBPath; // Custom Profile Builder's path CPBKeyType CPBKeys; // Custom Profile Builder's key type int editorToSendTo; + enum EditorOutDir { + EDITOR_OUT_DIR_TEMP, + EDITOR_OUT_DIR_CURRENT, + EDITOR_OUT_DIR_CUSTOM + }; + EditorOutDir editor_out_dir; // output directory for "open in external editor" + Glib::ustring editor_custom_out_dir; + bool editor_float32; + bool editor_bypass_output_profile; + int maxThumbnailHeight; int maxThumbnailWidth; std::size_t maxCacheEntries; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 9d9603297..11e9d34fa 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -1244,7 +1244,48 @@ Gtk::Widget* Preferences::getGeneralPanel() externaleditorGrid->attach_next_to(*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1); #endif - fdg->add(*externaleditorGrid); + + // fdg->add(*externaleditorGrid); + editor_dir_temp = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_TEMP"))); + editor_dir_current = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_CURRENT"))); + editor_dir_custom = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_CUSTOM") + ": ")); + editor_dir_custom_path = Gtk::manage(new MyFileChooserButton("", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + ge = editor_dir_temp->get_group(); + editor_dir_current->set_group(ge); + editor_dir_custom->set_group(ge); + + editor_float32 = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_EXTEDITOR_FLOAT32"))); + editor_bypass_output_profile = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_EXTEDITOR_BYPASS_OUTPUT_PROFILE"))); + { + Gtk::Frame *f = Gtk::manage(new Gtk::Frame(M("PREFERENCES_EXTEDITOR_DIR"))); + setExpandAlignProperties(f, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + Gtk::Box *vb = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); + vb->pack_start(*editor_dir_temp); + vb->pack_start(*editor_dir_current); + Gtk::Box *hb = Gtk::manage(new Gtk::Box()); + hb->pack_start(*editor_dir_custom, Gtk::PACK_SHRINK); + hb->pack_start(*editor_dir_custom_path, Gtk::PACK_EXPAND_WIDGET, 2); + vb->pack_start(*hb); + f->add(*vb); + + hb = Gtk::manage(new Gtk::Box()); + hb->pack_start(*externaleditorGrid); + hb->pack_start(*f, Gtk::PACK_EXPAND_WIDGET, 4); + + vb = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); + vb->pack_start(*hb); + hb = Gtk::manage(new Gtk::Box()); + //I disabled these 2 functionnalities...easy to enable +// hb->pack_start(*editor_float32, Gtk::PACK_SHRINK); +// hb->pack_start(*editor_bypass_output_profile, Gtk::PACK_SHRINK, 4); + vb->pack_start(*hb, Gtk::PACK_SHRINK, 4); + + vb->show_all_children(); + vb->show(); + fdg->add(*vb); + } + + vbGeneral->attach_next_to (*fdg, *fclip, Gtk::POS_BOTTOM, 2, 1); langAutoDetectConn = ckbLangAutoDetect->signal_toggled().connect(sigc::mem_fun(*this, &Preferences::langAutoDetectToggled)); tconn = themeCBT->signal_changed().connect ( sigc::mem_fun (*this, &Preferences::themeChanged) ); @@ -1727,6 +1768,17 @@ void Preferences::storePreferences() moptions.editorToSendTo = 3; } + if (editor_dir_temp->get_active()) { + moptions.editor_out_dir = Options::EDITOR_OUT_DIR_TEMP; + } else if (editor_dir_current->get_active()) { + moptions.editor_out_dir = Options::EDITOR_OUT_DIR_CURRENT; + } else { + moptions.editor_out_dir = Options::EDITOR_OUT_DIR_CUSTOM; + } + moptions.editor_custom_out_dir = editor_dir_custom_path->get_filename(); + moptions.editor_float32 = editor_float32->get_active(); + moptions.editor_bypass_output_profile = editor_bypass_output_profile->get_active(); + moptions.CPBPath = txtCustProfBuilderPath->get_text(); moptions.CPBKeys = CPBKeyType(custProfBuilderLabelType->get_active_row_number()); @@ -2010,6 +2062,17 @@ void Preferences::fillPreferences() #endif editorToSendTo->set_text(moptions.customEditorProg); + editor_dir_temp->set_active(moptions.editor_out_dir == Options::EDITOR_OUT_DIR_TEMP); + editor_dir_current->set_active(moptions.editor_out_dir == Options::EDITOR_OUT_DIR_CURRENT); + editor_dir_custom->set_active(moptions.editor_out_dir == Options::EDITOR_OUT_DIR_CUSTOM); + if (Glib::file_test(moptions.editor_custom_out_dir, Glib::FILE_TEST_IS_DIR)) { + editor_dir_custom_path->set_current_folder(moptions.editor_custom_out_dir); + } else { + editor_dir_custom_path->set_current_folder(Glib::get_tmp_dir()); + } + editor_float32->set_active(moptions.editor_float32); + editor_bypass_output_profile->set_active(moptions.editor_bypass_output_profile); + txtCustProfBuilderPath->set_text(moptions.CPBPath); custProfBuilderLabelType->set_active(moptions.CPBKeys); diff --git a/rtgui/preferences.h b/rtgui/preferences.h index df4e3327a..d5e888251 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -101,6 +101,14 @@ class Preferences final : Gtk::RadioButton* edGimp; Gtk::RadioButton* edPS; Gtk::RadioButton* edOther; + + Gtk::RadioButton *editor_dir_temp; + Gtk::RadioButton *editor_dir_current; + Gtk::RadioButton *editor_dir_custom; + MyFileChooserButton *editor_dir_custom_path; + Gtk::CheckButton *editor_float32; + Gtk::CheckButton *editor_bypass_output_profile; + MyFileChooserButton* darkFrameDir; MyFileChooserButton* flatFieldDir; MyFileChooserButton* clutsDir; From 09621242f440420e67388c3860ef087405647d7c Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Thu, 13 May 2021 13:01:41 +0200 Subject: [PATCH 067/135] Fix forgotten HBox -> Box change in header --- rtgui/spot.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/spot.h b/rtgui/spot.h index bbe70469d..db1fdac05 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -84,7 +84,7 @@ private: void resetPressed (); protected: - Gtk::HBox* labelBox; + Gtk::Box* labelBox; Gtk::CheckButton* editedCheckBox; Gtk::Label* countLabel; Gtk::ToggleButton* edit; From f098e70d4a80bf2773b2a92aecbf0d228bfe848b Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Thu, 13 May 2021 13:03:07 +0200 Subject: [PATCH 068/135] Capitalize tool name for consistency in GUI --- rtdata/languages/default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 0f8761b50..bfe524b45 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -3510,7 +3510,7 @@ TP_SOFTLIGHT_STRENGTH;Strength TP_SPOT_COUNTLABEL;%1 point(s) TP_SPOT_ENTRYCHANGED;Point changed TP_SPOT_HINT;Click on this button to be able to operate on the preview area.\n\nTo edit a spot, hover the white mark locating an edited aera, making the editing geometry appear.\n\nTo add a spot, press Ctrl and left mouse button, drag the circle (Ctrl key can be released) to a source location, then release the mouse button.\n\nTo move the source or destination spot, hover its center then drag it.\n\nThe inner circle (maximum effect area) and the "feather" circle can be resized by hovering them (the circle becomes orange) and draging it (the circle becomes red).\n\nWhen the changes are done, right click outside any spot to end the Spot editing mode, or click on this button again. -TP_SPOT_LABEL;Spot removal +TP_SPOT_LABEL;Spot Removal TP_TM_FATTAL_AMOUNT;Amount TP_TM_FATTAL_ANCHOR;Anchor TP_TM_FATTAL_LABEL;Dynamic Range Compression From fc4814420be0fa508e14be0bf0472d2d697132ae Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Thu, 13 May 2021 14:32:50 +0200 Subject: [PATCH 069/135] Some additions and modifications to camconst.json Some matrices were already loaded in but are now explicit. More to come. Verified new entries with the recent Adobe DNG 13.2 * Canon EOS 400D DIGITAL (now explicit) * Canon PowerShot SX50 HS (now explicit) * OLYMPUS E-M1X (new) * OLYMPUS E-PL9 (now explicit) * Sony DSC-RX0 / DCS-RX0M2 (now explicit) * Sony ILCE-7RM4 (new) * Sony DCS-HX99 (new incl. black/white level) --- rtengine/camconst.json | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 7c3e2818d..a83824022 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -815,7 +815,8 @@ Camera constants: // Canon mid-range DSLRs (Rebels) { // Quality C - "make_model": [ "Canon EOS 400D DIGITAL" ], + "make_model": "Canon EOS 400D DIGITAL", + "dcraw_matrix": [ 7054, -1501, -990, -8156, 15544, 2812, -1278, 1414, 7796 ], "ranges": { "white": 4056 } @@ -1264,6 +1265,7 @@ Camera constants: { // Quality C "make_model": "Canon PowerShot SX50 HS", + "dcraw_matrix": [ 12432, -4753, -1247, -2110, 10691, 1629, -412, 1623, 4926 ], "ranges": { "white": 4050 } }, @@ -1896,6 +1898,7 @@ Camera constants: { // Quality C, only raw crop for highres mode "make_model": "OLYMPUS E-M1X", + "dcraw_matrix": [ 11896, -5110, -1076, -3181, 11378, 2048, -519, 1224, 5165 ], // DNG v11.2 "raw_crop": [ 0, 0, 10388, 0 ] // Highres mode largest valid, full 80Mp 10400X7792, works also for non highres mode because larger width will be ignored }, @@ -1916,6 +1919,7 @@ Camera constants: { // Quality C "make_model": [ "OLYMPUS E-PL9" ], + "dcraw_matrix": [ 8380, -2630, -639, -2887, 10725, 2496, -628, 1427, 5437 ], "ranges": { "white": 4080 } // nominal 4093 }, @@ -2657,6 +2661,7 @@ Camera constants: { // Quality C, correction for frame width "make_model": [ "Sony DSC-RX0", "Sony DSC-RX0M2" ], + "dcraw_matrix": [ 9396, -3507, -843, -2497, 11111, 1572, -343, 1355, 5089 ], "raw_crop": [ 0, 0, -8, 0 ] // 8 rightmost columns are garbage }, @@ -2710,6 +2715,7 @@ Camera constants: { // Quality C, "make_model": "Sony ILCE-7RM4", + "dcraw_matrix": [ 7662, -2686, -660, -5240, 12965, 2530, -796, 1508, 6167 ], "raw_crop": [ 0, 0, -32, 0 ] // full raw frame 9600x6376 - 32 rightmost columns are garbage. Using -32 instead of 9568 to support also 16-shot pixelshift files }, @@ -2734,7 +2740,9 @@ Camera constants: { // Quality C "make_model": [ "Sony DSC-HX99" ], - "raw_crop": [ 0, 0, -8, 0 ] // 8 rightmost columns are garbage + "dcraw_matrix": [ 13076, -5686, -1481, -4027, 12851, 1251, -167, 725, 4937 ], + "raw_crop": [ 0, 0, -8, 0 ], // 8 rightmost columns are garbage + "ranges": { "black": 800, "white": 16300 } }, { // Quality B From 6c96bf7507d631284c4c71134f12e09e3dbe9090 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Thu, 13 May 2021 19:35:37 +0200 Subject: [PATCH 070/135] Update camconst.json to support a lot more camera's Color matrices added or slightly modified for: * Fujifilm X-E4 * Leica C-Lux * Leica M8 * Panasonic DC-FZ1000M2 * Nikon D2Hs * Nikon D2Xs * Nikon D6 * Nikon D3500 * Nikon D300s * Nikon D780 * Nikon D810A * Nikon D70s * Nikon Z 6 2 * Nikon Z 7 2 * Olympus E-M5 Mark III * Olympus E-M1 Mark III * Olympus E-M10 Mark IV * Olympus E-PL10 * Olympus Stylus 1 and 1s * Panasonic DC-G90, G95, G99, G100, G110 * Panasonic DMC-ZS60 (equivalent TZ80, TZ85) * Panasonic DC-ZS80 (equivalent TZ95) * Panasonic DC-S1H * Panasonic DC-S5 * Pentax K-1 Mark II * Sigma fp * Sigma NEX-F3 * Sony alpha 1 (ILCE-1) * Sony A6100, A6400, A6600 (ILCE-6100, ILCE-6400, ILCE-6600) * Sony alpha 7C (ILCE-7C) * Sony Cybershot RX1R (DSC-RX1R) * Sony alpha 9 Mark II (ILCE-9M2) * Sony alpha 7S Mark III (ILCE-7SM3) * Sony Cybershot HX95, HX99 (DSC-HX95, DSC-HX99) * Sony Cybershot DSC-RX100 * Sony Cyberhsot DSC-RX100 VA * Sony Cybershot DSC-RX100 VI * Sony Cybershot DSC-RX100 VII * Sony ZV-1 * Sony SLT-A99V * DJI Mavic 2 Pro (Hasselblad L1D-20c) --- rtengine/camconst.json | 228 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 216 insertions(+), 12 deletions(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index a83824022..a43f97553 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1427,6 +1427,7 @@ Camera constants: { // Quality C "make_model": "FUJIFILM X-E4", + "dcraw_matrix": [ 13426, -6334, -1177, -4244, 12136, 2371, -580, 1303, 5980 ], // DNG v13.2 "raw_crop": [ 0, 5, 6252, 4126 ] }, @@ -1471,10 +1472,16 @@ Camera constants: "dcraw_matrix": [ 9252,-2704,-1064,-5893,14265,1717,-1101,2341,4349 ], // DNG_v8.8 D65 "ranges": { "white": 4040 } }, + + { // Quality C, Leica C-Lux names can differ? + "make_model" : [ "LEICA C-LUX", "LEICA CAM-DC25" ], + "dcraw_matrix" : [7790, -2736, -755, -3452, 11870, 1769, -628, 1647, 4898] + }, - { // Quality B, Matrix from ART + { // Quality B "make_model" : "LEICA D-LUX 7", - "dcraw_matrix" : [11577, -4230, -1106, -3967, 12211, 1957, -758, 1762, 5610] + "dcraw_matrix" : [11577, -4230, -1106, -3967, 12211, 1957, -758, 1762, 5610] // DNG + // "dcraw_matrix" : [8585, -3127, -833, -4005, 12250, 1953, -650, 1494, 4862] // DNG alternate }, { // Quality B, Matrix from Adobe's dcp D65 instead of the internal in Leica's DNG @@ -1483,6 +1490,12 @@ Camera constants: "raw_crop": [ 4, 4, -4, -4 ] // full raw 6016x4016, Official 6000x4000 }, + { // Quality C + "make_model": "LEICA M8", + "dcraw_matrix": [ 7675, -2196, -305, -5860, 14119, 1855, -2425, 4006, 6578 ], // DNG + "ranges": { "white": 16383 } + }, + { // Quality C "make_model": "LEICA Q2", "raw_crop": [ 0, 0, 8392, 5624 ] @@ -1504,9 +1517,9 @@ Camera constants: "raw_crop": [ 0, 2, 6024, 4042 ] // 2 rows at top and 4 rows at bottom are black }, - { // Quality B, Matrix from ART - "make_model" : "LEICA V-LUX 5", - "dcraw_matrix" : [9803, -4185, -992, -4066, 12578, 1628, -838, 1824, 5288] + { // Quality C + "make_model" : ["LEICA V-LUX 5","Panasonic DC-FZ1000M2"], + "dcraw_matrix" : [9803, -4185, -992, -4066, 12578, 1628, -838, 1824, 5288] // DNG }, { // Quality C @@ -1548,6 +1561,16 @@ Camera constants: "dcraw_matrix": [ 6612,-1342,-618,-3338,11055,2623,-174,1792,5075 ], // matrix from DNG_v8.5 d65 "ranges": { "white": 4080 } // BL autodetected from Exif }, + + { // Quality C + "make_model": "Nikon D2Hs", + "dcraw_matrix": [ 5733, -911, -629, -7967, 15987, 2055, -3050, 4013, 7048 ] // DNG + }, + + { // Quality C + "make_model": "Nikon D2Xs", + "dcraw_matrix": [ 10230, -2768, -1255, -8302, 15900, 2551, -797, 680, 7148 ] // DNG + }, // For all Nikon DSLRs which have multiple bitdepth options (14- and 12-bit) we define the 14-bit value and RT adapts it to 12-bit // when a 12-bit bitdepth is detected (WL12 = WL14*4095/16383) @@ -1645,12 +1668,22 @@ Camera constants: "ranges": { "black": 0, "white": 16300 } // WL typical 16383 set to 16300 for safety }, + { // Quality C + "make_model": "Nikon D6", + "dcraw_matrix": [ 9028, -3423, -1035, -6321, 14265, 2217, -1013, 1683, 6928 ] // DNG + }, + { // Quality B "make_model": "Nikon D3400", "dcraw_matrix": [ 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 ], // adobe dng_v9.7 d65 "ranges": { "white": 16300 } // WL value is for 14-bit files, RT auto adapts it for 12-bit files. WL typical 16383 set to 16300 for safety }, + { // Quality C + "make_model": "Nikon D3500", + "dcraw_matrix": [ 8821, -2938, -785, -4178, 12142, 2287, -824, 1651, 6860 ] // DNG + }, + { // Quality B "make_model": "Nikon D5300", "dcraw_matrix": [ 6988,-1384,-714,-5631,13410,2447,-1485,2204,7318 ], // adobe dng_v8.8 d65 @@ -1674,6 +1707,12 @@ Camera constants: "dcraw_matrix": [ 8813,-3210,-1036,-4703,12868,2021,-1054,1940,6129 ], // adobe dng_v9.12 d65 "ranges": { "white": 16300 } // WL value is for 14-bit files, RT auto adapts it for 12-bit files. WL typical 16383 set to 16300 for safety, }, + + { // Quality C + "make_model": "Nikon D300s", + "dcraw_matrix": [ 9030, -1992, -716, -8465, 16302, 2256, -2689, 3217, 8068 ] // DNG + //"dcraw_matrix": [ 9000, -1966, -711, -7030, 14976, 2185, -2354, 2959, 7990 ] // DNG alternate + }, { // Quality B, samples by joachip at RT forums, are measures at long exposures with LongExposureNoiseReduction // aperture scaling known to exist, but little to gain as the levels are so close to white_max @@ -1722,6 +1761,11 @@ Camera constants: "dcraw_matrix": [ 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 ], // adobe dcp d65 DNGv8.7 "ranges": { "white": 16300 } // WL values for 14-bit files, RT auto adapts it for 12-bit files. TypicalWL 16383 set to 16300 for safety }, + + { // Quality C + "make_model": "Nikon D780", + "dcraw_matrix": [ 9943, -3270, -839, -5323, 13269, 2259, -1198, 2083, 7557 ] // DNG + }, { // Quality B, data from RussellCottrell at RT forums. Largest aperture scale factor is 1.013, about 1/50th of a stop "make_model": [ "Nikon D800", "Nikon D800E" ], @@ -1741,6 +1785,11 @@ Camera constants: "raw_crop": [ 0, 0, 7380, 4928 ], // Official raw crop 7380x4928, "ranges": { "white": 16300 } // WL values for 14-bit files, RT auto adapts it for 12-bit files. Typical WL at 16383 }, + + { // Quality C + "make_model": "Nikon D810A", + "dcraw_matrix": [ 11973, -5685, -888, -1965, 10326, 1901, -115, 1123, 7169 ] // DNG + }, { // Quality A, Samples by zorgtool at RT forums "make_model": "Nikon D850", @@ -1774,6 +1823,11 @@ Camera constants: } }, + { // Quality C + "make_model": "Nikon D70s", + "dcraw_matrix": [ 7732, -2421, -789, -8238, 15883, 2498, -859, 783, 7330 ] // DNG + }, + { // Quality B "make_model": "Nikon D80", "dcraw_matrix": [ 8629,-2410,-883,-9055,16940,2171,-1490,1363,8520 ], // Dcraw.c d65 @@ -1786,6 +1840,11 @@ Camera constants: "pdaf_pattern" : [0, 12], "pdaf_offset" : 29 }, + + { // Quality C + "make_model" : "Nikon Z 7_2", + "dcraw_matrix" : [13705, -6004, -1401, -5464, 13568, 2062, -940, 1706, 7618] // DNG + }, { // Quality C, only color matrix and PDAF lines info "make_model" : "Nikon Z 6", @@ -1793,6 +1852,11 @@ Camera constants: "pdaf_pattern" : [0, 12], "pdaf_offset" : 32 }, + + { // Quality C + "make_model" : "Nikon Z 6_2", + "dcraw_matrix" : [9943, -3270, -839, -5323, 13269, 2259, -1198, 2083, 7557] // DNG + }, { // Quality C, only dcraw looted from ART commit ad88c7d97 "make_model" : "NIKON Z 5", @@ -1861,6 +1925,11 @@ Camera constants: } }, + { // Quality C + "make_model": "OLYMPUS E-M5MarkIII", + "dcraw_matrix": [ 11896, -5110, -1076, -3181, 11378, 2048, -519, 1224, 5165 ] // DNG + }, + { // Quality B, 20Mp and 80Mp raw frames "make_model": "OLYMPUS PEN-F", "dcraw_matrix": [ 9476,-3182,-765,-2613,10958,1893,-449,1315,5268 ], // dng_v9.5 D65 @@ -1876,8 +1945,7 @@ Camera constants: { // Quality B, 20Mp and 80Mp raw frames, "make_model": "OLYMPUS E-M1MarkII", - "dcraw_matrix": [ 9383,-3170,-763,-2457,10702,2020,-384,1236,5552 ], // dng_V9.10 D65 - //"dcraw_matrix": [ 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 ], // beta, dng_v9.8 D65 + "dcraw_matrix": [ 9383,-3170,-764,-2457,10702,2020,-384,1236,5552 ], // dng_V9.10 D65 "raw_crop": [ 8, 8, -16, -8 ], // full raw 5240X3912, jpeg top12,left12,5184x3888, full hires 10400X7792, jpeg crop 8,8,10368x7776 "ranges": { "white": [ @@ -1895,6 +1963,11 @@ Camera constants: "dcraw_matrix": [ 7687,-1984,-606,-4327,11928,2721,-1381,2339,6452 ], // dng d65 "ranges": { "white": 4080 } // nominal 4095-4094, spread with some settings as long exposure }, + + { // Quality C + "make_model": "OLYMPUS E-M1MarkIII", + "dcraw_matrix": [ 11896, -5110, -1076, -3181, 11378, 2048, -519, 1224, 5165 ] // DNG + }, { // Quality C, only raw crop for highres mode "make_model": "OLYMPUS E-M1X", @@ -1909,6 +1982,12 @@ Camera constants: //"raw_crop": [ 4, 4, 4616, 3464 ], // olympus jpeg crop 8, 8, 4608, 3456 "ranges": { "white": 4080 } }, + + { // Quality C + "make_model": "OLYMPUS E-M10MarkIV", + "dcraw_matrix": [ 9476, -3182, -765, -2613, 10958, 1893, -449, 1315, 5268 ], + "range": { "white": 4000, "black": 254 } + }, { // Quality A, white level correction "make_model": "OLYMPUS E-PM2", @@ -1922,6 +2001,11 @@ Camera constants: "dcraw_matrix": [ 8380, -2630, -639, -2887, 10725, 2496, -628, 1427, 5437 ], "ranges": { "white": 4080 } // nominal 4093 }, + + { // Quality C + "make_model": [ "OLYMPUS E-PL10" ], + "dcraw_matrix": [ 9197, -3190, -659, -2606, 10830, 2039, -458, 1250, 5457 ] + }, { // Quality B, with long exposure noise reduction White Level gets WL-BL = around 256_12-bit levels less "make_model": [ "OLYMPUS E-PL7", "OLYMPUS E-PL8" ], @@ -1954,6 +2038,11 @@ Camera constants: "global_green_equilibration" : true }, + { // Quality C + "make_model": ["OLYMPUS STYLUS1", "OLYMPUS STYLUS1,1s"], + "dcraw_matrix" : [8360, -2420, -880, -3928, 12353, 1739, -1381, 2416, 5173] // DNG + }, + { // Quality X "make_model": [ "Panasonic DC-LX100M2" ], "dcraw_matrix": [ 11577, -4230, -1106, -3967, 12211, 1957, -758, 1762, 5610 ], // Adobe DNG Converter 11.0 ColorMatrix2 @@ -1974,6 +2063,16 @@ Camera constants: } }, + { // Quality C + "make_model": [ "Panasonic DC-G90", "Panasonic DC-G95", "Panasonic DC-G99" ], + "dcraw_matrix": [ 9657, -3963, -748, -3361, 11378, 2258, -568, 1414, 5158 ] // DNG + }, + + { // Quality C + "make_model": [ "Panasonic DC-G100", "Panasonic DC-G110" ], + "dcraw_matrix": [ 8370, -2869, -710, -3389, 11372, 2298, -640, 1598, 4887 ] // DNG + }, + { // Quality C, only color matrix "make_model" : "Panasonic DC-GF10", "dcraw_matrix": [ 7610, -2780, -576, -4614, 12195, 2733, -1375, 2393, 6490 ], // ColorMatrix2 from Adobe DNG Converter 11.3 @@ -2075,6 +2174,11 @@ Camera constants: "ranges": { "black": 14, "white": 4050 } // 12+1+1 is BL offset }, + { // Quality C + "make_model": [ "Panasonic DMC-ZS60", "Panasonic DMC-TZ80", "Panasonic DMC-TZ85" ], + "dcraw_matrix": [ 8550, -2908, -842, -3195, 11529, 1881, -338, 1603, 4631 ] // DNG + }, + { // Quality A, samples by Hombre "make_model": [ "Panasonic DC-ZS70", "Panasonic DC-TZ90", "Panasonic DC-TZ91", "Panasonic DC-TZ92", "Panasonic DC-TZ93" ], "dcraw_matrix": [ 9052,-3117,-883,-3045,11346,1927,-205,1520,4730 ], // DNG_V9.10.1 D65 @@ -2082,6 +2186,12 @@ Camera constants: "ranges": { "black": 16, "white": 4050 } // 12+3+1 is BL offset }, + { // Quality C + "make_model": [ "Panasonic DC-ZS80", "Panasonic DC-TZ95" ], + "dcraw_matrix": [ 12194, -5340, -1329, -3035, 11394, 1858, -50, 1418, 5219 ] // DNG + }, + + // Panasonic DMC-FZ150,G10,G1,G2,G3,G5,GF1,GF2,GF3 are included as overwrites of the same items of rawimage.cc to test the dcraw9.21 patch { // Quality A, Replicated from rawimage.cc @@ -2375,6 +2485,16 @@ Camera constants: ] } }, + + { // Quality C + "make_model": "Panasonic DC-S1H", + "dcraw_matrix": [ 9397, -3719, -805, -5425, 13326, 2309, -972, 1715, 6034 ] // DNG + }, + + { // Quality C, possibly the same as DC-S1. We have a custom DCP which is better. + "make_model": "Panasonic DC-S5", + "dcraw_matrix": [ 9744, -3905, -779, -4899, 12807, 2324, -798, 1630, 5827 ] // DNG + }, { // Quality B, per ISO info missing "make_model": "PENTAX K-x", @@ -2443,6 +2563,11 @@ Camera constants: } }, + { // Quality C, possibly the same as K-1 + "make_model": [ "RICOH PENTAX K-1 Mark II", "PENTAX K-1 Mark II" ], + "dcraw_matrix": [ 8596, -2981, -639, -4202, 12045, 2431, -685, 1424, 6122 ] // DNG + }, + { // Quality B, intermediate ISOs info missing "make_model": [ "RICOH PENTAX K-3", "PENTAX K-3" ], "dcraw_matrix": [ 7415,-2052,-721,-5186,12788,2682,-1446,2157,6773 ], // adobe dcp d65 @@ -2575,6 +2700,17 @@ Camera constants: "make_model": "Sigma sd Quattro", "raw_crop": [ 200, 74, 5632, 3698 ] }, + + { // Quality C + "make_model": "Sigma fp", + "dcraw_matrix": [ 12431, -5541, -1000, -4387, 12361, 2265, -732, 1526, 5970 ] // DNG + }, + + { // Quality C + "make_model": "Sony NEX-F3", + "dcraw_matrix": [ 5991, -1456, -455, -4764, 12135, 2980, -707, 1424, 6701 ] // DNG + }, + { // Quality A, correction for color matrix from Colin Walker's d50 to dng d65 "make_model": "Sony NEX-C3", //"dcraw_matrix": [ 5130,-1055,-269,-4473,11797,3050,-701,1310,7121 ], // Colin walker's d50 kept for possible consistency issues @@ -2609,6 +2745,11 @@ Camera constants: "raw_crop": [ 0, 0, -36, 0 ], // full raw frame 8000x5320 - 36 rightmost columns are garbage "ranges": { "black": 512, "white": 16300 } }, + + { // Quality C + "make_model": "Sony ILCE-1", + "dcraw_matrix": [ 8161, -2947, -739, -4811, 12668, 2389, -437, 1229, 6524 ] // DNG v13.2 + }, { // Quality A, correction for frame width "make_model": [ "Sony ILCE-3000", "Sony ILCE-3500", "Sony ILCE-5000", "Sony ILCE-QX1" ], @@ -2626,7 +2767,7 @@ Camera constants: { // Quality A "make_model": "Sony ILCE-6000", - "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], // adobe dcp d65 + "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1424,6701 ], // adobe dcp d65 "raw_crop": [ 0, 0, 6024, 4024 ], "ranges": { "black": 512, "white": 16300 }, // detected by hand, using the picture from https://www.dpreview.com/forums/thread/3923513 @@ -2635,9 +2776,18 @@ Camera constants: "pdaf_offset" : 3 }, + { // Quality B, probably similar to ILCE-6000 / 6300 / 6500, not checked + "make_model": [ "Sony ILCE-6100","Sony ILCE-6400","Sony ILCE-6600" ], + "dcraw_matrix": [ 7657, -2847, -607, -4083, 11966, 2389, -684, 1418, 5844 ], // DNG + "raw_crop": [ 0, 0, 6024, 4024 ], + "ranges": { "black": 512, "white": 16300 }, + "pdaf_pattern" : [ 0,12,36,54,72,90,114,126,144,162,180,204,216,240,252,270,294,306,324,342,366,384,396,414,432,450,474,492,504,522,540,564,576,594,606,630 ], + "pdaf_offset" : 3 + }, + { // Quality A "make_model": [ "Sony ILCE-6300","Sony ILCE-6500" ], - "dcraw_matrix": [ 5973,-1695,-419,-3826,11797,2293,-639,1398,5789 ], // DNG_v9.8 D65 + "dcraw_matrix": [ 5973,-1696,-419,-3826,11797,2293,-639,1398,5789 ], // DNG_v9.8 D65 "raw_crop": [ 0, 0, 6024, 4024 ], "ranges": { "black": 512, "white": 16300 }, // contributed by Horshak from https://www.dpreview.com/forums/post/60873077 @@ -2645,6 +2795,11 @@ Camera constants: "pdaf_offset" : 3 }, + { // Quality C + "make_model": "Sony ILCE-7C", + "dcraw_matrix": [ 7374, -2389, -551, -5435, 13162, 2519, -1006, 1795, 6552 ] + }, + { // Quality A, correction for frame width "make_model": "Sony ILCE-7R", "dcraw_matrix": [ 4913,-541,-202,-6130,13513,2906,-1564,2151,7183 ], @@ -2665,6 +2820,11 @@ Camera constants: "raw_crop": [ 0, 0, -8, 0 ] // 8 rightmost columns are garbage }, + { // Quality C + "make_model": "Sony DSC-RX1R", + "dcraw_matrix": [ 6344, -1612, -462, -4863, 12477, 2681, -865, 1786, 6899 ] + }, + { // Quality B, correction for frame width, crop modes covered "make_model": [ "Sony ILCE-7RM2", "Sony DSC-RX1RM2" ], "dcraw_matrix": [ 6629,-1900,-483,-4618,12349,2550,-622,1381,6514 ], // DNG_v9.1.1 D65 @@ -2719,8 +2879,8 @@ Camera constants: "raw_crop": [ 0, 0, -32, 0 ] // full raw frame 9600x6376 - 32 rightmost columns are garbage. Using -32 instead of 9568 to support also 16-shot pixelshift files }, - { // Quality B, color matrix copied from a7rm2 - "make_model": "Sony ILCE-9", + { // Quality B, assumed correct for 9M2 as well + "make_model": ["Sony ILCE-9","Sony ILCE-9M2"], "dcraw_matrix": [ 6389,-1703,-378,-4562,12265,2587,-670,1489,6550 ], // DNG_v9.12 D65 "raw_crop": [ 8, 8, 6008, 4008 ], // full raw frame 6048x4024 Dcraw auto identify 6024x4024, jpeg 12,12,6000x4000 "ranges": { "black": 512, "white": 16300 }, @@ -2739,7 +2899,12 @@ Camera constants: }, { // Quality C - "make_model": [ "Sony DSC-HX99" ], + "make_model": "Sony ILCE-7SM3", + "dcraw_matrix": [ 6912, -2127, -469, -4470, 12175, 2587, -398, 1477, 6492 ] // DNG + }, + + { // Quality C + "make_model": [ "Sony DSC-HX95", "Sony DSC-HX99" ], "dcraw_matrix": [ 13076, -5686, -1481, -4027, 12851, 1251, -167, 725, 4937 ], "raw_crop": [ 0, 0, -8, 0 ], // 8 rightmost columns are garbage "ranges": { "black": 800, "white": 16300 } @@ -2751,18 +2916,52 @@ Camera constants: "ranges": { "white": 16368 } }, + { // Quality C + "make_model": "Sony DSC-RX100", + "dcraw_matrix": [ 8651, -2754, -1057, -3464, 12206, 1373, -568, 1398, 4434 ], // DNG + "ranges": { "black": 800, "white": 16300 } + }, + { // Quality A "make_model": [ "Sony DSC-RX100M2", "Sony DSC-RX100M3", "Sony DSC-RX100M4", "Sony DSC-RX100M5" ], "dcraw_matrix": [ 6596,-2079,-562,-4782,13016,1933,-970,1581,5181 ], // DNG_v9.8 D65 "ranges": { "black": 800, "white": 16300 } }, + { // Quality C + "make_model": "Sony DSC-RX100M5A", + "dcraw_matrix": [ 11176, -4700, -965, -4004, 12184, 2032, -764, 1726, 5876 ], // DNG + "ranges": { "black": 800, "white": 16300 } + }, + + { // Quality C + "make_model": "Sony DSC-RX100M6", + "dcraw_matrix": [ 7325, -2321, -596, -3494, 11674, 2055, -668, 1562, 5031 ], // DNG + "ranges": { "black": 800, "white": 16300 } + }, + + { // Quality C + "make_model": "Sony DSC-RX100M7", + "dcraw_matrix": [ 10315, -4390, -937, -4859, 12734, 2365, -735, 1537, 5997 ], // DNG + "ranges": { "black": 800, "white": 16300 } + }, + { // Quality B "make_model": [ "Sony DSC-RX10M2", "Sony DSC-RX10M3", "Sony DSC-RX10M4" ], "dcraw_matrix": [ 6679,-1825,-745,-5047,13256,1953,-1580,2422,5183 ], // DNG_v9.6 D65 "ranges": { "black": 800, "white": 16300 } }, + { // Quality C + "make_model": "Sony DCZV1B", // Sony ZV-1 + "dcraw_matrix": [ 8280, -2987, -703, -3532, 11645, 2133, -550, 1542, 5312 ] // DNG + }, + + { // Quality C + "make_model": "Sony SLT-A99V", + "dcraw_matrix": [ 6344, -1612, -462, -4863, 12477, 2681, -865, 1786, 6899 ] // DNG + }, + { // Quality C, No proper color data, beta samples, frame set to official jpeg, "make_model": [ "XIAOYI M1", "YI TECHNOLOGY M1" ], "dcraw_matrix": [ 7158,-1911,-606,-3603,10669,2530,-659,1236,5530 ], // XIAO YI DNG D65 @@ -2881,6 +3080,11 @@ Camera constants: "make_model": [ "Hasselblad H6D-100cMS" ], "raw_crop": [ 64, 108, 11608, 8708 ] }, + + { // Quality C + "make_model": "Hasselblad L1D-20c", // DJI Mavic 2 Pro + "dcraw_matrix": [ 6267, -2021, -687, -4664, 13343, 1399, -234, 1019, 5524 ] // DNG 13.2 + }, { "make_model": [ "HUAWEI DLI-L22" ], From 8fafaa7aba92b2f607f0a055bb35af26825eabe4 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Thu, 13 May 2021 20:09:12 +0200 Subject: [PATCH 071/135] Add color matrix for Canon EOS-1Ds --- rtengine/camconst.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index a43f97553..fad423876 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -360,6 +360,11 @@ Camera constants: } }, + { // Quality C + "make_model": "Canon EOS-1Ds", + "dcraw_matrix": [ 3925, 4060, -1739, -8973, 16552, 2545, -3287, 3945, 8243 ] // DNG + }, + { // Quality C, INTERMEDIATE ISO SAMPLES MISSING "make_model": "Canon EOS-1D X Mark II", "dcraw_matrix": [ 7596,-978,-967,-4808,12571,2503,-1398,2567,5752 ], From dde6bea80e12cce54ccc4a171399fe15ad9d3f4e Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Thu, 13 May 2021 22:54:54 +0200 Subject: [PATCH 072/135] Minor changes to several camconst matrices after comparison with current Adobe DNG database --- rtengine/camconst.json | 156 ++++++++++++++++++++++++----------------- 1 file changed, 90 insertions(+), 66 deletions(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index fad423876..909d19fd3 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -314,7 +314,7 @@ Camera constants: { // Quality A "make_model": "Canon EOS 5D Mark II", - "dcraw_matrix": [ 4716,603,-830,-7798,15474,2480,-1496,1937,6651 ], + "dcraw_matrix": [ 4716,603,-830,-7799,15474,2480,-1496,1937,6651 ], "ranges": { // black levels are read from raw masked pixels // white levels are same for all colors, but vary on ISO @@ -415,7 +415,7 @@ Camera constants: { // Quality A "make_model": "Canon EOS 5D Mark III", - "dcraw_matrix": [ 6722,-635,-963,-4287,12460,2028,-908,2162,5668 ], + "dcraw_matrix": [ 6722,-635,-963,-4287,12460,2028,-909,2162,5668 ], "ranges": { // black levels are read from raw masked pixels // white levels are same for all colors, but vary on ISO @@ -443,7 +443,7 @@ Camera constants: { // Quality B, some intermediate ISO samples missing, LENR samples missing so White Levels not properly indicated, some aperture scaling missing "make_model": "Canon EOS 5D Mark IV", "global_green_equilibration" : true, - "dcraw_matrix": [ 6446,-366,-864,-4436,12204,2513,-952,2496,6348 ], // DNG_V9.7 D65 + "dcraw_matrix": [ 6445,-366,-864,-4436,12204,2513,-953,2496,6348 ], // DNG v13.2 "raw_crop": [ 136, 42, 6740, 4500 ], // full size 6880x4544, official crop 148,54,6867,4533 "masked_areas": [ 54, 4, 4534, 132 ], "ranges": { @@ -569,7 +569,7 @@ Camera constants: { // Quality A, ISO and aperture WL data by CharlyW at RawTherapee forums, missing samples safely guessed "make_model": "Canon EOS 7D", "dcraw_matrix": [ 5962,-171,-732,-4189,12307,2099,-911,1981,6304 ], // Colin Walker - //"dcraw_matrix": [ 6844,-996,-856,-3876,11761,2396,-593,1772,6198 ], // dcraw + //"dcraw_matrix": [ 6843,-996,-856,-3876,11761,2396,-593,1772,6198 ], // DNG v13.2 "ranges": { "white": [ { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13584 @@ -623,7 +623,7 @@ Camera constants: { // Quality A - ISO and aperture WL data by Ilias at Avclub gr forums "make_model": "Canon EOS 40D", - "dcraw_matrix": [ 6071,-747,-856,-7653,15365,2441,-2025,2553,7315 ], + "dcraw_matrix": [ 6070,-746,-856,-7652,15365,2442,-2026,2553,7314 ], // DNG v13.2 "raw_crop": [ 30, 18, 3908, 2602 ], "masked_areas": [ 20, 2, 2616, 20 ], "ranges": { @@ -652,7 +652,7 @@ Camera constants: { // Quality A, ISO and aperture WL data by Ayshih at Magic Lantern forums "make_model": "Canon EOS 50D", - "dcraw_matrix": [ 4920,616,-593,-6493,13964,2784,-1774,3178,7005 ], + "dcraw_matrix": [ 4920,616,-593,-6494,13965,2784,-1774,3178,7004 ], // DNG v13.2 "ranges": { "white": [ { "iso": [ 100, 125 ], "levels": 13300 }, // typical 13432 @@ -702,7 +702,8 @@ Camera constants: { // Quality A, ISO and aperture WL data by Shalrath at RawTherapee forums "make_model": "Canon EOS 60D", - "dcraw_matrix": [ 6719,-994,-925,-4408,12426,2211,-887,2129,6051 ], + "dcraw_matrix": [ 6719,-994,-925,-4408,12426,2211,-887,2129,6051 ], // Origin unknown + //"dcraw_matrix": [ 6941, -1164, -857, -3825, 11597, 2534, -416, 1540, 6039 ], // DNG v13.2 "ranges": { "white": [ { "iso": [ 100, 125 ], "levels": 13480 }, // typical 13583 @@ -755,7 +756,7 @@ Camera constants: { // Quality B, White Levels not properly indicated, aperture scaling..missing scaling factors are guessed "make_model": "Canon EOS 80D", - "dcraw_matrix": [ 7457,-671,-937,-4849,12495,2643,-1213,2354,5492 ], // DNG_V9.5 D65 + "dcraw_matrix": [ 7457,-672,-937,-4849,12495,2643,-1213,2354,5492 ], // DNG v13.2 "raw_crop": [ 264, 34, 6024, 4022 ], // full size 6288x4056, official crop 276,46,6275,4045 "masked_areas": [ 40, 96, 4000, 260 ], "ranges": { @@ -936,7 +937,7 @@ Camera constants: { // Quality C, white levels and aperture scaling copied from Canon EOS77d "make_model": [ "Canon EOS Rebel T7i", "Canon EOS 800D", "Canon EOS Kiss X9i" ], - "dcraw_matrix": [ 6970,-512,-968,-4425,12161,2553,-739,1982,5601 ], // DNG_V9.10.1 D65 + "dcraw_matrix": [ 6969,-512,-968,-4425,12161,2553,-739,1981,5601 ], // DNG v13.2 "raw_crop": [ 264, 36, 6024, 4020 ], // full size 6288x4056, official crop 276,48,6275,4047 "masked_areas": [ 40, 96, 4000, 260 ], "ranges": { @@ -1067,7 +1068,7 @@ Camera constants: { // Quality C, inconsistent WL per ISO, missing scaling factors "make_model": "Canon EOS M10", - "dcraw_matrix": [ 6400,-480,-888,-5294,13416,2047,-1296,2203,6137 ], // DNGv9.3 D65 + "dcraw_matrix": [ 6400,-480,-888,-5294,13415,2047,-1296,2203,6137 ], // DNG v13.2 "ranges": { "white": [ { "iso": [ 100, 125, 160, 320, 500, 2000, 4000, 6400 ], "levels": 16300 }, // typical 16383 @@ -1236,7 +1237,8 @@ Camera constants: { // Quality B "make_model": "Canon PowerShot G3 X", - "dcraw_matrix": [ 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 ], // DNG_V9.1.1 D65 + //"dcraw_matrix": [ 9701,-3857,-921,-3149,11537,1817,-786,1817,5147 ], // DNG_V9.1.1 D65 + "dcraw_matrix": [ 6941, -1164, -857, -3825, 11597, 2534, -416, 1540, 6039 ], // DNG v13.2 - looks worse "raw_crop": [ 128, 36, 5480, 3656 ], // Default official 3/2 frame 5472X3648, 4pix borders, Left Border 132-4, Top border 40-4 "masked_areas": [ 40, 4, 3680, 76 ], "ranges": { "white": 16300 } @@ -1244,7 +1246,7 @@ Camera constants: { // Quality B, "make_model": "Canon PowerShot G7 X", - "dcraw_matrix": [ 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 ], // DNG_V8.7 D65 + "dcraw_matrix": [ 9602,-3823,-937,-2984,11495,1675,-407,1414,5049 ], // DNG v13.2 //"raw_crop": [ 116, 24, 5504, 3680 ], // Sensor size 5632x3710. Largest useful frame 120-5616X28-3702 = 5504x3682, 4pix RTborders, Left Border 120-4, Top border 28-4 "raw_crop": [ 128, 36, 5480, 3656 ], // Default official 3/2 frame 5472X3648, 4pix borders, Left Border 132-4, Top border 40-4 "masked_areas": [ 40, 4, 3680, 76 ], @@ -1252,17 +1254,27 @@ Camera constants: }, { // Quality B, - "make_model": [ "Canon PowerShot G5 X", "Canon PowerShot G9 X", "Canon PowerShot G7 X Mark II", "Canon PowerShot G9 X Mark II" ], - "dcraw_matrix": [ 9602,-3823,-937,-2984,11495,1675,-407,1415,5049 ], // DNG_V8.7 D65 + "make_model": [ "Canon PowerShot G5 X", "Canon PowerShot G7 X Mark II" ], + "dcraw_matrix": [ 9602,-3823,-937,-2984,11495,1675,-407,1414,5049 ], // DNG v13.2 //"raw_crop": [ 116, 24, 5504, 3680 ], // Sensor size 5632x3710. Largest useful frame 120-5616X28-3702 = 5504x3682, 4pix RTborders, Left Border 120-4, Top border 28-4 "raw_crop": [ 128, 36, 5480, 3656 ], // Default official 3/2 frame 5472X3648, 4pix borders, Left Border 132-4, Top border 40-4 "masked_areas": [ 40, 4, 3680, 76 ], "ranges": { "white": 15500 } // some sporadic samples are clipped lower than 16383, one ISO125 sample at 15500 }, + { // Quality B, separated entry from above due to alternate color matrix (effect unsure) + "make_model": "Canon PowerShot G9 X Mark II", + "dcraw_matrix": [ 10056, -4131, -944, -2576, 11143, 1625, -239, 1293, 5179 ], // DNG v13.2 + //"dcraw_matrix": [ 9602,-3823,-937,-2984,11495,1675,-407,1414,5049 ], // DNG v8.7 + "raw_crop": [ 128, 36, 5480, 3656 ], + "masked_areas": [ 40, 4, 3680, 76 ], + "ranges": { "white": 15500 } + }, + { // Quality A, changes for raw crop which is wrong (larger) in dcraw "make_model": "Canon PowerShot S120", - "dcraw_matrix": [ 6961, -1685, -695, -4625, 12945, 1836, -1114, 2152, 5518 ], // ColorMatrix2 using illuminant D65 from Adobe DNG Converter 12.2 + "dcraw_matrix": [ 6941, -1164, -857, -3825, 11597, 2534, -416, 1540, 6039 ], // Adobe DNG v13.2 + //"dcraw_matrix": [ 6961, -1685, -695, -4625, 12945, 1836, -1114, 2152, 5518 ], // Adobe DNG v12.2 "raw_crop": [ 120, 30, 4024, 3030 ], "masked_areas": [ 32, 2, 3028, 80 ], "ranges": { "white": 4050 } @@ -1276,7 +1288,7 @@ Camera constants: { // Quality B "make_model": "Canon PowerShot SX60 HS", - "dcraw_matrix": [ 13161,-5451,-1344,-1989,10654,1531,-47,1271,4955 ], // DNG_V8.7 D65 + "dcraw_matrix": [ 13161,-5451,-1344,-1989,10653,1531,-47,1271,4955 ], // DNG v13.2 "raw_crop": [ 120, 34, 4616, 3464 ], // full raw 4768x3516, Usable 96,16,4672,3498 - Canon official 4608x3456 left 124 top 38, "masked_areas": [ 20, 2, 3480, 80 ], "ranges": { "white": 4050 } // nominal 4080-4093 @@ -1542,15 +1554,21 @@ Camera constants: }, { // Quality A - "make_model": [ "Nikon 1 V3", "Nikon 1 J4" ], // Same format + "make_model": "Nikon 1 V3", "dcraw_matrix": [ 5958,-1559,-571,-4021,11453,2939,-634,1548,5087 ], // matrix from DNG_v8.5 d65 //"dcraw_matrix": [ 5306,-1066,-469,-3865,11189,3076,-399,1341,5120 ], // matrix dXo D50, "ranges": { "white": 4080 } // Black is auto extracted from Exif, lower WL to 4080 from 4095 due to some non linearity detected at raw highlights }, + { // Quality A + "make_model": "Nikon 1 J4", // Similar to V3, different matrix + "dcraw_matrix": [ 6588, -1305, -693, -3277, 10987, 2634, -355, 2016, 5106 ], // DNG v13.2 + "ranges": { "white": 4080 } + }, + { // Quality B "make_model": "Nikon 1 J5", // - "dcraw_matrix": [ 7520,-2518,-645,-3844,12102,1945,-913,2249,6835 ], // DNG_v9.1 D65 + "dcraw_matrix": [ 7520,-2519,-645,-3844,12102,1945,-914,2249,6835 ], // DNG v13.2 //"dcraw_matrix": [ 7651,-2102,-751,-3299,11101,1651,-1011,2242,5770 ], // matrix from ICC converted to dcraw format XYZ on ImagingResource still life sample "ranges": { "white": [ @@ -1583,7 +1601,7 @@ Camera constants: { // Quality B, samples by Johan Thor at RT.Issues, measures at long exposures with LENR are missing // but a safety margin is included - aperture scaling makes no significant difference "make_model": "Nikon D3S", - "dcraw_matrix": [ 8828,-2406,-694,-4874,12603,2541,-660,1509,7587 ], // dcp d65 + "dcraw_matrix": [ 8828,-2406,-694,-4874,12603,2541,-660,1509,7586 ], // DNG v13.2 "ranges": { "white": [ { "iso": [ 100, 125, 160, 200, 250, 320, 400, 500 ], "levels": 15520 }, // typical G1,G2 15520-15800 R,B 16383 @@ -1618,6 +1636,7 @@ Camera constants: { // Quality B, lacks aperture and ISO scaling, known to exist, but little to gain as the levels are so close to white_max "make_model": "Nikon D7000", "dcraw_matrix": [ 7530,-1942,-255,-4318,11390,3362,-926,1694,7649 ], // matrix provided by Tanveer(tsk1979) + //"dcraw_matrix": [ 8198, -2239, -725, -4871, 12388, 2798, -1043, 2050, 7181 ], // DNG v13.2 "ranges": { // measured at ISO 100. ISO differences not measured, but known to exist "white": [ 16300, 15700, 16300 ], // typical R 16383, G 15778, B 16383 @@ -1628,7 +1647,7 @@ Camera constants: { // Quality B "make_model": "NIKON COOLPIX A", - "dcraw_matrix": [ 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 ], // dng_d65 + "dcraw_matrix": [ 8198,-2239,-725,-4871,12388,2798,-1043,2050,7181 ], // DNG v13.2 "ranges": { "white": [ { "iso": [ 100, 125, 160, 200, 250, 320, 400, 500, 640, 800 ], "levels": [ 16300, 15700, 16300 ] }, // typical G1,G2 15760-15800 R,B 16383 @@ -1655,7 +1674,7 @@ Camera constants: // Sensor shows some non-uniformity, need other sample to verify // There seems to be some aperture scaling, but insufficient data to accurately determine "make_model": "Nikon COOLPIX P950", - "dcraw_matrix": [ 13307,-5641,-1290,-2048,10581,1689,-64,1222,5176 ], // ColorMatrix2 from Adobe DNG Converter 13.1 + "dcraw_matrix": [ 13307,-5642,-1290,-2048,10581,1689,-64,1222,5175 ], // DNG v13.2 "ranges": { "black": 200, "white": [ @@ -1669,7 +1688,7 @@ Camera constants: { // Quality B, no LENR samples "make_model": "Nikon D5", - "dcraw_matrix": [ 9200,-3522,-992,-5755,13803,2117,-753,1486,6338 ], // adobe dng_v9.5 d65 + "dcraw_matrix": [ 9200,-3522,-992,-5755,13803,2117,-754,1486,6338 ], // DNG v13.2 "ranges": { "black": 0, "white": 16300 } // WL typical 16383 set to 16300 for safety }, @@ -1754,7 +1773,7 @@ Camera constants: { // Quality B, data from RusselCottrell at RT forums. sensor is not uniform "make_model": "Nikon D700", - "dcraw_matrix": [ 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 ], + "dcraw_matrix": [ 8139,-2171,-664,-8748,16541,2296,-1924,2008,8093 ], // DNG v13.2 //"dcraw_matrix": [ 9336,-3405,14,-7321,14779,2764,-914,1171,8248 ], // illuminant A "ranges": { "white": [ 15500, 15500, 15500 ] } // Non linearities start at 15500 (hi ISOs) 15850 (low ISOs) with long exposures (>2sec) and LENR ON .. nominal 15892 @@ -1763,7 +1782,7 @@ Camera constants: { // Quality B, "make_model": "Nikon D750", - "dcraw_matrix": [ 9020,-2890,-715,-4535,12436,2348,-934,1919,7086 ], // adobe dcp d65 DNGv8.7 + "dcraw_matrix": [ 9020,-2890,-715,-4535,12436,2348,-934,1918,7086 ], // DNG v13.2 "ranges": { "white": 16300 } // WL values for 14-bit files, RT auto adapts it for 12-bit files. TypicalWL 16383 set to 16300 for safety }, @@ -1798,7 +1817,7 @@ Camera constants: { // Quality A, Samples by zorgtool at RT forums "make_model": "Nikon D850", - "dcraw_matrix": [ 10405,-3755,-1270,-5461,13787,1793,-1040,2015,6785 ], // DNGv9.12.1 d65 + "dcraw_matrix": [ 10405,-3755,-1270,-5461,13787,1792,-1040,2015,6785 ], // DNG v13.2 "ranges": { "white": [ { "iso": [ 64, 80, 100, 125, 160, 200, 250, 320 ], "levels": [ 16250, 16050, 16250 ] }, // R,B 16383 G1,G2 16145-16155 @@ -1835,13 +1854,13 @@ Camera constants: { // Quality B "make_model": "Nikon D80", - "dcraw_matrix": [ 8629,-2410,-883,-9055,16940,2171,-1490,1363,8520 ], // Dcraw.c d65 + "dcraw_matrix": [ 8628,-2410,-883,-9055,16940,2171,-1491,1363,8520 ], // DNG v13.2 "ranges": { "white": 3980 } // 12-bit files. }, { // Quality C, only color matrix and PDAF lines info "make_model" : "Nikon Z 7", - "dcraw_matrix" : [10405,-3755,-1270,-5461,13787,1793,-1040,2015,6785], // Adobe DNG Converter 11.0 ColorMatrix2 + "dcraw_matrix" : [10405,-3755,-1270,-5461,13787,1792,-1040,2015,6785], // DNG v13.2 "pdaf_pattern" : [0, 12], "pdaf_offset" : 29 }, @@ -1853,7 +1872,7 @@ Camera constants: { // Quality C, only color matrix and PDAF lines info "make_model" : "Nikon Z 6", - "dcraw_matrix" : [8210, -2534, -683, -5355, 13338, 2212, -1143, 1929, 6464], // Adobe DNG Converter 11.1 Beta ColorMatrix2 + "dcraw_matrix" : [8210, -2534, -683, -5355, 13338, 2212, -1143, 1928, 6464], // DNG v13.2 "pdaf_pattern" : [0, 12], "pdaf_offset" : 32 }, @@ -1863,9 +1882,9 @@ Camera constants: "dcraw_matrix" : [9943, -3270, -839, -5323, 13269, 2259, -1198, 2083, 7557] // DNG }, - { // Quality C, only dcraw looted from ART commit ad88c7d97 + { // Quality C "make_model" : "NIKON Z 5", - "dcraw_matrix" : [8695, -2558, -648, -5015, 12711, 2575, -1279, 2215, 7514] + "dcraw_matrix" : [8695, -2559, -648, -5015, 12710, 2575, -1280, 2215, 7514] // DNG v13.2 }, { // Quality A, white levels and PDAF lines measured by Yann Leprince #5851 @@ -1982,7 +2001,7 @@ Camera constants: { // Quality B, crop correction "make_model": [ "OLYMPUS E-M10", "OLYMPUS E-M10MarkII", "OLYMPUS E-M10 Mark III" ], - "dcraw_matrix": [ 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 ], + "dcraw_matrix": [ 8380,-2630,-639,-2887,10725,2496,-628,1427,5437 ], // DNG v13.2 "raw_crop": [ 0, 0, 4624, 3472 ], // largest valid - full frame is 4640x3472 //"raw_crop": [ 4, 4, 4616, 3464 ], // olympus jpeg crop 8, 8, 4608, 3456 "ranges": { "white": 4080 } @@ -1997,7 +2016,7 @@ Camera constants: { // Quality A, white level correction "make_model": "OLYMPUS E-PM2", "global_green_equilibration" : true, - "dcraw_matrix": [ 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 ], + "dcraw_matrix": [ 8380,-2630,-639,-2887,10725,2496,-628,1427,5437 ], // DNG v13.2 "ranges": { "white": 4040 } // nominal 4056 }, @@ -2015,13 +2034,13 @@ Camera constants: { // Quality B, with long exposure noise reduction White Level gets WL-BL = around 256_12-bit levels less "make_model": [ "OLYMPUS E-PL7", "OLYMPUS E-PL8" ], "global_green_equilibration" : true, - "dcraw_matrix": [ 9197,-3190,-659,-2606,10830,2039,-458,1250,5458 ], // DNG_v9.8 D65 + "dcraw_matrix": [ 9197,-3190,-659,-2606,10830,2039,-458,1250,5457 ], // DNG v13.2 "ranges": { "white": 4080 } // nominal 4093 }, { // Quality B, per ISO WL measures missing "make_model": [ "OLYMPUS SH-2", "Olympus SH-3" ], - "dcraw_matrix": [ 10156,-3425,-1077,-2611,11177,1624,-385,1592,5080 ], // DNG_V9.1 D65 + "dcraw_matrix": [ 10156,-3426,-1077,-2611,11177,1624,-385,1592,5080 ], // DNG v13.2 "ranges": { "white": 4050 } // safe for worst case detected, nominal is 4093 }, @@ -2032,9 +2051,9 @@ Camera constants: "ranges": { "white": 4050 } // safe for worst case detected, nominal is 4093 }, - { // Quality C, only raw crop + { // Quality B "make_model": "OLYMPUS TG-6", - "dcraw_matrix" : [10899, -3832, -1082, -2112, 10736, 1575, -267, 1452, 5269], // taken from ART + "dcraw_matrix" : [10899, -3833, -1082, -2112, 10736, 1575, -267, 1452, 5269], // DNG v13.2 "raw_crop": [ 0, 0, -24, 0 ] // 24 pixels at right are garbage }, @@ -2048,16 +2067,17 @@ Camera constants: "dcraw_matrix" : [8360, -2420, -880, -3928, 12353, 1739, -1381, 2416, 5173] // DNG }, - { // Quality X + { // Quality B "make_model": [ "Panasonic DC-LX100M2" ], - "dcraw_matrix": [ 11577, -4230, -1106, -3967, 12211, 1957, -758, 1762, 5610 ], // Adobe DNG Converter 11.0 ColorMatrix2 + "dcraw_matrix": [ 11577, -4230, -1106, -3967, 12211, 1957, -759, 1762, 5610 ], // DNG v13.2 + //"dcraw_matrix": [ 8585, -3127, -833, -4005, 12250, 1953, -650, 1494, 4862 ], // DNG v13.2 alternate "raw_crop": [ 0, 0, 0, 0 ], "ranges": { "black": 15 } }, { // Quality C, proper ISO 100-125-160 samples missing, pixelshift files have no black offset etc. #4574 "make_model": [ "Panasonic DC-G9" ], - "dcraw_matrix": [ 7685, -2375, -634, -3687, 11700, 2249, -748, 1546, 5111 ], // Adobe DNG Converter 10.3 ColorMatrix2 + "dcraw_matrix": [ 7685, -2375, -634, -3688, 11700, 2249, -748, 1545, 5111 ], // DNG v13.2 "ranges": { "black": 15, // 15 is BL offset. dcraw/RT reads the base black from Exif and calculates total BL = BLbase+BLoffset "white": [ @@ -2080,11 +2100,9 @@ Camera constants: { // Quality C, only color matrix "make_model" : "Panasonic DC-GF10", - "dcraw_matrix": [ 7610, -2780, -576, -4614, 12195, 2733, -1375, 2393, 6490 ], // ColorMatrix2 from Adobe DNG Converter 11.3 + "dcraw_matrix": [ 7610, -2781, -576, -4614, 12195, 2733, -1375, 2393, 6490 ], // DNG v13.2 "raw_crop": [ 0, 0, 4600, 0 ], // SensorWidth=4816 SensorHeight=3464. Width=4600 to match DNG. - "ranges": { - "black": 15 - } + "ranges": { "black": 15 } }, { // Quality B, CameraPhone, some samples are missing but has the same sensor as FZ1000 .. @@ -2102,7 +2120,7 @@ Camera constants: { // Quality B "make_model": [ "Panasonic DC-FZ80", "Panasonic DC-FZ81", "Panasonic DC-FZ82", "Panasonic DC-FZ83" ], - "dcraw_matrix": [ 8550,-2908,-842,-3195,11529,1881,-338,1603,4631 ], // DNGv9.10.1 D65 + "dcraw_matrix": [ 11532, -4324, -1066, -2375, 10847, 1749, -564, 1699, 4351 ], // DNG v13.2 "raw_crop": [ 0, 6, -8, -2 ], // fullraw4/3 5040x3688 official 8,8,4904,3680 = 4896X3672. Dcraw 0,0,4912,3688 RT's frame gets smaller than dcraw but works better with auto distortion "ranges": { "black": 15, "white": 4050 } // 15 is BL offset. dcraw/RT read the base offset from Exif and calculates total BL = BLbase+BLoffset }, @@ -2121,7 +2139,7 @@ Camera constants: { // Quality A, samples by helices at RT forums "make_model": [ "Panasonic DMC-FZ1000", "Leica V-LUX (Typ 114)" ], - "dcraw_matrix": [ 7830,-2696,-763,-3325,11667,1866,-641,1712,4824 ], // dcp_v8.6 d65 + "dcraw_matrix": [ 7830,-2696,-764,-3325,11667,1865,-641,1712,4824 ], // DNG v13.2 "ranges": { "black": 15, // 15 is BL offset. dcraw/RT read the base BL from Exif and calculates total BL = BLbase+BLoffset "white": [ @@ -2134,7 +2152,7 @@ Camera constants: { // Quality B, "make_model": [ "Panasonic DMC-FZ2500", "Panasonic DMC-FZ2000", "Panasonic DMC-FZH1" ], - "dcraw_matrix": [ 7386,-2443,-743,-3437,11864,1757,-608,1660,4766 ], // dcp_v9.8 d65 + "dcraw_matrix": [ 7386,-2443,-743,-3437,11863,1757,-608,1660,4766 ], // DNG v13.2 "ranges": { "black": 15, // 15 is BL offset. dcraw/RT read the base BL from Exif and calculates total BL = BLbase+BLoffset "white": [ @@ -2309,7 +2327,7 @@ Camera constants: { // Quality B, some ISO WLevels are safely guessed "make_model": "Panasonic DMC-GH4", - "dcraw_matrix": [ 7122,-2108,-512,-3155,11201,2231,-541,1423,5045 ], // dng_v8.5 d65 + "dcraw_matrix": [ 7122,-2108,-512,-3155,11201,2231,-541,1423,5044 ], // DNG v13.2 "ranges": { "black": 16, // 16 is BL offset. dcraw/RT read the base black from Exif and calculates total BL = BLbase+BLoffset "white": [ @@ -2322,7 +2340,7 @@ Camera constants: { // Quality C "make_model": "Panasonic DC-GH5", - "dcraw_matrix": [ 7641,-2336,-605,-3218,11299,2187,-485,1338,5121 ], // DNG_v9.9 D65 + "dcraw_matrix": [ 7641,-2336,-605,-3218,11298,2187,-485,1338,5121 ], // DNG v13.2 "ranges": { "black": 15, // 16 is BL offset. dcraw/RT read the base BL from Exif and calculates total BL = BLbase+BLoffset "white": [ @@ -2373,7 +2391,7 @@ Camera constants: { // Quality A "make_model": [ "Panasonic DMC-G7", "Panasonic DMC-G70" ], - "dcraw_matrix": [ 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 ], // DNG_v9.1 D65 + "dcraw_matrix": [ 7610,-2781,-576,-4614,12195,2733,-1375,2393,6490 ], // DNG v13.2 "ranges": { "black": 16, // 16 is BL offset. dcraw/RT read the base black from Exif and calculates total BL = BLbase+BLoffset "white": [ @@ -2386,7 +2404,7 @@ Camera constants: { // Quality B "make_model": [ "Panasonic DMC-GX80", "Panasonic DMC-GX85", "Panasonic DMC-GX7MK2" ], - "dcraw_matrix": [ 7771,-3020,-629,-4029,11950,2345,-821,1977,6119 ], // DNG_v9.6 D65 + "dcraw_matrix": [ 7771,-3020,-629,-4029,11950,2345,-822,1976,6119 ], // DNG v13.2 "ranges": { "black": 16, // 16 is BL offset. dcraw/RT read the base black from Exif and calculates total BL = BLbase+BLoffset "white": [ @@ -2399,7 +2417,7 @@ Camera constants: { // Quality X, no white-frames nor black-frames yet, see #4550 "make_model": [ "Panasonic DC-GX9" ], - "dcraw_matrix": [ 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 ], // ColorMatrix2 from Adobe DNG Converter 10.3 + "dcraw_matrix": [ 7564,-2263,-606,-3149,11238,2177,-540,1435,4853 ], // DNG v13.2 "ranges": { "black": 16, "white": 4080 @@ -2408,7 +2426,7 @@ Camera constants: { // Quality B, Same as Panasonic G7 "make_model": [ "Panasonic DMC-G8", "Panasonic DMC-G80", "Panasonic DMC-G81", "Panasonic DMC-G85" ], - "dcraw_matrix": [ 7610,-2780,-576,-4614,12195,2733,-1375,2393,6490 ], // DNG_v9.7 D65 + "dcraw_matrix": [ 7610,-2781,-576,-4614,12195,2733,-1375,2393,6490 ], // DNG v13.2 "ranges": { "black": 16, // 16 is BL offset. dcraw/RT read the base black from Exif and calculates total BL = BLbase+BLoffset "white": [ @@ -2421,7 +2439,7 @@ Camera constants: { // Quality B "make_model": "Panasonic DMC-GX8", - "dcraw_matrix": [ 7564,-2263,-606,-3148,11239,2177,-540,1435,4853 ], // DNG_v9.1.1 D65 + "dcraw_matrix": [ 7564,-2263,-606,-3149,11238,2177,-540,1435,4853 ], // DNG v13.2 "ranges": { "black": 15, // 16 is BL offset. dcraw/RT read the base BL from Exif and calculates total BL = BLbase+BLoffset "white": [ @@ -2554,7 +2572,7 @@ Camera constants: { // Quality B, Intemediate ISO samples missing, Pentax_DNG WLtags are after BL sutraction and not valid "make_model": [ "RICOH PENTAX K-1", "PENTAX K-1" ], - "dcraw_matrix": [ 8596,-2981,-639,-4202,12046,2431,-685,1424,6122 ], // adobe DNG v9.7 D65 + "dcraw_matrix": [ 8596,-2981,-639,-4202,12045,2431,-685,1424,6122 ], // DNG v13.2 //"dcraw_matrix": [ 8566,-2746,-1201,-3612,12204,1550,-893,1680,6264 ], // PENTAX DNG //"raw_crop": [ 6, 18, 7376, 4932 ], // full frame 7392x4950, cropped to official DNG raw_crop 6,18,7382,4950, official jpeg crop 8,10,7360x4912 "ranges": { @@ -2607,7 +2625,7 @@ Camera constants: { // Quality B, intermediate ISOs info missing, spread due to blackframe subtraction guessed to be around 10levels "make_model": "PENTAX K10D", - "dcraw_matrix": [ 9566,-2863,-803,-7170,15172,2112,-818,803,9705 ], // adobe DNG d65 + "dcraw_matrix": [ 9679, -2965, -811, -8622, 16514, 2182, -975, 883, 9793 ], // DNG v13.2 //"raw_crop": [ 0, , 3888, 2608 ], "ranges": { "white": [ @@ -2719,13 +2737,13 @@ Camera constants: { // Quality A, correction for color matrix from Colin Walker's d50 to dng d65 "make_model": "Sony NEX-C3", //"dcraw_matrix": [ 5130,-1055,-269,-4473,11797,3050,-701,1310,7121 ], // Colin walker's d50 kept for possible consistency issues - "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], + "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1424,6701 ], // DNG v13.2 "ranges": { "black": 512, "white": 16300 } }, { // Quality A, correction for frame width "make_model": "Sony NEX-5N", - "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], + "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1424,6701 ], // DNG v13.2 "raw_crop": [ 0, 0, 4920, 3276 ], "ranges": { "black": 512, "white": 16300 } }, @@ -2739,14 +2757,14 @@ Camera constants: { // Quality B "make_model": "Sony ILCA-68", - "dcraw_matrix": [ 6435,-1903,-536,-4722,12449,2550,-663,1363,6517 ], // adobe DNGv9.5 d65 + "dcraw_matrix": [ 6435,-1903,-536,-4722,12448,2550,-663,1363,6516 ], // DNG v13.2 "raw_crop": [ 0, 0, -30, 0 ], "ranges": { "black": 512, "white": 16300 } }, { // Quality B, correction for frame width, crop modes covered "make_model": "Sony ILCA-99M2", - "dcraw_matrix": [ 6660,-1918,-471,-4613,12398,2485,-649,1433,6447 ], // DNG_v9.8 D65 + "dcraw_matrix": [ 6660,-1918,-472,-4613,12398,2485,-649,1433,6447 ], // DNG v13.2 "raw_crop": [ 0, 0, -36, 0 ], // full raw frame 8000x5320 - 36 rightmost columns are garbage "ranges": { "black": 512, "white": 16300 } }, @@ -2758,14 +2776,14 @@ Camera constants: { // Quality A, correction for frame width "make_model": [ "Sony ILCE-3000", "Sony ILCE-3500", "Sony ILCE-5000", "Sony ILCE-QX1" ], - "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], // adobe dcp d65 + "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1424,6701 ], // DNG v13.2 "ranges": { "black": 512, "white": 16300 }, "raw_crop": [ 0, 0, 5476, 3656 ] }, { // Quality A "make_model": "Sony ILCE-5100", - "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 ], // adobe dcp d65 + "dcraw_matrix": [ 5991,-1456,-455,-4764,12135,2980,-707,1424,6701 ], // DNG v13.2 "raw_crop": [ 0, 0, 6024, 4024 ], "ranges": { "black": 512, "white": 16300 } }, @@ -2842,7 +2860,7 @@ Camera constants: { // Quality C, color matrix copied from ILCE-9, LongExposures 2-3sec only "make_model": "Sony ILCE-7M3", - "dcraw_matrix": [ 6389,-1703,-378,-4562,12265,2587,-670,1489,6550 ], // ILCE-9, DNG_v9.12 D65 + "dcraw_matrix": [ 7374, -2389, -551, -5435, 13162, 2519, -1006, 1795, 6552 ], // DNG v13.2 // "raw_crop": [ 8, 8, 6008, 4008 ], // full raw frame 6048x4024 Dcraw auto identify 6024x4024, jpeg 12,12,6000x4000 // "ranges": { "black": 512, "white": 16300 } "ranges": { @@ -2871,7 +2889,7 @@ Camera constants: { // Quality C, "make_model": "Sony ILCE-7RM3", - "dcraw_matrix": [ 6640,-1847,-503,-5238,13010,2474,-993,1673,6527 ], // DNG_v10.1 D65 + "dcraw_matrix": [ 6640,-1847,-503,-5238,13010,2474,-993,1673,6526 ], // DNG v13.2 "raw_crop": [ 0, 0, -36, 0 ], // full raw frame 8000x5320 - 36 rightmost columns are garbage "ranges": { "black": 512, "white": 16300 }, "pdaf_pattern" : [0, 24, 36, 60, 84, 120, 132, 156, 192, 204, 240, 252, 276, 300, 324, 360, 372, 396, 420, 444, 480, 492, 504, 540, 564, 576, 612, 636, 660, 696, 720, 732, 756, 780, 804, 840], @@ -2952,8 +2970,14 @@ Camera constants: }, { // Quality B - "make_model": [ "Sony DSC-RX10M2", "Sony DSC-RX10M3", "Sony DSC-RX10M4" ], - "dcraw_matrix": [ 6679,-1825,-745,-5047,13256,1953,-1580,2422,5183 ], // DNG_v9.6 D65 + "make_model": [ "Sony DSC-RX10M2", "Sony DSC-RX10M3" ], + "dcraw_matrix": [ 6679,-1825,-745,-5047,13255,1953,-1580,2422,5183 ], //DNG v13.2 + "ranges": { "black": 800, "white": 16300 } + }, + + { // Quality B + "make_model": "Sony DSC-RX10M4", // Similar to M2 and M3, different matrix + "dcraw_matrix": [ 7699, -2566, -629, -2967, 11270, 1928, -378, 1286, 4807 ], // DNG v13.2 "ranges": { "black": 800, "white": 16300 } }, @@ -3037,7 +3061,7 @@ Camera constants: { // Quality B "make_model": ["HASSELBLAD NEX-7", "SONY NEX-7"], // Hasselblad NEX-7 also known as Hasselblad Lunar - "dcraw_matrix": [ 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 ], // adobe DNGv12.2 d65 + "dcraw_matrix": [ 5491,-1192,-363,-4951,12342,2948,-911,1722,7191 ], // DNG v13.2 "ranges": { "black": 512, "white": 16372 } // Typical white level (samples provided by @ggc on Pixls, influence from LENR unknown }, From ad1770f431016ff269d4a902e74d2f62ca8f864e Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Thu, 13 May 2021 21:35:21 -0700 Subject: [PATCH 073/135] Fix history message --- rtdata/languages/Francais | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 172da2508..4145002a3 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -663,7 +663,7 @@ HISTORY_MSG_421;Retinex - Gamma HISTORY_MSG_422;Retinex - Gamma HISTORY_MSG_423;Retinex - Pente Gamma HISTORY_MSG_424;Retinex - Seuille HL -HISTORY_MSG_425;Retrait de taches +HISTORY_MSG_425;Retinex - Base Log HISTORY_MSG_426;Retinex - Égaliseur de teinte HISTORY_MSG_427;Intention de rendu de sortie HISTORY_MSG_428;Intention de rendu du moniteur From 7040aed540c681829d2e1b0bc89f7ef4e0cc1c5d Mon Sep 17 00:00:00 2001 From: Desmis Date: Sat, 15 May 2021 06:40:39 +0200 Subject: [PATCH 074/135] Some change issue6234 (#6238) --- rtdata/languages/default | 2 +- rtgui/locallabtools.cc | 12 ++++++++---- rtgui/options.cc | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 150d16705..aa0be0a9f 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2823,7 +2823,7 @@ TP_LOCALLAB_LOGLIGHTQ;Brightness (Q) TP_LOCALLAB_LOGLIGHTQ_TOOLTIP;Perceived amount of light emanating from a stimulus.\nIndicator that a stimulus appears to be more or less bright, clear. TP_LOCALLAB_LOGLIN;Logarithm mode TP_LOCALLAB_LOGPFRA;Relative Exposure Levels -TP_LOCALLAB_LOGREPART;Strength +TP_LOCALLAB_LOGREPART;Overall strength TP_LOCALLAB_LOGREPART_TOOLTIP;Allows you to adjust the relative strength of the log-encoded image with respect to the original image.\nDoes not affect the Ciecam component. TP_LOCALLAB_LOGSATURL_TOOLTIP;Saturation (s) in CIECAM16 corresponds to the color of a stimulus in relation to its own brightness.\nActs mainly on medium and highlights tones TP_LOCALLAB_LOGSCENE_TOOLTIP;Corresponds to the shooting conditions. diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc index 6f8ccea7a..444a4d5b2 100644 --- a/rtgui/locallabtools.cc +++ b/rtgui/locallabtools.cc @@ -791,6 +791,7 @@ LocallabColor::LocallabColor(): // Add Color & Light specific widgets to GUI pack_start(*reparcol); + pack_start(*invers); ToolParamBlock* const lumBox = Gtk::manage(new ToolParamBlock()); lumBox->pack_start(*lightness); lumBox->pack_start(*contrast); @@ -813,7 +814,7 @@ LocallabColor::LocallabColor(): pack_start(*structcol); pack_start(*blurcolde); pack_start(*softradiuscol); - pack_start(*invers); +// pack_start(*invers); ToolParamBlock* const colBox3 = Gtk::manage(new ToolParamBlock()); colBox3->pack_start(*maskusablec, Gtk::PACK_SHRINK, 0); colBox3->pack_start(*maskunusablec, Gtk::PACK_SHRINK, 0); @@ -2723,6 +2724,7 @@ LocallabExposure::LocallabExposure(): // Add Color & Light specific widgets to GUI pack_start(*sensiex); pack_start(*reparexp); + pack_start(*inversex); ToolParamBlock* const pdeBox = Gtk::manage(new ToolParamBlock()); pdeBox->pack_start(*laplacexp); pdeBox->pack_start(*linear); @@ -2776,7 +2778,7 @@ LocallabExposure::LocallabExposure(): expgradexp->add(*gradBox, false); pack_start(*expgradexp); pack_start(*softradiusexp); - pack_start(*inversex); + // pack_start(*inversex); ToolParamBlock* const maskexpBox = Gtk::manage(new ToolParamBlock()); maskexpBox->pack_start(*showmaskexpMethod, Gtk::PACK_SHRINK, 4); maskexpBox->pack_start(*showmaskexpMethodinv, Gtk::PACK_SHRINK, 4); @@ -4029,6 +4031,7 @@ LocallabShadow::LocallabShadow(): // Add Shadow highlight specific widgets to GUI pack_start(*reparsh); + pack_start(*inverssh); pack_start(*shMethod); for (const auto multiplier : multipliersh) { @@ -4064,7 +4067,7 @@ LocallabShadow::LocallabShadow(): gradSHBox->pack_start(*angSH); expgradsh->add(*gradSHBox, false); pack_start(*expgradsh); - pack_start(*inverssh); +// pack_start(*inverssh); ToolParamBlock* const maskSHBox = Gtk::manage(new ToolParamBlock()); maskSHBox->pack_start(*showmaskSHMethod, Gtk::PACK_SHRINK, 4); maskSHBox->pack_start(*showmaskSHMethodinv, Gtk::PACK_SHRINK, 4); @@ -6657,6 +6660,7 @@ LocallabBlur::LocallabBlur(): // Add Blur, Noise & Denoise specific widgets to GUI ToolParamBlock* const blnoisebox = Gtk::manage(new ToolParamBlock()); blnoisebox->pack_start(*sensibn); + blnoisebox->pack_start(*invbl); blnoisebox->pack_start(*blMethod); blnoisebox->pack_start(*fftwbl, Gtk::PACK_SHRINK, 0); blnoisebox->pack_start(*radius); @@ -6689,7 +6693,7 @@ LocallabBlur::LocallabBlur(): blnoisebox->pack_start(*expdenoise2); // blnoisebox->pack_start(*sensibn); // blnoisebox->pack_start(*blurMethod); - blnoisebox->pack_start(*invbl); +// blnoisebox->pack_start(*invbl); blnoisebox->pack_start(*chroMethod); // blnoisebox->pack_start(*activlum); expblnoise->add(*blnoisebox, false); diff --git a/rtgui/options.cc b/rtgui/options.cc index e17b2f074..1b6d09f4c 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -488,7 +488,7 @@ void Options::setDefaults() menuGroupFileOperations = true; menuGroupProfileOperations = true; menuGroupExtProg = true; - showtooltip = true; + showtooltip = false; ICCPC_primariesPreset = "sRGB", ICCPC_redPrimaryX = 0.6400; From c41eb247607e3165e93c18f597f7b4c55a02e352 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 14 May 2021 22:07:01 -0700 Subject: [PATCH 075/135] Remove dead code --- rtengine/spot.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/rtengine/spot.cc b/rtengine/spot.cc index cd19cc62a..6ef0ba5e0 100644 --- a/rtengine/spot.cc +++ b/rtengine/spot.cc @@ -400,7 +400,6 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s || !srcSpotBox->imageIntersects(*dstSpotBox, true)) { continue; - ++i; } // If spot intersect the preview image, add it to the visible spots From 1b7ddf2b31eb35660b9aac853db22bf4add1d1a2 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 14 May 2021 22:20:25 -0700 Subject: [PATCH 076/135] Fix perspective and local adjustments cursor icons Correctly override the getCursor virtual function. --- rtgui/controllines.cc | 2 +- rtgui/controllines.h | 2 +- rtgui/controlspotpanel.cc | 2 +- rtgui/controlspotpanel.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rtgui/controllines.cc b/rtgui/controllines.cc index 573b3263f..c078b4322 100644 --- a/rtgui/controllines.cc +++ b/rtgui/controllines.cc @@ -268,7 +268,7 @@ bool ControlLineManager::getEdited(void) const return edited; } -CursorShape ControlLineManager::getCursor(int objectID) const +CursorShape ControlLineManager::getCursor(int objectID, int xPos, int yPos) const { return cursor; } diff --git a/rtgui/controllines.h b/rtgui/controllines.h index c623ee1db..2b2d179a4 100644 --- a/rtgui/controllines.h +++ b/rtgui/controllines.h @@ -109,7 +109,7 @@ public: bool pick1(bool picked) override; bool pick3(bool picked) override; bool drag1(int modifierKey) override; - CursorShape getCursor(int objectID) const; + CursorShape getCursor(int objectID, int xPos, int yPos) const override; bool mouseOver(int modifierKey) override; void switchOffEditMode(void) override; }; diff --git a/rtgui/controlspotpanel.cc b/rtgui/controlspotpanel.cc index 5450ba3ed..6289ed1ae 100644 --- a/rtgui/controlspotpanel.cc +++ b/rtgui/controlspotpanel.cc @@ -2196,7 +2196,7 @@ void ControlSpotPanel::updateCurveOpacity(const Gtk::TreeModel::Row& selectedRow } } -CursorShape ControlSpotPanel::getCursor(int objectID) const +CursorShape ControlSpotPanel::getCursor(int objectID, int xPos, int yPos) const { // printf("Object ID: %d\n", objectID); diff --git a/rtgui/controlspotpanel.h b/rtgui/controlspotpanel.h index bebc24bee..b748df544 100644 --- a/rtgui/controlspotpanel.h +++ b/rtgui/controlspotpanel.h @@ -267,7 +267,7 @@ private: void updateControlSpotCurve(const Gtk::TreeModel::Row& row); void deleteControlSpotCurve(Gtk::TreeModel::Row& row); void updateCurveOpacity(const Gtk::TreeModel::Row& selectedRow); - CursorShape getCursor(int objectID) const; + CursorShape getCursor(int objectID, int xPos, int yPos) const override; bool mouseOver(int modifierKey) override; bool button1Pressed(int modifierKey) override; bool button1Released() override; From 22e89d83947246a7d48a20a010533691d3f5b4ce Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 15 May 2021 14:24:16 -0700 Subject: [PATCH 077/135] Fix spot removal spot dependency calculation Recursively find dependencies and output them in order. --- rtengine/spot.cc | 92 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 12 deletions(-) diff --git a/rtengine/spot.cc b/rtengine/spot.cc index 6ef0ba5e0..f43eaa909 100644 --- a/rtengine/spot.cc +++ b/rtengine/spot.cc @@ -25,6 +25,40 @@ #include "rt_math.h" #include #include +#include + +namespace rtengine +{ + +class SpotBox; + +} + +namespace +{ + +using Boxes = std::vector>; + +/** + * Add the spot and its dependencies to a set of dependencies. + * + * @param spotNum The spot's index. + * @param dependencies A set to place the dependencies in. Spots that are + * already in the set must have all their dependencies included already. + * @param srcSpots Information on spot sources. + * @param dstSpots Information on spot destinations. + */ +void addSpotDependencies(int spotNum, std::unordered_set &dependencies, const Boxes &srcSpots, const Boxes &dstSpots); + +/** + * Returns the supplied spots and all their dependencies. + * + * @param visibleSpots The spots to get dependencies for. + * @param srcSpots Information on spot sources. + * @param dstSpots Information on spot destinations. + */ +std::unordered_set calcSpotDependencies(const std::set &visibleSpots, const Boxes &srcSpots, const Boxes &dstSpots); +} namespace rtengine { @@ -461,18 +495,10 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s // Construct list of upstream dependancies - std::set requiredSpots = visibleSpots; // starting point, visible spots are necessarilly required spots - for (auto i = requiredSpots.rbegin(); i != requiredSpots.rend(); i++) { - int spotNbr = *i; - requiredSpots.insert(spotNbr); - if (spotNbr > 0) { - for (int j = spotNbr - 1; j >= 0; --j) { - if ((srcSpotBoxs.at(spotNbr))->imageIntersects(*dstSpotBoxs.at(j))) { - requiredSpots.insert(spotNbr); - } - } - } - } + std::unordered_set requiredSpotsSet = calcSpotDependencies(visibleSpots, srcSpotBoxs, dstSpotBoxs); + std::vector requiredSpots(requiredSpotsSet.size()); + std::copy(requiredSpotsSet.begin(), requiredSpotsSet.end(), requiredSpots.begin()); + std::sort(requiredSpots.begin(), requiredSpots.end()); // Process spots and copy them downstream @@ -510,3 +536,45 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s } +namespace +{ + +void addSpotDependencies(int spotNum, std::unordered_set &dependencies, const Boxes &srcSpots, const Boxes &dstSpots) +{ + dependencies.insert(spotNum); + + // Our spot can depend on previous spots. + for (int i = spotNum - 1; i >= 0; --i) { + if (dependencies.find(i) != dependencies.end()) { + continue; // Spot already has its dependencies added. + } + + // Check if our spot depends on this previous spot. + if (srcSpots.at(spotNum)->imageIntersects(*dstSpots.at(i))) { + // If so, add it and its dependencies. + addSpotDependencies(i, dependencies, srcSpots, dstSpots); + } + } +} + +std::unordered_set calcSpotDependencies(const std::set &visibleSpots, const Boxes &srcSpots, const Boxes &dstSpots) +{ + std::unordered_set dependencies; + std::vector visibleSpotsOrdered(visibleSpots.size()); + + std::copy(visibleSpots.begin(), visibleSpots.end(), visibleSpotsOrdered.begin()); + std::sort(visibleSpotsOrdered.begin(), visibleSpotsOrdered.end()); + + // Add dependencies, starting with the last spot. + for (auto i = visibleSpotsOrdered.crbegin(); i != visibleSpotsOrdered.crend(); ++i) { + if (dependencies.find(*i) != dependencies.end()) { + continue; // Spot already has its dependencies added. + } + addSpotDependencies(*i, dependencies, srcSpots, dstSpots); + } + + return dependencies; +} + +} + From 35abd92209bf87ebb76a4b09936d3c8feb1c0ffc Mon Sep 17 00:00:00 2001 From: Desmis Date: Sun, 16 May 2021 06:18:25 +0200 Subject: [PATCH 078/135] Custom TRC Tone response curve and Illuminant - change Histogram - RGB and Lab values - for output (screen, TIF, JPG..) (#5949) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Change TRC in the process * Improve GUI slope * Add tooltip output profile * Various change to enable and tooltip * Chnage rtthumbnail * Small change tooltip trc * Another small change tooltip * Improve GUI - change default TRC BT709 - change tooltip * Other GUI improvment * Small changes to BT709 values * Various change to TRC - add illuminant working profile * Change labels tooltip TRC illuminant * Display wp in console if wp provided * Change tooltip * Change max wlope * Init trc + illum + primaries * Add black point compensation * Change location abstract * Fixed bug with rtthumbnail... * Added tooltip * Logscale for wslope * Change tooltip abstract * Change labels tooltips abstract profile * Added 6 sliders custom primaries X and Y * Change GUI custom primaries * Use custom primaries abstract profiles * Tooltip with primaries red green blue * Fixed warning gtk * Change one tooltip * Change range custom primaries * Change GUI default Primaries * Change one tooltip * Speedup for trc * Rendering intent for abstract profile * Hide intent abstract * Preserve neutral tones * Chnage settings preserves neutral tones * Improve GUI * Improvment to preserv * Clean code - speedup TRC when illuminant and primaries default * Change label * Change bad default value Blux * Add forgoten illuminant when selecting primaries * clean code * Change labels * improve workingtrc for LA * Change default primaries when select default * Added others working profile to primaries * Change labels and GUI * Change tooltip * CIExy diagram displaying the primaries (interactive) and the white point (#6207) * Ciexy diagram * Change to Ciexy graph * Change graph and defaut coordonates * Various changes to graph - params * Disable setListener(ToolPanelListener) * Add some graduation to graph * Clean comment code graph * Change radius 0 * Enable sensitive graph Ciexy * update Ciexy graph with primaries * Remove reset button graph * Change labels and behavior * First step third spot green * Second step 3rd spot green * First try 3 primaries graph Ciexy * Fixed bad behavior in lab grid * Fixed another bad behavior graph * Clean and comment code * Change default gamma * More accurate graph Cie xy * Added white point to Ciexy graph * Added tooltip Cie xy diagram * Improvment when illuminant change * Refine diagram CIE xy - added WP 2000K * White point D120 + tooltip * Change label * Change labels * Change tooltips * Improve diagram CIE xy with parabolic * Other parabolic to improve Cie xy diagram * Small change GUI * Added Label CIE xy - change labels * Change behavior when none - change labels * Improve gUI and trys to fix LGTM alerts * CIE xy change set sensitive * Improve tooltip primaries sliders * Adapt tooltip to new labels * Fixed crash and some bad behavior * First fix bad behavior with some primaries * Second fixed bad behavior primaries * Third fixed bad behavior primaries * Change white point BestRGB * Change order rgb in history msg Ciexy * Change tooltip * Change tooltip * Improve GUI primaries * Illuminant 1500K - display in console matrix XYZ-RGB * Improve GUI illuminant * Change a tooltip * Somme changes to GUI and verbose * Test code for wprim in read * clean code for wprims * further cleanups, not tested * Some cleanups and bugfixes, #5949 * Simplify `std::unique_ptr<>` dereferencing Also some minor cleanups. * Some changes suggested by Floessie * Others change suggested * Others changes suggested by Floessie * Forgotten change in procparams.cc * Added black and white for use with the primaries channel mixer * Small change behavior GUI - illuminant * Change pragma omp in iplab2rgb * Add enums and clean up * Remove unused code icmpanel.cc * Fix LGTM alert, #5949 Co-authored-by: Ingo Weyrich Co-authored-by: Flössie --- rtdata/languages/default | 74 ++- rtengine/color.cc | 1 + rtengine/dcrop.cc | 82 ++- rtengine/improccoordinator.cc | 202 ++++-- rtengine/improccoordinator.h | 5 + rtengine/improcfun.cc | 10 +- rtengine/improcfun.h | 3 +- rtengine/iplab2rgb.cc | 379 ++++++++++- rtengine/iplocallab.cc | 54 +- rtengine/ipretinex.cc | 4 +- rtengine/procparams.cc | 251 ++++++- rtengine/procparams.h | 61 +- rtengine/rawimagesource.cc | 14 +- rtengine/refreshmap.cc | 3 +- rtengine/rtengine.h | 11 + rtengine/rtthumbnail.cc | 6 +- rtengine/simpleprocess.cc | 92 ++- rtgui/colortoning.cc | 18 +- rtgui/icmpanel.cc | 1180 +++++++++++++++++++++++++++++++-- rtgui/icmpanel.h | 78 ++- rtgui/labgrid.cc | 334 ++++++++-- rtgui/labgrid.h | 33 +- rtgui/locallabtools.cc | 22 +- rtgui/paramsedited.cc | 114 ++++ rtgui/paramsedited.h | 20 +- rtgui/toolpanelcoord.cc | 1 + rtgui/wavelet.cc | 8 +- 27 files changed, 2751 insertions(+), 309 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index aa0be0a9f..54742eea6 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1338,10 +1338,22 @@ HISTORY_MSG_HLBL;Color propagation - blur HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D HISTORY_MSG_ICM_OUTPUT_TYPE;Output - Type -HISTORY_MSG_ICM_WORKING_GAMMA;Working - Gamma -HISTORY_MSG_ICM_WORKING_SLOPE;Working - Slope -HISTORY_MSG_ICM_WORKING_TRC_METHOD;Working - TRC method +HISTORY_MSG_ICM_WORKING_GAMMA;TRC - Gamma +HISTORY_MSG_ICM_WORKING_SLOPE;TRC - Slope +HISTORY_MSG_ICM_WORKING_TRC_METHOD;TRC method +HISTORY_MSG_ICM_WORKING_ILLUM_METHOD;Illuminant method +HISTORY_MSG_ICM_WORKING_PRIM_METHOD;Primaries method +HISTORY_MSG_ICM_REDX;Primaries Red X +HISTORY_MSG_ICM_REDY;Primaries Red Y +HISTORY_MSG_ICM_GREX;Primaries Green X +HISTORY_MSG_ICM_GREY;Primaries Green Y +HISTORY_MSG_ICM_BLUX;Primaries Blue X +HISTORY_MSG_ICM_BLUY;Primaries Blue Y +HISTORY_MSG_ICL_LABGRIDCIEXY;Cie xy +HISTORY_MSG_ICM_AINTENT;Abstract profile intent HISTORY_MSG_ILLUM;Illuminant +HISTORY_MSG_ICM_FBW;Black and White +HISTORY_MSG_ICM_PRESER;Preserve neutral HISTORY_MSG_LOCALCONTRAST_AMOUNT;Local Contrast - Amount HISTORY_MSG_LOCALCONTRAST_DARKNESS;Local Contrast - Darkness HISTORY_MSG_LOCALCONTRAST_ENABLED;Local Contrast @@ -2402,10 +2414,14 @@ TP_ICM_APPLYHUESATMAP;Base table TP_ICM_APPLYHUESATMAP_TOOLTIP;Employ the embedded DCP base table (HueSatMap). The setting is only available if the selected DCP has one. TP_ICM_APPLYLOOKTABLE;Look table TP_ICM_APPLYLOOKTABLE_TOOLTIP;Employ the embedded DCP look table. The setting is only available if the selected DCP has one. +TP_ICM_BLUFRAME;Blue Primaries TP_ICM_BPC;Black Point Compensation TP_ICM_DCPILLUMINANT;Illuminant TP_ICM_DCPILLUMINANT_INTERPOLATED;Interpolated TP_ICM_DCPILLUMINANT_TOOLTIP;Select which embedded DCP illuminant to employ. Default is "interpolated" which is a mix between the two based on white balance. The setting is only available if a dual-illuminant DCP with interpolation support is selected. +TP_ICM_FBW;Black-and-White +TP_ICM_GREFRAME;Green Primaries +TP_ICM_ILLUMPRIM_TOOLTIP;Choose the illuminant closest to the shooting conditions.\nChanges can only be made when the ‘Destination primaries’ selection is set to ‘Custom (sliders)’. TP_ICM_INPUTCAMERA;Camera standard TP_ICM_INPUTCAMERAICC;Auto-matched camera profile TP_ICM_INPUTCAMERAICC_TOOLTIP;Use RawTherapee's camera-specific DCP or ICC input color profiles. These profiles are more precise than simpler matrix ones. They are not available for all cameras. These profiles are stored in the /iccprofiles/input and /dcpprofiles folders and are automatically retrieved based on a file name matching to the exact model name of the camera. @@ -2418,22 +2434,66 @@ TP_ICM_INPUTEMBEDDED_TOOLTIP;Use color profile embedded in non-raw files. TP_ICM_INPUTNONE;No profile TP_ICM_INPUTNONE_TOOLTIP;Use no input color profile at all.\nUse only in special cases. TP_ICM_INPUTPROFILE;Input Profile -TP_ICM_LABEL;Color Management +TP_ICM_LABEL;Color Management +TP_ICM_LABGRID_CIEXY;R(x)=%1 R(y)=%2\nG(x)=%3 G(y)=%4\nB(x)=%5 B(y)=%6 TP_ICM_NOICM;No ICM: sRGB Output TP_ICM_OUTPUTPROFILE;Output Profile +TP_ICM_OUTPUTPROFILE_TOOLTIP;By default all RTv4 or RTv2 profiles are with TRC - sRGB: g=2.4 s=12.92\n\nWith 'ICC Profile Creator' you can generate v4 or v2 profiles with the following choices;\n-Primaries: Aces AP0, Aces AP1, AdobeRGB, Prophoto, Rec2020, sRGB, Widegamut, BestRGB, BetaRGB, BruceRGB, Custom\n-TRC: BT709, sRGB, linear, standard g=2.2, standard g=1.8, Custom\n-Illuminant: D41, D50, D55, D60, D65, D80, stdA 2856K +TP_ICM_PRIMRED_TOOLTIP;Primaries Red:\nsRGB x=0.64 y=0.33\nAdobe x=0.64 y=0.33\nWidegamut x=0.735 y=0.265\nRec2020 x=0.708 y=0.292\nACES P1 x=0.713 y= 0.293\nACES P0 x=0.7347 y=0.2653\nProphoto x=0.7347 y=0.2653\nBruceRGB x=0.64 y=0.33\nBeta RGB x=0.688 y=0.3112\nBestRGB x=0.7347 y=0.2653 +TP_ICM_PRIMGRE_TOOLTIP;Primaries Green:\nsRGB x=0.3 y=0.6\nAdobe x=0.21 y=0.71\nWidegamut x=0.115 y=0.826\nRec2020 x=0.17 y=0.797\nACES P1 x=0.165 y= 0.83\nACES P0 x=0.0 y=1.0\nProphoto x=0.1596 y=0.8404\nBruceRGB x=0.28 y=0.65\nBeta RGB x=0.1986 y=0.7551\nBest RGB x=0.2150 0.7750 +TP_ICM_PRIMBLU_TOOLTIP;Primaries Blue:\nsRGB x=0.15 y=0.06\nAdobe x=0.15 y=0.06\nWidegamut x=0.157 y=0.018\nRec2020 x=0.131 y=0.046\nACES P1 x=0.128 y= 0.044\nACES P0 x=0.0001 y=-0.077\nProphoto x=0.0366 y=0.0001\nBruceRGB x=0.15 y=0.06\nBeta RGB x=0.1265 y=0.0352\nBestRGB x=0.131 y=0.046 TP_ICM_PROFILEINTENT;Rendering Intent +TP_ICM_REDFRAME;Custom Primaries TP_ICM_SAVEREFERENCE;Save Reference Image TP_ICM_SAVEREFERENCE_APPLYWB;Apply white balance TP_ICM_SAVEREFERENCE_APPLYWB_TOOLTIP;Generally, apply the white balance when saving images to create ICC profiles, and do not apply the white balance to create DCP profiles. TP_ICM_SAVEREFERENCE_TOOLTIP;Save the linear TIFF image before the input profile is applied. The result can be used for calibration purposes and generation of a camera profile. TP_ICM_TONECURVE;Tone curve TP_ICM_TONECURVE_TOOLTIP;Employ the embedded DCP tone curve. The setting is only available if the selected DCP has a tone curve. +TP_ICM_TRCFRAME;Abstract Profile +TP_ICM_TRCFRAME_TOOLTIP;Also known as ‘synthetic’ or ‘virtual’ profiles, which are applied at the end of the processing pipeline (prior to ciecam) allowing you to create custom image effects.\nYou can make changes to the:\n ‘Tone response curve’, which modifies the tones of the image.\n ‘Illuminant’ : which allows you to change the profile primaries to adapt them to the shooting conditions.\n ‘Destination primaries’: which allows you to change the destination primaries with two main uses - channel mixer and calibration.\nNote: Abstract profiles take into account the built-in Working profiles without modifying them. They do not work with custom Working profiles. +TP_ICM_WORKING_CIEDIAG;CIE xy diagram TP_ICM_WORKINGPROFILE;Working Profile +TP_ICM_WORKING_PRESER;Preserves Pastel tones TP_ICM_WORKING_TRC;Tone response curve: +TP_ICM_WORKING_TRC_BT709;BT709 g=2.22 s=4.5 +TP_ICM_WORKING_TRC_SRGB;sRGB g=2.4 s=12.92 +TP_ICM_WORKING_TRC_22;Adobe g=2.2 +TP_ICM_WORKING_TRC_18;Prophoto g=1.8 +TP_ICM_WORKING_TRC_LIN;Linear g=1 TP_ICM_WORKING_TRC_CUSTOM;Custom TP_ICM_WORKING_TRC_GAMMA;Gamma TP_ICM_WORKING_TRC_NONE;None TP_ICM_WORKING_TRC_SLOPE;Slope +TP_ICM_TRC_TOOLTIP;Allows you to change the default sRGB ‘Tone response curve’ in RT (g=2.4 s=12.92).\nThis TRC modifies the tones of the image. The RGB and Lab values, histogram and output (screen, TIF, JPG) are changed:\n-Gamma acts mainly on light tones -Slope acts mainly on dark tones.\nYou can choose any pair of 'gamma and slope' (values >1) and the algorithm will ensure that there is continuity between the linear and parabolic parts of the curve.\nA selection other than 'none' activates the 'Illuminant' and 'Destination primaries' menus. +TP_ICM_WORKING_ILLU;Illuminant +TP_ICM_WORKING_ILLU_NONE;Default +TP_ICM_WORKING_ILLU_D41;D41 +TP_ICM_WORKING_ILLU_D50;D50 +TP_ICM_WORKING_ILLU_D55;D55 +TP_ICM_WORKING_ILLU_D60;D60 +TP_ICM_WORKING_ILLU_D65;D65 +TP_ICM_WORKING_ILLU_D80;D80 +TP_ICM_WORKING_ILLU_D120;D120 +TP_ICM_WORKING_ILLU_STDA;stdA 2875K +TP_ICM_WORKING_ILLU_2000;Tungsten 2000K +TP_ICM_WORKING_ILLU_1500;Tungsten 1500K +TP_ICM_WORKING_PRIM;Destination primaries +TP_ICM_PRIMILLUM_TOOLTIP;You can change an image from its original mode (‘working profile’) to a different mode (‘destination primaries’). When you choose a different color mode for an image, you permanently change the color values in the image.\n\nChanging the ‘primaries’ is quite complex and difficult to use. It requires a lot of experimenting.\n It is capable of making exotic color adjustments as Channel Mixer primaries.\n Allows you to modify the camera calibration with Custom (sliders). +TP_ICM_WORKING_PRIM_NONE;Default +TP_ICM_WORKING_PRIM_SRGB;sRGB +TP_ICM_WORKING_PRIM_ADOB;Adobe RGB +TP_ICM_WORKING_PRIM_PROP;ProPhoto +TP_ICM_WORKING_PRIM_REC;Rec2020 +TP_ICM_WORKING_PRIM_ACE;ACESp1 +TP_ICM_WORKING_PRIM_WID;WideGamut +TP_ICM_WORKING_PRIM_AC0;ACESp0 +TP_ICM_WORKING_PRIM_BRU;BruceRGB +TP_ICM_WORKING_PRIM_BET;Beta RGB +TP_ICM_WORKING_PRIM_BST;BestRGB +TP_ICM_WORKING_PRIM_CUS;Custom (sliders) +TP_ICM_WORKING_PRIM_CUSGR;Custom (CIE xy Diagram) +TP_ICM_WORKING_PRIMFRAME_TOOLTIP;When ‘Custom CIE xy diagram’ is selected in ‘Destination- primaries’’ combobox, you can modify the values of the 3 primaries directly on the graph.\nNote that in this case, the white point position on the graph will not be updated. TP_ICM_WORKING_TRC_TOOLTIP;Only for built-in profiles. TP_IMPULSEDENOISE_LABEL;Impulse Noise Reduction TP_IMPULSEDENOISE_THRESH;Threshold @@ -3299,6 +3359,12 @@ TP_PREPROCWB_LABEL;Preprocess White Balance TP_PREPROCWB_MODE;Mode TP_PREPROCWB_MODE_AUTO;Auto TP_PREPROCWB_MODE_CAMERA;Camera +TC_PRIM_BLUX;Bx +TC_PRIM_BLUY;By +TC_PRIM_GREX;Gx +TC_PRIM_GREY;Gy +TC_PRIM_REDX;Rx +TC_PRIM_REDY;Ry TP_PRSHARPENING_LABEL;Post-Resize Sharpening TP_PRSHARPENING_TOOLTIP;Sharpens the image after resizing. Only works when the "Lanczos" resizing method is used. It is impossible to preview the effects of this tool. See RawPedia for usage instructions. TP_RAWCACORR_AUTO;Auto-correction diff --git a/rtengine/color.cc b/rtengine/color.cc index 3fcd44eb8..d6c35208d 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -944,6 +944,7 @@ void Color::xyz2Prophoto (float x, float y, float z, float &r, float &g, float & g = ((prophoto_xyz[1][0] * x + prophoto_xyz[1][1] * y + prophoto_xyz[1][2] * z)) ; b = ((prophoto_xyz[2][0] * x + prophoto_xyz[2][1] * y + prophoto_xyz[2][2] * z)) ; } + void Color::Prophotoxyz (float r, float g, float b, float &x, float &y, float &z) { x = ((xyz_prophoto[0][0] * r + xyz_prophoto[0][1] * g + xyz_prophoto[0][2] * b)) ; diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 852ba0ba7..2641f8885 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -19,9 +19,11 @@ */ #include "cieimage.h" +#include "color.h" #include "curves.h" #include "dcp.h" #include "dcrop.h" +#include "guidedfilter.h" #include "image8.h" #include "imagefloat.h" #include "improccoordinator.h" @@ -30,9 +32,9 @@ #include "procparams.h" #include "refreshmap.h" #include "rt_math.h" -#include "color.h" +#include "utils.h" + #include "../rtgui/editcallbacks.h" -#include "guidedfilter.h" #pragma GCC diagnostic warning "-Wall" #pragma GCC diagnostic warning "-Wextra" @@ -278,7 +280,7 @@ void Crop::update(int todo) crW = 250; } - // if(settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int((tileWskip/2));}//adapted to scale of preview + // if (settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int((tileWskip/2));}//adapted to scale of preview if (settings->leveldnv == 2) { crW = int (tileWskip / 2); } @@ -402,7 +404,7 @@ void Crop::update(int todo) crH = 250; } - // if(settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int((tileWskip/2));}//adapted to scale of preview + // if (settings->leveldnv ==2) {crW=int(tileWskip/2);crH=int((tileWskip/2));}//adapted to scale of preview if (settings->leveldnv == 2) { crW = int (tileWskip / 2); crH = int (tileHskip / 2); @@ -607,7 +609,7 @@ void Crop::update(int todo) //end evaluate noise } - // if(params.dirpyrDenoise.Cmethod=="AUT" || params.dirpyrDenoise.Cmethod=="PON") {//reinit origCrop after Auto + // if (params.dirpyrDenoise.Cmethod=="AUT" || params.dirpyrDenoise.Cmethod=="PON") {//reinit origCrop after Auto if ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) { //reinit origCrop after Auto PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); @@ -975,7 +977,7 @@ void Crop::update(int todo) double hlcomprthresh = params.locallab.spots.at(sp).hlcomprthresh; double shcompr = params.locallab.spots.at(sp).shcompr; double br = params.locallab.spots.at(sp).lightness; - if(black < 0. && params.locallab.spots.at(sp).expMethod == "pde" ) { + if (black < 0. && params.locallab.spots.at(sp).expMethod == "pde" ) { black *= 1.5; } @@ -1053,7 +1055,7 @@ void Crop::update(int todo) parent->previewDeltaE, parent->locallColorMask, parent->locallColorMaskinv, parent->locallExpMask, parent->locallExpMaskinv, parent->locallSHMask, parent->locallSHMaskinv, parent->locallvibMask, parent->localllcMask, parent->locallsharMask, parent->locallcbMask, parent->locallretiMask, parent->locallsoftMask, parent->localltmMask, parent->locallblMask, parent->localllogMask, parent->locall_Mask, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, meantme, stdtme, meanretie, stdretie); - if(parent->previewDeltaE || parent->locallColorMask == 5 || parent->locallvibMask == 4 || parent->locallExpMask == 5 || parent->locallSHMask == 4 || parent->localllcMask == 4 || parent->localltmMask == 4 || parent->localllogMask == 4 || parent->locallsoftMask == 6 || parent->localllcMask == 4) { + if (parent->previewDeltaE || parent->locallColorMask == 5 || parent->locallvibMask == 4 || parent->locallExpMask == 5 || parent->locallSHMask == 4 || parent->localllcMask == 4 || parent->localltmMask == 4 || parent->localllogMask == 4 || parent->locallsoftMask == 6 || parent->localllcMask == 4) { params.blackwhite.enabled = false; params.colorToning.enabled = false; params.rgbCurves.enabled = false; @@ -1137,20 +1139,6 @@ void Crop::update(int todo) if (todo & M_RGBCURVE) { Imagefloat *workingCrop = baseCrop; -/* - if (params.icm.workingTRC == "Custom") { //exec TRC IN free - const Glib::ustring profile = params.icm.workingProfile; - if (profile == "sRGB" || profile == "Adobe RGB" || profile == "ProPhoto" || profile == "WideGamut" || profile == "BruceRGB" || profile == "Beta RGB" || profile == "BestRGB" || profile == "Rec2020" || profile == "ACESp0" || profile == "ACESp1") { - const int cw = baseCrop->getWidth(); - const int ch = baseCrop->getHeight(); - workingCrop = new Imagefloat(cw, ch); - //first put gamma TRC to 1 - parent->ipf.workingtrc(baseCrop, workingCrop, cw, ch, -5, params.icm.workingProfile, 2.4, 12.92310, parent->getCustomTransformIn(), true, false, true); - //adjust gamma TRC - parent->ipf.workingtrc(workingCrop, workingCrop, cw, ch, 5, params.icm.workingProfile, params.icm.workingTRCGamma, params.icm.workingTRCSlope, parent->getCustomTransformOut(), false, true, true); - } - } -*/ double rrm, ggm, bbm; DCPProfileApplyState as; DCPProfile *dcpProf = parent->imgsrc->getDCP(params.icm, as); @@ -1228,7 +1216,7 @@ void Crop::update(int todo) int minwin = min(labnCrop->W, labnCrop->H); int maxlevelcrop = 10; - // if(cp.mul[9]!=0)maxlevelcrop=10; + // if (cp.mul[9]!=0)maxlevelcrop=10; // adap maximum level wavelet to size of crop if (minwin * skip < 1024) { maxlevelcrop = 9; //sampling wavelet 512 @@ -1314,7 +1302,7 @@ void Crop::update(int todo) bool proton = WaveParams.exptoning; bool pronois = WaveParams.expnoise; - if(WaveParams.showmask) { + if (WaveParams.showmask) { // WaveParams.showmask = false; // WaveParams.expclari = true; } @@ -1441,7 +1429,7 @@ void Crop::update(int todo) } float indic = 1.f; - if(WaveParams.showmask){ + if (WaveParams.showmask){ mL0 = mC0 = -1.f; indic = -1.f; mL = fabs(mL); @@ -1476,6 +1464,50 @@ void Crop::update(int todo) parent->ipf.softLight(labnCrop, params.softlight); + if (params.icm.workingTRC != ColorManagementParams::WorkingTrc::NONE) { + const int GW = labnCrop->W; + const int GH = labnCrop->H; + std::unique_ptr provis; + const float pres = 0.01f * params.icm.preser; + if (pres > 0.f && params.icm.wprim != ColorManagementParams::Primaries::DEFAULT) { + provis.reset(new LabImage(GW, GH)); + provis->CopyFrom(labnCrop); + } + + const std::unique_ptr tmpImage1(new Imagefloat(GW, GH)); + + parent->ipf.lab2rgb(*labnCrop, *tmpImage1, params.icm.workingProfile); + + const float gamtone = parent->params->icm.workingTRCGamma; + const float slotone = parent->params->icm.workingTRCSlope; + + int illum = rtengine::toUnderlying(params.icm.will); + const int prim = rtengine::toUnderlying(params.icm.wprim); + + Glib::ustring prof = params.icm.workingProfile; + + cmsHTRANSFORM dummy = nullptr; + int ill = 0; + parent->ipf.workingtrc(tmpImage1.get(), tmpImage1.get(), GW, GH, -5, prof, 2.4, 12.92310, ill, 0, dummy, true, false, false); + parent->ipf.workingtrc(tmpImage1.get(), tmpImage1.get(), GW, GH, 5, prof, gamtone, slotone, illum, prim, dummy, false, true, true); + + parent->ipf.rgb2lab(*tmpImage1, *labnCrop, params.icm.workingProfile); + //labnCrop and provis + if (provis) { + parent->ipf.preserv(labnCrop, provis.get(), GW, GH); + } + if (params.icm.fbw) { +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int x = 0; x < GH; x++) + for (int y = 0; y < GW; y++) { + labnCrop->a[x][y] = 0.f; + labnCrop->b[x][y] = 0.f; + } + } + } + if (params.colorappearance.enabled) { float fnum = parent->imgsrc->getMetaData()->getFNumber(); // F number float fiso = parent->imgsrc->getMetaData()->getISOSpeed() ; // ISO @@ -1519,6 +1551,8 @@ void Crop::update(int todo) // all pipette buffer processing should be finished now PipetteBuffer::setReady(); + + // Computing the preview image, i.e. converting from lab->Monitor color space (soft-proofing disabled) or lab->Output profile->Monitor color space (soft-proofing enabled) parent->ipf.lab2monitorRgb(labnCrop, cropImg); diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 71468fd8f..b3913103e 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -17,6 +17,7 @@ * along with RawTherapee. If not, see . */ #include + #include #include "improccoordinator.h" @@ -27,6 +28,7 @@ #include "colortemp.h" #include "curves.h" #include "dcp.h" +#include "guidedfilter.h" #include "iccstore.h" #include "image8.h" #include "imagefloat.h" @@ -35,7 +37,7 @@ #include "lcp.h" #include "procparams.h" #include "refreshmap.h" -#include "guidedfilter.h" +#include "utils.h" #include "../rtgui/options.h" @@ -600,16 +602,16 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) float max_r[nbw*nbh]; float max_b[nbw*nbh]; - if(denoiseParams.Lmethod == "CUR") { - if(noiseLCurve) + if (denoiseParams.Lmethod == "CUR") { + if (noiseLCurve) denoiseParams.luma = 0.5f; else denoiseParams.luma = 0.0f; - } else if(denoiseParams.Lmethod == "SLI") + } else if (denoiseParams.Lmethod == "SLI") noiseLCurve.Reset(); - if(noiseLCurve || noiseCCurve){//only allocate memory if enabled and scale=1 + if (noiseLCurve || noiseCCurve){//only allocate memory if enabled and scale=1 // we only need image reduced to 1/4 here calclum = new Imagefloat ((pW+1)/2, (pH+1)/2);//for luminance denoise curve for(int ii=0;iiicm.workingTRC == "Custom") { //exec TRC IN free - if (oprevi == orig_prev) { - oprevi = new Imagefloat(pW, pH); - orig_prev->copyData(oprevi); - } - const Glib::ustring profile = params->icm.workingProfile; - - if (profile == "sRGB" || profile == "Adobe RGB" || profile == "ProPhoto" || profile == "WideGamut" || profile == "BruceRGB" || profile == "Beta RGB" || profile == "BestRGB" || profile == "Rec2020" || profile == "ACESp0" || profile == "ACESp1") { - const int cw = oprevi->getWidth(); - const int ch = oprevi->getHeight(); - - // put gamma TRC to 1 - if (customTransformIn) { - cmsDeleteTransform(customTransformIn); - customTransformIn = nullptr; - } - - ipf.workingtrc(oprevi, oprevi, cw, ch, -5, params->icm.workingProfile, 2.4, 12.92310, customTransformIn, true, false, true); - - //adjust TRC - if (customTransformOut) { - cmsDeleteTransform(customTransformOut); - customTransformOut = nullptr; - } - - ipf.workingtrc(oprevi, oprevi, cw, ch, 5, params->icm.workingProfile, params->icm.workingTRCGamma, params->icm.workingTRCSlope, customTransformOut, false, true, true); - } - } - */ - } - - // if ((todo & (M_LUMINANCE + M_COLOR)) || (todo & M_AUTOEXP)) { - // if (todo & M_RGBCURVE) { - if (((todo & (M_AUTOEXP | M_RGBCURVE)) || (todo & M_CROP)) && params->locallab.enabled && !params->locallab.spots.empty()) { + if ((todo & (M_AUTOEXP | M_RGBCURVE | M_CROP)) && params->locallab.enabled && !params->locallab.spots.empty()) { ipf.rgb2lab(*oprevi, *oprevl, params->icm.workingProfile); @@ -920,11 +888,11 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) for (int sp = 0; sp < (int)params->locallab.spots.size(); sp++) { - if(params->locallab.spots.at(sp).equiltm && params->locallab.spots.at(sp).exptonemap) { + if (params->locallab.spots.at(sp).equiltm && params->locallab.spots.at(sp).exptonemap) { savenormtm.reset(new LabImage(*oprevl, true)); } - if(params->locallab.spots.at(sp).equilret && params->locallab.spots.at(sp).expreti) { + if (params->locallab.spots.at(sp).equilret && params->locallab.spots.at(sp).expreti) { savenormreti.reset(new LabImage(*oprevl, true)); } // Set local curves of current spot to LUT @@ -1034,7 +1002,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) float yend = 1.f; float xsta = 0.f; float xend = 1.f; - if(istm || isreti) { + if (istm || isreti) { locx = params->locallab.spots.at(sp).loc.at(0) / 2000.0; locy = params->locallab.spots.at(sp).loc.at(2) / 2000.0; locxl= params->locallab.spots.at(sp).loc.at(1) / 2000.0; @@ -1054,10 +1022,10 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) int yys = ysta * hh; int yye = yend * hh; - if(istm) { //calculate mean and sigma on full image for RT-spot use by normalize_mean_dt + if (istm) { //calculate mean and sigma on full image for RT-spot use by normalize_mean_dt ipf.mean_sig (nprevl->L, meantme, stdtme, xxs, xxe, yys, yye); } - if(isreti) { //calculate mean and sigma on full image for RT-spot use by normalize_mean_dt + if (isreti) { //calculate mean and sigma on full image for RT-spot use by normalize_mean_dt ipf.mean_sig (nprevl->L, meanretie, stdretie,xxs, xxe, yys, yye) ; } @@ -1146,20 +1114,20 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) - if(istm) { //calculate mean and sigma on full image for use by normalize_mean_dt + if (istm) { //calculate mean and sigma on full image for use by normalize_mean_dt float meanf = 0.f; float stdf = 0.f; - ipf.mean_sig (savenormtm.get()->L, meanf, stdf, xxs, xxe, yys, yye); + ipf.mean_sig (savenormtm->L, meanf, stdf, xxs, xxe, yys, yye); //using 2 unused variables noiselumc and softradiustm params->locallab.spots.at(sp).noiselumc = (int) meanf; params->locallab.spots.at(sp).softradiustm = stdf ; } - if(isreti) { //calculate mean and sigma on full image for use by normalize_mean_dt + if (isreti) { //calculate mean and sigma on full image for use by normalize_mean_dt float meanf = 0.f; float stdf = 0.f; - ipf.mean_sig (savenormreti.get()->L, meanf, stdf,xxs, xxe, yys, yye ); + ipf.mean_sig (savenormreti->L, meanf, stdf,xxs, xxe, yys, yye ); //using 2 unused variables sensihs and sensiv params->locallab.spots.at(sp).sensihs = (int) meanf; params->locallab.spots.at(sp).sensiv = (int) stdf; @@ -1334,7 +1302,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) lhist16.clear(); #ifdef _OPENMP const int numThreads = min(max(pW * pH / (int)lhist16.getSize(), 1), omp_get_max_threads()); - #pragma omp parallel num_threads(numThreads) if(numThreads>1) + #pragma omp parallel num_threads(numThreads) if (numThreads>1) #endif { LUTu lhist16thr(lhist16.getSize()); @@ -1414,7 +1382,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) bool proton = WaveParams.exptoning; bool pronois = WaveParams.expnoise; - if(WaveParams.showmask) { + if (WaveParams.showmask) { // WaveParams.showmask = false; // WaveParams.expclari = true; } @@ -1540,7 +1508,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } float indic = 1.f; - if(WaveParams.showmask){ + if (WaveParams.showmask){ mL0 = mC0 = -1.f; indic = -1.f; mL = fabs(mL); @@ -1611,6 +1579,134 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) ipf.softLight(nprevl, params->softlight); + if (params->icm.workingTRC != ColorManagementParams::WorkingTrc::NONE) { + const int GW = nprevl->W; + const int GH = nprevl->H; + std::unique_ptr provis; + const float pres = 0.01f * params->icm.preser; + if (pres > 0.f && params->icm.wprim != ColorManagementParams::Primaries::DEFAULT) { + provis.reset(new LabImage(GW, GH)); + provis->CopyFrom(nprevl); + } + + std::unique_ptr tmpImage1(new Imagefloat(GW, GH)); + + ipf.lab2rgb(*nprevl, *tmpImage1, params->icm.workingProfile); + + const float gamtone = params->icm.workingTRCGamma; + const float slotone = params->icm.workingTRCSlope; + + int illum = toUnderlying(params->icm.will); + const int prim = toUnderlying(params->icm.wprim); + + Glib::ustring prof = params->icm.workingProfile; + cmsHTRANSFORM dummy = nullptr; + int ill = 0; + ipf.workingtrc(tmpImage1.get(), tmpImage1.get(), GW, GH, -5, prof, 2.4, 12.92310, ill, 0, dummy, true, false, false); + ipf.workingtrc(tmpImage1.get(), tmpImage1.get(), GW, GH, 5, prof, gamtone, slotone, illum, prim, dummy, false, true, true); + + ipf.rgb2lab(*tmpImage1, *nprevl, params->icm.workingProfile); + //nprevl and provis + if (provis) { + ipf.preserv(nprevl, provis.get(), GW, GH); + } + if (params->icm.fbw) { +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int x = 0; x < GH; x++) + for (int y = 0; y < GW; y++) { + nprevl->a[x][y] = 0.f; + nprevl->b[x][y] = 0.f; + } + } + + tmpImage1.reset(); + + if (prim == 12) {//pass red gre blue xy in function of area dats Ciexy + float redgraphx = params->icm.labgridcieALow; + float redgraphy = params->icm.labgridcieBLow; + float blugraphx = params->icm.labgridcieAHigh; + float blugraphy = params->icm.labgridcieBHigh; + float gregraphx = params->icm.labgridcieGx; + float gregraphy = params->icm.labgridcieGy; + float redxx = 0.55f * (redgraphx + 1.f) - 0.1f; + redxx = rtengine::LIM(redxx, 0.41f, 1.f); + float redyy = 0.55f * (redgraphy + 1.f) - 0.1f; + redyy = rtengine::LIM(redyy, 0.f, 0.7f); + float bluxx = 0.55f * (blugraphx + 1.f) - 0.1f; + bluxx = rtengine::LIM(bluxx, -0.1f, 0.5f); + float bluyy = 0.55f * (blugraphy + 1.f) - 0.1f; + bluyy = rtengine::LIM(bluyy, -0.1f, 0.5f); + + float grexx = 0.55f * (gregraphx + 1.f) - 0.1f; + grexx = rtengine::LIM(grexx, -0.1f, 0.4f); + float greyy = 0.55f * (gregraphy + 1.f) - 0.1f; + greyy = rtengine::LIM(greyy, 0.5f, 1.f); + + if (primListener) { + primListener->primChanged (redxx, redyy, bluxx, bluyy, grexx, greyy); + } + } else {//all other cases - pass Cie xy to update graph Ciexy + float r_x = params->icm.redx; + float r_y = params->icm.redy; + float b_x = params->icm.blux; + float b_y = params->icm.bluy; + float g_x = params->icm.grex; + float g_y = params->icm.grey; + //printf("rx=%f ry=%f \n", (double) r_x, (double) r_y); + float wx = 0.33f; + float wy = 0.33f; + + switch (illum) { + case 1://D41 + wx = 0.37798f; + wy = 0.38123f; + break; + case 2://D50 + wx = 0.3457f; + wy = 0.3585f; + break; + case 3://D55 + wx = 0.3324f; + wy = 0.3474f; + break; + case 4://D60 + wx = 0.3217f; + wy = 0.3377f; + break; + case 5://D65 + wx = 0.3127f; + wy = 0.3290f; + break; + case 6://D80 + wx = 0.2937f; + wy = 0.3092f; + break; + case 7://D120 + wx = 0.2697f; + wy = 0.2808f; + break; + case 8://stdA + wx = 0.4476f; + wy = 0.4074f; + break; + case 9://2000K + wx = 0.5266f; + wy = 0.4133f; + break; + case 10://1500K + wx = 0.5857f; + wy = 0.3932f; + break; + } + + if (primListener) { + primListener->iprimChanged (r_x, r_y, b_x, b_y, g_x, g_y, wx, wy); + } + } + } + if (params->colorappearance.enabled) { // L histo and Chroma histo for ciecam // histogram well be for Lab (Lch) values, because very difficult to do with J,Q, M, s, C @@ -1718,6 +1814,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } + // if (todo & (M_AUTOEXP | M_RGBCURVE)) { + // Update the monitor color transform if necessary if ((todo & M_MONITOR) || (lastOutputProfile != params->icm.outputProfile) || lastOutputIntent != params->icm.outputIntent || lastOutputBPC != params->icm.outputBPC) { lastOutputProfile = params->icm.outputProfile; diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 9735f8be8..796895125 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -190,6 +190,7 @@ protected: ImageTypeListener *imageTypeListener; FilmNegListener *filmNegListener; AutoColorTonListener* actListener; + AutoprimListener* primListener; AutoChromaListener* adnListener; WaveletListener* awavListener; RetinexListener* dehaListener; @@ -501,6 +502,10 @@ public: { actListener = bwct; } + void setAutoprimListener (AutoprimListener* pri) override + { + primListener = pri; + } void setAutoChromaListener (AutoChromaListener* adn) override { adnListener = adn; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 047f045e2..c421f72d1 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -3582,21 +3582,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } if (sCurveEnabled) { - delete sCurve; + delete sCurve; } if (vCurveEnabled) { delete vCurve; } - // shadowsHighlights(lab); - // shadowsHighlights(lab, params->sh.enabled, params->sh.lab,params->sh.highlights ,params->sh.shadows, params->sh.radius, scale, params->sh.htonalwidth, params->sh.stonalwidth); -/* - if (params->localContrast.enabled) { - // Alberto's local contrast - localContrast(lab, lab->L, params->localContrast, false, scale); - } - */ } /** diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index c11f0810b..5020b36f2 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -477,7 +477,8 @@ enum class BlurType { void rgb2lab(const Image8 &src, int x, int y, int w, int h, float L[], float a[], float b[], const procparams::ColorManagementParams &icm, bool consider_histogram_settings = true) const; Imagefloat* lab2rgbOut(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm); // CieImage *ciec; - void workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, int ch, int mul, const Glib::ustring &profile, double gampos, double slpos, cmsHTRANSFORM &transform, bool normalizeIn = true, bool normalizeOut = true, bool keepTransForm = false) const; + void workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, int ch, int mul, Glib::ustring &profile, double gampos, double slpos, int &illum, int prim, cmsHTRANSFORM &transform, bool normalizeIn = true, bool normalizeOut = true, bool keepTransForm = false) const; + void preserv(LabImage *nprevl, LabImage *provis, int cw, int ch); bool transCoord(int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1, const LensCorrection *pLCPMap = nullptr) const; bool transCoord(int W, int H, const std::vector &src, std::vector &red, std::vector &green, std::vector &blue, double ascaleDef = -1, const LensCorrection *pLCPMap = nullptr) const; diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 81a304fd3..f07601c45 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -16,18 +16,20 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "rtengine.h" -#include "image8.h" -#include "imagefloat.h" -#include "labimage.h" -#include "improcfun.h" #include -#include "iccstore.h" -#include "iccmatrices.h" -#include "settings.h" + #include "alignedbuffer.h" #include "color.h" +#include "iccmatrices.h" +#include "iccstore.h" +#include "image8.h" +#include "imagefloat.h" +#include "improcfun.h" +#include "labimage.h" #include "procparams.h" +#include "rtengine.h" +#include "settings.h" +#include "utils.h" namespace rtengine { @@ -120,6 +122,19 @@ inline void copyAndClamp(const LabImage *src, unsigned char *dst, const double r } // namespace + +float gammalog(float x, float p, float s, float g3, float g4) +{ + return x <= g3 ? x * s : (1.f + g4) * xexpf(xlogf(x) / p) - g4;//continuous +} + +#ifdef __SSE2__ +vfloat gammalog(vfloat x, vfloat p, vfloat s, vfloat g3, vfloat g4) +{ + return vself(vmaskf_le(x, g3), x * s, (F2V(1.f) + g4) * xexpf(xlogf(x) / p) - g4);//continuous +} +#endif + // Used in ImProcCoordinator::updatePreviewImage (rtengine/improccoordinator.cc) // Crop::update (rtengine/dcrop.cc) // Thumbnail::processImage (rtengine/rtthumbnail.cc) @@ -373,8 +388,31 @@ Imagefloat* ImProcFunctions::lab2rgbOut(LabImage* lab, int cx, int cy, int cw, i return image; } +void ImProcFunctions::preserv(LabImage *nprevl, LabImage *provis, int cw, int ch) +{//avoid too strong in middle values chroma when changing primaries + float pres = 0.01f * params->icm.preser; + float neutral = 2000000000.f;//if a2 + b2 < 200000000 scale 0..100 a and b about : 140 > a & b > -140 decrease effect + float medneutral = 10000000.f;//plein effect 10 > a & b > -10 + float aaneu = 1.f / (medneutral - neutral); + float bbneu = - aaneu * neutral; +#ifdef _OPENMP + #pragma omp for schedule(dynamic, 16) nowait +#endif + for (int i = 0; i < ch; ++i) + for (int j = 0; j < cw; ++j) { + float neu = SQR(provis->a[i][j]) + SQR(provis->b[i][j]); + if (neu < medneutral) {//plein effect + nprevl->a[i][j] = intp(pres, provis->a[i][j], nprevl->a[i][j]); + nprevl->b[i][j] = intp(pres, provis->b[i][j], nprevl->b[i][j]); + } else if (neu < neutral) {//decrease effect + float presred = aaneu * neu + bbneu; + nprevl->a[i][j] = intp(pres * presred, provis->a[i][j], nprevl->a[i][j]); + nprevl->b[i][j] = intp(pres * presred, provis->b[i][j], nprevl->b[i][j]); + } + } +} -void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, int ch, int mul, const Glib::ustring &profile, double gampos, double slpos, cmsHTRANSFORM &transform, bool normalizeIn, bool normalizeOut, bool keepTransForm) const +void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, int ch, int mul, Glib::ustring &profile, double gampos, double slpos, int &illum, int prim, cmsHTRANSFORM &transform, bool normalizeIn, bool normalizeOut, bool keepTransForm) const { const TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); @@ -394,6 +432,163 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, } }; + if (profile == "sRGB" || profile == "Adobe RGB" || profile == "ProPhoto" || profile == "WideGamut" || profile == "BruceRGB" || profile == "Beta RGB" || profile == "BestRGB" || profile == "Rec2020" || profile == "ACESp0" || profile == "ACESp1") { + if (settings->verbose) { + printf("Profile=%s\n", profile.c_str()); + } + } else { + if (settings->verbose) { + printf("profile not accepted\n"); + } + return; + } + + if (mul == -5 && gampos == 2.4 && slpos == 12.92310) {//must be change if we change settings RT sRGB + //only in this case we can shortcut..all process..no gamut control..because we reduce...leads to very small differences, but big speedup +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, 16) if (multiThread) +#endif + + for (int i = 0; i < ch; ++i) + for (int j = 0; j < cw; ++j) { + float r = src->r(i, j); + float g = src->g(i, j); + float b = src->b(i, j); + r = (Color::igammatab_srgb[r]) / 65535.f; + g = (Color::igammatab_srgb[g]) / 65535.f; + b = (Color::igammatab_srgb[b]) / 65535.f; + dst->r(i, j) = r; + dst->g(i, j) = g; + dst->b(i, j) = b; + } + return; + + } + + if (mul == 1 ||(params->icm.wprim == ColorManagementParams::Primaries::DEFAULT && params->icm.will == ColorManagementParams::Illuminant::DEFAULT)) {//shortcut and speedup when no call primaries and illuminant - no gamut control...in this case be carefull + GammaValues g_a; //gamma parameters + double pwr = 1.0 / static_cast(gampos); + Color::calcGamma(pwr, slpos, g_a); // call to calcGamma with selected gamma and slope + +#ifdef _OPENMP +# pragma omp parallel for schedule(dynamic,16) if (multiThread) +#endif + for (int y = 0; y < ch; ++y) { + int x = 0; +#ifdef __SSE2__ + for (; x < cw - 3; x += 4) { + STVFU(dst->r(y,x), F2V(65536.f) * gammalog(LVFU(src->r(y,x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); + STVFU(dst->g(y,x), F2V(65536.f) * gammalog(LVFU(src->g(y,x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); + STVFU(dst->b(y,x), F2V(65536.f) * gammalog(LVFU(src->b(y,x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); + } +#endif + for (; x < cw; ++x) { + dst->r(y,x) = 65536.f * gammalog(src->r(y,x), gampos, slpos, g_a[3], g_a[4]); + dst->g(y,x) = 65536.f * gammalog(src->g(y,x), gampos, slpos, g_a[3], g_a[4]); + dst->b(y,x) = 65536.f * gammalog(src->b(y,x), gampos, slpos, g_a[3], g_a[4]); + } + } + return; + } + + + float redxx = params->icm.redx; + float redyy = params->icm.redy; + float bluxx = params->icm.blux; + float bluyy = params->icm.bluy; + float grexx = params->icm.grex; + float greyy = params->icm.grey; + + if (prim == 12) {//convert datas area to xy + float redgraphx = params->icm.labgridcieALow; + float redgraphy = params->icm.labgridcieBLow; + float blugraphx = params->icm.labgridcieAHigh; + float blugraphy = params->icm.labgridcieBHigh; + float gregraphx = params->icm.labgridcieGx; + float gregraphy = params->icm.labgridcieGy; + redxx = 0.55f * (redgraphx + 1.f) - 0.1f; + redxx = rtengine::LIM(redxx, 0.41f, 1.f);//limit values for xy (arbitrary) + redyy = 0.55f * (redgraphy + 1.f) - 0.1f; + redyy = rtengine::LIM(redyy, 0.f, 0.7f); + bluxx = 0.55f * (blugraphx + 1.f) - 0.1f; + bluxx = rtengine::LIM(bluxx, -0.1f, 0.5f); + bluyy = 0.55f * (blugraphy + 1.f) - 0.1f; + bluyy = rtengine::LIM(bluyy, -0.1f, 0.5f); + grexx = 0.55f * (gregraphx + 1.f) - 0.1f; + grexx = rtengine::LIM(grexx, -0.1f, 0.4f); + greyy = 0.55f * (gregraphy + 1.f) - 0.1f; + greyy = rtengine::LIM(greyy, 0.5f, 1.f); + } + + switch (ColorManagementParams::Primaries(prim)) { + case ColorManagementParams::Primaries::DEFAULT: { + break; + } + + case ColorManagementParams::Primaries::SRGB: { + profile = "sRGB"; + break; + } + + case ColorManagementParams::Primaries::ADOBE_RGB: { + profile = "Adobe RGB"; + break; + } + + case ColorManagementParams::Primaries::PRO_PHOTO: { + profile = "ProPhoto"; + break; + } + + case ColorManagementParams::Primaries::REC2020: { + profile = "Rec2020"; + break; + } + + case ColorManagementParams::Primaries::ACES_P1: { + profile = "ACESp1"; + break; + } + + case ColorManagementParams::Primaries::WIDE_GAMUT: { + profile = "WideGamut"; + break; + } + + case ColorManagementParams::Primaries::ACES_P0: { + profile = "ACESp0"; + break; + } + + case ColorManagementParams::Primaries::BRUCE_RGB: { + profile = "BruceRGB"; + break; + } + + case ColorManagementParams::Primaries::BETA_RGB: { + profile = "Beta RGB"; + break; + } + + case ColorManagementParams::Primaries::BEST_RGB: { + profile = "BestRGB"; + break; + } + + case ColorManagementParams::Primaries::CUSTOM: { + profile = "Custom"; + break; + } + + case ColorManagementParams::Primaries::CUSTOM_GRID: { + profile = "Custom"; + break; + } + } + + if (settings->verbose && prim != 0) { + printf("prim=%i Profile Destination=%s\n", prim, profile.c_str()); + } cmsHTRANSFORM hTransform = nullptr; if (transform) { hTransform = transform; @@ -418,8 +613,7 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, D60 = 6005 // for ACES AP0 and AP1 }; - ColorTemp temp = ColorTemp::D50; - + double tempv4 = 5003.; float p[6]; //primaries //primaries for 10 working profiles ==> output profiles @@ -430,6 +624,7 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[3] = 0.8260; p[4] = 0.1570; p[5] = 0.0180; + illum = toUnderlying(ColorManagementParams::Illuminant::D50); } else if (profile == "Adobe RGB") { p[0] = 0.6400; //Adobe primaries p[1] = 0.3300; @@ -437,7 +632,8 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[3] = 0.7100; p[4] = 0.1500; p[5] = 0.0600; - temp = ColorTemp::D65; + tempv4 = 6504.; + illum = toUnderlying(ColorManagementParams::Illuminant::D65); } else if (profile == "sRGB") { p[0] = 0.6400; // sRGB primaries p[1] = 0.3300; @@ -445,7 +641,8 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[3] = 0.6000; p[4] = 0.1500; p[5] = 0.0600; - temp = ColorTemp::D65; + tempv4 = 6504.; + illum = toUnderlying(ColorManagementParams::Illuminant::D65); } else if (profile == "BruceRGB") { p[0] = 0.6400; // Bruce primaries p[1] = 0.3300; @@ -453,14 +650,16 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[3] = 0.6500; p[4] = 0.1500; p[5] = 0.0600; - temp = ColorTemp::D65; - } else if (profile == "Beta RGB") { + tempv4 = 6504.; + illum = toUnderlying(ColorManagementParams::Illuminant::D65); + } else if (profile == "Beta RGB") { p[0] = 0.6888; // Beta primaries p[1] = 0.3112; p[2] = 0.1986; p[3] = 0.7551; p[4] = 0.1265; p[5] = 0.0352; + illum = toUnderlying(ColorManagementParams::Illuminant::D50); } else if (profile == "BestRGB") { p[0] = 0.7347; // Best primaries p[1] = 0.2653; @@ -468,6 +667,7 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[3] = 0.7750; p[4] = 0.1300; p[5] = 0.0350; + illum = toUnderlying(ColorManagementParams::Illuminant::D50); } else if (profile == "Rec2020") { p[0] = 0.7080; // Rec2020 primaries p[1] = 0.2920; @@ -475,7 +675,8 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[3] = 0.7970; p[4] = 0.1310; p[5] = 0.0460; - temp = ColorTemp::D65; + tempv4 = 6504.; + illum = toUnderlying(ColorManagementParams::Illuminant::D65); } else if (profile == "ACESp0") { p[0] = 0.7347; // ACES P0 primaries p[1] = 0.2653; @@ -483,7 +684,8 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[3] = 1.0; p[4] = 0.0001; p[5] = -0.0770; - temp = ColorTemp::D60; + tempv4 = 6004.; + illum = toUnderlying(ColorManagementParams::Illuminant::D60); } else if (profile == "ACESp1") { p[0] = 0.713; // ACES P1 primaries p[1] = 0.293; @@ -491,7 +693,8 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[3] = 0.830; p[4] = 0.128; p[5] = 0.044; - temp = ColorTemp::D60; + tempv4 = 6004.; + illum = toUnderlying(ColorManagementParams::Illuminant::D60); } else if (profile == "ProPhoto") { p[0] = 0.7347; //ProPhoto and default primaries p[1] = 0.2653; @@ -499,6 +702,14 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[3] = 0.8404; p[4] = 0.0366; p[5] = 0.0001; + illum = toUnderlying(ColorManagementParams::Illuminant::D50); + } else if (profile == "Custom") { + p[0] = redxx; + p[1] = redyy; + p[2] = grexx; + p[3] = greyy; + p[4] = bluxx; + p[5] = bluyy; } else { p[0] = 0.7347; //default primaries always unused p[1] = 0.2653; @@ -528,27 +739,145 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, // 7 parameters for smoother curves cmsCIExyY xyD; - cmsWhitePointFromTemp(&xyD, (double)temp); - if (profile == "ACESp0") { - xyD = {0.32168, 0.33767, 1.0};//refine white point to avoid differences + Glib::ustring ills = "D50"; + switch (ColorManagementParams::Illuminant(illum)) { + case ColorManagementParams::Illuminant::DEFAULT: + case ColorManagementParams::Illuminant::STDA: + case ColorManagementParams::Illuminant::TUNGSTEN_2000K: + case ColorManagementParams::Illuminant::TUNGSTEN_1500K: { + break; + } + + case ColorManagementParams::Illuminant::D41: { + tempv4 = 4100.; + ills = "D41"; + break; + } + + case ColorManagementParams::Illuminant::D50: { + tempv4 = 5003.; + ills = "D50"; + break; + } + + case ColorManagementParams::Illuminant::D55: { + tempv4 = 5500.; + ills = "D55"; + break; + } + + case ColorManagementParams::Illuminant::D60: { + tempv4 = 6004.; + ills = "D60"; + break; + } + + case ColorManagementParams::Illuminant::D65: { + tempv4 = 6504.; + ills = "D65"; + break; + } + + case ColorManagementParams::Illuminant::D80: { + tempv4 = 8000.; + ills = "D80"; + break; + } + + case ColorManagementParams::Illuminant::D120: { + tempv4 = 12000.; + ills = "D120"; + break; + } } + cmsWhitePointFromTemp(&xyD, tempv4); + + switch (ColorManagementParams::Illuminant(illum)) { + case ColorManagementParams::Illuminant::DEFAULT: + case ColorManagementParams::Illuminant::D55: + case ColorManagementParams::Illuminant::D80: { + break; + } + + case ColorManagementParams::Illuminant::D41: { + break; + } + + case ColorManagementParams::Illuminant::D50: { + xyD = {0.3457, 0.3585, 1.0}; // near LCMS values but not perfect... it's a compromise!! + break; + } + + case ColorManagementParams::Illuminant::D60: { + xyD = {0.32168, 0.33767, 1.0}; + break; + } + + case ColorManagementParams::Illuminant::D65: { + xyD = {0.312700492, 0.329000939, 1.0}; + break; + } + + case ColorManagementParams::Illuminant::D120: { + xyD = {0.269669, 0.28078, 1.0}; + break; + } + + case ColorManagementParams::Illuminant::STDA: { + xyD = {0.447573, 0.407440, 1.0}; + ills = "stdA 2875K"; + break; + } + + case ColorManagementParams::Illuminant::TUNGSTEN_2000K: { + xyD = {0.526591, 0.41331, 1.0}; + ills = "Tungsten 2000K"; + break; + } + + case ColorManagementParams::Illuminant::TUNGSTEN_1500K: { + xyD = {0.585703, 0.393157, 1.0}; + ills = "Tungsten 1500K"; + break; + } + } + + //D41 0.377984 0.381229 + //D55 0.332424 0.347426 + //D80 0.293755 0.309185 + //D75 0.299021 0.314852 cmsToneCurve* GammaTRC[3]; GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(NULL, five, gammaParams);//5 = more smoother than 4 + cmsHPROFILE oprofdef = nullptr; const cmsCIExyYTRIPLE Primaries = { {p[0], p[1], 1.0}, // red {p[2], p[3], 1.0}, // green {p[4], p[5], 1.0} // blue }; - const cmsHPROFILE oprofdef = cmsCreateRGBProfile(&xyD, &Primaries, GammaTRC); - cmsFreeToneCurve(GammaTRC[0]); + oprofdef = cmsCreateRGBProfile(&xyD, &Primaries, GammaTRC); + cmsWriteTag(oprofdef, cmsSigRedTRCTag, GammaTRC[0]); + cmsWriteTag(oprofdef, cmsSigGreenTRCTag, GammaTRC[1]); + cmsWriteTag(oprofdef, cmsSigBlueTRCTag, GammaTRC[2]); + //to read XYZ values and illuminant + if (rtengine::settings->verbose) { + cmsCIEXYZ *redT = static_cast(cmsReadTag(oprofdef, cmsSigRedMatrixColumnTag)); + cmsCIEXYZ *greenT = static_cast(cmsReadTag(oprofdef, cmsSigGreenMatrixColumnTag)); + cmsCIEXYZ *blueT = static_cast(cmsReadTag(oprofdef, cmsSigBlueMatrixColumnTag)); + printf("Illuminant=%s\n", ills.c_str()); + printf("rX=%f gX=%f bX=%f\n", redT->X, greenT->X, blueT->X); + printf("rY=%f gY=%f bY=%f\n", redT->Y, greenT->Y, blueT->Y); + printf("rZ=%f gZ=%f bZ=%f\n", redT->Z, greenT->Z, blueT->Z); + } + + cmsFreeToneCurve(GammaTRC[0]); if (oprofdef) { - constexpr cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; + constexpr cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE | cmsFLAGS_BLACKPOINTCOMPENSATION | cmsFLAGS_GAMUTCHECK; const cmsHPROFILE iprof = ICCStore::getInstance()->getXYZProfile(); lcmsMutex->lock(); - hTransform = cmsCreateTransform(iprof, TYPE_RGB_FLT, oprofdef, TYPE_RGB_FLT, params->icm.outputIntent, flags); + hTransform = cmsCreateTransform(iprof, TYPE_RGB_FLT, oprofdef, TYPE_RGB_FLT, params->icm.aRendIntent, flags); lcmsMutex->unlock(); } } diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 35df6d350..00b379271 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -5069,7 +5069,7 @@ void ImProcFunctions::maskcalccol(bool invmask, bool pde, int bfw, int bfh, int if (delt) { const std::unique_ptr> rdEBuffer(new JaggedArray(bfw, bfh)); - float** rdE = *(rdEBuffer.get()); + float** rdE = *rdEBuffer; deltaEforMask(rdE, bfw, bfh, bufreserv.get(), hueref, chromaref, lumaref, maxdE, mindE, maxdElim, mindElim, iterat, limscope, scope, lp.balance, lp.balanceh); #ifdef _OPENMP @@ -6080,13 +6080,16 @@ void ImProcFunctions::InverseColorLight_Local(bool tonequ, bool tonecurv, int sp const std::unique_ptr tmpImage(new Imagefloat(GW, GH)); lab2rgb(*temp, *tmpImage, params->icm.workingProfile); - + Glib::ustring prof = params->icm.workingProfile; if (tonecurv) { //Tone response curve : does nothing if gamma=2.4 and slope=12.92 ==> gamma sRGB const float gamtone = params->locallab.spots.at(sp).gamSH; const float slotone = params->locallab.spots.at(sp).sloSH; + int ill = 0; cmsHTRANSFORM dummy = nullptr; - workingtrc(tmpImage.get(), tmpImage.get(), GW, GH, -5, params->icm.workingProfile, 2.4, 12.92310, dummy, true, false, false); - workingtrc(tmpImage.get(), tmpImage.get(), GW, GH, 5, params->icm.workingProfile, gamtone, slotone, dummy, false, true, true); + workingtrc(tmpImage.get(), tmpImage.get(), GW, GH, -5, prof, 2.4, 12.92310, ill, 0, dummy, true, false, false); + // workingtrc(tmpImage.get(), tmpImage.get(), GW, GH, 5, prof, gamtone, slotone, illum, 0, dummy, false, true, true);//to keep if we want improve with illuminant and primaries + workingtrc(tmpImage.get(), tmpImage.get(), GW, GH, 1, prof, gamtone, slotone, ill, 0, dummy, false, true, true);//be carefull no gamut control + } if (tonequ) { @@ -11559,7 +11562,7 @@ void ImProcFunctions::Lab_Local( } } - rgb2lab(*(tmpImage.get()), *bufexpfin, params->icm.workingProfile); + rgb2lab(*tmpImage, *bufexpfin, params->icm.workingProfile); tmpImageorig.reset(); tmpImage.reset(); @@ -12341,7 +12344,7 @@ void ImProcFunctions::Lab_Local( ImProcFunctions::impulse_nr(bufwv.get(), threshold); } - DeNoise_Local(call, lp, originalmaskbl.get(), levred, huerefblur, lumarefblur, chromarefblur, original, transformed, *(bufwv.get()), cx, cy, sk); + DeNoise_Local(call, lp, originalmaskbl.get(), levred, huerefblur, lumarefblur, chromarefblur, original, transformed, *bufwv, cx, cy, sk); if (lp.recur) { original->CopyFrom(transformed, multiThread); @@ -12753,7 +12756,7 @@ void ImProcFunctions::Lab_Local( const float refb = chromaref * sin(hueref); const std::unique_ptr> reducDEBuffer(new JaggedArray(Wd, Hd)); - float** reducDE = *(reducDEBuffer.get()); + float** reducDE = *reducDEBuffer; float ade = 0.01f * raddE; float bde = 100.f - raddE; @@ -12769,10 +12772,10 @@ void ImProcFunctions::Lab_Local( } const std::unique_ptr> origBuffer(new JaggedArray(Wd, Hd)); - float** orig = *(origBuffer.get()); + float** orig = *origBuffer; const std::unique_ptr> origBuffer1(new JaggedArray(Wd, Hd)); - float** orig1 = *(origBuffer1.get()); + float** orig1 = *origBuffer1; #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) if (multiThread) @@ -13100,7 +13103,7 @@ void ImProcFunctions::Lab_Local( const float refb = chromaref * sin(hueref); const std::unique_ptr> reducDEBuffer(new JaggedArray(Wd, Hd)); - float** reducDE = *(reducDEBuffer.get()); + float** reducDE = *reducDEBuffer; float ade = 0.01f * raddE; float bde = 100.f - raddE; float sensibefore = ade * lp.sensh + bde;//we can change sensitivity 0.1 90 or 0.3 70 or 0.4 60 @@ -13116,10 +13119,10 @@ void ImProcFunctions::Lab_Local( } const std::unique_ptr> origBuffer(new JaggedArray(Wd, Hd)); - float** orig = *(origBuffer.get()); + float** orig = *origBuffer; const std::unique_ptr> origBuffer1(new JaggedArray(Wd, Hd)); - float** orig1 = *(origBuffer1.get()); + float** orig1 = *origBuffer1; LabImage *tmpl = nullptr; @@ -13952,13 +13955,16 @@ void ImProcFunctions::Lab_Local( Imagefloat *tmpImage = nullptr; tmpImage = new Imagefloat(bfw, bfh); lab2rgb(*bufexpfin, *tmpImage, params->icm.workingProfile); + Glib::ustring prof = params->icm.workingProfile; if (tonecurv) { //Tone response curve : does nothing if gamma=2.4 and slope=12.92 ==> gamma sRGB - const float gamtone = params->locallab.spots.at(sp).gamSH; - const float slotone = params->locallab.spots.at(sp).sloSH; - cmsHTRANSFORM dummyTransForm = nullptr; - workingtrc(tmpImage, tmpImage, bfw, bfh, -5, params->icm.workingProfile, 2.4, 12.92310, dummyTransForm, true, false, false); - workingtrc(tmpImage, tmpImage, bfw, bfh, 5, params->icm.workingProfile, gamtone, slotone, dummyTransForm, false, true, true); + float gamtone = params->locallab.spots.at(sp).gamSH; + float slotone = params->locallab.spots.at(sp).sloSH; + cmsHTRANSFORM dummy = nullptr; + int ill =0; + workingtrc(tmpImage, tmpImage, bfw, bfh, -5, prof, 2.4, 12.92310, ill, 0, dummy, true, false, false); + // workingtrc(tmpImage, tmpImage, bfw, bfh, 5, prof, gamtone, slotone, 0, 0, dummy, false, true, true); //to keep if we want improve with illuminant and primaries + workingtrc(tmpImage, tmpImage, bfw, bfh, 1, prof, gamtone, slotone, ill, 0, dummy, false, true, true);//be carefull no gamut control } if (tonequ) { @@ -14941,13 +14947,13 @@ void ImProcFunctions::Lab_Local( //const float sigm = 1.f; //params->locallab.spots.at(sp).fatlevel; //const float mean = 1.f;// params->locallab.spots.at(sp).fatanchor; const std::unique_ptr tmpImagefat(new Imagefloat(bfwr, bfhr)); - lab2rgb(*bufexpfin, *(tmpImagefat.get()), params->icm.workingProfile); + lab2rgb(*bufexpfin, *tmpImagefat, params->icm.workingProfile); int alg = 0; if(fatParams.anchor == 50.f) { alg = 1; } ToneMapFattal02(tmpImagefat.get(), fatParams, 3, 0, nullptr, 0, 0, alg);//last parameter = 1 ==>ART algorithm - rgb2lab(*(tmpImagefat.get()), *bufexpfin, params->icm.workingProfile); + rgb2lab(*tmpImagefat, *bufexpfin, params->icm.workingProfile); } @@ -15358,7 +15364,7 @@ void ImProcFunctions::Lab_Local( usergb = true; const std::unique_ptr tmpImage(new Imagefloat(bfw, bfh)); - lab2rgb(*buftemp, *(tmpImage.get()), params->icm.workingProfile); + lab2rgb(*buftemp, *tmpImage, params->icm.workingProfile); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) if (multiThread) #endif @@ -15425,7 +15431,7 @@ void ImProcFunctions::Lab_Local( } } - rgb2lab(*(tmpImage.get()), *buftemp, params->icm.workingProfile); + rgb2lab(*tmpImage, *buftemp, params->icm.workingProfile); // end rgb curves } @@ -15742,7 +15748,7 @@ void ImProcFunctions::Lab_Local( } const std::unique_ptr> rdEBuffer(new JaggedArray(bfw, bfh)); - float** rdE = *(rdEBuffer.get()); + float** rdE = *rdEBuffer; deltaEforMask(rdE, bfw, bfh, bufreser.get(), hueref, chromaref, lumaref, maxdE, mindE, maxdElim, mindElim, lp.iterat, limscope, mercol, lp.balance, lp.balanceh); @@ -15904,11 +15910,11 @@ void ImProcFunctions::Lab_Local( //prepare RGB values in 0 1(or more)for current image and reserved std::unique_ptr tmpImageorig(new Imagefloat(bfw, bfh)); - lab2rgb(*bufcolfin, *(tmpImageorig.get()), params->icm.workingProfile); + lab2rgb(*bufcolfin, *tmpImageorig, params->icm.workingProfile); tmpImageorig->normalizeFloatTo1(); std::unique_ptr tmpImagereserv(new Imagefloat(bfw, bfh)); - lab2rgb(*bufcolreserv, *(tmpImagereserv.get()), params->icm.workingProfile); + lab2rgb(*bufcolreserv, *tmpImagereserv, params->icm.workingProfile); tmpImagereserv->normalizeFloatTo1(); float minR = tmpImagereserv->r(0, 0); diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index 67db52e55..491e17cb9 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -397,7 +397,7 @@ void RawImageSource::MSR(float** luminance, float** originalLuminance, float **e } std::unique_ptr> srcBuffer(new JaggedArray(W_L, H_L)); - float** src = *(srcBuffer.get()); + float** src = *srcBuffer; #ifdef _OPENMP #pragma omp parallel for @@ -1238,7 +1238,7 @@ void ImProcFunctions::MSRLocal(int call, int sp, bool fftw, int lum, float** red const int H_L = height; const int W_L = width; std::unique_ptr> srcBuffer(new JaggedArray(W_L, H_L)); - float** src = *(srcBuffer.get()); + float** src = *srcBuffer; #ifdef _OPENMP diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 5768f9c3e..317b34893 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2216,9 +2216,28 @@ ColorManagementParams::ColorManagementParams() : applyHueSatMap(true), dcpIlluminant(0), workingProfile("ProPhoto"), - workingTRC("none"), - workingTRCGamma(2.4), - workingTRCSlope(12.92310), + workingTRC(WorkingTrc::NONE), + will(Illuminant::DEFAULT), + wprim(Primaries::DEFAULT), + workingTRCGamma(2.4),//gamma sRGB + workingTRCSlope(12.92), + redx(0.64), + redy(0.33), + grex(0.21), + grey(0.71), + blux(0.15), + bluy(0.06), + preser(0.), + fbw(false), + labgridcieALow(0.51763),//Prophoto red = (0.7347+0.1) * 1.81818 - 1 + labgridcieBLow(-0.33582), + labgridcieAHigh(-0.75163),//Prophoto blue + labgridcieBHigh(-0.8180), + labgridcieGx(-0.69164),//Prophoto green 0.1596 + labgridcieGy(-0.70909),//0.84 + labgridcieWx(-0.18964),//D50 0.3457, 0.3585, + labgridcieWy(-0.16636),// + aRendIntent(RI_RELATIVE), outputProfile(options.rtSettings.srgb), outputIntent(RI_RELATIVE), outputBPC(true) @@ -2236,8 +2255,27 @@ bool ColorManagementParams::operator ==(const ColorManagementParams& other) cons && dcpIlluminant == other.dcpIlluminant && workingProfile == other.workingProfile && workingTRC == other.workingTRC + && will == other.will + && wprim == other.wprim && workingTRCGamma == other.workingTRCGamma && workingTRCSlope == other.workingTRCSlope + && redx == other.redx + && redy == other.redy + && grex == other.grex + && grey == other.grey + && blux == other.blux + && bluy == other.bluy + && labgridcieALow == other.labgridcieALow + && labgridcieBLow == other.labgridcieBLow + && labgridcieAHigh == other.labgridcieAHigh + && labgridcieBHigh == other.labgridcieBHigh + && labgridcieGx == other.labgridcieGx + && labgridcieGy == other.labgridcieGy + && labgridcieWx == other.labgridcieWx + && labgridcieWy == other.labgridcieWy + && preser == other.preser + && fbw == other.fbw + && aRendIntent == other.aRendIntent && outputProfile == other.outputProfile && outputIntent == other.outputIntent && outputBPC == other.outputBPC; @@ -3979,6 +4017,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : // Log encoding visilog(false), explog(false), + complexlog(0), autocompute(false), sourceGray(10.), sourceabs(2000.), @@ -6493,10 +6532,97 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->icm.applyHueSatMap, "Color Management", "ApplyHueSatMap", icm.applyHueSatMap, keyFile); saveToKeyfile(!pedited || pedited->icm.dcpIlluminant, "Color Management", "DCPIlluminant", icm.dcpIlluminant, keyFile); saveToKeyfile(!pedited || pedited->icm.workingProfile, "Color Management", "WorkingProfile", icm.workingProfile, keyFile); - saveToKeyfile(!pedited || pedited->icm.workingTRC, "Color Management", "WorkingTRC", icm.workingTRC, keyFile); + saveToKeyfile( + !pedited || pedited->icm.workingTRC, + "Color Management", + "WorkingTRC", + { + {ColorManagementParams::WorkingTrc::NONE, "none"}, + {ColorManagementParams::WorkingTrc::CUSTOM, "Custom"}, + {ColorManagementParams::WorkingTrc::BT709, "bt709"}, + {ColorManagementParams::WorkingTrc::SRGB, "srgb"}, + {ColorManagementParams::WorkingTrc::GAMMA_2_2, "22"}, + {ColorManagementParams::WorkingTrc::GAMMA_1_8, "18"}, + {ColorManagementParams::WorkingTrc::LINEAR, "lin"} + }, + icm.workingTRC, + keyFile + ); + saveToKeyfile( + !pedited || pedited->icm.will, + "Color Management", + "Will", + { + {ColorManagementParams::Illuminant::DEFAULT, "def"}, + {ColorManagementParams::Illuminant::D41, "D41"}, + {ColorManagementParams::Illuminant::D50, "D50"}, + {ColorManagementParams::Illuminant::D55, "D55"}, + {ColorManagementParams::Illuminant::D60, "D60"}, + {ColorManagementParams::Illuminant::D65, "D65"}, + {ColorManagementParams::Illuminant::D80, "D80"}, + {ColorManagementParams::Illuminant::D120, "D120"}, + {ColorManagementParams::Illuminant::STDA, "stda"}, + {ColorManagementParams::Illuminant::TUNGSTEN_2000K, "2000"}, + {ColorManagementParams::Illuminant::TUNGSTEN_1500K, "1500"} + }, + icm.will, + keyFile + ); + saveToKeyfile( + !pedited || pedited->icm.wprim, + "Color Management", + "Wprim", + { + {ColorManagementParams::Primaries::DEFAULT, "def"}, + {ColorManagementParams::Primaries::SRGB, "srgb"}, + {ColorManagementParams::Primaries::ADOBE_RGB, "adob"}, + {ColorManagementParams::Primaries::PRO_PHOTO, "prop"}, + {ColorManagementParams::Primaries::REC2020, "rec"}, + {ColorManagementParams::Primaries::ACES_P1, "aces"}, + {ColorManagementParams::Primaries::WIDE_GAMUT, "wid"}, + {ColorManagementParams::Primaries::ACES_P0, "ac0"}, + {ColorManagementParams::Primaries::BRUCE_RGB, "bru"}, + {ColorManagementParams::Primaries::BETA_RGB, "bet"}, + {ColorManagementParams::Primaries::BEST_RGB, "bst"}, + {ColorManagementParams::Primaries::CUSTOM, "cus"}, + {ColorManagementParams::Primaries::CUSTOM_GRID, "cusgr"} + }, + icm.wprim, + keyFile + ); saveToKeyfile(!pedited || pedited->icm.workingTRCGamma, "Color Management", "WorkingTRCGamma", icm.workingTRCGamma, keyFile); saveToKeyfile(!pedited || pedited->icm.workingTRCSlope, "Color Management", "WorkingTRCSlope", icm.workingTRCSlope, keyFile); + saveToKeyfile(!pedited || pedited->icm.redx, "Color Management", "Redx", icm.redx, keyFile); + saveToKeyfile(!pedited || pedited->icm.redy, "Color Management", "Redy", icm.redy, keyFile); + saveToKeyfile(!pedited || pedited->icm.grex, "Color Management", "Grex", icm.grex, keyFile); + saveToKeyfile(!pedited || pedited->icm.grey, "Color Management", "Grey", icm.grey, keyFile); + saveToKeyfile(!pedited || pedited->icm.blux, "Color Management", "Blux", icm.blux, keyFile); + saveToKeyfile(!pedited || pedited->icm.bluy, "Color Management", "Bluy", icm.bluy, keyFile); + saveToKeyfile(!pedited || pedited->icm.labgridcieALow, "Color Management", "LabGridcieALow", icm.labgridcieALow, keyFile); + saveToKeyfile(!pedited || pedited->icm.labgridcieBLow, "Color Management", "LabGridcieBLow", icm.labgridcieBLow, keyFile); + saveToKeyfile(!pedited || pedited->icm.labgridcieAHigh, "Color Management", "LabGridcieAHigh", icm.labgridcieAHigh, keyFile); + saveToKeyfile(!pedited || pedited->icm.labgridcieBHigh, "Color Management", "LabGridcieBHigh", icm.labgridcieBHigh, keyFile); + saveToKeyfile(!pedited || pedited->icm.labgridcieGx, "Color Management", "LabGridcieGx", icm.labgridcieGx, keyFile); + saveToKeyfile(!pedited || pedited->icm.labgridcieGy, "Color Management", "LabGridcieGy", icm.labgridcieGy, keyFile); + saveToKeyfile(!pedited || pedited->icm.labgridcieWx, "Color Management", "LabGridcieWx", icm.labgridcieWx, keyFile); + saveToKeyfile(!pedited || pedited->icm.labgridcieWy, "Color Management", "LabGridcieWy", icm.labgridcieWy, keyFile); + saveToKeyfile(!pedited || pedited->icm.preser, "Color Management", "Preser", icm.preser, keyFile); + saveToKeyfile(!pedited || pedited->icm.fbw, "Color Management", "Fbw", icm.fbw, keyFile); saveToKeyfile(!pedited || pedited->icm.outputProfile, "Color Management", "OutputProfile", icm.outputProfile, keyFile); + saveToKeyfile( + !pedited || pedited->icm.aRendIntent, + "Color Management", + "aIntent", + { + {RI_PERCEPTUAL, "Perceptual"}, + {RI_RELATIVE, "Relative"}, + {RI_SATURATION, "Saturation"}, + {RI_ABSOLUTE, "Absolute"} + }, + icm.aRendIntent, + keyFile + ); + saveToKeyfile( !pedited || pedited->icm.outputIntent, "Color Management", @@ -8455,10 +8581,125 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Color Management", "ApplyHueSatMap", pedited, icm.applyHueSatMap, pedited->icm.applyHueSatMap); assignFromKeyfile(keyFile, "Color Management", "DCPIlluminant", pedited, icm.dcpIlluminant, pedited->icm.dcpIlluminant); assignFromKeyfile(keyFile, "Color Management", "WorkingProfile", pedited, icm.workingProfile, pedited->icm.workingProfile); - assignFromKeyfile(keyFile, "Color Management", "WorkingTRC", pedited, icm.workingTRC, pedited->icm.workingTRC); + if ( + !assignFromKeyfile( + keyFile, + "Color Management", + "WorkingTRC", + pedited, + { + {"none", ColorManagementParams::WorkingTrc::NONE}, + {"Custom", ColorManagementParams::WorkingTrc::CUSTOM}, + {"bt709", ColorManagementParams::WorkingTrc::BT709}, + {"srgb", ColorManagementParams::WorkingTrc::SRGB}, + {"22", ColorManagementParams::WorkingTrc::GAMMA_2_2}, + {"18", ColorManagementParams::WorkingTrc::GAMMA_1_8}, + {"lin", ColorManagementParams::WorkingTrc::LINEAR} + }, + icm.workingTRC, + pedited->icm.workingTRC + ) + ) { + icm.workingTRC = ColorManagementParams::WorkingTrc::NONE; + if (pedited) { + pedited->icm.workingTRC = true; + } + } + if ( + !assignFromKeyfile( + keyFile, + "Color Management", + "Will", + pedited, + { + {"def", ColorManagementParams::Illuminant::DEFAULT}, + {"D41", ColorManagementParams::Illuminant::D41}, + {"D50", ColorManagementParams::Illuminant::D50}, + {"D55", ColorManagementParams::Illuminant::D55}, + {"D60", ColorManagementParams::Illuminant::D60}, + {"D65", ColorManagementParams::Illuminant::D65}, + {"D80", ColorManagementParams::Illuminant::D80}, + {"D120", ColorManagementParams::Illuminant::D120}, + {"stda", ColorManagementParams::Illuminant::STDA}, + {"2000", ColorManagementParams::Illuminant::TUNGSTEN_2000K}, + {"1500", ColorManagementParams::Illuminant::TUNGSTEN_1500K} + }, + icm.will, + pedited->icm.will + ) + ) { + icm.will = ColorManagementParams::Illuminant::DEFAULT; + if (pedited) { + pedited->icm.will = true; + } + } + if ( + !assignFromKeyfile( + keyFile, + "Color Management", + "Wprim", + pedited, + { + {"def", ColorManagementParams::Primaries::DEFAULT}, + {"srgb", ColorManagementParams::Primaries::SRGB}, + {"adob", ColorManagementParams::Primaries::ADOBE_RGB}, + {"prop", ColorManagementParams::Primaries::PRO_PHOTO}, + {"rec", ColorManagementParams::Primaries::REC2020}, + {"aces", ColorManagementParams::Primaries::ACES_P1}, + {"wid", ColorManagementParams::Primaries::WIDE_GAMUT}, + {"ac0", ColorManagementParams::Primaries::ACES_P0}, + {"bru", ColorManagementParams::Primaries::BRUCE_RGB}, + {"bet", ColorManagementParams::Primaries::BETA_RGB}, + {"bst", ColorManagementParams::Primaries::BEST_RGB}, + {"cus", ColorManagementParams::Primaries::CUSTOM}, + {"cusgr", ColorManagementParams::Primaries::CUSTOM_GRID} + }, + icm.wprim, + pedited->icm.wprim + ) + ) { + icm.wprim = ColorManagementParams::Primaries::DEFAULT; + if (pedited) { + pedited->icm.wprim = true; + } + } assignFromKeyfile(keyFile, "Color Management", "WorkingTRCGamma", pedited, icm.workingTRCGamma, pedited->icm.workingTRCGamma); assignFromKeyfile(keyFile, "Color Management", "WorkingTRCSlope", pedited, icm.workingTRCSlope, pedited->icm.workingTRCSlope); + assignFromKeyfile(keyFile, "Color Management", "Redx", pedited, icm.redx, pedited->icm.redx); + assignFromKeyfile(keyFile, "Color Management", "Redy", pedited, icm.redy, pedited->icm.redy); + assignFromKeyfile(keyFile, "Color Management", "Grex", pedited, icm.grex, pedited->icm.grex); + assignFromKeyfile(keyFile, "Color Management", "Grey", pedited, icm.grey, pedited->icm.grey); + assignFromKeyfile(keyFile, "Color Management", "Blux", pedited, icm.blux, pedited->icm.blux); + assignFromKeyfile(keyFile, "Color Management", "Bluy", pedited, icm.bluy, pedited->icm.bluy); + assignFromKeyfile(keyFile, "Color Management", "Preser", pedited, icm.preser, pedited->icm.preser); + assignFromKeyfile(keyFile, "Color Management", "Fbw", pedited, icm.fbw, pedited->icm.fbw); + assignFromKeyfile(keyFile, "Color Management", "LabGridcieALow", pedited, icm.labgridcieALow, pedited->icm.labgridcieALow); + assignFromKeyfile(keyFile, "Color Management", "LabGridcieBLow", pedited, icm.labgridcieBLow, pedited->icm.labgridcieBLow); + assignFromKeyfile(keyFile, "Color Management", "LabGridcieAHigh", pedited, icm.labgridcieAHigh, pedited->icm.labgridcieAHigh); + assignFromKeyfile(keyFile, "Color Management", "LabGridcieBHigh", pedited, icm.labgridcieBHigh, pedited->icm.labgridcieBHigh); + assignFromKeyfile(keyFile, "Color Management", "LabGridcieGx", pedited, icm.labgridcieGx, pedited->icm.labgridcieGx); + assignFromKeyfile(keyFile, "Color Management", "LabGridcieGy", pedited, icm.labgridcieGy, pedited->icm.labgridcieGy); + assignFromKeyfile(keyFile, "Color Management", "LabGridcieWx", pedited, icm.labgridcieWx, pedited->icm.labgridcieWx); + assignFromKeyfile(keyFile, "Color Management", "LabGridcieWy", pedited, icm.labgridcieWy, pedited->icm.labgridcieWy); + if (keyFile.has_key("Color Management", "aIntent")) { + Glib::ustring intent = keyFile.get_string("Color Management", "aIntent"); + + if (intent == "Perceptual") { + icm.aRendIntent = RI_PERCEPTUAL; + } else if (intent == "Relative") { + icm.aRendIntent = RI_RELATIVE; + } else if (intent == "Saturation") { + icm.aRendIntent = RI_SATURATION; + } else if (intent == "Absolute") { + icm.aRendIntent = RI_ABSOLUTE; + } + + if (pedited) { + pedited->icm.aRendIntent = true; + } + } + assignFromKeyfile(keyFile, "Color Management", "OutputProfile", pedited, icm.outputProfile, pedited->icm.outputProfile); if (ppVersion < 341) { if (icm.outputProfile == "RT_Medium_gsRGB") { diff --git a/rtengine/procparams.h b/rtengine/procparams.h index ef14a6e05..f7ca3e0f6 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1701,6 +1701,46 @@ struct ResizeParams { * Parameters of the color spaces used during the processing */ struct ColorManagementParams { + enum class WorkingTrc { + NONE, + CUSTOM, + BT709, + SRGB, + GAMMA_2_2, + GAMMA_1_8, + LINEAR + }; + + enum class Illuminant { + DEFAULT, + D41, + D50, + D55, + D60, + D65, + D80, + D120, + STDA, + TUNGSTEN_2000K, + TUNGSTEN_1500K + }; + + enum class Primaries { + DEFAULT, + SRGB, + ADOBE_RGB, + PRO_PHOTO, + REC2020, + ACES_P1, + WIDE_GAMUT, + ACES_P0, + BRUCE_RGB, + BETA_RGB, + BEST_RGB, + CUSTOM, + CUSTOM_GRID + }; + Glib::ustring inputProfile; bool toneCurve; bool applyLookTable; @@ -1709,9 +1749,28 @@ struct ColorManagementParams { int dcpIlluminant; Glib::ustring workingProfile; - Glib::ustring workingTRC; + WorkingTrc workingTRC; + Illuminant will; + Primaries wprim; double workingTRCGamma; double workingTRCSlope; + double redx; + double redy; + double grex; + double grey; + double blux; + double bluy; + double preser; + bool fbw; + double labgridcieALow; + double labgridcieBLow; + double labgridcieAHigh; + double labgridcieBHigh; + double labgridcieGx; + double labgridcieGy; + double labgridcieWx; + double labgridcieWy; + RenderingIntent aRendIntent; Glib::ustring outputProfile; RenderingIntent outputIntent; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 7ae919e0a..6c4bfd8f9 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1325,7 +1325,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le if (ri->zeroIsBad()) { // mark all pixels with value zero as bad, has to be called before FF and DF. dcraw sets this flag only for some cameras (mainly Panasonic and Leica) bitmapBads.reset(new PixelsMap(W, H)); - totBP = findZeroPixels(*(bitmapBads.get())); + totBP = findZeroPixels(*bitmapBads); if (settings->verbose) { printf("%d pixels with value zero marked as bad pixels\n", totBP); @@ -1469,7 +1469,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le bitmapBads.reset(new PixelsMap(W, H)); } - int nFound = findHotDeadPixels(*(bitmapBads.get()), raw.hotdeadpix_thresh, raw.hotPixelFilter, raw.deadPixelFilter); + int nFound = findHotDeadPixels(*bitmapBads, raw.hotdeadpix_thresh, raw.hotPixelFilter, raw.deadPixelFilter); totBP += nFound; if (settings->verbose && nFound > 0) { @@ -1484,7 +1484,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le bitmapBads.reset(new PixelsMap(W, H)); } - int n = f.mark(rawData, *(bitmapBads.get())); + int n = f.mark(rawData, *bitmapBads); totBP += n; if (n > 0) { @@ -1548,15 +1548,15 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le if (ri->getSensorType() == ST_BAYER) { if (numFrames == 4) { for (int i = 0; i < 4; ++i) { - interpolateBadPixelsBayer(*(bitmapBads.get()), *rawDataFrames[i]); + interpolateBadPixelsBayer(*bitmapBads, *rawDataFrames[i]); } } else { - interpolateBadPixelsBayer(*(bitmapBads.get()), rawData); + interpolateBadPixelsBayer(*bitmapBads, rawData); } } else if (ri->getSensorType() == ST_FUJI_XTRANS) { - interpolateBadPixelsXtrans(*(bitmapBads.get())); + interpolateBadPixelsXtrans(*bitmapBads); } else { - interpolateBadPixelsNColours(*(bitmapBads.get()), ri->get_colors()); + interpolateBadPixelsNColours(*bitmapBads, ri->get_colors()); } } diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 225cef180..451164b8c 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -200,7 +200,8 @@ int refreshmap[rtengine::NUMOFEVENTS] = { LUMINANCECURVE, // EvLLCCurve LUMINANCECURVE, // EvLLCredsk ALLNORAW, // EvDPDNLdetail - ALLNORAW, // EvCATEnabled + //ALLNORAW, // EvCATEnabled + LUMINANCECURVE, // EvCATEnabled LUMINANCECURVE, // EvCATDegree LUMINANCECURVE, // EvCATMethodsur LUMINANCECURVE, // EvCATAdapscen diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index c4ffb91f7..142f2751e 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -449,6 +449,15 @@ public: virtual void autoColorTonChanged(int bwct, int satthres, int satprot) = 0; }; +class AutoprimListener +{ +public: + virtual ~AutoprimListener() = default; + virtual void primChanged(float rx, float ry, float bx, float by, float gx, float gy) = 0; + virtual void iprimChanged(float r_x, float r_y, float b_x, float b_y, float g_x, float g_y, float w_x, float w_y) = 0; +}; + + class AutoBWListener { public: @@ -621,6 +630,8 @@ public: virtual void setAutoBWListener (AutoBWListener* l) = 0; virtual void setAutoWBListener (AutoWBListener* l) = 0; virtual void setAutoColorTonListener (AutoColorTonListener* l) = 0; + virtual void setAutoprimListener (AutoprimListener* l) = 0; + virtual void setAutoChromaListener (AutoChromaListener* l) = 0; virtual void setRetinexListener (RetinexListener* l) = 0; virtual void setWaveletListener (WaveletListener* l) = 0; diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 1cc45aef6..8dc998862 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -1455,12 +1455,15 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT ipf.labColorCorrectionRegions(labView); + + if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || !params.colorappearance.enabled) { ipf.EPDToneMap (labView, 5, 6); } ipf.softLight(labView, params.softlight); + if (params.colorappearance.enabled) { CurveFactory::curveLightBrightColor ( params.colorappearance.curve, @@ -1508,7 +1511,8 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT ipf.ciecam_02float (cieView, adap, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, sk, execsharp, d, dj, yb, rtt); delete cieView; } - + + // color processing //ipf.colorCurve (labView, labView); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index a1c1e6d44..9a0d3b90b 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -16,27 +16,31 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ + +#include +#include + #include "cieimage.h" -#include "dcp.h" -#include "imagefloat.h" -#include "labimage.h" -#include "rtengine.h" +#include "clutstore.h" +#include "color.h" #include "colortemp.h" +#include "curves.h" +#include "dcp.h" +#include "guidedfilter.h" +#include "iccstore.h" +#include "imagefloat.h" #include "imagesource.h" #include "improcfun.h" -#include "curves.h" -#include "iccstore.h" -#include "clutstore.h" +#include "labimage.h" +#include "mytime.h" #include "processingjob.h" #include "procparams.h" -#include -#include -#include "../rtgui/options.h" #include "rawimagesource.h" +#include "rtengine.h" +#include "utils.h" + #include "../rtgui/multilangmgr.h" -#include "mytime.h" -#include "guidedfilter.h" -#include "color.h" +#include "../rtgui/options.h" #undef THREAD_PRIORITY_NORMAL @@ -924,21 +928,6 @@ private: ipf.lab2rgb(labcbdl, *baseImg, params.icm.workingProfile); } -/* //gamma TRC working - if (params.icm.workingTRC == "Custom") { //exec TRC IN free - const Glib::ustring profile = params.icm.workingProfile; - - if (profile == "sRGB" || profile == "Adobe RGB" || profile == "ProPhoto" || profile == "WideGamut" || profile == "BruceRGB" || profile == "Beta RGB" || profile == "BestRGB" || profile == "Rec2020" || profile == "ACESp0" || profile == "ACESp1") { - const int cw = baseImg->getWidth(); - const int ch = baseImg->getHeight(); - cmsHTRANSFORM dummyTransForm = nullptr; - // put gamma TRC to 1 - ipf.workingtrc(baseImg, baseImg, cw, ch, -5, params.icm.workingProfile, 2.4, 12.92310, dummyTransForm, true, false, false); - //adjust TRC - ipf.workingtrc(baseImg, baseImg, cw, ch, 5, params.icm.workingProfile, params.icm.workingTRCGamma, params.icm.workingTRCSlope, dummyTransForm, false, true, false); - } - } -*/ // RGB processing labView = new LabImage(fw, fh); @@ -1371,6 +1360,7 @@ private: ipf.chromiLuminanceCurve(nullptr, 1, labView, labView, curve1, curve2, satcurve, lhskcurve, clcurve, lumacurve, utili, autili, butili, ccutili, cclutili, clcutili, dummy, dummy); + if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { ipf.EPDToneMap (labView, 0, 1); } @@ -1570,6 +1560,52 @@ private: ipf.softLight(labView, params.softlight); + + if (params.icm.workingTRC != ColorManagementParams::WorkingTrc::NONE) { + const int GW = labView->W; + const int GH = labView->H; + std::unique_ptr provis; + const float pres = 0.01f * params.icm.preser; + if (pres > 0.f && params.icm.wprim != ColorManagementParams::Primaries::DEFAULT) { + provis.reset(new LabImage(GW, GH)); + provis->CopyFrom(labView); + } + + const std::unique_ptr tmpImage1(new Imagefloat(GW, GH)); + + ipf.lab2rgb(*labView, *tmpImage1, params.icm.workingProfile); + + const float gamtone = params.icm.workingTRCGamma; + const float slotone = params.icm.workingTRCSlope; + + int illum = toUnderlying(params.icm.will); + const int prim = toUnderlying(params.icm.wprim); + + Glib::ustring prof = params.icm.workingProfile; + + cmsHTRANSFORM dummy = nullptr; + int ill = 0; + ipf.workingtrc(tmpImage1.get(), tmpImage1.get(), GW, GH, -5, prof, 2.4, 12.92310, ill, 0, dummy, true, false, false); + ipf.workingtrc(tmpImage1.get(), tmpImage1.get(), GW, GH, 5, prof, gamtone, slotone, illum, prim, dummy, false, true, true); + + ipf.rgb2lab(*tmpImage1, *labView, params.icm.workingProfile); + // labView and provis + if(provis) { + ipf.preserv(labView, provis.get(), GW, GH); + } + if(params.icm.fbw) { +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int x = 0; x < GH; x++) + for (int y = 0; y < GW; y++) { + labView->a[x][y] = 0.f; + labView->b[x][y] = 0.f; + } + } + + } + //Colorappearance and tone-mapping associated int f_w = 1, f_h = 1; diff --git a/rtgui/colortoning.cc b/rtgui/colortoning.cc index 51ca3a4bc..0140c5b62 100644 --- a/rtgui/colortoning.cc +++ b/rtgui/colortoning.cc @@ -646,7 +646,7 @@ void ColorToning::read (const ProcParams* pp, const ParamsEdited* pedited) lastLumamode = pp->colorToning.lumamode; - labgrid->setParams(pp->colorToning.labgridALow / ColorToningParams::LABGRID_CORR_MAX, pp->colorToning.labgridBLow / ColorToningParams::LABGRID_CORR_MAX, pp->colorToning.labgridAHigh / ColorToningParams::LABGRID_CORR_MAX, pp->colorToning.labgridBHigh / ColorToningParams::LABGRID_CORR_MAX, false); + labgrid->setParams(pp->colorToning.labgridALow / ColorToningParams::LABGRID_CORR_MAX, pp->colorToning.labgridBLow / ColorToningParams::LABGRID_CORR_MAX, pp->colorToning.labgridAHigh / ColorToningParams::LABGRID_CORR_MAX, pp->colorToning.labgridBHigh / ColorToningParams::LABGRID_CORR_MAX, 0, 0, 0, 0,false); if (pedited && !pedited->colorToning.method) { method->set_active (7); @@ -715,8 +715,10 @@ void ColorToning::write (ProcParams* pp, ParamsEdited* pedited) pp->colorToning.satProtectionThreshold = satProtectionThreshold->getIntValue(); pp->colorToning.saturatedOpacity = saturatedOpacity->getIntValue(); pp->colorToning.strength = strength->getIntValue(); - - labgrid->getParams(pp->colorToning.labgridALow, pp->colorToning.labgridBLow, pp->colorToning.labgridAHigh, pp->colorToning.labgridBHigh); + double zerox = 0.; + double zeroy = 0.; + + labgrid->getParams(pp->colorToning.labgridALow, pp->colorToning.labgridBLow, pp->colorToning.labgridAHigh, pp->colorToning.labgridBHigh, zerox, zeroy, zerox, zeroy); pp->colorToning.labgridALow *= ColorToningParams::LABGRID_CORR_MAX; pp->colorToning.labgridAHigh *= ColorToningParams::LABGRID_CORR_MAX; pp->colorToning.labgridBLow *= ColorToningParams::LABGRID_CORR_MAX; @@ -832,7 +834,7 @@ void ColorToning::setDefaults (const ProcParams* defParams, const ParamsEdited* hlColSat->setDefault (defParams->colorToning.hlColSat); shadowsColSat->setDefault (defParams->colorToning.shadowsColSat); strength->setDefault (defParams->colorToning.strength); - labgrid->setDefault(defParams->colorToning.labgridALow / ColorToningParams::LABGRID_CORR_MAX, defParams->colorToning.labgridBLow / ColorToningParams::LABGRID_CORR_MAX, defParams->colorToning.labgridAHigh / ColorToningParams::LABGRID_CORR_MAX, defParams->colorToning.labgridBHigh / ColorToningParams::LABGRID_CORR_MAX); + labgrid->setDefault(defParams->colorToning.labgridALow / ColorToningParams::LABGRID_CORR_MAX, defParams->colorToning.labgridBLow / ColorToningParams::LABGRID_CORR_MAX, defParams->colorToning.labgridAHigh / ColorToningParams::LABGRID_CORR_MAX, defParams->colorToning.labgridBHigh / ColorToningParams::LABGRID_CORR_MAX, 0, 0, 0, 0); if (pedited) { @@ -1430,7 +1432,9 @@ void ColorToning::labRegionGet(int idx) auto &r = labRegionData[idx]; double la, lb; - labRegionAB->getParams(la, lb, r.a, r.b); + double zerox = 0.; + double zeroy = 0.; + labRegionAB->getParams(la, lb, r.a, r.b, zerox, zeroy, zerox, zeroy); r.saturation = labRegionSaturation->getValue(); r.slope = labRegionSlope->getValue(); r.offset = labRegionOffset->getValue(); @@ -1566,9 +1570,9 @@ void ColorToning::labRegionShow(int idx, bool list_only) disableListener(); } rtengine::procparams::ColorToningParams::LabCorrectionRegion dflt; - auto &r = labRegionData[idx]; + auto &r = labRegionData[idx]; if (!list_only) { - labRegionAB->setParams(0, 0, r.a, r.b, false); + labRegionAB->setParams(0, 0, r.a, r.b,0, 0, 0, 0, false); labRegionSaturation->setValue(r.saturation); labRegionSlope->setValue(r.slope); labRegionOffset->setValue(r.offset); diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index e0fd7cd96..6e3b69904 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -22,6 +22,7 @@ #include "eventmapper.h" #include "guiutils.h" +#include "labgrid.h" #include "options.h" #include "pathutils.h" #include "rtimage.h" @@ -29,6 +30,7 @@ #include "../rtengine/dcp.h" #include "../rtengine/iccstore.h" #include "../rtengine/procparams.h" +#include "../rtengine/utils.h" using namespace rtengine; using namespace rtengine::procparams; @@ -45,15 +47,27 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha EvICMpgrey = m->newEvent(GAMMA, "HISTORY_MSG_ICMPGREY"); EvICMpblux = m->newEvent(GAMMA, "HISTORY_MSG_ICMPBLUX"); EvICMpbluy = m->newEvent(GAMMA, "HISTORY_MSG_ICMPBLUY"); - EvICMgamm = m->newEvent(AUTOEXP, "HISTORY_MSG_ICM_WORKING_GAMMA"); - EvICMslop = m->newEvent(AUTOEXP, "HISTORY_MSG_ICM_WORKING_SLOPE"); - EvICMtrcinMethod = m->newEvent(AUTOEXP, "HISTORY_MSG_ICM_WORKING_TRC_METHOD"); - + EvICMgamm = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_WORKING_GAMMA"); + EvICMslop = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_WORKING_SLOPE"); + EvICMtrcinMethod = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_WORKING_TRC_METHOD"); + EvICMwillMethod = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_WORKING_ILLUM_METHOD"); + EvICMwprimMethod = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_WORKING_PRIM_METHOD"); + EvICMredx = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_REDX"); + EvICMredy = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_REDY"); + EvICMgrex = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_GREX"); + EvICMgrey = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_GREY"); + EvICMblux = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_BLUX"); + EvICMbluy = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_BLUY"); + EvaIntent = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_AINTENT"); + EvICMpreser = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_PRESER"); + EvICMLabGridciexy = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICL_LABGRIDCIEXY"); + EvICMfbw = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_FBW"); isBatchMode = lastToneCurve = lastApplyLookTable = lastApplyBaselineExposureOffset = lastApplyHueSatMap = false; ipDialog = Gtk::manage(new MyFileChooserButton(M("TP_ICM_INPUTDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); ipDialog->set_tooltip_text(M("TP_ICM_INPUTCUSTOM_TOOLTIP")); bindCurrentFolder(*ipDialog, options.lastIccDir); + labgridcie = Gtk::manage(new LabGrid(EvICMLabGridciexy, M("TP_ICM_LABGRID_CIEXY"), true, true)); // ------------------------------- Input profile @@ -184,44 +198,184 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha wProfNames->set_active(0); - // wFrame->add(*wVBox); + wFrame->add(*wProfVBox); //-----------------gamma TRC working + Gtk::Frame *trcFrame = Gtk::manage(new Gtk::Frame(M("TP_ICM_TRCFRAME"))); + trcFrame->set_label_align(0.025, 0.5); + Gtk::Box *trcProfVBox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); + trcFrame->set_tooltip_text(M("TP_ICM_TRCFRAME_TOOLTIP")); - wTRCHBox = Gtk::manage(new Gtk::Box()); + wTRCBox = Gtk::manage(new Gtk::Box()); - Gtk::Label* wtrclab = Gtk::manage(new Gtk::Label(M("TP_ICM_WORKING_TRC"))); - - wTRCHBox->pack_start(*wtrclab, Gtk::PACK_SHRINK); wTRC = Gtk::manage(new MyComboBoxText()); - wTRCHBox->pack_start(*wTRC, Gtk::PACK_EXPAND_WIDGET); - // wProfVBox->pack_start(*wTRCHBox, Gtk::PACK_EXPAND_WIDGET); + wTRCBox->pack_start(*wTRC, Gtk::PACK_EXPAND_WIDGET); + trcProfVBox->pack_start(*wTRCBox, Gtk::PACK_EXPAND_WIDGET); wTRC->append(M("TP_ICM_WORKING_TRC_NONE")); wTRC->append(M("TP_ICM_WORKING_TRC_CUSTOM")); + wTRC->append(M("TP_ICM_WORKING_TRC_BT709")); + wTRC->append(M("TP_ICM_WORKING_TRC_SRGB")); + wTRC->append(M("TP_ICM_WORKING_TRC_22")); + wTRC->append(M("TP_ICM_WORKING_TRC_18")); + wTRC->append(M("TP_ICM_WORKING_TRC_LIN")); -// wTRC->set_active(0); -// wTRC->set_tooltip_text(M("TP_ICM_WORKING_TRC_TOOLTIP")); + wTRC->set_active(0); + wTRC->set_tooltip_text(M("TP_ICM_TRC_TOOLTIP")); + + wFrame->set_tooltip_text(M("TP_ICM_WORKING_TRC_TOOLTIP")); - wGamma = Gtk::manage(new Adjuster(M("TP_ICM_WORKING_TRC_GAMMA"), 0.40, 15.0, 0.001, 2.4)); - wSlope = Gtk::manage(new Adjuster(M("TP_ICM_WORKING_TRC_SLOPE"), 0., 150., 0.01, 12.92310)); -// wProfVBox->pack_start(*wGamma, Gtk::PACK_SHRINK); -// wGamma->show(); + wGamma = Gtk::manage(new Adjuster(M("TP_ICM_WORKING_TRC_GAMMA"), 0.40, 15.0, 0.001, 2.222)); + wSlope = Gtk::manage(new Adjuster(M("TP_ICM_WORKING_TRC_SLOPE"), 0., 300., 0.01, 4.5)); + trcProfVBox->pack_start(*wGamma, Gtk::PACK_SHRINK); + wGamma->show(); -// wProfVBox->pack_start(*wSlope, Gtk::PACK_SHRINK); -// wSlope->show(); + trcProfVBox->pack_start(*wSlope, Gtk::PACK_SHRINK); + wSlope->show(); + willuBox = Gtk::manage(new Gtk::Box()); + willulab = Gtk::manage(new Gtk::Label(M("TP_ICM_WORKING_ILLU") + ":")); + + willuBox->pack_start(*willulab, Gtk::PACK_SHRINK); + will = Gtk::manage(new MyComboBoxText()); + willuBox->pack_start(*will, Gtk::PACK_EXPAND_WIDGET); + trcProfVBox->pack_start(*willuBox, Gtk::PACK_EXPAND_WIDGET); + will->append(M("TP_ICM_WORKING_ILLU_NONE")); + will->append(M("TP_ICM_WORKING_ILLU_D41")); + will->append(M("TP_ICM_WORKING_ILLU_D50")); + will->append(M("TP_ICM_WORKING_ILLU_D55")); + will->append(M("TP_ICM_WORKING_ILLU_D60")); + will->append(M("TP_ICM_WORKING_ILLU_D65")); + will->append(M("TP_ICM_WORKING_ILLU_D80")); + will->append(M("TP_ICM_WORKING_ILLU_D120")); + will->append(M("TP_ICM_WORKING_ILLU_STDA")); + will->append(M("TP_ICM_WORKING_ILLU_2000")); + will->append(M("TP_ICM_WORKING_ILLU_1500")); + will->set_active(0); + will->set_tooltip_text(M("TP_ICM_ILLUMPRIM_TOOLTIP")); + + + wprimBox = Gtk::manage(new Gtk::Box()); + wprimlab = Gtk::manage(new Gtk::Label(M("TP_ICM_WORKING_PRIM") + ":")); + + wprimBox->pack_start(*wprimlab, Gtk::PACK_SHRINK); + wprim = Gtk::manage(new MyComboBoxText()); + wprimBox->pack_start(*wprim, Gtk::PACK_EXPAND_WIDGET); + fbw = Gtk::manage(new Gtk::CheckButton((M("TP_ICM_FBW")))); + fbw->set_active(true); + trcProfVBox->pack_start(*wprimBox, Gtk::PACK_EXPAND_WIDGET); + trcProfVBox->pack_start(*fbw, Gtk::PACK_EXPAND_WIDGET); + + wprim->append(M("TP_ICM_WORKING_PRIM_NONE")); + wprim->append(M("TP_ICM_WORKING_PRIM_SRGB")); + wprim->append(M("TP_ICM_WORKING_PRIM_ADOB")); + wprim->append(M("TP_ICM_WORKING_PRIM_PROP")); + wprim->append(M("TP_ICM_WORKING_PRIM_REC")); + wprim->append(M("TP_ICM_WORKING_PRIM_ACE")); + wprim->append(M("TP_ICM_WORKING_PRIM_WID")); + wprim->append(M("TP_ICM_WORKING_PRIM_AC0")); + wprim->append(M("TP_ICM_WORKING_PRIM_BRU")); + wprim->append(M("TP_ICM_WORKING_PRIM_BET")); + wprim->append(M("TP_ICM_WORKING_PRIM_BST")); + wprim->append(M("TP_ICM_WORKING_PRIM_CUS")); + wprim->append(M("TP_ICM_WORKING_PRIM_CUSGR")); + wprim->set_active(0); + + wprim->set_tooltip_text(M("TP_ICM_PRIMILLUM_TOOLTIP")); + + + redx = Gtk::manage(new Adjuster(M("TC_PRIM_REDX"), 0.41, 1.0, 0.0001, 0.6400)); + setExpandAlignProperties(redx, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + redy = Gtk::manage(new Adjuster(M("TC_PRIM_REDY"), 0.0, 0.70, 0.0001, 0.3300)); + setExpandAlignProperties(redy, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + grex = Gtk::manage(new Adjuster(M("TC_PRIM_GREX"), -0.1, 0.4, 0.0001, 0.2100)); + setExpandAlignProperties(grex, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + grey = Gtk::manage(new Adjuster(M("TC_PRIM_GREY"), 0.50, 1.0, 0.0001, 0.7100)); + setExpandAlignProperties(grey, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + blux = Gtk::manage(new Adjuster(M("TC_PRIM_BLUX"), -0.1, 0.4, 0.0001, 0.1500)); + setExpandAlignProperties(blux, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + bluy = Gtk::manage(new Adjuster(M("TC_PRIM_BLUY"), -0.1, 0.5, 0.0001, 0.060)); + setExpandAlignProperties(bluy, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + + redx->set_tooltip_text(M("TP_ICM_PRIMRED_TOOLTIP")); + grex->set_tooltip_text(M("TP_ICM_PRIMGRE_TOOLTIP")); + blux->set_tooltip_text(M("TP_ICM_PRIMBLU_TOOLTIP")); + blr = Gtk::manage(new Gtk::Label(M(" "))); + blg = Gtk::manage(new Gtk::Label(M(" "))); + blb = Gtk::manage(new Gtk::Label(M(" "))); + + redBox = Gtk::manage(new Gtk::Box()); + redBox->pack_start(*redx);//, Gtk::PACK_SHRINK); + redBox->pack_start(*blr, Gtk::PACK_SHRINK); + redBox->pack_start(*redy);//, Gtk::PACK_SHRINK); + redFrame = Gtk::manage(new Gtk::Frame(M("TP_ICM_REDFRAME"))); + redFrame->set_label_align(0.025, 0.5); + Gtk::Box *redVBox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); + redVBox->pack_start(*redBox, Gtk::PACK_EXPAND_WIDGET); + redFrame->set_tooltip_text(M("TP_ICM_WORKING_PRIMFRAME_TOOLTIP")); + + greBox = Gtk::manage(new Gtk::Box()); + greBox->pack_start(*grex);//, Gtk::PACK_SHRINK, 2); + greBox->pack_start(*blg, Gtk::PACK_SHRINK); + greBox->pack_start(*grey);//, Gtk::PACK_SHRINK, 2); + redVBox->pack_start(*greBox, Gtk::PACK_EXPAND_WIDGET); + Gtk::Separator* const separator1 = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)); + Gtk::Separator* const separator2 = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)); + + bluBox = Gtk::manage(new Gtk::Box()); + bluBox->pack_start(*blux);//, Gtk::PACK_SHRINK); + bluBox->pack_start(*blb, Gtk::PACK_SHRINK); + bluBox->pack_start(*bluy);//, Gtk::PACK_SHRINK); + redVBox->pack_start(*bluBox, Gtk::PACK_EXPAND_WIDGET); + preser = Gtk::manage(new Adjuster(M("TP_ICM_WORKING_PRESER"), 0., 100., 0.5, 0.)); + preser->setAdjusterListener(this); + + preBox = Gtk::manage(new Gtk::Box()); + preBox->pack_start(*preser, Gtk::PACK_SHRINK); + redVBox->pack_start(*separator1, Gtk::PACK_SHRINK); + redVBox->pack_start(*preBox, Gtk::PACK_EXPAND_WIDGET); + redVBox->pack_start(*separator2, Gtk::PACK_SHRINK); + + cielab = Gtk::manage(new Gtk::Label(M("TP_ICM_WORKING_CIEDIAG") + ":")); + + redVBox->pack_start(*cielab, Gtk::PACK_SHRINK); + + redVBox->pack_start(*labgridcie, Gtk::PACK_EXPAND_WIDGET, 4); + + redFrame->add(*redVBox); wGamma->setAdjusterListener(this); + wSlope->setLogScale(16, 0); wSlope->setAdjusterListener(this); + redx->setAdjusterListener(this); + redy->setAdjusterListener(this); + grex->setAdjusterListener(this); + grey->setAdjusterListener(this); + blux->setAdjusterListener(this); + bluy->setAdjusterListener(this); wGamma->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); wSlope->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); - wFrame->add(*wProfVBox); + // Rendering intent + riaHBox = Gtk::manage(new Gtk::Box()); + Gtk::Label* abIntentLbl = Gtk::manage(new Gtk::Label(M("TP_ICM_PROFILEINTENT"))); + riaHBox->pack_start(*abIntentLbl, Gtk::PACK_SHRINK); + aRendIntent.reset(new PopUpButton()); + aRendIntent->addEntry("intent-perceptual.png", M("PREFERENCES_INTENT_PERCEPTUAL")); + aRendIntent->addEntry("intent-relative.png", M("PREFERENCES_INTENT_RELATIVE")); + aRendIntent->addEntry("intent-saturation.png", M("PREFERENCES_INTENT_SATURATION")); + aRendIntent->addEntry("intent-absolute.png", M("PREFERENCES_INTENT_ABSOLUTE")); + aRendIntent->setSelected(1); + aRendIntent->show(); + riaHBox->pack_start(*aRendIntent->buttonGroup, Gtk::PACK_EXPAND_PADDING); + + trcFrame->add(*trcProfVBox); pack_start(*wFrame, Gtk::PACK_EXPAND_WIDGET); + pack_start(*trcFrame, Gtk::PACK_EXPAND_WIDGET); + pack_start(*redFrame, Gtk::PACK_EXPAND_WIDGET); // ---------------------------- Output profile @@ -229,6 +383,7 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha Gtk::Frame *oFrame = Gtk::manage(new Gtk::Frame(M("TP_ICM_OUTPUTPROFILE"))); oFrame->set_label_align(0.025, 0.5); + oFrame->set_tooltip_text(M("TP_ICM_OUTPUTPROFILE_TOOLTIP")); Gtk::Box* oProfVBox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); @@ -303,9 +458,13 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha wprofnamesconn = wProfNames->signal_changed().connect(sigc::mem_fun(*this, &ICMPanel::wpChanged)); oprofnamesconn = oProfNames->signal_changed().connect(sigc::mem_fun(*this, &ICMPanel::opChanged)); orendintentconn = oRendIntent->signal_changed().connect(sigc::mem_fun(*this, &ICMPanel::oiChanged)); + arendintentconn = aRendIntent->signal_changed().connect(sigc::mem_fun(*this, &ICMPanel::aiChanged)); dcpillconn = dcpIll->signal_changed().connect(sigc::mem_fun(*this, &ICMPanel::dcpIlluminantChanged)); wtrcconn = wTRC->signal_changed().connect(sigc::mem_fun(*this, &ICMPanel::wtrcinChanged)); + willconn = will->signal_changed().connect(sigc::mem_fun(*this, &ICMPanel::willChanged)); + wprimconn = wprim->signal_changed().connect(sigc::mem_fun(*this, &ICMPanel::wprimChanged)); + fbwconn = fbw->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::fbwChanged)); obpcconn = obpc->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::oBPCChanged)); tcurveconn = ckbToneCurve->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::toneCurveChanged)); ltableconn = ckbApplyLookTable->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::applyLookTableChanged)); @@ -339,6 +498,13 @@ void ICMPanel::updateRenderingIntent(const Glib::ustring &profile) oRendIntent->setItemSensitivity(1, supportsRelative); oRendIntent->setItemSensitivity(2, supportsSaturation); oRendIntent->setItemSensitivity(3, supportsAbsolute); + + aRendIntent->set_sensitive(true); + aRendIntent->setItemSensitivity(0, supportsPerceptual); + aRendIntent->setItemSensitivity(1, supportsRelative); + aRendIntent->setItemSensitivity(2, supportsSaturation); + aRendIntent->setItemSensitivity(3, supportsAbsolute); + } else { oRendIntent->setItemSensitivity(0, true); oRendIntent->setItemSensitivity(1, true); @@ -346,9 +512,91 @@ void ICMPanel::updateRenderingIntent(const Glib::ustring &profile) oRendIntent->setItemSensitivity(3, true); oRendIntent->set_sensitive(false); oRendIntent->setSelected(1); + + aRendIntent->setItemSensitivity(0, true); + aRendIntent->setItemSensitivity(1, true); + aRendIntent->setItemSensitivity(2, true); + aRendIntent->setItemSensitivity(3, true); + aRendIntent->set_sensitive(false); + aRendIntent->setSelected(1); + } } +ICMPanel::~ICMPanel() +{ + idle_register.destroy(); +} + +void ICMPanel::primChanged (float rx, float ry, float bx, float by, float gx, float gy) +{ //update sliders R G B Ciexy + nextrx = rx; + nextry = ry; + nextbx = bx; + nextby = by; + nextgx = gx; + nextgy = gy; + + idle_register.add( + [this]() -> bool + { + disableListener(); + redx->setValue(nextrx); + redy->setValue(nextry); + blux->setValue(nextbx); + bluy->setValue(nextby); + grex->setValue(nextgx); + grey->setValue(nextgy); + + enableListener(); + return false; + } + ); +} + +void ICMPanel::iprimChanged (float r_x, float r_y, float b_x, float b_y, float g_x, float g_y, float w_x, float w_y) +{//update CIE xy graph + nextrx = r_x; + nextry = r_y; + nextbx = b_x; + nextby = b_y; + nextgx = g_x; + nextgy = g_y; + nextwx = w_x; + nextwy = w_y; + //convert xy datas in datas for labgrid areas + nextrx = 1.81818f * (nextrx + 0.1f) - 1.f; + nextry = 1.81818f * (nextry + 0.1f) - 1.f; + nextbx = 1.81818f * (nextbx + 0.1f) - 1.f; + nextby = 1.81818f * (nextby + 0.1f) - 1.f; + nextgx = 1.81818f * (nextgx + 0.1f) - 1.f; + nextgy = 1.81818f * (nextgy + 0.1f) - 1.f; + nextwx = 1.81818f * (nextwx + 0.1f) - 1.f; + nextwy = 1.81818f * (nextwy + 0.1f) - 1.f; + + idle_register.add( + [this]() -> bool + { + disableListener(); + labgridcie->setParams(nextrx, nextry, nextbx, nextby, nextgx, nextgy, nextwx, nextwy, false); + enableListener(); + return false; + } + ); +} + + +void ICMPanel::setEditProvider(EditDataProvider *provider) +{ + //in case of +} + +void ICMPanel::setListener(ToolPanelListener *tpl) +{//enable listener Toolpanel and Labgridcie + ToolPanel::setListener(tpl); + labgridcie->setListener(tpl); +} + void ICMPanel::updateDCP(int dcpIlluminant, Glib::ustring dcp_name) { ConnectionBlocker dcpillconn_(dcpillconn); @@ -481,6 +729,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) disableListener(); ConnectionBlocker obpcconn_(obpcconn); + ConnectionBlocker fbwconn_(fbwconn); ConnectionBlocker ipc_(ipc); ConnectionBlocker tcurveconn_(tcurveconn); ConnectionBlocker ltableconn_(ltableconn); @@ -489,7 +738,11 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) ConnectionBlocker wprofnamesconn_(wprofnamesconn); ConnectionBlocker oprofnamesconn_(oprofnamesconn); ConnectionBlocker orendintentconn_(orendintentconn); + ConnectionBlocker arendintentconn_(arendintentconn); ConnectionBlocker dcpillconn_(dcpillconn); + ConnectionBlocker wtrcconn_(wtrcconn); + ConnectionBlocker willconn_(willconn); + ConnectionBlocker wprimconn_(wprimconn); if (pp->icm.inputProfile.substr(0, 5) != "file:" && !ipDialog->get_filename().empty()) { ipDialog->set_filename(pp->icm.inputProfile); @@ -525,13 +778,15 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) wProfNames->set_active_text(pp->icm.workingProfile); - if (pp->icm.workingTRC == "none") { - wTRC->set_active(0); - } else if (pp->icm.workingTRC == "Custom") { - wTRC->set_active(1); - } + wTRC->set_active(rtengine::toUnderlying(pp->icm.workingTRC)); + + will->set_active(rtengine::toUnderlying(pp->icm.will)); + + wprim->set_active(rtengine::toUnderlying(pp->icm.wprim)); wtrcinChanged(); + willChanged(); + wprimChanged(); if (pp->icm.outputProfile == ColorManagementParams::NoICMString) { oProfNames->set_active_text(M("TP_ICM_NOICM")); @@ -544,8 +799,10 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) } oRendIntent->setSelected(pp->icm.outputIntent); + aRendIntent->setSelected(pp->icm.aRendIntent); obpc->set_active(pp->icm.outputBPC); + fbw->set_active(pp->icm.fbw); ckbToneCurve->set_active(pp->icm.toneCurve); lastToneCurve = pp->icm.toneCurve; ckbApplyLookTable->set_active(pp->icm.applyLookTable); @@ -557,10 +814,19 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) wGamma->setValue(pp->icm.workingTRCGamma); wSlope->setValue(pp->icm.workingTRCSlope); + redx->setValue(pp->icm.redx); + redy->setValue(pp->icm.redy); + grex->setValue(pp->icm.grex); + grey->setValue(pp->icm.grey); + blux->setValue(pp->icm.blux); + bluy->setValue(pp->icm.bluy); + preser->setValue(pp->icm.preser); + labgridcie->setParams(pp->icm.labgridcieALow, pp->icm.labgridcieBLow, pp->icm.labgridcieAHigh, pp->icm.labgridcieBHigh, pp->icm.labgridcieGx, pp->icm.labgridcieGy, pp->icm.labgridcieWx, pp->icm.labgridcieWy, false); if (pedited) { iunchanged->set_active(!pedited->icm.inputProfile); obpc->set_inconsistent(!pedited->icm.outputBPC); + fbw->set_inconsistent(!pedited->icm.fbw); ckbToneCurve->set_inconsistent(!pedited->icm.toneCurve); ckbApplyLookTable->set_inconsistent(!pedited->icm.applyLookTable); ckbApplyBaselineExposureOffset->set_inconsistent(!pedited->icm.applyBaselineExposureOffset); @@ -578,6 +844,10 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) oRendIntent->setSelected(4); } + if (!pedited->icm.aRendIntent) { + aRendIntent->setSelected(4); + } + if (!pedited->icm.dcpIlluminant) { dcpIll->set_active_text(M("GENERAL_UNCHANGED")); } @@ -586,11 +856,206 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) wTRC->set_active_text(M("GENERAL_UNCHANGED")); } + if (!pedited->icm.will) { + will->set_active_text(M("GENERAL_UNCHANGED")); + } + + if (!pedited->icm.wprim) { + wprim->set_active_text(M("GENERAL_UNCHANGED")); + } + labgridcie->setEdited(pedited->icm.labgridcieALow || pedited->icm.labgridcieBLow || pedited->icm.labgridcieAHigh || pedited->icm.labgridcieBHigh || pedited->icm.labgridcieGx || pedited->icm.labgridcieGy || pedited->icm.labgridcieWx || pedited->icm.labgridcieWy); + wGamma->setEditedState(pedited->icm.workingTRCGamma ? Edited : UnEdited); wSlope->setEditedState(pedited->icm.workingTRCSlope ? Edited : UnEdited); + redx->setEditedState(pedited->icm.redx ? Edited : UnEdited); + redy->setEditedState(pedited->icm.redy ? Edited : UnEdited); + grex->setEditedState(pedited->icm.grex ? Edited : UnEdited); + grey->setEditedState(pedited->icm.grey ? Edited : UnEdited); + blux->setEditedState(pedited->icm.blux ? Edited : UnEdited); + bluy->setEditedState(pedited->icm.bluy ? Edited : UnEdited); + preser->setEditedState(pedited->icm.preser ? Edited : UnEdited); } + switch (ColorManagementParams::WorkingTrc(wTRC->get_active_row_number())) { + case ColorManagementParams::WorkingTrc::NONE: { + wSlope->set_sensitive(false); + wGamma->set_sensitive(false); + will->set_sensitive(false); + willulab->set_sensitive(false); + wprim->set_sensitive(false); + fbw->set_sensitive(false); + wprimlab->set_sensitive(false); + riaHBox->set_sensitive(false); + redFrame->hide(); + break; + } + + case ColorManagementParams::WorkingTrc::CUSTOM: { + will->set_sensitive(false); + willulab->set_sensitive(true); + wprim->set_sensitive(true); + fbw->set_sensitive(true); + wprimlab->set_sensitive(true); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { + redFrame->hide(); + } else { + redFrame->show(); + if ( + ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM + && ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM_GRID + ) { + will->set_sensitive(false); + redBox->set_sensitive(false); + greBox->set_sensitive(false); + bluBox->set_sensitive(false); + labgridcie->set_sensitive(false); + + } else { + will->set_sensitive(false); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::CUSTOM) { + will->set_sensitive(true); + } + redBox->set_sensitive(true); + greBox->set_sensitive(true); + bluBox->set_sensitive(true); + labgridcie->set_sensitive(true); + } + + } + riaHBox->set_sensitive(true); + + if (pp->icm.workingTRCGamma <= 1.) { + wGamma->set_sensitive(true); + wSlope->set_sensitive(false); + } else { + wGamma->set_sensitive(true); + wSlope->set_sensitive(true); + } + break; + } + + case ColorManagementParams::WorkingTrc::BT709: + wGamma->setValue(2.222); + wSlope->setValue(4.5); + will->set_sensitive(true); + willulab->set_sensitive(true); + wprim->set_sensitive(true); + fbw->set_sensitive(true); + wprimlab->set_sensitive(true); + wGamma->set_sensitive(false); + wSlope->set_sensitive(false); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { + redFrame->hide(); + } else { + redFrame->show(); + } + riaHBox->set_sensitive(true); + break; + case ColorManagementParams::WorkingTrc::SRGB: + wGamma->setValue(2.4); + wSlope->setValue(12.92); + will->set_sensitive(true); + willulab->set_sensitive(true); + wprim->set_sensitive(true); + fbw->set_sensitive(true); + wprimlab->set_sensitive(true); + wGamma->set_sensitive(false); + wSlope->set_sensitive(false); + riaHBox->set_sensitive(true); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { + redFrame->hide(); + } else { + redFrame->show(); + } + break; + case ColorManagementParams::WorkingTrc::GAMMA_2_2: + wGamma->setValue(2.2); + wSlope->setValue(0.); + will->set_sensitive(true); + willulab->set_sensitive(true); + wprim->set_sensitive(true); + fbw->set_sensitive(true); + wprimlab->set_sensitive(true); + redFrame->show(); + wGamma->set_sensitive(false); + wSlope->set_sensitive(false); + riaHBox->set_sensitive(true); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { + redFrame->hide(); + } else { + redFrame->show(); + } + break; + case ColorManagementParams::WorkingTrc::GAMMA_1_8: + wGamma->setValue(1.8); + wSlope->setValue(0.); + will->set_sensitive(true); + willulab->set_sensitive(true); + wprim->set_sensitive(true); + fbw->set_sensitive(true); + wprimlab->set_sensitive(true); + riaHBox->set_sensitive(true); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { + redFrame->hide(); + } else { + redFrame->show(); + } + wGamma->set_sensitive(false); + wSlope->set_sensitive(false); + break; + case ColorManagementParams::WorkingTrc::LINEAR: + wGamma->setValue(1.); + wSlope->setValue(1.); + will->set_sensitive(true); + willulab->set_sensitive(true); + wprim->set_sensitive(true); + fbw->set_sensitive(true); + wprimlab->set_sensitive(true); + wGamma->set_sensitive(false); + wSlope->set_sensitive(false); + riaHBox->set_sensitive(true); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { + redFrame->hide(); + } else { + redFrame->show(); + } + break; + } + + switch (ColorManagementParams::Primaries(wprim->get_active_row_number())) { + case ColorManagementParams::Primaries::DEFAULT: + case ColorManagementParams::Primaries::SRGB: + case ColorManagementParams::Primaries::ADOBE_RGB: + case ColorManagementParams::Primaries::PRO_PHOTO: + case ColorManagementParams::Primaries::REC2020: + case ColorManagementParams::Primaries::ACES_P1: + case ColorManagementParams::Primaries::WIDE_GAMUT: + case ColorManagementParams::Primaries::ACES_P0: + case ColorManagementParams::Primaries::BRUCE_RGB: + case ColorManagementParams::Primaries::BETA_RGB: + case ColorManagementParams::Primaries::BEST_RGB: { + labgridcie->set_sensitive(false); + will->set_sensitive(false); + break; + } + + case ColorManagementParams::Primaries::CUSTOM: { + will->set_sensitive(true); + labgridcie->set_sensitive(false); + break; + } + + case ColorManagementParams::Primaries::CUSTOM_GRID: { + labgridcie->set_sensitive(true); + redBox->set_sensitive(false); + greBox->set_sensitive(false); + bluBox->set_sensitive(false); + will->set_sensitive(false); + break; + } + } + enableListener(); } @@ -615,7 +1080,7 @@ void ICMPanel::write(ProcParams* pp, ParamsEdited* pedited) pp->icm.workingProfile = wProfNames->get_active_text(); pp->icm.dcpIlluminant = rtengine::max(dcpIll->get_active_row_number(), 0); - pp->icm.workingTRC = wTRC->get_active_text(); + labgridcie->getParams(pp->icm.labgridcieALow, pp->icm.labgridcieBLow, pp->icm.labgridcieAHigh, pp->icm.labgridcieBHigh, pp->icm.labgridcieGx, pp->icm.labgridcieGy, pp->icm.labgridcieWx, pp->icm.labgridcieWy); if (oProfNames->get_active_text() == M("TP_ICM_NOICM")) { pp->icm.outputProfile = ColorManagementParams::NoICMString; @@ -631,27 +1096,43 @@ void ICMPanel::write(ProcParams* pp, ParamsEdited* pedited) pp->icm.outputIntent = rtengine::RI_RELATIVE; } - if (wTRC->get_active_row_number() == 0) { - pp->icm.workingTRC = "none"; - } else if (wTRC->get_active_row_number() == 1) { - pp->icm.workingTRC = "Custom"; + int aintentVal = aRendIntent->getSelected(); + + if (aintentVal >= 0 && aintentVal < RI__COUNT) { + pp->icm.aRendIntent = static_cast(aintentVal); + } else { + pp->icm.aRendIntent = rtengine::RI_RELATIVE; } + pp->icm.workingTRC = ColorManagementParams::WorkingTrc(wTRC->get_active_row_number()); + pp->icm.will = ColorManagementParams::Illuminant(will->get_active_row_number()); + pp->icm.wprim = ColorManagementParams::Primaries(wprim->get_active_row_number()); + pp->icm.toneCurve = ckbToneCurve->get_active(); pp->icm.applyLookTable = ckbApplyLookTable->get_active(); pp->icm.applyBaselineExposureOffset = ckbApplyBaselineExposureOffset->get_active(); pp->icm.applyHueSatMap = ckbApplyHueSatMap->get_active(); pp->icm.outputBPC = obpc->get_active(); - pp->icm.workingTRCGamma = (double) wGamma->getValue(); - pp->icm.workingTRCSlope = (double) wSlope->getValue(); + pp->icm.fbw = fbw->get_active(); + pp->icm.workingTRCGamma = wGamma->getValue(); + pp->icm.workingTRCSlope = wSlope->getValue(); + pp->icm.redx = redx->getValue(); + pp->icm.redy = redy->getValue(); + pp->icm.grex = grex->getValue(); + pp->icm.grey = grey->getValue(); + pp->icm.blux = blux->getValue(); + pp->icm.bluy = bluy->getValue(); pp->toneCurve.fromHistMatching = false; + pp->icm.preser = preser->getValue(); if (pedited) { pedited->icm.inputProfile = !iunchanged->get_active(); pedited->icm.workingProfile = wProfNames->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.outputProfile = oProfNames->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.outputIntent = oRendIntent->getSelected() < 4; + pedited->icm.aRendIntent = aRendIntent->getSelected() < 4; pedited->icm.outputBPC = !obpc->get_inconsistent(); + pedited->icm.fbw = !fbw->get_inconsistent(); pedited->icm.dcpIlluminant = dcpIll->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.toneCurve = !ckbToneCurve->get_inconsistent(); pedited->icm.applyLookTable = !ckbApplyLookTable->get_inconsistent(); @@ -660,21 +1141,50 @@ void ICMPanel::write(ProcParams* pp, ParamsEdited* pedited) pedited->icm.workingTRCGamma = wGamma->getEditedState(); pedited->icm.workingTRCSlope = wSlope->getEditedState(); pedited->icm.workingTRC = wTRC->get_active_text() != M("GENERAL_UNCHANGED"); - } + pedited->icm.will = will->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->icm.wprim = wprim->get_active_text() != M("GENERAL_UNCHANGED"); + pedited->icm.redx = redx->getEditedState(); + pedited->icm.redy = redy->getEditedState(); + pedited->icm.labgridcieALow = pedited->icm.labgridcieBLow = pedited->icm.labgridcieAHigh = pedited->icm.labgridcieBHigh = pedited->icm.labgridcieGx = pedited->icm.labgridcieGy = pedited->icm.labgridcieWx = pedited->icm.labgridcieWy = labgridcie->getEdited(); + } } void ICMPanel::setDefaults(const ProcParams* defParams, const ParamsEdited* pedited) { wGamma->setDefault(defParams->icm.workingTRCGamma); wSlope->setDefault(defParams->icm.workingTRCSlope); + redx->setDefault(defParams->icm.redx); + redy->setDefault(defParams->icm.redy); + grex->setDefault(defParams->icm.grex); + grey->setDefault(defParams->icm.grey); + blux->setDefault(defParams->icm.blux); + bluy->setDefault(defParams->icm.bluy); + preser->setDefault(defParams->icm.preser); + labgridcie->setDefault(defParams->icm.labgridcieALow, defParams->icm.labgridcieBLow , defParams->icm.labgridcieAHigh, defParams->icm.labgridcieBHigh, defParams->icm.labgridcieGx, defParams->icm.labgridcieGy, defParams->icm.labgridcieWx, defParams->icm.labgridcieWy); if (pedited) { wGamma->setDefaultEditedState(pedited->icm.workingTRCGamma ? Edited : UnEdited); wSlope->setDefaultEditedState(pedited->icm.workingTRCSlope ? Edited : UnEdited); + redx->setDefaultEditedState(pedited->icm.redx ? Edited : UnEdited); + redy->setDefaultEditedState(pedited->icm.redy ? Edited : UnEdited); + grex->setDefaultEditedState(pedited->icm.grex ? Edited : UnEdited); + grey->setDefaultEditedState(pedited->icm.grey ? Edited : UnEdited); + blux->setDefaultEditedState(pedited->icm.blux ? Edited : UnEdited); + bluy->setDefaultEditedState(pedited->icm.bluy ? Edited : UnEdited); + labgridcie->setEdited((pedited->icm.labgridcieALow || pedited->icm.labgridcieBLow || pedited->icm.labgridcieAHigh || pedited->icm.labgridcieBHigh || pedited->icm.labgridcieGx || pedited->icm.labgridcieGy || pedited->icm.labgridcieWx || pedited->icm.labgridcieWy) ? Edited : UnEdited); + preser->setDefaultEditedState(pedited->icm.preser ? Edited : UnEdited); } else { wGamma->setDefaultEditedState(Irrelevant); wSlope->setDefaultEditedState(Irrelevant); + redx->setDefaultEditedState(Irrelevant); + redy->setDefaultEditedState(Irrelevant); + grex->setDefaultEditedState(Irrelevant); + grey->setDefaultEditedState(Irrelevant); + blux->setDefaultEditedState(Irrelevant); + bluy->setDefaultEditedState(Irrelevant); + preser->setDefaultEditedState(Irrelevant); + labgridcie->setEdited(Edited); } } @@ -685,9 +1195,28 @@ void ICMPanel::adjusterChanged(Adjuster* a, double newval) Glib::ustring costr2 = Glib::ustring::format(std::setw(3), std::fixed, std::setprecision(2), newval); if (a == wGamma) { + if (wGamma->getValue() <= 1.) { + wSlope->set_sensitive(false); + } else { + wSlope->set_sensitive(true); + } listener->panelChanged(EvICMgamm, costr2); } else if (a == wSlope) { listener->panelChanged(EvICMslop, costr2); + } else if (a == redx) { + listener->panelChanged(EvICMredx, costr2); + } else if (a == redy) { + listener->panelChanged(EvICMredy, costr2); + } else if (a == grex) { + listener->panelChanged(EvICMgrex, costr2); + } else if (a == grey) { + listener->panelChanged(EvICMgrey, costr2); + } else if (a == blux) { + listener->panelChanged(EvICMblux, costr2); + } else if (a == bluy) { + listener->panelChanged(EvICMbluy, costr2); + } else if (a == preser) { + listener->panelChanged(EvICMpreser, costr2); } } @@ -702,13 +1231,236 @@ void ICMPanel::wpChanged() void ICMPanel::wtrcinChanged() { - if (wTRC->get_active_row_number() == 0) { - wGamma->set_sensitive(false); - wSlope->set_sensitive(false); + switch (ColorManagementParams::WorkingTrc(wTRC->get_active_row_number())) { + case ColorManagementParams::WorkingTrc::NONE: { + wGamma->set_sensitive(false); + wSlope->set_sensitive(false); + will->set_sensitive(false); + willulab->set_sensitive(false); + wprim->set_sensitive(false); + fbw->set_sensitive(false); + wprimlab->set_sensitive(false); + redFrame->hide(); + riaHBox->set_sensitive(false); + break; + } - } else { - wGamma->set_sensitive(true); - wSlope->set_sensitive(true); + case ColorManagementParams::WorkingTrc::CUSTOM: { + will->set_sensitive(false); + wprim->set_sensitive(true); + fbw->set_sensitive(true); + wprimlab->set_sensitive(true); + willulab->set_sensitive(true); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { + redFrame->hide(); + } else { + redFrame->show(); + if ( + ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM + && ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM_GRID + ) { + redBox->set_sensitive(false); + greBox->set_sensitive(false); + bluBox->set_sensitive(false); + } else { + redBox->set_sensitive(true); + greBox->set_sensitive(true); + bluBox->set_sensitive(true); + } + } + riaHBox->set_sensitive(true); + if (wGamma->getValue() <= 1.) { + wGamma->set_sensitive(true); + wSlope->set_sensitive(false); + } else { + wGamma->set_sensitive(true); + wSlope->set_sensitive(true); + } + break; + } + + case ColorManagementParams::WorkingTrc::BT709: { + wGamma->setValue(2.222); + wSlope->setValue(4.5); + will->set_sensitive(false); + willulab->set_sensitive(true); + wprim->set_sensitive(true); + fbw->set_sensitive(true); + wprimlab->set_sensitive(true); + wGamma->set_sensitive(false); + wSlope->set_sensitive(false); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { + redFrame->hide(); + } else { + redFrame->show(); + if ( + ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM + && ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM_GRID + ) { + redBox->set_sensitive(false); + greBox->set_sensitive(false); + bluBox->set_sensitive(false); + } + } + riaHBox->set_sensitive(true); + break; + } + + case ColorManagementParams::WorkingTrc::SRGB: { + wGamma->setValue(2.4); + wSlope->setValue(12.92); + will->set_sensitive(false); + willulab->set_sensitive(true); + wGamma->set_sensitive(false); + wSlope->set_sensitive(false); + riaHBox->set_sensitive(true); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { + redFrame->hide(); + } else { + redFrame->show(); + if ( + ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM + && ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM_GRID + ) { + redBox->set_sensitive(false); + greBox->set_sensitive(false); + bluBox->set_sensitive(false); + } else { + redBox->set_sensitive(true); + greBox->set_sensitive(true); + bluBox->set_sensitive(true); + } + } + break; + } + + case ColorManagementParams::WorkingTrc::GAMMA_2_2: { + wGamma->setValue(2.2); + wSlope->setValue(0.); + will->set_sensitive(false); + willulab->set_sensitive(true); + wprim->set_sensitive(true); + fbw->set_sensitive(true); + wprimlab->set_sensitive(true); + wGamma->set_sensitive(false); + wSlope->set_sensitive(false); + riaHBox->set_sensitive(true); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { + redFrame->hide(); + } else { + redFrame->show(); + if ( + ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM + && ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM_GRID + ) { + redBox->set_sensitive(false); + greBox->set_sensitive(false); + bluBox->set_sensitive(false); + } else { + redBox->set_sensitive(true); + greBox->set_sensitive(true); + bluBox->set_sensitive(true); + } + } + break; + } + + case ColorManagementParams::WorkingTrc::GAMMA_1_8: { + wGamma->setValue(1.8); + wSlope->setValue(0.); + will->set_sensitive(false); + willulab->set_sensitive(true); + wprim->set_sensitive(true); + fbw->set_sensitive(true); + wprimlab->set_sensitive(true); + wGamma->set_sensitive(false); + wSlope->set_sensitive(false); + riaHBox->set_sensitive(true); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { + redFrame->hide(); + } else { + redFrame->show(); + if ( + ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM + && ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM_GRID + ) { + redBox->set_sensitive(false); + greBox->set_sensitive(false); + bluBox->set_sensitive(false); + } else { + redBox->set_sensitive(true); + greBox->set_sensitive(true); + bluBox->set_sensitive(true); + } + } + break; + } + + case ColorManagementParams::WorkingTrc::LINEAR: { + wGamma->setValue(1.0); + wSlope->setValue(1.); + will->set_sensitive(false); + willulab->set_sensitive(true); + wprim->set_sensitive(true); + fbw->set_sensitive(true); + wprimlab->set_sensitive(true); + wGamma->set_sensitive(false); + wSlope->set_sensitive(false); + riaHBox->set_sensitive(true); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { + redFrame->hide(); + } else { + redFrame->show(); + if ( + ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM + && ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM_GRID + ) { + redBox->set_sensitive(false); + greBox->set_sensitive(false); + bluBox->set_sensitive(false); + } else { + redBox->set_sensitive(true); + greBox->set_sensitive(true); + bluBox->set_sensitive(true); + } + } + break; + } + } + wprimChanged(); + + switch (ColorManagementParams::Primaries(wprim->get_active_row_number())) { + case ColorManagementParams::Primaries::DEFAULT: + case ColorManagementParams::Primaries::SRGB: + case ColorManagementParams::Primaries::ADOBE_RGB: + case ColorManagementParams::Primaries::PRO_PHOTO: + case ColorManagementParams::Primaries::REC2020: + case ColorManagementParams::Primaries::ACES_P1: + case ColorManagementParams::Primaries::WIDE_GAMUT: + case ColorManagementParams::Primaries::ACES_P0: + case ColorManagementParams::Primaries::BRUCE_RGB: + case ColorManagementParams::Primaries::BETA_RGB: + case ColorManagementParams::Primaries::BEST_RGB: { + labgridcie->set_sensitive(false); + will->set_sensitive(false); + break; + } + + case ColorManagementParams::Primaries::CUSTOM: { + will->set_sensitive(true); + labgridcie->set_sensitive(false); + break; + } + + case ColorManagementParams::Primaries::CUSTOM_GRID: { + labgridcie->set_sensitive(true); + will->set_sensitive(false); + break; + } + } + + if (ColorManagementParams::WorkingTrc(wTRC->get_active_row_number()) == ColorManagementParams::WorkingTrc::NONE) { + redFrame->hide(); } if (listener) { @@ -716,6 +1468,284 @@ void ICMPanel::wtrcinChanged() } } +void ICMPanel::willChanged() +{ + switch (ColorManagementParams::Primaries(wprim->get_active_row_number())) { + case ColorManagementParams::Primaries::DEFAULT: + case ColorManagementParams::Primaries::SRGB: + case ColorManagementParams::Primaries::ADOBE_RGB: + case ColorManagementParams::Primaries::PRO_PHOTO: + case ColorManagementParams::Primaries::REC2020: + case ColorManagementParams::Primaries::ACES_P1: + case ColorManagementParams::Primaries::WIDE_GAMUT: + case ColorManagementParams::Primaries::ACES_P0: + case ColorManagementParams::Primaries::BRUCE_RGB: + case ColorManagementParams::Primaries::BETA_RGB: + case ColorManagementParams::Primaries::BEST_RGB: { + labgridcie->set_sensitive(false); + will->set_sensitive(false); + break; + } + + case ColorManagementParams::Primaries::CUSTOM: { + will->set_sensitive(true); + labgridcie->set_sensitive(false); + break; + } + + case ColorManagementParams::Primaries::CUSTOM_GRID: { + labgridcie->set_sensitive(true); + will->set_sensitive(false); + break; + } + } + + if (listener) { + listener->panelChanged(EvICMwillMethod, will->get_active_text()); + } +} + + + +void ICMPanel::wprimChanged() +{ + switch (ColorManagementParams::Primaries(wprim->get_active_row_number())) { + case ColorManagementParams::Primaries::DEFAULT: + case ColorManagementParams::Primaries::CUSTOM: + case ColorManagementParams::Primaries::CUSTOM_GRID: { + break; + } + + case ColorManagementParams::Primaries::SRGB: { + redx->setValue(0.64); + redy->setValue(0.33); + grex->setValue(0.30); + grey->setValue(0.60); + blux->setValue(0.15); + bluy->setValue(0.06); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D65)); + break; + } + + case ColorManagementParams::Primaries::ADOBE_RGB: { + redx->setValue(0.64); + redy->setValue(0.33); + grex->setValue(0.21); + grey->setValue(0.71); + blux->setValue(0.15); + bluy->setValue(0.06); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D65)); + break; + } + + case ColorManagementParams::Primaries::PRO_PHOTO: { + redx->setValue(0.7347); + redy->setValue(0.2653); + grex->setValue(0.1596); + grey->setValue(0.8404); + blux->setValue(0.0366); + bluy->setValue(0.0001); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D50)); + break; + } + + case ColorManagementParams::Primaries::REC2020: { + redx->setValue(0.708); + redy->setValue(0.292); + grex->setValue(0.17); + grey->setValue(0.797); + blux->setValue(0.131); + bluy->setValue(0.046); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D65)); + break; + } + + case ColorManagementParams::Primaries::ACES_P1: { + redx->setValue(0.713); + redy->setValue(0.293); + grex->setValue(0.165); + grey->setValue(0.830); + blux->setValue(0.128); + bluy->setValue(0.044); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D60)); + break; + } + + case ColorManagementParams::Primaries::WIDE_GAMUT: { + redx->setValue(0.735); + redy->setValue(0.265); + grex->setValue(0.115); + grey->setValue(0.826); + blux->setValue(0.1570); + bluy->setValue(0.018); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D50)); + break; + } + + case ColorManagementParams::Primaries::ACES_P0: { + redx->setValue(0.7347); + redy->setValue(0.2653); + grex->setValue(0.); + grey->setValue(1.0); + blux->setValue(0.0001); + bluy->setValue(-0.077); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D60)); + break; + } + + case ColorManagementParams::Primaries::BRUCE_RGB: { + redx->setValue(0.64); + redy->setValue(0.33); + grex->setValue(0.28); + grey->setValue(0.65); + blux->setValue(0.15); + bluy->setValue(0.06); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D65)); + break; + } + + case ColorManagementParams::Primaries::BETA_RGB: { + redx->setValue(0.6888); + redy->setValue(0.3112); + grex->setValue(0.1986); + grey->setValue(0.7551); + blux->setValue(0.1265); + bluy->setValue(0.0352); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D50)); + break; + } + + case ColorManagementParams::Primaries::BEST_RGB: { + redx->setValue(0.7347); + redy->setValue(0.2653); + grex->setValue(0.2150); + grey->setValue(0.7750); + blux->setValue(0.130); + bluy->setValue(0.035); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D50)); + break; + } + } + + + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { + if (wProfNames->get_active_text() == "Rec2020") { + redx->setValue(0.708); + redy->setValue(0.292); + grex->setValue(0.17); + grey->setValue(0.797); + blux->setValue(0.131); + bluy->setValue(0.046); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D65)); + } else if (wProfNames->get_active_text() == "sRGB") { + redx->setValue(0.64); + redy->setValue(0.33); + grex->setValue(0.30); + grey->setValue(0.60); + blux->setValue(0.15); + bluy->setValue(0.06); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D65)); + } else if (wProfNames->get_active_text() == "Adobe RGB") { + redx->setValue(0.64); + redy->setValue(0.33); + grex->setValue(0.21); + grey->setValue(0.71); + blux->setValue(0.15); + bluy->setValue(0.06); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D65)); + } else if (wProfNames->get_active_text() == "ProPhoto") { + redx->setValue(0.7347); + redy->setValue(0.2653); + grex->setValue(0.1596); + grey->setValue(0.8404); + blux->setValue(0.0366); + bluy->setValue(0.0001); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D50)); + } else if (wProfNames->get_active_text() == "ACESp1") { + redx->setValue(0.713); + redy->setValue(0.293); + grex->setValue(0.165); + grey->setValue(0.830); + blux->setValue(0.128); + bluy->setValue(0.044); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D60)); + } else if (wProfNames->get_active_text() == "WideGamut") { + redx->setValue(0.735); + redy->setValue(0.265); + grex->setValue(0.115); + grey->setValue(0.826); + blux->setValue(0.1570); + bluy->setValue(0.018); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D50)); + } else if (wProfNames->get_active_text() == "ACESp0") { + redx->setValue(0.7347); + redy->setValue(0.2653); + grex->setValue(0.); + grey->setValue(1.0); + blux->setValue(0.0001); + bluy->setValue(-0.077); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D60)); + } else if (wProfNames->get_active_text() == "BruceRGB") { + redx->setValue(0.64); + redy->setValue(0.33); + grex->setValue(0.28); + grey->setValue(0.65); + blux->setValue(0.15); + bluy->setValue(0.06); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D65)); + } else if (wProfNames->get_active_text() == "Beta RGB") { + redx->setValue(0.6888); + redy->setValue(0.3112); + grex->setValue(0.1986); + grey->setValue(0.7551); + blux->setValue(0.1265); + bluy->setValue(0.0352); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D50)); + } else if (wProfNames->get_active_text() == "BestRGB") { + redx->setValue(0.7347); + redy->setValue(0.2653); + grex->setValue(0.2150); + grey->setValue(0.7750); + blux->setValue(0.130); + bluy->setValue(0.035); + will->set_active(toUnderlying(ColorManagementParams::Illuminant::D50)); + } + + redFrame->hide(); + } else { + redFrame->show(); + + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) != ColorManagementParams::Primaries::CUSTOM) { + redBox->set_sensitive(false); + greBox->set_sensitive(false); + bluBox->set_sensitive(false); + labgridcie->set_sensitive(false); + will->set_sensitive(false); + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::CUSTOM_GRID) { + labgridcie->set_sensitive(true); + } + } else { + redBox->set_sensitive(true); + greBox->set_sensitive(true); + bluBox->set_sensitive(true); + labgridcie->set_sensitive(false); + will->set_sensitive(true); + } + + } + willChanged (); + + if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::CUSTOM_GRID) { + labgridcie->set_sensitive(true); + } else { + labgridcie->set_sensitive(false); + } + + if (listener) { + listener->panelChanged(EvICMwprimMethod, wprim->get_active_text()); + } +} + void ICMPanel::dcpIlluminantChanged() { if (listener) { @@ -897,6 +1927,39 @@ void ICMPanel::oiChanged(int n) } } +void ICMPanel::aiChanged(int n) +{ + + if (listener) { + Glib::ustring str; + + switch (n) { + case 0: + str = M("PREFERENCES_INTENT_PERCEPTUAL"); + break; + + case 1: + str = M("PREFERENCES_INTENT_RELATIVE"); + break; + + case 2: + str = M("PREFERENCES_INTENT_SATURATION"); + break; + + case 3: + str = M("PREFERENCES_INTENT_ABSOLUTE"); + break; + + case 4: + default: + str = M("GENERAL_UNCHANGED"); + break; + } + + listener->panelChanged(EvaIntent, str); + } +} + void ICMPanel::oBPCChanged() { if (multiImage) { @@ -923,6 +1986,32 @@ void ICMPanel::oBPCChanged() } } +void ICMPanel::fbwChanged() +{ + if (multiImage) { + if (fbw->get_inconsistent()) { + fbw->set_inconsistent(false); + fbwconn.block(true); + fbw->set_active(false); + fbwconn.block(false); + } else if (lastfbw) { + fbw->set_inconsistent(true); + } + + lastfbw = fbw->get_active(); + } + + if (listener) { + if (fbw->get_inconsistent()) { + listener->panelChanged(EvICMfbw, M("GENERAL_UNCHANGED")); + } else if (fbw->get_active()) { + listener->panelChanged(EvICMfbw, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(EvICMfbw, M("GENERAL_DISABLED")); + } + } +} + void ICMPanel::setRawMeta(bool raw, const rtengine::FramesData* pMeta) { @@ -948,6 +2037,8 @@ void ICMPanel::ipSelectionChanged() ipChanged(); } + + void ICMPanel::saveReferencePressed() { @@ -1022,10 +2113,21 @@ void ICMPanel::setBatchMode(bool batchMode) oProfNames->append(M("GENERAL_UNCHANGED")); oRendIntent->addEntry("template-24.png", M("GENERAL_UNCHANGED")); oRendIntent->show(); + aRendIntent->addEntry("template-24.png", M("GENERAL_UNCHANGED")); + aRendIntent->show(); wProfNames->append(M("GENERAL_UNCHANGED")); wTRC->append(M("GENERAL_UNCHANGED")); + will->append(M("GENERAL_UNCHANGED")); + wprim->append(M("GENERAL_UNCHANGED")); dcpIll->append(M("GENERAL_UNCHANGED")); wGamma->showEditedCB(); wSlope->showEditedCB(); + redx->showEditedCB(); + redy->showEditedCB(); + grex->showEditedCB(); + grey->showEditedCB(); + blux->showEditedCB(); + bluy->showEditedCB(); + preser->showEditedCB(); } diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 81a011c59..fb3673188 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -36,24 +36,36 @@ public: virtual void saveInputICCReference(const Glib::ustring& fname, bool apply_wb) = 0; }; +class LabGrid; + class ICMPanel final : public ToolParamBlock, - public AdjusterListener, - public FoldableToolPanel + public FoldableToolPanel, + public rtengine::AutoprimListener, + public AdjusterListener { protected: Gtk::Frame* dcpFrame; Gtk::Frame* coipFrame; + Gtk::Frame* redFrame; Adjuster* wGamma; Adjuster* wSlope; + Adjuster* redx; + Adjuster* redy; + Adjuster* grex; + Adjuster* grey; + Adjuster* blux; + Adjuster* bluy; + Adjuster* preser; Gtk::Label* labmga; Gtk::Box* gabox; + Gtk::Label* blr; + Gtk::Label* blg; + Gtk::Label* blb; - - //bool freegamma; bool lastToneCurve; sigc::connection tcurveconn; bool lastApplyLookTable; @@ -64,6 +76,8 @@ protected: sigc::connection hsmconn; bool lastobpc; sigc::connection obpcconn; + bool lastfbw; + sigc::connection fbwconn; bool isBatchMode; private: @@ -79,9 +93,34 @@ private: rtengine::ProcEvent EvICMgamm; rtengine::ProcEvent EvICMslop; rtengine::ProcEvent EvICMtrcinMethod; + rtengine::ProcEvent EvICMwillMethod; + rtengine::ProcEvent EvICMwprimMethod; + rtengine::ProcEvent EvICMredx; + rtengine::ProcEvent EvICMredy; + rtengine::ProcEvent EvICMgrex; + rtengine::ProcEvent EvICMgrey; + rtengine::ProcEvent EvICMblux; + rtengine::ProcEvent EvICMbluy; + rtengine::ProcEvent EvaIntent; + rtengine::ProcEvent EvICMpreser; + rtengine::ProcEvent EvICMLabGridciexy; + rtengine::ProcEvent EvICMfbw; + LabGrid *labgridcie; + IdleRegister idle_register; + Gtk::Box* willuBox; + Gtk::Label* willulab; + Gtk::Box* wprimBox; + Gtk::Label* wprimlab; + Gtk::Label* cielab; + Gtk::Box* redBox; + Gtk::Box* greBox; + Gtk::Box* bluBox; + Gtk::Box* riaHBox; + Gtk::Box* preBox; Gtk::Box* iVBox; - Gtk::Box* wTRCHBox; + Gtk::Box* wTRCBox; + Gtk::CheckButton* fbw; Gtk::CheckButton* obpc; Gtk::RadioButton* inone; @@ -101,6 +140,12 @@ private: sigc::connection wprofnamesconn; MyComboBoxText* wTRC; sigc::connection wtrcconn; + MyComboBoxText* will; + sigc::connection willconn; + MyComboBoxText* wprim; + sigc::connection wprimconn; + std::unique_ptr aRendIntent; + sigc::connection arendintentconn; MyComboBoxText* oProfNames; sigc::connection oprofnamesconn; @@ -113,26 +158,43 @@ private: sigc::connection ipc; Glib::ustring oldip; ICMPanelListener* icmplistener; - + double dcpTemperatures[2]; Glib::ustring lastRefFilename; Glib::ustring camName; void updateDCP(int dcpIlluminant, Glib::ustring dcp_name); void updateRenderingIntent(const Glib::ustring &profile); + + float nextrx; + float nextry; + float nextbx; + float nextby; + float nextgx; + float nextgy; + float nextwx; + float nextwy; + public: ICMPanel(); + ~ICMPanel() override; void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; void setBatchMode(bool batchMode) override; void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; void adjusterChanged(Adjuster* a, double newval) override; + void primChanged (float rx, float ry, float bx, float by, float gx, float gy) override; + void iprimChanged (float r_x, float r_y, float b_x, float b_y, float g_x, float g_y, float w_x, float w_y) override; void wpChanged(); void wtrcinChanged(); + void willChanged(); + void wprimChanged(); void opChanged(); void oiChanged(int n); + void aiChanged(int n); void oBPCChanged(); + void fbwChanged(); void ipChanged(); void ipSelectionChanged(); void dcpIlluminantChanged(); @@ -143,9 +205,13 @@ public: void setRawMeta(bool raw, const rtengine::FramesData* pMeta); void saveReferencePressed(); + void setListener(ToolPanelListener* tpl) override; + void setEditProvider(EditDataProvider *provider) override; void setICMPanelListener(ICMPanelListener* ipl) { icmplistener = ipl; } + }; + diff --git a/rtgui/labgrid.cc b/rtgui/labgrid.cc index d8a22b1d9..d0443d58d 100644 --- a/rtgui/labgrid.cc +++ b/rtgui/labgrid.cc @@ -4,6 +4,8 @@ * * Copyright (c) 2017 Alberto Griggio * + * Copyright (c) 2021 Jacques Desmis for CIE xy graph + * * 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 @@ -57,22 +59,34 @@ bool LabGridArea::notifyListener() { return int(v * 1000) / 1000.f; }; - listener->panelChanged(evt, Glib::ustring::compose(evtMsg, round(high_a), round(high_b), round(low_a), round(low_b))); + if (! ciexy_enabled){ + listener->panelChanged(evt, Glib::ustring::compose(evtMsg, round(high_a), round(high_b), round(low_a), round(low_b))); + } else { + float high_a1 = 0.55f * (high_a + 1.f) - 0.1f; + float high_b1 = 0.55f * (high_b + 1.f) - 0.1f; + float low_a1 = 0.55f * (low_a + 1.f) - 0.1f; + float low_b1 = 0.55f * (low_b + 1.f) - 0.1f; + float gre_x1 = 0.55f * (gre_x + 1.f) - 0.1f; + float gre_y1 = 0.55f * (gre_y + 1.f) - 0.1f; + listener->panelChanged(evt, Glib::ustring::compose(evtMsg, round(low_a1), round(low_b1), round(gre_x1), round(gre_y1), round(high_a1), round(high_b1))); + } } return false; } -LabGridArea::LabGridArea(rtengine::ProcEvent evt, const Glib::ustring &msg, bool enable_low): +LabGridArea::LabGridArea(rtengine::ProcEvent evt, const Glib::ustring &msg, bool enable_low, bool ciexy): Gtk::DrawingArea(), evt(evt), evtMsg(msg), litPoint(NONE), - low_a(0.f), high_a(0.f), low_b(0.f), high_b(0.f), - defaultLow_a(0.f), defaultHigh_a(0.f), defaultLow_b(0.f), defaultHigh_b(0.f), + low_a(0.f), high_a(0.f), low_b(0.f), high_b(0.f), gre_x(0.f), gre_y(0.f), whi_x(0.f), whi_y(0.f),//these variables are used as xy in Ciexy - no change labels + defaultLow_a(0.f), defaultHigh_a(0.f), defaultLow_b(0.f), defaultHigh_b(0.f), defaultgre_x(0.f), defaultgre_y(0.f), defaultwhi_x(0.f), defaultwhi_y(0.f), listener(nullptr), edited(false), isDragged(false), - low_enabled(enable_low) + low_enabled(enable_low), + ciexy_enabled(ciexy) + { set_can_focus(false); // prevent moving the grid while you're moving a point add_events(Gdk::EXPOSURE_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK); @@ -80,16 +94,21 @@ LabGridArea::LabGridArea(rtengine::ProcEvent evt, const Glib::ustring &msg, bool get_style_context()->add_class("drawingarea"); } -void LabGridArea::getParams(double &la, double &lb, double &ha, double &hb) const +void LabGridArea::getParams(double &la, double &lb, double &ha, double &hb, double &gx, double &gy, double &wx, double &wy) const { la = low_a; ha = high_a; lb = low_b; hb = high_b; + gx = gre_x; + gy = gre_y; + wx = whi_x; + wy = whi_y; + // printf("la=%f ha=%f lb=%f hb=%f gx=%f gy=%f\n", la, ha, lb, hb, gx, gy); } -void LabGridArea::setParams(double la, double lb, double ha, double hb, bool notify) +void LabGridArea::setParams(double la, double lb, double ha, double hb, double gx, double gy, double wx, double wy, bool notify) { const double lo = -1.0; const double hi = 1.0; @@ -97,27 +116,37 @@ void LabGridArea::setParams(double la, double lb, double ha, double hb, bool not low_b = rtengine::LIM(lb, lo, hi); high_a = rtengine::LIM(ha, lo, hi); high_b = rtengine::LIM(hb, lo, hi); + gre_x = rtengine::LIM(gx, lo, hi); + gre_y = rtengine::LIM(gy, lo, hi); + whi_x = rtengine::LIM(wx, lo, hi); + whi_y = rtengine::LIM(wy, lo, hi); + queue_draw(); if (notify) { notifyListener(); } } -void LabGridArea::setDefault (double la, double lb, double ha, double hb) +void LabGridArea::setDefault (double la, double lb, double ha, double hb, double gx, double gy, double wx, double wy) { defaultLow_a = la; defaultLow_b = lb; defaultHigh_a = ha; defaultHigh_b = hb; + defaultgre_x = gx; + defaultgre_y = gy; + defaultwhi_x = wx; + defaultwhi_y = wy; } void LabGridArea::reset(bool toInitial) { if (toInitial) { - setParams(defaultLow_a, defaultLow_b, defaultHigh_a, defaultHigh_b, true); + setParams(defaultLow_a, defaultLow_b, defaultHigh_a, defaultHigh_b, defaultgre_x, defaultgre_y, defaultwhi_x, defaultwhi_y, true); } else { - setParams(0., 0., 0., 0., true); + // printf("RESET \n"); + setParams(0., 0., 0., 0., 0., 0., 0., 0., true); } } @@ -166,6 +195,7 @@ bool LabGridArea::on_draw(const ::Cairo::RefPtr &crf) Gtk::Border padding = getPadding(style); // already scaled Cairo::RefPtr cr = getContext(); + if (isDirty()) { int width = allocation.get_width(); int height = allocation.get_height(); @@ -195,55 +225,208 @@ bool LabGridArea::on_draw(const ::Cairo::RefPtr &crf) // flip y: cr->translate(0, height); cr->scale(1., -1.); - const int cells = 8; - float step = 12000.f / float(cells/2); - double cellW = double(width) / double(cells); - double cellH = double(height) / double(cells); - double cellYMin = 0.; - double cellYMax = std::floor(cellH); - for (int j = 0; j < cells; j++) { - double cellXMin = 0.; - double cellXMax = std::floor(cellW); - for (int i = 0; i < cells; i++) { - float R, G, B; - float x, y, z; - int ii = i - cells/2; - int jj = j - cells/2; - float a = step * (ii + 0.5f); - float b = step * (jj + 0.5f); - Color::Lab2XYZ(25000.f, a, b, x, y, z); - Color::xyz2srgb(x, y, z, R, G, B); - cr->set_source_rgb(R / 65535.f, G / 65535.f, B / 65535.f); - cr->rectangle( - cellXMin, - cellYMin, - cellXMax - cellXMin - (i == cells-1 ? 0. : double(s)), - cellYMax - cellYMin - (j == cells-1 ? 0. : double(s)) - ); - cellXMin = cellXMax; - cellXMax = std::floor(cellW * double(i+2) + 0.01); - cr->fill(); - } - cellYMin = cellYMax; - cellYMax = std::floor(cellH * double(j+2) + 0.01); - } + if (! ciexy_enabled) {//draw cells for Labgrid + int cells = 8; + float step = 12000.f / float(cells/2); + double cellW = double(width) / double(cells); + double cellH = double(height) / double(cells); + double cellYMin = 0.; + double cellYMax = std::floor(cellH); + for (int j = 0; j < cells; j++) { + double cellXMin = 0.; + double cellXMax = std::floor(cellW); + for (int i = 0; i < cells; i++) { + float R, G, B; + float x, y, z; + int ii = i - cells/2; + int jj = j - cells/2; + float a = step * (ii + 0.5f); + float b = step * (jj + 0.5f); + Color::Lab2XYZ(25000.f, a, b, x, y, z); + Color::xyz2srgb(x, y, z, R, G, B); + cr->set_source_rgb(R / 65535.f, G / 65535.f, B / 65535.f); + cr->rectangle( + cellXMin, + cellYMin, + cellXMax - cellXMin - (i == cells-1 ? 0. : double(s)), + cellYMax - cellYMin - (j == cells-1 ? 0. : double(s)) + ); + cellXMin = cellXMax; + cellXMax = std::floor(cellW * double(i+2) + 0.01); + cr->fill(); + } + cellYMin = cellYMax; + cellYMax = std::floor(cellH * double(j+2) + 0.01); + } + } else {//cells for CIE xy + int cells = 600; + float step = 1.f / float(cells); + double cellW = double(width) / double(cells); + double cellH = double(height) / double(cells); + double cellYMin = 0.; + double cellYMax = std::floor(cellH); + //various approximations to simulate Ciexy curves graph + // this graph is not accurate...I replace curve by polygon or parabolic + float xa = 0.2653f / (0.7347f - 0.17f); + float xb = -0.17f * xa; + //linaer values + // float ax = (0.1f - 0.6f) / 0.08f; + // float bx = 0.6f; + // float ax0 = -0.1f / (0.17f - 0.08f); + // float bx0 = -0.17f* ax0; + float axs = (0.2653f - 0.65f) / (0.7347f - 0.35f); + float bxs = 0.65f - axs * 0.35f; + // float axss = (0.7f - 0.83f) / (0.3f - 0.1f); + // float bxss = 0.7f - 0.3f * axss; + //float bxsss = 0.65f; + //float axsss = (0.83f - bxsss) / 0.05f; + //float bx4s = 0.83f; + float ay = 0.4f; + float by = 0.4f; + for (int j = 0; j < cells; j++) { + double cellXMin = 0.; + double cellXMax = std::floor(cellW); + for (int i = 0; i < cells; i++) { + float R, G, B; + float XX, YY, ZZ; + float x = 1.1f * step * i - 0.1f;//Graph CIExy with -0.1 to 1 - must be enough + float y = 1.1f * step * j - 0.1;//Graph CIExy with -0.1 to 1 - must be enough + if(y > 0.5f) { + YY = 0.6f; + } else { + YY = ay * y + by; + } + XX = (x * YY) / y; + ZZ = ((1.f - x - y)* YY) / y; + float yr = xa * x + xb; + // float y0 = ax0 * x + bx0; + // float y1 = ax * x + bx; + float y2 = axs * x + bxs; + // float y3 = axss * x + bxss; + // float y4 = axsss * x + bxsss; + // float y5 = bx4s; + float y6 = 22.52f * x * x - 7.652f * x + 0.65f;//parabolic passing in x=0.17 y=0 - x=0.1 y =0.11 - x=0 y= 0.65 + float y3 = -1.266666f * x * x -0.170002f * x + 0.859686f;//other parabolic for green passing in x=0.35 y=0.65 - x=0.20 y=0.775 - x=0.1 y=0.83 + float y4 = -60.71428f * x * x + 6.821428f * x + 0.65f;//other parabolic x=0 y=0.65 - x=0.03 y=0.8 - x=0.07 y=0.83 + //small difference in the connection of the 2 last parabolic + + Color::xyz2srgb(XX, YY, ZZ, R, G, B); + //replace color by gray + if(y < yr && x > 0.17f) { + R = 0.7f; G = 0.7f; B = 0.7f; + } + /* + if(y < y0 && x <= 0.17f && x >= 0.08f) { + R = 0.7f; G = 0.7f; B = 0.7f; + } + if(y < y1 && x < 0.08f) { + R = 0.7f; G = 0.7f; B = 0.7f; + } + */ + if(y < y6 && y < 0.65f && x < 0.17f) { + R = 0.7f; G = 0.7f; B = 0.7f; + } + + if(y > y2 && x > 0.35f) {//0.35 + R = 0.7f; G = 0.7f; B = 0.7f; + } + if(y > y3 && x <= 0.35f && x > 0.06f) {//0.35 + R = 0.7f; G = 0.7f; B = 0.7f; + } + if(y > y4 && x <= 0.06f) { + R = 0.7f; G = 0.7f; B = 0.7f; + } + // if(y > y5 && x >= 0.07f && x <= 0.1f) { + // R = 0.7f; G = 0.7f; B = 0.7f; + // } + + cr->set_source_rgb(R , G , B); + + cr->rectangle( + cellXMin, + cellYMin, + cellXMax - cellXMin - (i == cells-1 ? 0. : 0.f * double(s)), + cellYMax - cellYMin - (j == cells-1 ? 0. : 0.f * double(s)) + ); + cellXMin = cellXMax; + cellXMax = std::floor(cellW * double(i+2) + 0.001); + cr->fill(); + } + cellYMin = cellYMax; + cellYMax = std::floor(cellH * double(j+2) + 0.001); + } + } // drawing the connection line cr->set_antialias(Cairo::ANTIALIAS_DEFAULT); - float loa, hia, lob, hib; + float loa, hia, lob, hib, grx, gry, whx, why; loa = .5 * (width + width * low_a); hia = .5 * (width + width * high_a); lob = .5 * (height + height * low_b); hib = .5 * (height + height * high_b); - cr->set_line_width(2. * double(s)); + grx = .5 * (width + width * gre_x); + gry = .5 * (height + height * gre_y); + whx = .5 * (width + width * whi_x); + why = .5 * (height + height * whi_y); + cr->set_line_width(1.5f * double(s)); cr->set_source_rgb(0.6, 0.6, 0.6); cr->move_to(loa, lob); cr->line_to(hia, hib); + if (ciexy_enabled) { + cr->move_to(loa, lob); + cr->line_to(grx, gry); + cr->move_to(grx, gry); + cr->line_to(hia, hib); + } cr->stroke(); + if (ciexy_enabled) { + //to convert from / to Ciexy <=> area + // pos_area = 1.81818 * (x + 0.1) - 1 + // x = 0.55 * (pos_area + 1) - 0.1 + cr->set_line_width(0.2f * double(s)); + cr->set_source_rgb(0.1, 0.1, 0.1); + //draw horiz and vertical lines + for(int i = 0; i < 22; i++) { + cr->move_to(0.04545 * i * width, 0.); + cr->line_to(0.04545 * i * width, height); + } + for(int i = 0; i < 22; i++) { + cr->move_to(0., 0.04545 * i * height ); + cr->line_to(width, 0.04545 * i * height); + } + + cr->stroke(); + //draw abciss and ordonate + cr->set_line_width(1.f * double(s)); + cr->set_source_rgb(0.4, 0., 0.); + cr->move_to(0.04545 * 2 * width, 0.); + cr->line_to(0.04545 * 2 * width, height); + cr->move_to(0., 0.04545 * 2 * height ); + cr->line_to(width, 0.04545 * 2 * height); + cr->stroke(); + + //draw 0 and 1 with circle and lines + cr->set_line_width(1.2f * double(s)); + cr->set_source_rgb(0.4, 0., 0.); + cr->arc(0.06 * width, 0.06 * height, 0.016 * width, 0, 2. * rtengine::RT_PI); + cr->stroke(); + cr->set_line_width(1.5f * double(s)); + cr->set_source_rgb(0.4, 0., 0.); + cr->move_to(0.985 * width, 0.08 * height); + cr->line_to(0.985 * width, 0.055 * height); + + cr->move_to(0.07 * width, 0.99 * height); + cr->line_to(0.07 * width, 0.965 * height); + + cr->stroke(); + + } + + // drawing points if (low_enabled) { - cr->set_source_rgb(0.1, 0.1, 0.1); + cr->set_source_rgb(0.1, 0.1, 0.1);//black for red in Ciexy if (litPoint == LOW) { cr->arc(loa, lob, 5 * s, 0, 2. * rtengine::RT_PI); } else { @@ -252,7 +435,23 @@ bool LabGridArea::on_draw(const ::Cairo::RefPtr &crf) cr->fill(); } - cr->set_source_rgb(0.9, 0.9, 0.9); + if (ciexy_enabled) { + cr->set_source_rgb(0.5, 0.5, 0.5);//gray for green + if (litPoint == GRE) { + cr->arc(grx, gry, 5 * s, 0, 2. * rtengine::RT_PI); + } else { + cr->arc(grx, gry, 3 * s, 0, 2. * rtengine::RT_PI); + } + cr->fill(); + } + + if (ciexy_enabled) {//White Point + cr->set_source_rgb(1., 1., 1.);//White + cr->arc(whx, why, 3 * s, 0, 2. * rtengine::RT_PI); + cr->fill(); + } + + cr->set_source_rgb(0.9, 0.9, 0.9);//white for blue en Ciexy if (litPoint == HIGH) { cr->arc(hia, hib, 5 * s, 0, 2. * rtengine::RT_PI); } else { @@ -269,10 +468,11 @@ bool LabGridArea::on_draw(const ::Cairo::RefPtr &crf) bool LabGridArea::on_button_press_event(GdkEventButton *event) { if (event->button == 1) { + if (!ciexy_enabled) { if (event->type == GDK_2BUTTON_PRESS) { switch (litPoint) { case NONE: - low_a = low_b = high_a = high_b = 0.f; + low_a = low_b = high_a = high_b = gre_x = gre_y = 0.f; break; case LOW: low_a = low_b = 0.f; @@ -280,6 +480,9 @@ bool LabGridArea::on_button_press_event(GdkEventButton *event) case HIGH: high_a = high_b = 0.f; break; + case GRE: + gre_x = gre_y = 0.f; + break; } edited = true; notifyListener(); @@ -287,6 +490,16 @@ bool LabGridArea::on_button_press_event(GdkEventButton *event) } else if (event->type == GDK_BUTTON_PRESS && litPoint != NONE) { isDragged = true; } + } else { + if (event->type == GDK_2BUTTON_PRESS) { + edited = true; + notifyListener(); + queue_draw(); + } else if (event->type == GDK_BUTTON_PRESS && litPoint != NONE) { + isDragged = true; + } + + } return false; } return true; @@ -328,6 +541,9 @@ bool LabGridArea::on_motion_notify_event(GdkEventMotion *event) } else if (litPoint == HIGH) { high_a = ma; high_b = mb; + } else if (litPoint == GRE) { + gre_x = ma; + gre_y = mb; } edited = true; grab_focus(); @@ -343,13 +559,18 @@ bool LabGridArea::on_motion_notify_event(GdkEventMotion *event) float lb = low_b; float ha = high_a; float hb = high_b; + float gx = gre_x; + float gy = gre_y; const float thrs = 0.05f; const float distlo = (la - ma) * (la - ma) + (lb - mb) * (lb - mb); const float disthi = (ha - ma) * (ha - ma) + (hb - mb) * (hb - mb); + const float distgxy = (gx - ma) * (gx - ma) + (gy - mb) * (gy - mb); if (low_enabled && distlo < thrs * thrs && distlo < disthi) { litPoint = LOW; } else if (disthi < thrs * thrs && disthi <= distlo) { litPoint = HIGH; + } else if (ciexy_enabled && distgxy < thrs * thrs && distgxy <= distlo) { + litPoint = GRE; } if ((oldLitPoint == NONE && litPoint != NONE) || (oldLitPoint != NONE && litPoint == NONE)) { queue_draw(); @@ -391,6 +612,10 @@ bool LabGridArea::lowEnabled() const return low_enabled; } +bool LabGridArea::ciexyEnabled() const +{ + return ciexy_enabled; +} void LabGridArea::setLowEnabled(bool yes) { @@ -400,17 +625,26 @@ void LabGridArea::setLowEnabled(bool yes) } } +void LabGridArea::setciexyEnabled(bool yes) +{ + if (ciexy_enabled != yes) { + ciexy_enabled = yes; + queue_draw(); + } +} //----------------------------------------------------------------------------- // LabGrid //----------------------------------------------------------------------------- -LabGrid::LabGrid(rtengine::ProcEvent evt, const Glib::ustring &msg, bool enable_low): - grid(evt, msg, enable_low) +LabGrid::LabGrid(rtengine::ProcEvent evt, const Glib::ustring &msg, bool enable_low, bool ciexy): + grid(evt, msg, enable_low, ciexy) { Gtk::Button *reset = Gtk::manage(new Gtk::Button()); reset->set_tooltip_markup(M("ADJUSTER_RESET_TO_DEFAULT")); - reset->add(*Gtk::manage(new RTImage("undo-small.png", "redo-small.png"))); + if(!ciexy) {//disabled for Cie xy + reset->add(*Gtk::manage(new RTImage("undo-small.png", "redo-small.png"))); + } reset->signal_button_release_event().connect(sigc::mem_fun(*this, &LabGrid::resetPressed)); setExpandAlignProperties(reset, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_START); diff --git a/rtgui/labgrid.h b/rtgui/labgrid.h index 78179210c..0ed4cdf98 100644 --- a/rtgui/labgrid.h +++ b/rtgui/labgrid.h @@ -48,17 +48,25 @@ private: rtengine::ProcEvent evt; Glib::ustring evtMsg; - enum State { NONE, HIGH, LOW }; + enum State { NONE, HIGH, LOW, GRE}; State litPoint; double low_a; double high_a; double low_b; double high_b; - + double gre_x; + double gre_y; + double whi_x; + double whi_y; + double defaultLow_a; double defaultHigh_a; double defaultLow_b; double defaultHigh_b; + double defaultgre_x; + double defaultgre_y; + double defaultwhi_x; + double defaultwhi_y; ToolPanelListener *listener; bool edited; @@ -67,16 +75,17 @@ private: static const int inset = 5; bool low_enabled; + bool ciexy_enabled; bool notifyListener(); void getLitPoint(); public: - LabGridArea(rtengine::ProcEvent evt, const Glib::ustring &msg, bool enable_low=true); + LabGridArea(rtengine::ProcEvent evt, const Glib::ustring &msg, bool enable_low=true, bool ciexy=false); - void getParams(double &la, double &lb, double &ha, double &hb) const; - void setParams(double la, double lb, double ha, double hb, bool notify); - void setDefault (double la, double lb, double ha, double hb); + void getParams(double &la, double &lb, double &ha, double &hb, double &gx, double &gy, double &wx, double &wy) const; + void setParams(double la, double lb, double ha, double hb, double gx, double gy, double wx, double wy, bool notify); + void setDefault (double la, double lb, double ha, double hb, double gx, double gy, double wx, double wy); void setEdited(bool yes); bool getEdited() const; void reset(bool toInitial); @@ -84,6 +93,8 @@ public: bool lowEnabled() const; void setLowEnabled(bool yes); + bool ciexyEnabled() const; + void setciexyEnabled(bool yes); bool on_draw(const ::Cairo::RefPtr &crf) override; void on_style_updated () override; @@ -103,16 +114,18 @@ private: bool resetPressed(GdkEventButton *event); public: - LabGrid(rtengine::ProcEvent evt, const Glib::ustring &msg, bool enable_low=true); + LabGrid(rtengine::ProcEvent evt, const Glib::ustring &msg, bool enable_low=true, bool ciexy=false); - void getParams(double &la, double &lb, double &ha, double &hb) const { return grid.getParams(la, lb, ha, hb); } - void setParams(double la, double lb, double ha, double hb, bool notify) { grid.setParams(la, lb, ha, hb, notify); } - void setDefault (double la, double lb, double ha, double hb) { grid.setDefault(la, lb, ha, hb); } + void getParams(double &la, double &lb, double &ha, double &hb, double &gx, double &gy, double &wx, double &wy) const { return grid.getParams(la, lb, ha, hb, gx, gy, wx, wy); } + void setParams(double la, double lb, double ha, double hb, double gx, double gy, double wx, double wy, bool notify) { grid.setParams(la, lb, ha, hb, gx, gy, wx, wy, notify); } + void setDefault (double la, double lb, double ha, double hb, double gx, double gy, double wx, double wy) { grid.setDefault(la, lb, ha, hb, gx, gy, wx, wy); } void setEdited(bool yes) { grid.setEdited(yes); } bool getEdited() const { return grid.getEdited(); } void reset(bool toInitial) { grid.reset(toInitial); } void setListener(ToolPanelListener *l) { grid.setListener(l); } bool lowEnabled() const { return grid.lowEnabled(); } void setLowEnabled(bool yes) { grid.setLowEnabled(yes); } + bool ciexyEnabled() const { return grid.ciexyEnabled(); } + void setciexyEnabled(bool yes) { grid.setciexyEnabled(yes); } }; diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc index 444a4d5b2..371c1892b 100644 --- a/rtgui/locallabtools.cc +++ b/rtgui/locallabtools.cc @@ -422,7 +422,7 @@ LocallabColor::LocallabColor(): chroma(Gtk::manage(new Adjuster(M("TP_LOCALLAB_CHROMA"), -100, 150, 1, 0))), curvactiv(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_CURV")))), gridFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_LABGRID")))), - labgrid(Gtk::manage(new LabGrid(EvLocallabLabGridValue, M("TP_LOCALLAB_LABGRID_VALUES")))), + labgrid(Gtk::manage(new LabGrid(EvLocallabLabGridValue, M("TP_LOCALLAB_LABGRID_VALUES"), true, false))), gridMethod(Gtk::manage(new MyComboBoxText())), strengthgrid(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRGRID"), 0, 100, 1, 30))), sensi(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSI"), 0, 100, 1, 15))), @@ -1139,8 +1139,8 @@ void LocallabColor::read(const rtengine::procparams::ProcParams* pp, const Param spot.labgridBLow / LocallabParams::LABGRIDL_CORR_MAX, spot.labgridAHigh / LocallabParams::LABGRIDL_CORR_MAX, spot.labgridBHigh / LocallabParams::LABGRIDL_CORR_MAX, - false); - + 0, 0, 0, 0, false); + // printf("labgridlow=%f \n", spot.labgridALow); if (spot.gridMethod == "one") { gridMethod->set_active(0); } else if (spot.gridMethod == "two") { @@ -1252,7 +1252,7 @@ void LocallabColor::read(const rtengine::procparams::ProcParams* pp, const Param labgridmerg->setParams(0, 0, spot.labgridAHighmerg / LocallabParams::LABGRIDL_CORR_MAX, spot.labgridBHighmerg / LocallabParams::LABGRIDL_CORR_MAX, - false); + 0, 0, 0, 0, false); merlucol->setValue(spot.merlucol); enaColorMask->set_active(spot.enaColorMask); CCmaskshape->setCurve(spot.CCmaskcurve); @@ -1310,10 +1310,12 @@ void LocallabColor::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pe spot.contrast = contrast->getIntValue(); spot.chroma = chroma->getIntValue(); spot.curvactiv = curvactiv->get_active(); + double zerox = 0.; + double zeroy = 0.; labgrid->getParams(spot.labgridALow, spot.labgridBLow, spot.labgridAHigh, - spot.labgridBHigh); + spot.labgridBHigh, zerox, zeroy, zerox, zeroy); spot.labgridALow *= LocallabParams::LABGRIDL_CORR_MAX; spot.labgridAHigh *= LocallabParams::LABGRIDL_CORR_MAX; spot.labgridBLow *= LocallabParams::LABGRIDL_CORR_MAX; @@ -1427,10 +1429,12 @@ void LocallabColor::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pe spot.mercol = mercol->getValue(); spot.opacol = opacol->getValue(); spot.conthrcol = conthrcol->getValue(); + double zerox1 = 0.; + double zeroy1 = 0.; labgridmerg->getParams(spot.labgridALowmerg, spot.labgridBLowmerg, spot.labgridAHighmerg, - spot.labgridBHighmerg); + spot.labgridBHighmerg, zerox1, zeroy1, zerox1, zeroy1); spot.labgridALowmerg *= LocallabParams::LABGRIDL_CORR_MAX; spot.labgridAHighmerg *= LocallabParams::LABGRIDL_CORR_MAX; spot.labgridBLowmerg *= LocallabParams::LABGRIDL_CORR_MAX; @@ -1476,7 +1480,7 @@ void LocallabColor::setDefaults(const rtengine::procparams::ProcParams* defParam labgrid->setDefault(defSpot.labgridALow / LocallabParams::LABGRIDL_CORR_MAX, defSpot.labgridBLow / LocallabParams::LABGRIDL_CORR_MAX, defSpot.labgridAHigh / LocallabParams::LABGRIDL_CORR_MAX, - defSpot.labgridBHigh / LocallabParams::LABGRIDL_CORR_MAX); + defSpot.labgridBHigh / LocallabParams::LABGRIDL_CORR_MAX, 0, 0, 0, 0); strengthgrid->setDefault((double) defSpot.strengthgrid); sensi->setDefault((double)defSpot.sensi); structcol->setDefault((double)defSpot.structcol); @@ -1492,7 +1496,7 @@ void LocallabColor::setDefaults(const rtengine::procparams::ProcParams* defParam labgridmerg->setDefault(defSpot.labgridALowmerg / LocallabParams::LABGRIDL_CORR_MAX, defSpot.labgridBLowmerg / LocallabParams::LABGRIDL_CORR_MAX, defSpot.labgridAHighmerg / LocallabParams::LABGRIDL_CORR_MAX, - defSpot.labgridBHighmerg / LocallabParams::LABGRIDL_CORR_MAX); + defSpot.labgridBHighmerg / LocallabParams::LABGRIDL_CORR_MAX, 0, 0, 0, 0); merlucol->setDefault(defSpot.merlucol); strumaskcol->setDefault(defSpot.strumaskcol); contcol->setDefault(defSpot.contcol); @@ -1962,7 +1966,7 @@ void LocallabColor::convertParamToNormal() labgridmerg->setParams(0, 0, defSpot.labgridAHighmerg / LocallabParams::LABGRIDL_CORR_MAX, defSpot.labgridBHighmerg / LocallabParams::LABGRIDL_CORR_MAX, - false); + 0, 0, 0, 0, false); merlucol->setValue(defSpot.merlucol); strumaskcol->setValue(defSpot.strumaskcol); toolcol->set_active(defSpot.toolcol); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index d6808cf38..f6ad44605 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -439,7 +439,26 @@ void ParamsEdited::set(bool v) icm.outputBPC = v; icm.workingTRCGamma = v; icm.workingTRCSlope = v; + icm.redx = v; + icm.redy = v; + icm.grex = v; + icm.grey = v; + icm.blux = v; + icm.bluy = v; + icm.preser = v; + icm.fbw = v; + icm.labgridcieALow = v; + icm.labgridcieBLow = v; + icm.labgridcieAHigh = v; + icm.labgridcieBHigh = v; + icm.labgridcieGx = v; + icm.labgridcieGy = v; + icm.labgridcieWx = v; + icm.labgridcieWy = v; + icm.aRendIntent = v; icm.workingTRC = v; + icm.will = v; + icm.wprim = v; raw.bayersensor.method = v; raw.bayersensor.border = v; raw.bayersensor.imageNum = v; @@ -1709,7 +1728,26 @@ void ParamsEdited::initFrom(const std::vector& icm.outputBPC = icm.outputBPC && p.icm.outputBPC == other.icm.outputBPC ; icm.workingTRCGamma = icm.workingTRCGamma && p.icm.workingTRCGamma == other.icm.workingTRCGamma; icm.workingTRCSlope = icm.workingTRCSlope && p.icm.workingTRCSlope == other.icm.workingTRCSlope; + icm.redx = icm.redx && p.icm.redx == other.icm.redx; + icm.redy = icm.redy && p.icm.redy == other.icm.redy; + icm.grex = icm.grex && p.icm.grex == other.icm.grex; + icm.grey = icm.grey && p.icm.grey == other.icm.grey; + icm.blux = icm.blux && p.icm.blux == other.icm.blux; + icm.bluy = icm.bluy && p.icm.bluy == other.icm.bluy; + icm.labgridcieALow = icm.labgridcieALow && p.icm.labgridcieALow == other.icm.labgridcieALow; + icm.labgridcieBLow = icm.labgridcieBLow && p.icm.labgridcieBLow == other.icm.labgridcieBLow; + icm.labgridcieAHigh = icm.labgridcieAHigh && p.icm.labgridcieAHigh == other.icm.labgridcieAHigh; + icm.labgridcieBHigh = icm.labgridcieBHigh && p.icm.labgridcieBHigh == other.icm.labgridcieBHigh; + icm.labgridcieGx = icm.labgridcieGx && p.icm.labgridcieGx == other.icm.labgridcieGx; + icm.labgridcieGy = icm.labgridcieGy && p.icm.labgridcieGy == other.icm.labgridcieGy; + icm.labgridcieWx = icm.labgridcieWx && p.icm.labgridcieWx == other.icm.labgridcieWx; + icm.labgridcieWy = icm.labgridcieWy && p.icm.labgridcieWy == other.icm.labgridcieWy; + icm.preser = icm.preser && p.icm.preser == other.icm.preser; + icm.fbw = icm.fbw && p.icm.fbw == other.icm.fbw; + icm.aRendIntent = icm.aRendIntent && p.icm.aRendIntent == other.icm.aRendIntent; icm.workingTRC = icm.workingTRC && p.icm.workingTRC == other.icm.workingTRC; + icm.will = icm.will && p.icm.will == other.icm.will; + icm.wprim = icm.wprim && p.icm.wprim == other.icm.wprim; raw.bayersensor.method = raw.bayersensor.method && p.raw.bayersensor.method == other.raw.bayersensor.method; raw.bayersensor.border = raw.bayersensor.border && p.raw.bayersensor.border == other.raw.bayersensor.border; raw.bayersensor.imageNum = raw.bayersensor.imageNum && p.raw.bayersensor.imageNum == other.raw.bayersensor.imageNum; @@ -5722,10 +5760,86 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.icm.workingTRCSlope = mods.icm.workingTRCSlope; } + if (icm.redx) { + toEdit.icm.redx = mods.icm.redx; + } + + if (icm.redy) { + toEdit.icm.redy = mods.icm.redy; + } + + if (icm.grex) { + toEdit.icm.grex = mods.icm.grex; + } + + if (icm.grey) { + toEdit.icm.grey = mods.icm.grey; + } + + if (icm.blux) { + toEdit.icm.blux = mods.icm.blux; + } + + if (icm.bluy) { + toEdit.icm.bluy = mods.icm.bluy; + } + + if (icm.preser) { + toEdit.icm.preser = mods.icm.preser; + } + + if (icm.fbw) { + toEdit.icm.fbw = mods.icm.fbw; + } + + if (icm.labgridcieALow) { + toEdit.icm.labgridcieALow = mods.icm.labgridcieALow; + } + + if (icm.labgridcieBLow) { + toEdit.icm.labgridcieBLow = mods.icm.labgridcieBLow; + } + + if (icm.labgridcieAHigh) { + toEdit.icm.labgridcieAHigh = mods.icm.labgridcieAHigh; + } + + if (icm.labgridcieBHigh) { + toEdit.icm.labgridcieBHigh = mods.icm.labgridcieBHigh; + } + + if (icm.labgridcieGx) { + toEdit.icm.labgridcieGx = mods.icm.labgridcieGx; + } + + if (icm.labgridcieGy) { + toEdit.icm.labgridcieGy = mods.icm.labgridcieGy; + } + + if (icm.labgridcieWx) { + toEdit.icm.labgridcieWx = mods.icm.labgridcieWx; + } + + if (icm.labgridcieWy) { + toEdit.icm.labgridcieWy = mods.icm.labgridcieWy; + } + + if (icm.aRendIntent) { + toEdit.icm.aRendIntent = mods.icm.aRendIntent; + } + if (icm.workingTRC) { toEdit.icm.workingTRC = mods.icm.workingTRC; } + if (icm.will) { + toEdit.icm.will = mods.icm.will; + } + + if (icm.wprim) { + toEdit.icm.wprim = mods.icm.wprim; + } + if (raw.bayersensor.method) { toEdit.raw.bayersensor.method = mods.raw.bayersensor.method; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 7094f5492..09623ea1d 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -1099,7 +1099,25 @@ struct ColorManagementParamsEdited { bool workingTRC; bool workingTRCGamma; bool workingTRCSlope; - + bool will; + bool wprim; + bool redx; + bool redy; + bool grex; + bool grey; + bool blux; + bool bluy; + bool preser; + bool fbw; + bool labgridcieALow; + bool labgridcieBLow; + bool labgridcieAHigh; + bool labgridcieBHigh; + bool labgridcieGx; + bool labgridcieGy; + bool labgridcieWx; + bool labgridcieWy; + bool aRendIntent; bool outputProfile; bool outputIntent; bool outputBPC; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 920585aed..0866e970b 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -714,6 +714,7 @@ void ToolPanelCoordinator::initImage(rtengine::StagedImageProcessor* ipc_, bool ipc->setpdSharpenAutoRadiusListener (pdSharpening); ipc->setAutoWBListener(whitebalance); ipc->setAutoColorTonListener(colortoning); + ipc->setAutoprimListener(icm); ipc->setAutoChromaListener(dirpyrdenoise); ipc->setWaveletListener(wavelet); ipc->setRetinexListener(retinex); diff --git a/rtgui/wavelet.cc b/rtgui/wavelet.cc index 448141497..12d133bc8 100644 --- a/rtgui/wavelet.cc +++ b/rtgui/wavelet.cc @@ -1749,7 +1749,7 @@ void Wavelet::read(const ProcParams* pp, const ParamsEdited* pedited) strend->setValue(pp->wavelet.strend); detend->setValue(pp->wavelet.detend); thrend->setValue(pp->wavelet.thrend); - labgrid->setParams(pp->wavelet.labgridALow / WaveletParams::LABGRID_CORR_MAX, pp->wavelet.labgridBLow / WaveletParams::LABGRID_CORR_MAX, pp->wavelet.labgridAHigh / WaveletParams::LABGRID_CORR_MAX, pp->wavelet.labgridBHigh / WaveletParams::LABGRID_CORR_MAX, false); + labgrid->setParams(pp->wavelet.labgridALow / WaveletParams::LABGRID_CORR_MAX, pp->wavelet.labgridBLow / WaveletParams::LABGRID_CORR_MAX, pp->wavelet.labgridAHigh / WaveletParams::LABGRID_CORR_MAX, pp->wavelet.labgridBHigh / WaveletParams::LABGRID_CORR_MAX, 0, 0, 0, 0, false); sigm->setValue(pp->wavelet.sigm); levden->setValue(pp->wavelet.levden); @@ -2210,7 +2210,9 @@ void Wavelet::write(ProcParams* pp, ParamsEdited* pedited) pp->wavelet.ballum = ballum->getValue(); pp->wavelet.chromfi = chromfi->getValue(); pp->wavelet.chromco = chromco->getValue(); - labgrid->getParams(pp->wavelet.labgridALow, pp->wavelet.labgridBLow, pp->wavelet.labgridAHigh, pp->wavelet.labgridBHigh); + double zerox = 0.; + double zeroy = 0.; + labgrid->getParams(pp->wavelet.labgridALow, pp->wavelet.labgridBLow, pp->wavelet.labgridAHigh, pp->wavelet.labgridBHigh, zerox, zeroy, zerox, zeroy); pp->wavelet.labgridALow *= WaveletParams::LABGRID_CORR_MAX; pp->wavelet.labgridAHigh *= WaveletParams::LABGRID_CORR_MAX; pp->wavelet.labgridBLow *= WaveletParams::LABGRID_CORR_MAX; @@ -2670,7 +2672,7 @@ void Wavelet::setDefaults(const ProcParams* defParams, const ParamsEdited* pedit balchrom->setDefault(defParams->wavelet.balchrom); chromfi->setDefault(defParams->wavelet.chromfi); chromco->setDefault(defParams->wavelet.chromco); - labgrid->setDefault(defParams->wavelet.labgridALow / WaveletParams::LABGRID_CORR_MAX, defParams->wavelet.labgridBLow / WaveletParams::LABGRID_CORR_MAX, defParams->wavelet.labgridAHigh / WaveletParams::LABGRID_CORR_MAX, defParams->wavelet.labgridBHigh / WaveletParams::LABGRID_CORR_MAX); + labgrid->setDefault(defParams->wavelet.labgridALow / WaveletParams::LABGRID_CORR_MAX, defParams->wavelet.labgridBLow / WaveletParams::LABGRID_CORR_MAX, defParams->wavelet.labgridAHigh / WaveletParams::LABGRID_CORR_MAX, defParams->wavelet.labgridBHigh / WaveletParams::LABGRID_CORR_MAX, 0, 0, 0, 0); greenlow->setDefault(defParams->wavelet.greenlow); bluelow->setDefault(defParams->wavelet.bluelow); From 64248ab5cdb01631bf76be343a712dae154942e5 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 15 May 2021 22:54:15 -0700 Subject: [PATCH 079/135] Refresh thumbnail when en/disabling spot removal --- rtengine/improccoordinator.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index fa338a7dd..e7af18fa0 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -2458,6 +2458,7 @@ void ImProcCoordinator::process() || params->dehaze != nextParams->dehaze || params->pdsharpening != nextParams->pdsharpening || params->filmNegative != nextParams->filmNegative + || params->spot.enabled != nextParams->spot.enabled || sharpMaskChanged; sharpMaskChanged = false; From 907da2db96d2d1b403ecd10064aa8b90d761c4c7 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 15 May 2021 22:55:49 -0700 Subject: [PATCH 080/135] Fix spelling in spot removal tooltip --- rtdata/languages/default | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index bfe524b45..dd77e2946 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -3509,7 +3509,7 @@ TP_SOFTLIGHT_LABEL;Soft Light TP_SOFTLIGHT_STRENGTH;Strength TP_SPOT_COUNTLABEL;%1 point(s) TP_SPOT_ENTRYCHANGED;Point changed -TP_SPOT_HINT;Click on this button to be able to operate on the preview area.\n\nTo edit a spot, hover the white mark locating an edited aera, making the editing geometry appear.\n\nTo add a spot, press Ctrl and left mouse button, drag the circle (Ctrl key can be released) to a source location, then release the mouse button.\n\nTo move the source or destination spot, hover its center then drag it.\n\nThe inner circle (maximum effect area) and the "feather" circle can be resized by hovering them (the circle becomes orange) and draging it (the circle becomes red).\n\nWhen the changes are done, right click outside any spot to end the Spot editing mode, or click on this button again. +TP_SPOT_HINT;Click on this button to be able to operate on the preview area.\n\nTo edit a spot, hover the white mark locating an edited area, making the editing geometry appear.\n\nTo add a spot, press Ctrl and left mouse button, drag the circle (Ctrl key can be released) to a source location, then release the mouse button.\n\nTo move the source or destination spot, hover its center then drag it.\n\nThe inner circle (maximum effect area) and the "feather" circle can be resized by hovering them (the circle becomes orange) and dragging it (the circle becomes red).\n\nWhen the changes are done, right click outside any spot to end the Spot editing mode, or click on this button again. TP_SPOT_LABEL;Spot Removal TP_TM_FATTAL_AMOUNT;Amount TP_TM_FATTAL_ANCHOR;Anchor From 38075be8cc5682e73bb59ddd6f784c125a401f99 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 15 May 2021 23:49:25 -0700 Subject: [PATCH 081/135] Fix thumbnail spot removal with dehaze & film neg. --- rtengine/dcrop.cc | 2 +- rtengine/improccoordinator.cc | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index d33a2e8d3..ed7ec2495 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -750,7 +750,7 @@ void Crop::update(int todo) parent->imgsrc->getImage(parent->currWB, tr, f, pp, params.toneCurve, params.raw); parent->imgsrc->convertColorSpace(f, params.icm, parent->currWB); - if (params.dirpyrDenoise.enabled || params.filmNegative.enabled) { + if (params.dirpyrDenoise.enabled || params.filmNegative.enabled || params.spot.enabled) { // copy the denoised crop int oy = trafy / skip; int ox = trafx / skip; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 4490f4ba0..3b0a17bcb 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -346,6 +346,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) RAWParams rp = params->raw; ColorManagementParams cmp = params->icm; LCurveParams lcur = params->labCurve; + bool spotsDone = false; if (!highDetailNeeded) { // if below 100% magnification, take a fast path @@ -609,6 +610,13 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) ipf.setScale(scale); imgsrc->getImage(currWB, tr, orig_prev, pp, params->toneCurve, params->raw); + + if ((todo & M_SPOT) && params->spot.enabled && !params->spot.entries.empty()) { + spotsDone = true; + PreviewProps pp(0, 0, fw, fh, scale); + ipf.removeSpots(orig_prev, imgsrc, params->spot.entries, pp, currWB, nullptr, tr); + } + denoiseInfoStore.valid = false; //ColorTemp::CAT02 (orig_prev, ¶ms) ; // printf("orig_prevW=%d\n scale=%d",orig_prev->width, scale); @@ -680,7 +688,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) oprevi = orig_prev; - if (todo & M_SPOT) { + if ((todo & M_SPOT) && !spotsDone) { if (params->spot.enabled && !params->spot.entries.empty()) { allocCache(spotprev); orig_prev->copyData(spotprev); @@ -694,10 +702,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } if (spotprev) { - if (oprevi == orig_prev) { - oprevi = new Imagefloat(pW, pH); - } - spotprev->copyData(oprevi); + spotprev->copyData(orig_prev); } if ((todo & M_HDR) && (params->fattal.enabled || params->dehaze.enabled)) { From c075f84fce6884b5993f94b6d2ca33ca4805a303 Mon Sep 17 00:00:00 2001 From: Desmis Date: Sun, 16 May 2021 16:28:36 +0200 Subject: [PATCH 082/135] Improve french labels tooltips --- rtdata/languages/Francais | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 083bf654a..dce3aa6b7 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -2069,7 +2069,8 @@ TP_LOCALLAB_LOGLIGHTQ;Brillance (Q) TP_LOCALLAB_LOGLIGHTQ_TOOLTIP;Taux de perception de lumière émanant d'un stimulus.\nIndicateur qu'un stimulus apparaît être plus ou moins brillant, clair. TP_LOCALLAB_LOGLIN;Logarithme mode TP_LOCALLAB_LOGPFRA;Niveaux d'Exposition relatif -TP_LOCALLAB_LOGREPART;Force +TP_LOCALLAB_LOGREPART;Force globale +TP_LOCALLAB_LOGREPART_TOOLTIP;Vous permet d'ajuster le nivaeu de l'image 'codage log' par rapport à l'image originale.\nNe concerne pas la composante Ciecam. TP_LOCALLAB_LOGSATURL_TOOLTIP;Saturation (s) CIECAM16 correspond à la couleur d'un stimulus en relation avec sa propre brillance.\nAgit principalement sur les tons moyens et hauts. TP_LOCALLAB_LOGSCENE_TOOLTIP;Correspond aux conditions de prise de vue. TP_LOCALLAB_LOGSURSOUR_TOOLTIP;Change les tons et couleurs en prenant en compte les conditions de prise de vue.\n\nMoyen: Environnement lumineux moyen (standard). L'image ne change pas.\n\nTamisé: Environnement tamisé. L'iamge va devenir un peu plus claire. @@ -2244,6 +2245,12 @@ TP_LOCALLAB_RECURS_TOOLTIP;Recalcule les références pour teinte, luma, chroma TP_LOCALLAB_REFLABEL;Ref. (0..1) Chroma=%1 Luma=%2 teinte=%3 TP_LOCALLAB_REN_DIALOG_LAB;Entrer le nouveau nom de Spot TP_LOCALLAB_REN_DIALOG_NAME;Renomme le Controle Spot +TP_LOCALLAB_REPARW_TOOLTIP;Vous permet d'ajuster le niveau de l'image modifiée par Contraste local et Ondelettes par rapport à l'image originale. +TP_LOCALLAB_REPARCOL_TOOLTIP;Vous permet d'ajuster le niveau de l'image modifiée par Couleurs et lumiéres par rapport à l'image originale. +TP_LOCALLAB_REPARDEN_TOOLTIP;Vous permet d'ajuster le niveau de l'image modifiée par De-bruite par rapport à l'image originale. +TP_LOCALLAB_REPARSH_TOOLTIP;Vous permet d'ajuster le niveau de l'image modifiée Ombres et Lumières et Egaliseur par rapport à l'image originale.. +TP_LOCALLAB_REPAREXP_TOOLTIP;Vous permet d'ajuster le niveau de l'image modifiée par Compression dynammique et Exposition par rapport à l'image originale.. +TP_LOCALLAB_REPARTM_TOOLTIP;Vous permet d'ajuster le niveau de l'image modifiée par Compression tonale par rapport à l'image originale.. TP_LOCALLAB_RESETSHOW;Annuler Montrer Toutes les Modifications TP_LOCALLAB_RESID;Image Résiduelle TP_LOCALLAB_RESIDBLUR;Flouter Image Résiduelle From bd9704da80c61eeac999b7a4a16aefd3afc70243 Mon Sep 17 00:00:00 2001 From: Desmis Date: Mon, 17 May 2021 12:56:20 +0200 Subject: [PATCH 083/135] Change default primaries slider from Adobe to ProPhoto --- rtengine/procparams.cc | 12 ++++++------ rtgui/icmpanel.cc | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index d9ee8c55f..d2ea1748d 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2276,12 +2276,12 @@ ColorManagementParams::ColorManagementParams() : wprim(Primaries::DEFAULT), workingTRCGamma(2.4),//gamma sRGB workingTRCSlope(12.92), - redx(0.64), - redy(0.33), - grex(0.21), - grey(0.71), - blux(0.15), - bluy(0.06), + redx(0.7347), + redy(0.2653), + grex(0.1596), + grey(0.8404), + blux(0.0366), + bluy(0.0001), preser(0.), fbw(false), labgridcieALow(0.51763),//Prophoto red = (0.7347+0.1) * 1.81818 - 1 diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index 6e3b69904..b5fae1d61 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -284,17 +284,17 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha wprim->set_tooltip_text(M("TP_ICM_PRIMILLUM_TOOLTIP")); - redx = Gtk::manage(new Adjuster(M("TC_PRIM_REDX"), 0.41, 1.0, 0.0001, 0.6400)); + redx = Gtk::manage(new Adjuster(M("TC_PRIM_REDX"), 0.41, 1.0, 0.0001, 0.7347)); setExpandAlignProperties(redx, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - redy = Gtk::manage(new Adjuster(M("TC_PRIM_REDY"), 0.0, 0.70, 0.0001, 0.3300)); + redy = Gtk::manage(new Adjuster(M("TC_PRIM_REDY"), 0.0, 0.70, 0.0001, 0.2653)); setExpandAlignProperties(redy, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - grex = Gtk::manage(new Adjuster(M("TC_PRIM_GREX"), -0.1, 0.4, 0.0001, 0.2100)); + grex = Gtk::manage(new Adjuster(M("TC_PRIM_GREX"), -0.1, 0.4, 0.0001, 0.1596)); setExpandAlignProperties(grex, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - grey = Gtk::manage(new Adjuster(M("TC_PRIM_GREY"), 0.50, 1.0, 0.0001, 0.7100)); + grey = Gtk::manage(new Adjuster(M("TC_PRIM_GREY"), 0.50, 1.0, 0.0001, 0.8404)); setExpandAlignProperties(grey, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - blux = Gtk::manage(new Adjuster(M("TC_PRIM_BLUX"), -0.1, 0.4, 0.0001, 0.1500)); + blux = Gtk::manage(new Adjuster(M("TC_PRIM_BLUX"), -0.1, 0.4, 0.0001, 0.0366)); setExpandAlignProperties(blux, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - bluy = Gtk::manage(new Adjuster(M("TC_PRIM_BLUY"), -0.1, 0.5, 0.0001, 0.060)); + bluy = Gtk::manage(new Adjuster(M("TC_PRIM_BLUY"), -0.1, 0.5, 0.0001, 0.0001)); setExpandAlignProperties(bluy, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); redx->set_tooltip_text(M("TP_ICM_PRIMRED_TOOLTIP")); From 21020f18c2149f6bc8459ab543d6ecd0b532ee11 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Mon, 17 May 2021 22:14:51 -0700 Subject: [PATCH 084/135] Fix spot removal link line visual bug The link was showing upon creating a new spot where the source and target inner circles overlap. --- rtgui/spot.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 10ff99767..322ffe106 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -370,14 +370,13 @@ void Spot::updateGeometry() p2.set (targetCircle.radius, p.angle + 180); p3 = p2; link.end = targetCircle.center + p3; - link.setActive (true); + link.setActive (draggedSide == DraggedSide::NONE); } else { link.setActive (false); } sourceCircle.setVisible(draggedSide != DraggedSide::SOURCE); targetCircle.setVisible(draggedSide != DraggedSide::TARGET); - link.setVisible(draggedSide == DraggedSide::NONE); } else { targetCircle.setActive (false); targetMODisc.setActive (false); From be3579e933afae91948243952d632270d5fe6b04 Mon Sep 17 00:00:00 2001 From: Desmis Date: Tue, 18 May 2021 07:53:45 +0200 Subject: [PATCH 085/135] ICM - Abstract profile - Added reset button (#6243) * Added reset button * Added black and white to reset * Reenable tooltip Retinex * Reset illuminant to default --- rtdata/languages/default | 1 + rtgui/icmpanel.cc | 43 ++++++++++++++++++++++++++++++++++++++++ rtgui/icmpanel.h | 3 +++ 3 files changed, 47 insertions(+) diff --git a/rtdata/languages/default b/rtdata/languages/default index bdc470762..773f7768b 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2439,6 +2439,7 @@ TP_ICM_INPUTNONE_TOOLTIP;Use no input color profile at all.\nUse only in special TP_ICM_INPUTPROFILE;Input Profile TP_ICM_LABEL;Color Management TP_ICM_LABGRID_CIEXY;R(x)=%1 R(y)=%2\nG(x)=%3 G(y)=%4\nB(x)=%5 B(y)=%6 +TP_ICM_NEUTRAL;Reset TP_ICM_NOICM;No ICM: sRGB Output TP_ICM_OUTPUTPROFILE;Output Profile TP_ICM_OUTPUTPROFILE_TOOLTIP;By default all RTv4 or RTv2 profiles are with TRC - sRGB: g=2.4 s=12.92\n\nWith 'ICC Profile Creator' you can generate v4 or v2 profiles with the following choices;\n-Primaries: Aces AP0, Aces AP1, AdobeRGB, Prophoto, Rec2020, sRGB, Widegamut, BestRGB, BetaRGB, BruceRGB, Custom\n-TRC: BT709, sRGB, linear, standard g=2.2, standard g=1.8, Custom\n-Illuminant: D41, D50, D55, D60, D65, D80, stdA 2856K diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index b5fae1d61..46dac4b64 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -266,6 +266,17 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha trcProfVBox->pack_start(*wprimBox, Gtk::PACK_EXPAND_WIDGET); trcProfVBox->pack_start(*fbw, Gtk::PACK_EXPAND_WIDGET); + neutral = Gtk::manage (new Gtk::Button (M ("TP_ICM_NEUTRAL"))); + setExpandAlignProperties (neutral, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); + RTImage *resetImg = Gtk::manage (new RTImage ("undo-small.png", "redo-small.png")); + setExpandAlignProperties (resetImg, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); + neutral->set_image (*resetImg); + neutralconn = neutral->signal_pressed().connect ( sigc::mem_fun (*this, &ICMPanel::neutral_pressed) ); + neutral->show(); + + trcProfVBox->pack_start (*neutral); + + wprim->append(M("TP_ICM_WORKING_PRIM_NONE")); wprim->append(M("TP_ICM_WORKING_PRIM_SRGB")); wprim->append(M("TP_ICM_WORKING_PRIM_ADOB")); @@ -482,6 +493,38 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha show_all(); } +void ICMPanel::neutral_pressed () +{ //find working profile and set the same destination proile + if (wProfNames->get_active_text() == "Rec2020") { + wprim->set_active(toUnderlying(ColorManagementParams::Primaries::REC2020)); + } else if (wProfNames->get_active_text() == "sRGB") { + wprim->set_active(toUnderlying(ColorManagementParams::Primaries::SRGB)); + } else if (wProfNames->get_active_text() == "Adobe RGB") { + wprim->set_active(toUnderlying(ColorManagementParams::Primaries::ADOBE_RGB)); + } else if (wProfNames->get_active_text() == "ProPhoto") { + wprim->set_active(toUnderlying(ColorManagementParams::Primaries::PRO_PHOTO)); + } else if (wProfNames->get_active_text() == "ACESp1") { + wprim->set_active(toUnderlying(ColorManagementParams::Primaries::ACES_P1)); + } else if (wProfNames->get_active_text() == "WideGamut") { + wprim->set_active(toUnderlying(ColorManagementParams::Primaries::WIDE_GAMUT)); + } else if (wProfNames->get_active_text() == "ACESp0") { + wprim->set_active(toUnderlying(ColorManagementParams::Primaries::ACES_P0)); + } else if (wProfNames->get_active_text() == "BruceRGB") { + wprim->set_active(toUnderlying(ColorManagementParams::Primaries::BRUCE_RGB)); + } else if (wProfNames->get_active_text() == "Beta RGB") { + wprim->set_active(toUnderlying(ColorManagementParams::Primaries::BETA_RGB)); + } else if (wProfNames->get_active_text() == "BestRGB") { + wprim->set_active(toUnderlying(ColorManagementParams::Primaries::BEST_RGB)); + } + const ColorManagementParams defPar; + wGamma->setValue(defPar.workingTRCGamma);//2.4 + wSlope->setValue(defPar.workingTRCSlope);//12.92 + preser->setValue(defPar.preser); + fbw->set_active(defPar.fbw); + wTRC->set_active(toUnderlying(ColorManagementParams::WorkingTrc::NONE));//reset to none + will->set_active(toUnderlying(ColorManagementParams::Illuminant::DEFAULT));//reset to default - after wprim +} + void ICMPanel::updateRenderingIntent(const Glib::ustring &profile) { const uint8_t supportedIntents = rtengine::ICCStore::getInstance()->getOutputIntents(profile); diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index fb3673188..063da28d1 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -65,7 +65,9 @@ protected: Gtk::Label* blr; Gtk::Label* blg; Gtk::Label* blb; + Gtk::Button* neutral; + sigc::connection neutralconn; bool lastToneCurve; sigc::connection tcurveconn; bool lastApplyLookTable; @@ -185,6 +187,7 @@ public: void adjusterChanged(Adjuster* a, double newval) override; void primChanged (float rx, float ry, float bx, float by, float gx, float gy) override; void iprimChanged (float r_x, float r_y, float b_x, float b_y, float g_x, float g_y, float w_x, float w_y) override; + void neutral_pressed(); void wpChanged(); void wtrcinChanged(); From 8c49b240f59a6fc0fa85d0ef668d2fc1eb03919a Mon Sep 17 00:00:00 2001 From: Desmis Date: Thu, 20 May 2021 07:28:41 +0200 Subject: [PATCH 086/135] Fixed bad behavior abstract profile issue 6245 --- rtgui/icmpanel.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index 46dac4b64..c52807497 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -1354,6 +1354,8 @@ void ICMPanel::wtrcinChanged() wSlope->setValue(12.92); will->set_sensitive(false); willulab->set_sensitive(true); + wprim->set_sensitive(true); + fbw->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); riaHBox->set_sensitive(true); From f1f147a8268fc115f66d4e920e966aab4ba73603 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Thu, 20 May 2021 22:15:46 +0200 Subject: [PATCH 087/135] On-Preview Editing Widgets: Crashes, #6244 --- rtgui/cropwindow.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index a3e00c80a..5a1debb23 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -705,15 +705,15 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y) state = SNormal; needRedraw = true; } else if (state == SEditDrag1 || state == SEditDrag2 || state == SEditDrag3) { - if (state == SEditDrag1) { - needRedraw = editSubscriber->button1Released(); - } else if (state == SEditDrag2) { - needRedraw = editSubscriber->button2Released(); - } else if (state == SEditDrag3) { - needRedraw = editSubscriber->button3Released(); - } - if (editSubscriber) { + if (state == SEditDrag1) { + needRedraw = editSubscriber->button1Released(); + } else if (state == SEditDrag2) { + needRedraw = editSubscriber->button2Released(); + } else if (state == SEditDrag3) { + needRedraw = editSubscriber->button3Released(); + } + rtengine::Crop* crop = static_cast(cropHandler.getCrop()); Coord imgPos; action_x = x; From 8037a5da93b4881ad523f0088a6e407369bc6a4a Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Fri, 21 May 2021 09:46:57 +0200 Subject: [PATCH 088/135] fix SpotParams::operator == --- rtengine/procparams.cc | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index d2ea1748d..26c51e3c6 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -1727,17 +1727,7 @@ SpotParams::SpotParams() : bool SpotParams::operator ==(const SpotParams& other) const { - if (enabled != other.enabled || entries.size() != other.entries.size()) { - return false; - } - - size_t i = 0; - for (auto entry : entries) { - if (entry != other.entries[i]) { - return false; - } - } - return true; + return enabled == other.enabled && entries == other.entries; } bool SpotParams::operator !=(const SpotParams& other) const From c407fe1e913a41422d6020b918380373d7b0ff89 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Fri, 21 May 2021 13:02:58 +0200 Subject: [PATCH 089/135] raw crop for Pentax K3mkIII --- rtengine/camconst.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 909d19fd3..ffd646c20 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -2608,6 +2608,11 @@ Camera constants: } }, + { // Quality C + "make_model": ["RICOH PENTAX K-3 MARK III", "PENTAX K-3 MARK III"], + "raw_crop": [ 24, 34, -28, -14 ] + }, + { // Quality B, intermediate ISOs info missing "make_model": [ "RICOH PENTAX 645Z", "PENTAX 645Z" ], "dcraw_matrix": [ 9519,-3591,-664,-4074,11725,2671,-624,1501,6653 ], // adobe dcp d65 From c32623882428ed000fd887b346c13c7653524fcb Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Fri, 21 May 2021 13:11:59 +0200 Subject: [PATCH 090/135] white level for Fujifilm X-A20 --- rtengine/camconst.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index ffd646c20..d3d5a9280 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1399,6 +1399,11 @@ Camera constants: "ranges": { "white": 4050 } }, + { // Quality C + "make_model": "Fujifilm X-A20", + "ranges": { "white": 3838 } + }, + { // Quality B "make_model": [ "FUJIFILM X-T10", "FUJIFILM X-E2" ], "dcraw_matrix": [ 8458,-2451,-855,-4597,12447,2407,-1475,2482,6526 ], // DNG D65 From d2f3f903f00bab9d6ad42a72064d4b50c8857913 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Sat, 22 May 2021 09:07:45 +0200 Subject: [PATCH 091/135] Add reset button to whitebalance panel (back to Camera defaults). Fixes #5054 --- rtgui/whitebalance.cc | 13 +++++++++++++ rtgui/whitebalance.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/rtgui/whitebalance.cc b/rtgui/whitebalance.cc index ba8ad6157..150fef5c4 100644 --- a/rtgui/whitebalance.cc +++ b/rtgui/whitebalance.cc @@ -248,10 +248,17 @@ WhiteBalance::WhiteBalance () : FoldableToolPanel(this, "whitebalance", M("TP_WB std::vector cells = method->get_cells(); Gtk::CellRendererText* cellRenderer = dynamic_cast(cells.at(1)); cellRenderer->property_ellipsize() = Pango::ELLIPSIZE_MIDDLE; + + resetButton = Gtk::manage (new Gtk::Button()); // No label, keep it short + setExpandAlignProperties(resetButton, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + resetButton->set_relief(Gtk::RELIEF_NONE); + resetButton->get_style_context()->add_class(GTK_STYLE_CLASS_FLAT); + resetButton->set_image (*Gtk::manage (new RTImage ("undo-small.png"))); method->set_active (0); // Camera methodgrid->attach (*lab, 0, 0, 1, 1); methodgrid->attach (*method, 1, 0, 1, 1); + methodgrid->attach (*resetButton, 2, 0, 1, 1); pack_start (*methodgrid, Gtk::PACK_SHRINK, 0 ); opt = 0; @@ -362,6 +369,7 @@ WhiteBalance::WhiteBalance () : FoldableToolPanel(this, "whitebalance", M("TP_WB spotbutton->signal_pressed().connect( sigc::mem_fun(*this, &WhiteBalance::spotPressed) ); methconn = method->signal_changed().connect( sigc::mem_fun(*this, &WhiteBalance::optChanged) ); + resetButton->signal_pressed().connect( sigc::mem_fun(*this, &WhiteBalance::resetWB) ); spotsize->signal_changed().connect( sigc::mem_fun(*this, &WhiteBalance::spotSizeChanged) ); } @@ -828,6 +836,11 @@ void WhiteBalance::setWB (int vtemp, double vgreen) } +void WhiteBalance::resetWB () +{ + setActiveMethod("Camera"); +} + void WhiteBalance::setAdjusterBehavior (bool tempadd, bool greenadd, bool equaladd, bool tempbiasadd) { diff --git a/rtgui/whitebalance.h b/rtgui/whitebalance.h index 17e45e8bb..1ed99a2aa 100644 --- a/rtgui/whitebalance.h +++ b/rtgui/whitebalance.h @@ -65,6 +65,7 @@ protected: Glib::RefPtr refTreeModel; MethodColumns methodColumns; MyComboBox* method; + Gtk::Button* resetButton; MyComboBoxText* spotsize; Adjuster* temp; Adjuster* green; @@ -122,6 +123,7 @@ public: wblistener = l; } void setWB (int temp, double green); + void resetWB (); void WBChanged (double temp, double green, float studgood) override; void setAdjusterBehavior (bool tempadd, bool greenadd, bool equaladd, bool tempbiasadd); From 1cce9a4ad2184364787db80c9b4803f9bf40066e Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sat, 22 May 2021 11:09:26 +0200 Subject: [PATCH 092/135] cppcheck clean rtengine/imagesource.h --- rtengine/imagesource.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 25c024ed2..6cb279efc 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -171,7 +171,7 @@ public: outCurve = { 0.0 }; } - double getDirPyrDenoiseExpComp ( ) + double getDirPyrDenoiseExpComp () const { return dirpyrdenoiseExpComp; } From 954ce94e3f071f9aac428b87d4d64a68e6d0f720 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sat, 22 May 2021 11:15:35 +0200 Subject: [PATCH 093/135] cppcheck clean rtengine/EdgePreservingDecomposition.h --- rtengine/EdgePreservingDecomposition.cc | 2 +- rtengine/EdgePreservingDecomposition.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rtengine/EdgePreservingDecomposition.cc b/rtengine/EdgePreservingDecomposition.cc index 5ae023122..dcb05c29a 100644 --- a/rtengine/EdgePreservingDecomposition.cc +++ b/rtengine/EdgePreservingDecomposition.cc @@ -208,7 +208,7 @@ bool MultiDiagonalSymmetricMatrix::CreateDiagonal(int index, int StartRow) return true; } -inline int MultiDiagonalSymmetricMatrix::FindIndex(int StartRow) +inline int MultiDiagonalSymmetricMatrix::FindIndex(int StartRow) const { //There's GOT to be a better way to do this. "Bidirectional map?" // Issue 1895 : Changed start of loop from zero to one diff --git a/rtengine/EdgePreservingDecomposition.h b/rtengine/EdgePreservingDecomposition.h index c90123ed3..73a7b1732 100644 --- a/rtengine/EdgePreservingDecomposition.h +++ b/rtengine/EdgePreservingDecomposition.h @@ -97,7 +97,7 @@ public: int *StartRows; bool CreateDiagonal(int index, int StartRow); int n, m; //The matrix is n x n, with m diagonals on the lower triangle. Don't change these. They should be private but aren't for convenience. - inline int DiagonalLength(int StartRow) //Gives number of elements in a diagonal. + inline int DiagonalLength(int StartRow) const //Gives number of elements in a diagonal. { return n - StartRow; }; @@ -109,7 +109,7 @@ public: void VectorProduct(float *Product, float *x); //Given the start row, attempts to find the corresponding index, or -1 if the StartRow doesn't exist. - inline int FindIndex(int StartRow) __attribute__((always_inline)); + inline int FindIndex(int StartRow) const __attribute__((always_inline)); //This is the same as above, but designed to take this class as a pass through variable. By this way you can feed //the meat of this class into an independent function, such as SparseConjugateGradient. From 35064451d63ecdb97052907f8f711309c58a29ad Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sat, 22 May 2021 11:31:48 +0200 Subject: [PATCH 094/135] cppcheck clean rtengine/pipettebuffer.h --- rtengine/pipettebuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/pipettebuffer.h b/rtengine/pipettebuffer.h index 6f017a196..3c541cb31 100644 --- a/rtengine/pipettebuffer.h +++ b/rtengine/pipettebuffer.h @@ -58,7 +58,7 @@ public: ~PipetteBuffer(); /** @brief Getter to know if the pipette buffer is correctly filled */ - bool isReady() + bool isReady() const { return ready; } From 9972c2e990d5f605a24e744deaa19e6a966db0c7 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sat, 22 May 2021 11:32:10 +0200 Subject: [PATCH 095/135] cppcheck clean rtengine/badpixels.cc --- rtengine/badpixels.cc | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/rtengine/badpixels.cc b/rtengine/badpixels.cc index 97294bdf7..f04afb1ee 100644 --- a/rtengine/badpixels.cc +++ b/rtengine/badpixels.cc @@ -182,7 +182,7 @@ int RawImageSource::interpolateBadPixelsBayer(const PixelsMap &bitmapBads, array /* interpolateBadPixelsNcolors: correct raw pixels looking at the bitmap * takes into consideration if there are multiple bad pixels in the neighborhood */ -int RawImageSource::interpolateBadPixelsNColours(const PixelsMap &bitmapBads, const int colors) +int RawImageSource::interpolateBadPixelsNColours(const PixelsMap &bitmapBads, const int colours) { constexpr float eps = 1.f; int counter = 0; @@ -204,9 +204,9 @@ int RawImageSource::interpolateBadPixelsNColours(const PixelsMap &bitmapBads, co continue; } - float wtdsum[colors]; - float norm[colors]; - for (int c = 0; c < colors; ++c) { + float wtdsum[colours]; + float norm[colours]; + for (int c = 0; c < colours; ++c) { wtdsum[c] = norm[c] = 0.f; } @@ -216,41 +216,41 @@ int RawImageSource::interpolateBadPixelsNColours(const PixelsMap &bitmapBads, co continue; } - for (int c = 0; c < colors; ++c) { - const float dirwt = 0.70710678f / (fabsf(rawData[row - 1][(col + dx) * colors + c] - rawData[row + 1][(col - dx) * colors + c]) + eps); - wtdsum[c] += dirwt * (rawData[row - 1][(col + dx) * colors + c] + rawData[row + 1][(col - dx) * colors + c]); + for (int c = 0; c < colours; ++c) { + const float dirwt = 0.70710678f / (fabsf(rawData[row - 1][(col + dx) * colours + c] - rawData[row + 1][(col - dx) * colours + c]) + eps); + wtdsum[c] += dirwt * (rawData[row - 1][(col + dx) * colours + c] + rawData[row + 1][(col - dx) * colours + c]); norm[c] += dirwt; } } // horizontal interpolation if (!(bitmapBads.get(col - 1, row) || bitmapBads.get(col + 1, row))) { - for (int c = 0; c < colors; ++c) { - const float dirwt = 1.f / (fabsf(rawData[row][(col - 1) * colors + c] - rawData[row][(col + 1) * colors + c]) + eps); - wtdsum[c] += dirwt * (rawData[row][(col - 1) * colors + c] + rawData[row][(col + 1) * colors + c]); + for (int c = 0; c < colours; ++c) { + const float dirwt = 1.f / (fabsf(rawData[row][(col - 1) * colours + c] - rawData[row][(col + 1) * colours + c]) + eps); + wtdsum[c] += dirwt * (rawData[row][(col - 1) * colours + c] + rawData[row][(col + 1) * colours + c]); norm[c] += dirwt; } } // vertical interpolation if (!(bitmapBads.get(col, row - 1) || bitmapBads.get(col, row + 1))) { - for (int c = 0; c < colors; ++c) { - const float dirwt = 1.f / (fabsf(rawData[row - 1][col * colors + c] - rawData[row + 1][col * colors + c]) + eps); - wtdsum[c] += dirwt * (rawData[row - 1][col * colors + c] + rawData[row + 1][col * colors + c]); + for (int c = 0; c < colours; ++c) { + const float dirwt = 1.f / (fabsf(rawData[row - 1][col * colours + c] - rawData[row + 1][col * colours + c]) + eps); + wtdsum[c] += dirwt * (rawData[row - 1][col * colours + c] + rawData[row + 1][col * colours + c]); norm[c] += dirwt; } } if (LIKELY(norm[0] > 0.f)) { // This means, we found at least one pair of valid pixels in the steps above, likelihood of this case is about 99.999% - for (int c = 0; c < colors; ++c) { - rawData[row][col * colors + c] = wtdsum[c] / (2.f * norm[c]); //gradient weighted average, Factor of 2.f is an optimization to avoid multiplications in former steps + for (int c = 0; c < colours; ++c) { + rawData[row][col * colours + c] = wtdsum[c] / (2.f * norm[c]); //gradient weighted average, Factor of 2.f is an optimization to avoid multiplications in former steps } counter++; } else { //backup plan -- simple average. Same method for all channels. We could improve this, but it's really unlikely that this case happens int tot = 0; - float sum[colors]; - for (int c = 0; c < colors; ++c) { + float sum[colours]; + for (int c = 0; c < colours; ++c) { sum[c] = 0.f; } @@ -260,8 +260,8 @@ int RawImageSource::interpolateBadPixelsNColours(const PixelsMap &bitmapBads, co continue; } - for (int c = 0; c < colors; ++c) { - sum[c] += rawData[row + dy][(col + dx) * colors + c]; + for (int c = 0; c < colours; ++c) { + sum[c] += rawData[row + dy][(col + dx) * colours + c]; } tot++; @@ -269,8 +269,8 @@ int RawImageSource::interpolateBadPixelsNColours(const PixelsMap &bitmapBads, co } if (tot > 0) { - for (int c = 0; c < colors; ++c) { - rawData[row][col * colors + c] = sum[c] / tot; + for (int c = 0; c < colours; ++c) { + rawData[row][col * colours + c] = sum[c] / tot; } counter ++; From ce3c5d4cf1ef45f7520de288fb25a4ce902e9e91 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sat, 22 May 2021 12:26:46 +0200 Subject: [PATCH 096/135] cppcheck clean rtengine/dcp.h --- rtengine/dcp.cc | 4 ++-- rtengine/dcp.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 89256bba4..b65bb5f72 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -1768,7 +1768,7 @@ inline void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vect } } -bool DCPProfile::isValid() +bool DCPProfile::isValid() const { return valid; } @@ -1850,7 +1850,7 @@ void DCPStore::init(const Glib::ustring& rt_profile_dir, bool loadAll) } } -bool DCPStore::isValidDCPFileName(const Glib::ustring& filename) const +bool DCPStore::isValidDCPFileName(const Glib::ustring& filename) { if (!Glib::file_test(filename, Glib::FILE_TEST_EXISTS) || Glib::file_test(filename, Glib::FILE_TEST_IS_DIR)) { return false; diff --git a/rtengine/dcp.h b/rtengine/dcp.h index 573349348..2aec6da12 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -63,7 +63,7 @@ public: bool getHasBaselineExposureOffset() const; Illuminants getIlluminants() const; - bool isValid(); + bool isValid() const; void apply( Imagefloat* img, @@ -159,7 +159,7 @@ public: void init(const Glib::ustring& rt_profile_dir, bool loadAll = true); - bool isValidDCPFileName(const Glib::ustring& filename) const; + static bool isValidDCPFileName(const Glib::ustring& filename); DCPProfile* getProfile(const Glib::ustring& filename) const; DCPProfile* getStdProfile(const Glib::ustring& camShortName) const; From a749a1abb1bfb968429b2f0bcb4badb8515d34eb Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sat, 22 May 2021 12:43:52 +0200 Subject: [PATCH 097/135] cppcheck clean rtexif/rtexif.h --- rtexif/rtexif.cc | 2 +- rtexif/rtexif.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc index b3d31b950..a7125fb9a 100644 --- a/rtexif/rtexif.cc +++ b/rtexif/rtexif.cc @@ -139,7 +139,7 @@ TagDirectory* TagDirectory::getRoot() } } -const TagAttrib* TagDirectory::getAttrib (int id) +const TagAttrib* TagDirectory::getAttrib (int id) const { if (attribs) diff --git a/rtexif/rtexif.h b/rtexif/rtexif.h index dd89b70ce..7b2f8ad23 100644 --- a/rtexif/rtexif.h +++ b/rtexif/rtexif.h @@ -145,12 +145,12 @@ public: { return tags.size (); } - const TagAttrib* getAttrib (int id); + const TagAttrib* getAttrib (int id) const; // Find a Tag by scanning the whole tag tree and stopping at the first occurrence const TagAttrib* getAttrib (const char* name); // Try to get the Tag at a given location. 'name' is a path relative to this directory (e.g. "LensInfo/FocalLength") const TagAttrib* getAttribP (const char* name); - const TagAttrib* getAttribTable() + const TagAttrib* getAttribTable() const { return attribs; } @@ -321,7 +321,7 @@ public: Tag* clone (TagDirectory* parent) const; // to control if the tag shall be written - bool getKeep () + bool getKeep () const { return keep; } @@ -331,7 +331,7 @@ public: } // get subdirectory (there can be several, the last is NULL) - bool isDirectory () + bool isDirectory () const { return directory != nullptr; } @@ -340,7 +340,7 @@ public: return (directory) ? directory[i] : nullptr; } - MNKind getMakerNoteFormat () + MNKind getMakerNoteFormat () const { return makerNoteKind; } From ce3ab707f2e8b94ef8f5f1249c948387eb4fc84a Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sat, 22 May 2021 21:50:38 +0200 Subject: [PATCH 098/135] cppcheck clean rtengine/dcrop.* --- rtengine/dcrop.cc | 25 ++++++++++--------------- rtengine/dcrop.h | 2 +- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 465fc8dd7..09e420c8e 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -98,7 +98,7 @@ void Crop::setListener(DetailedCropListener* il) } } -EditUniqueID Crop::getCurrEditID() +EditUniqueID Crop::getCurrEditID() const { const EditSubscriber *subscriber = PipetteBuffer::dataProvider ? PipetteBuffer::dataProvider->getCurrSubscriber() : nullptr; return subscriber ? subscriber->getEditID() : EUID_None; @@ -1168,20 +1168,15 @@ void Crop::update(int todo) } if (todo & M_RGBCURVE) { - Imagefloat *workingCrop = baseCrop; double rrm, ggm, bbm; DCPProfileApplyState as; DCPProfile *dcpProf = parent->imgsrc->getDCP(params.icm, as); LUTu histToneCurve; - parent->ipf.rgbProc (workingCrop, laboCrop, this, parent->hltonecurve, parent->shtonecurve, parent->tonecurve, + parent->ipf.rgbProc (baseCrop, laboCrop, this, parent->hltonecurve, parent->shtonecurve, parent->tonecurve, params.toneCurve.saturation, parent->rCurve, parent->gCurve, parent->bCurve, parent->colourToningSatLimit, parent->colourToningSatLimitOpacity, parent->ctColorCurve, parent->ctOpacityCurve, parent->opautili, parent->clToningcurve, parent->cl2Toningcurve, parent->customToneCurve1, parent->customToneCurve2, parent->beforeToneCurveBW, parent->afterToneCurveBW, rrm, ggm, bbm, parent->bwAutoR, parent->bwAutoG, parent->bwAutoB, dcpProf, as, histToneCurve); - - if (workingCrop != baseCrop) { - delete workingCrop; - } } // apply luminance operations @@ -1516,10 +1511,10 @@ void Crop::update(int todo) Glib::ustring prof = params.icm.workingProfile; - cmsHTRANSFORM dummy = nullptr; + cmsHTRANSFORM cmsDummy = nullptr; int ill = 0; - parent->ipf.workingtrc(tmpImage1.get(), tmpImage1.get(), GW, GH, -5, prof, 2.4, 12.92310, ill, 0, dummy, true, false, false); - parent->ipf.workingtrc(tmpImage1.get(), tmpImage1.get(), GW, GH, 5, prof, gamtone, slotone, illum, prim, dummy, false, true, true); + parent->ipf.workingtrc(tmpImage1.get(), tmpImage1.get(), GW, GH, -5, prof, 2.4, 12.92310, ill, 0, cmsDummy, true, false, false); + parent->ipf.workingtrc(tmpImage1.get(), tmpImage1.get(), GW, GH, 5, prof, gamtone, slotone, illum, prim, cmsDummy, false, true, true); parent->ipf.rgb2lab(*tmpImage1, *labnCrop, params.icm.workingProfile); //labnCrop and provis @@ -1684,7 +1679,7 @@ bool check_need_larger_crop_for_lcp_distortion(int fw, int fh, int x, int y, int * If the scale changes, this method will free all buffers and reallocate ones of the new size. * It will then tell to the SizeListener that size has changed (sizeChanged) */ -bool Crop::setCropSizes(int rcx, int rcy, int rcw, int rch, int skip, bool internal) +bool Crop::setCropSizes(int cropX, int cropY, int cropW, int cropH, int skip, bool internal) { if (!internal) { @@ -1693,10 +1688,10 @@ bool Crop::setCropSizes(int rcx, int rcy, int rcw, int rch, int skip, bool inter bool changed = false; - rqcropx = rcx; - rqcropy = rcy; - rqcropw = rcw; - rqcroph = rch; + rqcropx = cropX; + rqcropy = cropY; + rqcropw = cropW; + rqcroph = cropH; // store and set requested crop size int rqx1 = LIM(rqcropx, 0, parent->fullw - 1); diff --git a/rtengine/dcrop.h b/rtengine/dcrop.h index 361f0462d..19d84c3f3 100644 --- a/rtengine/dcrop.h +++ b/rtengine/dcrop.h @@ -65,7 +65,7 @@ protected: MyMutex cropMutex; ImProcCoordinator* const parent; const bool isDetailWindow; - EditUniqueID getCurrEditID(); + EditUniqueID getCurrEditID() const; bool setCropSizes(int cropX, int cropY, int cropW, int cropH, int skip, bool internal); void freeAll(); From 99f2a878197233b3ded77ed0e4342695d56c3595 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sat, 22 May 2021 22:16:22 +0200 Subject: [PATCH 099/135] added matrix for Pentax K3mkIII, taken from ART --- rtengine/camconst.json | 1 + 1 file changed, 1 insertion(+) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index d3d5a9280..3f21449e6 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -2615,6 +2615,7 @@ Camera constants: { // Quality C "make_model": ["RICOH PENTAX K-3 MARK III", "PENTAX K-3 MARK III"], + "dcraw_matrix" : [7003, -1618, -887, -4614, 12728, 2065, -645, 1441, 5734], "raw_crop": [ 24, 34, -28, -14 ] }, From 36f1300a6b39f5addb3aa47f156582089d8de375 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 22 May 2021 15:50:35 -0700 Subject: [PATCH 100/135] Fix control line edit crash when undoing history When perspective control line editing is active and the history entry is changed such that edit mode is automatically disabled, there is a crash. The history change triggers a processing parameters update and disables editing. When editing is disabled, the perspective tool also tries to update the processing parameters, causing a double mutex lock attempt. This commit avoids updating parameters from the perspective tool and uses the tweak operator (introduced with the spot removal tool) to achieve the same effect. Closes #6251. --- rtgui/lensgeomlistener.h | 1 - rtgui/perspective.cc | 15 +++++++++++---- rtgui/perspective.h | 3 +++ rtgui/toolpanelcoord.cc | 10 ---------- rtgui/toolpanelcoord.h | 1 - 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/rtgui/lensgeomlistener.h b/rtgui/lensgeomlistener.h index b9979f9a2..7f437c170 100644 --- a/rtgui/lensgeomlistener.h +++ b/rtgui/lensgeomlistener.h @@ -35,5 +35,4 @@ public: virtual void autoCropRequested () = 0; virtual double autoDistorRequested () = 0; virtual void autoPerspRequested (bool corr_pitch, bool corr_yaw, double& rot, double& pitch, double& yaw, const std::vector *lines = nullptr) = 0; - virtual void updateTransformPreviewRequested (rtengine::ProcEvent event, bool render_perspective) = 0; }; diff --git a/rtgui/perspective.cc b/rtgui/perspective.cc index b3fabd31a..8db91ee2e 100644 --- a/rtgui/perspective.cc +++ b/rtgui/perspective.cc @@ -543,6 +543,11 @@ void PerspCorrection::applyControlLines(void) adjusterChanged(camera_pitch, pitch); } +void PerspCorrection::tweakParams(rtengine::procparams::ProcParams &pparams) +{ + pparams.perspective.render = render; +} + void PerspCorrection::autoCorrectionPressed(Gtk::Button* b) { if (!lens_geom_listener) { @@ -754,8 +759,9 @@ void PerspCorrection::linesEditButtonPressed(void) lines->setActive(true); lines->setDrawMode(true); render = false; - if (lens_geom_listener) { - lens_geom_listener->updateTransformPreviewRequested(EvPerspRender, false); + if (listener) { + listener->setTweakOperator(this); + listener->refreshPreview(EvPerspRender); } lines_button_apply->set_sensitive(true); lines_button_erase->set_sensitive(true); @@ -768,8 +774,9 @@ void PerspCorrection::linesEditButtonPressed(void) lines_button_apply->set_sensitive(false); lines_button_erase->set_sensitive(false); render = true; - if (lens_geom_listener) { - lens_geom_listener->updateTransformPreviewRequested(EvPerspRender, true); + if (listener) { + listener->unsetTweakOperator(this); + listener->refreshPreview(EvPerspRender); } lines->setDrawMode(false); lines->setActive(false); diff --git a/rtgui/perspective.h b/rtgui/perspective.h index 3c677ba6e..6f4a4ff52 100644 --- a/rtgui/perspective.h +++ b/rtgui/perspective.h @@ -24,6 +24,7 @@ #include "controllines.h" #include "lensgeomlistener.h" #include "toolpanel.h" +#include "../rtengine/tweakoperator.h" class PerspCorrectionPanelListener { @@ -34,6 +35,7 @@ public: }; class PerspCorrection final : + public rtengine::TweakOperator, public ToolParamBlock, public AdjusterListener, public FoldableToolPanel @@ -91,6 +93,7 @@ protected: const rtengine::FramesMetaData* metadata; void applyControlLines (void); + void tweakParams(rtengine::procparams::ProcParams &pparams) override; void setCamBasedEventsActive (bool active = true); void setFocalLengthValue (const rtengine::procparams::ProcParams* pparams, const rtengine::FramesMetaData* metadata); diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 12e780cca..00fcb208d 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -1037,16 +1037,6 @@ double ToolPanelCoordinator::autoDistorRequested() return rtengine::ImProcFunctions::getAutoDistor(ipc->getInitialImage()->getFileName(), 400); } -void ToolPanelCoordinator::updateTransformPreviewRequested(rtengine::ProcEvent event, bool render_perspective) -{ - if (!ipc) { - return; - } - - ipc->beginUpdateParams()->perspective.render = render_perspective; - ipc->endUpdateParams(event); -} - void ToolPanelCoordinator::spotWBRequested(int size) { diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 28bfed5ab..13686d6e3 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -321,7 +321,6 @@ public: void autoCropRequested () override; void autoPerspRequested (bool corr_pitch, bool corr_yaw, double& rot, double& pitch, double& yaw, const std::vector *lines = nullptr) override; double autoDistorRequested () override; - void updateTransformPreviewRequested (rtengine::ProcEvent event, bool render_perspective) override; // spotwblistener interface void spotWBRequested (int size) override; From 76706ac2766d926d0df56d35c7ed400525f1917d Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 22 May 2021 17:35:22 -0700 Subject: [PATCH 101/135] Leave spot removal widgets in good state on commit Set the correct geometry states if edit mode is toggled off while a spot is being dragged. --- rtgui/spot.cc | 20 ++++++++++++++++++++ rtgui/spot.h | 1 + 2 files changed, 21 insertions(+) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 322ffe106..7facb8f93 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -185,6 +185,25 @@ void Spot::resetPressed() } } +/** + * Release anything that's currently being dragged. + */ +void Spot::releaseEdit() +{ + Geometry *loGeom = getVisibleGeometryFromMO (lastObject); + + if (!loGeom) { + EditSubscriber::action = EditSubscriber::Action::NONE; + return; + } + + loGeom->state = Geometry::ACTIVE; + sourceIcon.state = Geometry::ACTIVE; + EditSubscriber::action = EditSubscriber::Action::NONE; + draggedSide = DraggedSide::NONE; + updateGeometry(); +} + void Spot::setBatchMode (bool batchMode) { ToolPanel::setBatchMode (batchMode); @@ -237,6 +256,7 @@ void Spot::editToggled () listener->refreshPreview(EvSpotEnabledOPA); // reprocess the preview w/o creating History entry subscribe(); } else { + releaseEdit(); unsubscribe(); listener->unsetTweakOperator(this); listener->refreshPreview(EvSpotEnabled); // reprocess the preview w/o creating History entry diff --git a/rtgui/spot.h b/rtgui/spot.h index db1fdac05..85cefa4c2 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -82,6 +82,7 @@ private: void addNewEntry (); void deleteSelectedEntry (); void resetPressed (); + void releaseEdit(); protected: Gtk::Box* labelBox; From a5de8920fba653ffc66919e9c2b46933a510e12a Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 22 May 2021 17:51:54 -0700 Subject: [PATCH 102/135] Fix crash when resetting spot removal with drag Do not attempt to update non-existent spots immediately after resetting the spot removal tool. --- rtgui/spot.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 7facb8f93..9911a9595 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -172,6 +172,7 @@ void Spot::resetPressed() } } else { if (!spots.empty()) { + EditSubscriber::action = EditSubscriber::Action::NONE; spots.clear(); activeSpot = -1; lastObject = -1; @@ -657,6 +658,10 @@ bool Spot::button3Released() bool Spot::drag1 (int modifierKey) { + if (EditSubscriber::action != EditSubscriber::Action::DRAGGING) { + return false; + } + EditDataProvider *editProvider = getEditProvider(); int imW, imH; editProvider->getImageSize (imW, imH); @@ -738,6 +743,10 @@ bool Spot::drag1 (int modifierKey) bool Spot::drag3 (int modifierKey) { + if (EditSubscriber::action != EditSubscriber::Action::DRAGGING) { + return false; + } + EditDataProvider *editProvider = getEditProvider(); int imW, imH; editProvider->getImageSize (imW, imH); From 3ade11c970a48dcb0be4955c6fba7e2a8fd0869b Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 22 May 2021 18:17:30 -0700 Subject: [PATCH 103/135] Leave control lines in good state on commit When exiting perspective control line editing mode while dragging a control line, set the geometry and control line state to the appropriate state corresponding to when lines are not being dragged. --- rtgui/controllines.cc | 18 ++++++++++++++++++ rtgui/controllines.h | 2 ++ rtgui/perspective.cc | 1 + 3 files changed, 21 insertions(+) diff --git a/rtgui/controllines.cc b/rtgui/controllines.cc index c078b4322..5918a75cb 100644 --- a/rtgui/controllines.cc +++ b/rtgui/controllines.cc @@ -199,6 +199,10 @@ bool ControlLineManager::pick3(bool picked) bool ControlLineManager::drag1(int modifierKey) { + if (action != Action::DRAGGING) { + return false; + } + EditDataProvider* provider = getEditProvider(); if (!provider || selected_object < 1) { @@ -263,6 +267,20 @@ bool ControlLineManager::drag1(int modifierKey) return false; } +void ControlLineManager::releaseEdit(void) +{ + action = Action::NONE; + + if (selected_object > 0) { + mouseOverGeometry[selected_object]->state = Geometry::NORMAL; + } + + edited = true; + callbacks->lineChanged(); + drawing_line = false; + selected_object = -1; +} + bool ControlLineManager::getEdited(void) const { return edited; diff --git a/rtgui/controllines.h b/rtgui/controllines.h index 2b2d179a4..a045eedd7 100644 --- a/rtgui/controllines.h +++ b/rtgui/controllines.h @@ -87,6 +87,8 @@ public: ~ControlLineManager(); bool getEdited(void) const; + /** Release anything that is currently being dragged. */ + void releaseEdit(void); void removeAll(void); /** Sets whether or not the lines are visible and interact-able. */ void setActive(bool active); diff --git a/rtgui/perspective.cc b/rtgui/perspective.cc index 8db91ee2e..fb4797ae4 100644 --- a/rtgui/perspective.cc +++ b/rtgui/perspective.cc @@ -778,6 +778,7 @@ void PerspCorrection::linesEditButtonPressed(void) listener->unsetTweakOperator(this); listener->refreshPreview(EvPerspRender); } + lines->releaseEdit(); lines->setDrawMode(false); lines->setActive(false); if (panel_listener) { From c9e58fea544dc18897cc0061194d0f8c89629793 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sun, 23 May 2021 14:35:59 +0200 Subject: [PATCH 104/135] cppcheck clean rtgui/thumbnail.* --- rtgui/thumbnail.cc | 22 ++++------------------ rtgui/thumbnail.h | 9 ++++----- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 324a0c0c1..cc8e9ad81 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -194,7 +194,7 @@ void Thumbnail::_generateThumbnailImage () } } -bool Thumbnail::isSupported () +bool Thumbnail::isSupported () const { return cfs.supported; } @@ -655,7 +655,7 @@ void Thumbnail::getFinalSize (const rtengine::procparams::ProcParams& pparams, i } } -void Thumbnail::getOriginalSize (int& w, int& h) +void Thumbnail::getOriginalSize (int& w, int& h) const { w = tw; h = th; @@ -784,7 +784,7 @@ void Thumbnail::getAutoWB (double& temp, double& green, double equal, double tem } -ThFileType Thumbnail::getType () +ThFileType Thumbnail::getType () const { return (ThFileType) cfs.format; @@ -909,20 +909,6 @@ void Thumbnail::_loadThumbnail(bool firstTrial) } } -/* - * Read all thumbnail's data from the cache; build and save them if doesn't exist - MUTEX PROTECTED - * This includes: - * - image's bitmap (*.rtti) - * - auto exposure's histogram (full thumbnail only) - * - embedded profile (full thumbnail only) - * - LiveThumbData section of the data file - */ -void Thumbnail::loadThumbnail (bool firstTrial) -{ - MyMutex::MyLock lock(mutex); - _loadThumbnail(firstTrial); -} - /* * Save thumbnail's data to the cache - NON PROTECTED * This includes: @@ -1178,7 +1164,7 @@ void Thumbnail::applyAutoExp (rtengine::procparams::ProcParams& pparams) } } -const CacheImageData* Thumbnail::getCacheImageData() +const CacheImageData* Thumbnail::getCacheImageData() const { return &cfs; } diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index aee5ee0a6..cda69f030 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -83,7 +83,6 @@ class Thumbnail void _saveThumbnail (); void _generateThumbnailImage (); int infoFromImage (const Glib::ustring& fname, std::unique_ptr rml = nullptr); - void loadThumbnail (bool firstTrial = true); void generateExifDateTimeStrings (); Glib::ustring getCacheFileName (const Glib::ustring& subdir, const Glib::ustring& fext) const; @@ -121,7 +120,7 @@ public: rtengine::IImage8* upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale); void getThumbnailSize (int &w, int &h, const rtengine::procparams::ProcParams *pparams = nullptr); void getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h); - void getOriginalSize (int& w, int& h); + void getOriginalSize (int& w, int& h) const; const Glib::ustring& getExifString () const; const Glib::ustring& getDateTimeString () const; @@ -130,16 +129,16 @@ public: void getSpotWB (int x, int y, int rect, double& temp, double& green); void applyAutoExp (rtengine::procparams::ProcParams& pparams); - ThFileType getType (); + ThFileType getType () const; Glib::ustring getFileName () const { return fname; } void setFileName (const Glib::ustring &fn); - bool isSupported (); + bool isSupported () const; - const CacheImageData* getCacheImageData(); + const CacheImageData* getCacheImageData() const; std::string getMD5 () const; int getRank () const; From 2f2720b763eb15118d4150d97c4e21ebcb497de7 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Sun, 23 May 2021 14:37:26 +0200 Subject: [PATCH 105/135] Perspective tool: Strange amplification interaction with Local Adjustments, fixes #6252 --- rtengine/refreshmap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h index 05a8f7f44..b53252796 100644 --- a/rtengine/refreshmap.h +++ b/rtengine/refreshmap.h @@ -61,7 +61,7 @@ #define CAPTURESHARPEN (M_INIT|M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR|M_CSHARP) #define HDR (M_SPOT|M_LINDENOISE|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define SPOTADJUST (M_SPOT|M_HDR|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) -#define TRANSFORM (M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) +#define TRANSFORM (M_SPOT|M_HDR|M_TRANSFORM|M_BLURMAP|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define AUTOEXP (M_SPOT|M_HDR|M_AUTOEXP|M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define RGBCURVE (M_RGBCURVE|M_LUMACURVE|M_LUMINANCE|M_COLOR) #define LUMINANCECURVE (M_LUMACURVE|M_LUMINANCE|M_COLOR) From 4bc69dc30c2ae91394d281e65bda1d82d1b18c1a Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 23 May 2021 12:00:30 -0700 Subject: [PATCH 106/135] Leave gradient widget in good state on commit Stop highlighting the hovered or dragged geometry when disabling the widget. --- rtgui/gradient.cc | 14 ++++++++++++++ rtgui/gradient.h | 1 + 2 files changed, 15 insertions(+) diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc index 972105dd0..cfe626ca7 100644 --- a/rtgui/gradient.cc +++ b/rtgui/gradient.cc @@ -325,6 +325,7 @@ void Gradient::editToggled () if (edit->get_active()) { subscribe(); } else { + releaseEdit(); unsubscribe(); } } @@ -579,6 +580,19 @@ bool Gradient::drag1(int modifierKey) return false; } +void Gradient::releaseEdit() +{ + if (lastObject >= 0) { + if (lastObject == 2 || lastObject == 3) { + EditSubscriber::visibleGeometry.at(2)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at(3)->state = Geometry::NORMAL; + } else { + EditSubscriber::visibleGeometry.at(lastObject)->state = Geometry::NORMAL; + } + } + action = Action::NONE; +} + void Gradient::switchOffEditMode () { if (edit->get_active()) { diff --git a/rtgui/gradient.h b/rtgui/gradient.h index 139b281a8..dc0371932 100644 --- a/rtgui/gradient.h +++ b/rtgui/gradient.h @@ -35,6 +35,7 @@ protected: sigc::connection editConn; void editToggled (); + void releaseEdit(); public: From 051d69331f1582e039f6cec2be298e7c209a9423 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 23 May 2021 12:10:40 -0700 Subject: [PATCH 107/135] Fix control line and spot removal spot highlight Return the geometry color to normal (white) when exiting edit mode. --- rtgui/controllines.cc | 3 +++ rtgui/spot.cc | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/rtgui/controllines.cc b/rtgui/controllines.cc index 5918a75cb..c08fbd1d2 100644 --- a/rtgui/controllines.cc +++ b/rtgui/controllines.cc @@ -274,6 +274,9 @@ void ControlLineManager::releaseEdit(void) if (selected_object > 0) { mouseOverGeometry[selected_object]->state = Geometry::NORMAL; } + if (prev_obj > 0) { + visibleGeometry[prev_obj - 1]->state = Geometry::NORMAL; + } edited = true; callbacks->lineChanged(); diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 9911a9595..45fc3eec8 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -198,8 +198,8 @@ void Spot::releaseEdit() return; } - loGeom->state = Geometry::ACTIVE; - sourceIcon.state = Geometry::ACTIVE; + loGeom->state = Geometry::NORMAL; + sourceIcon.state = Geometry::NORMAL; EditSubscriber::action = EditSubscriber::Action::NONE; draggedSide = DraggedSide::NONE; updateGeometry(); From 56e634da81880e65ab9c8ff1605c717b9a2a1b32 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 23 May 2021 21:45:23 -0700 Subject: [PATCH 108/135] Improve control lines dragging behavior Fix control line not updating when dragging and allow dragging when starting with the mouse cursor outside the preview image area. --- rtgui/controllines.cc | 11 +++++++---- rtgui/cropwindow.cc | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/rtgui/controllines.cc b/rtgui/controllines.cc index c08fbd1d2..d321abd07 100644 --- a/rtgui/controllines.cc +++ b/rtgui/controllines.cc @@ -104,6 +104,9 @@ bool ControlLineManager::button1Pressed(int modifierKey) action = Action::DRAGGING; } } else if (draw_mode && (modifierKey & GDK_CONTROL_MASK)) { // Add new line. + if (object < 0) { + return false; + } addLine(dataProvider->posImage, dataProvider->posImage); drawing_line = true; selected_object = mouseOverGeometry.size() - 1; // Select endpoint. @@ -125,7 +128,7 @@ bool ControlLineManager::button1Released(void) callbacks->lineChanged(); drawing_line = false; selected_object = -1; - return false; + return true; } bool ControlLineManager::button3Pressed(int modifierKey) @@ -139,7 +142,7 @@ bool ControlLineManager::button3Pressed(int modifierKey) } action = Action::PICKING; - return false; + return true; } bool ControlLineManager::pick1(bool picked) @@ -194,7 +197,7 @@ bool ControlLineManager::pick3(bool picked) removeLine((provider->getObject() - 1) / ::ControlLine::OBJ_COUNT); prev_obj = -1; selected_object = -1; - return false; + return true; } bool ControlLineManager::drag1(int modifierKey) @@ -264,7 +267,7 @@ bool ControlLineManager::drag1(int modifierKey) autoSetLineType(selected_object); } - return false; + return true; } void ControlLineManager::releaseEdit(void) diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index 5a1debb23..b612de2e7 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -540,7 +540,7 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) action_y = 0; } - } else if (iarea->getToolMode () == TMHand) { // events outside of the image domain + } else if (iarea->getToolMode () == TMHand || iarea->getToolMode() == TMPerspective) { // events outside of the image domain EditSubscriber *editSubscriber = iarea->getCurrSubscriber(); if (editSubscriber && editSubscriber->getEditingType() == ET_OBJECTS) { From 3441854a19e6776b19f62781b0c01f32edd67101 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 23 May 2021 22:01:01 -0700 Subject: [PATCH 109/135] Prevent making spot removal spots outside image --- rtgui/spot.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 45fc3eec8..16e8cf391 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -567,6 +567,12 @@ bool Spot::button1Pressed (int modifierKey) if (editProvider) { if (lastObject == -1 && (modifierKey & GDK_CONTROL_MASK)) { + int imW, imH; + const auto startPos = editProvider->posImage; + editProvider->getImageSize(imW, imH); + if (startPos.x < 0 || startPos.y < 0 || startPos.x > imW || startPos.y > imH) { + return false; // Outside of image area. + } draggedSide = DraggedSide::SOURCE; addNewEntry(); EditSubscriber::action = EditSubscriber::Action::DRAGGING; From 6189a0e816cef3eefee7e35e3c1d82c2f7eed8ba Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Mon, 24 May 2021 08:00:09 +0200 Subject: [PATCH 110/135] Prevent crash when opening Canon RP files with different crop factor. Fixes #6255 --- rtengine/camconst.json | 38 ++++++++++++++++++++++++++++++++++++-- rtengine/dcraw.cc | 1 + 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 3f21449e6..0d50b35f7 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -531,10 +531,10 @@ Camera constants: } }, - { // Quality B, some missing scaling factors are safely guessed; assuming the RP is the same as the 6DII because they share sensors + { // Quality B, some missing scaling factors are safely guessed "make_model": [ "Canon EOS 6D Mark II", "Canon EOS RP" ], "dcraw_matrix": [ 6875,-970,-932,-4691,12459,2501,-874,1953,5809 ], // DNG v_9.12 D65 - "raw_crop": [ 120, 44, 6264, 4180 ], // fullraw size 6384x4224 useful 120,44,6264x4180 + "raw_crop": [ 120, 44, 6264, 4180 ], // fullraw size 6384x4224 useful 120,44,6264x4180 // TODO: See EOS RP // "raw_crop": [ 128, 52, 6248, 4168 ], // official jpeg crop 120+12,44+12,6240x4160 "masked_areas": [ 44, 4, 4220, 116 ], "ranges": { @@ -566,6 +566,40 @@ Camera constants: } }, + { // Quality B, taken from 6D Mark II because identical sensor (different matrix) + "make_model": "Canon EOS RP", + "dcraw_matrix": [ 8608,-2097,-1178,-5425,13265,2383,-1149,2238,5680 ], // DNG v13.2 + // Let dcraw handle crop, because camconst shouldn't override for diferent crop factors. See #6255 + "masked_areas": [ 44, 4, 4220, 116 ], // Potential problem for different crop factor as well + "ranges": { + "white": [ + { "iso": [ 50, 100, 125, 200, 250, 400, 500, 800, 1000, 1600, 2000, 3200 ], "levels": 16300 }, // typical 16383 + { "iso": [ 4000, 6400, 8000, 12800 ], "levels": 16200 }, // typical 16383 + { "iso": [ 16000, 25600 ], "levels": 16100 }, // typical 16383 + { "iso": [ 160 ], "levels": 13000 }, // typical 13044 + { "iso": [ 320, 640, 1250, 2500 ], "levels": 13250 }, // typical 13337 + { "iso": [ 5000, 10000 ], "levels": 13100 }, // typical 13367 + { "iso": [ 20000, 40000 ], "levels": 12900 }, // typical 13367 + { "iso": [ 51200, 102400 ], "levels": 15900 } // typical 16383 + ], + "white_max": 16383, + "aperture_scaling": [ + // no scale factors known for f/1.0 (had no lenses to test with), but the + // ISO 160-320... 13044 white levels maxes out at "white_max" for f/1.2 and below anyway. + { "aperture": 1.2, "scale_factor": 1.130 }, // guessed + { "aperture": 1.4, "scale_factor": 1.100 }, // guessed + { "aperture": 1.6, "scale_factor": 1.080 }, // guessed + { "aperture": 1.8, "scale_factor": 1.060 }, // 13890/13044=1.065 11284/10512 = 1.073 + { "aperture": 2.0, "scale_factor": 1.040 }, // 13602/13044=1.042 11151/10512 = 1.060 + { "aperture": 2.2, "scale_factor": 1.030 }, // 10982/10512=1.045 + { "aperture": 2.5, "scale_factor": 1.020 }, // 10840/10512 = 1.030 + { "aperture": 2.8, "scale_factor": 1.010 }, // 13530/13367= 1.012 - 12225/12048 = 1.015 + { "aperture": 3.2, "scale_factor": 1.005 }, // 12194/12048 = 1.012 + { "aperture": 3.5, "scale_factor": 1.000 } // 12092/12048 = 1.004 + ] + } + }, + { // Quality A, ISO and aperture WL data by CharlyW at RawTherapee forums, missing samples safely guessed "make_model": "Canon EOS 7D", "dcraw_matrix": [ 5962,-171,-732,-4189,12307,2099,-911,1981,6304 ], // Colin Walker diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index ea15cefbe..ef0b4e8dc 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -9175,6 +9175,7 @@ void CLASS identify() { 3944, 2622, 30, 18, 6, 2 }, { 3948, 2622, 42, 18, 0, 2 }, { 3984, 2622, 76, 20, 0, 2, 14 }, + { 4032, 2656, 112, 44, 10, 0 }, { 4104, 3048, 48, 12, 24, 12 }, { 4116, 2178, 4, 2, 0, 0 }, { 4152, 2772, 192, 12, 0, 0 }, From 6e68cab5d970191b92e03aa7da7e6b0be7d9a3e4 Mon Sep 17 00:00:00 2001 From: Desmis Date: Tue, 25 May 2021 09:05:04 +0200 Subject: [PATCH 111/135] Change range primaries ICC profile creator --- rtgui/iccprofilecreator.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rtgui/iccprofilecreator.cc b/rtgui/iccprofilecreator.cc index 3f1ed4089..b7e6bc20e 100644 --- a/rtgui/iccprofilecreator.cc +++ b/rtgui/iccprofilecreator.cc @@ -101,17 +101,17 @@ ICCProfileCreator::ICCProfileCreator(RTWindow *rtwindow) Gtk::Image* gamutl5 = Gtk::manage(new RTImage("rt-logo-small.png")); */ - aPrimariesRedX = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_PRIM_REDX"), 0.6300, 0.7350, 0.0001, 0.6400/*, gamuts0, gamutl0*/)); + aPrimariesRedX = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_PRIM_REDX"), 0.4100, 0.9000, 0.0001, 0.6400/*, gamuts0, gamutl0*/)); setExpandAlignProperties(aPrimariesRedX, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - aPrimariesRedY = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_PRIM_REDY"), 0.2650, 0.3350, 0.0001, 0.3300/*, gamutl1, gamuts1*/)); + aPrimariesRedY = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_PRIM_REDY"), 0.1000, 0.6000, 0.0001, 0.3300/*, gamutl1, gamuts1*/)); setExpandAlignProperties(aPrimariesRedY, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - aPrimariesGreenX = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_PRIM_GREX"), 0.0000, 0.3100, 0.0001, 0.3000/*, gamutl2, gamuts2*/)); + aPrimariesGreenX = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_PRIM_GREX"), -0.100, 0.4000, 0.0001, 0.3000/*, gamutl2, gamuts2*/)); setExpandAlignProperties(aPrimariesGreenX, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - aPrimariesGreenY = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_PRIM_GREY"), 0.5900, 1.0000, 0.0001, 0.6000/*, gamuts3, gamutl3*/)); + aPrimariesGreenY = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_PRIM_GREY"), 0.50, 1.0000, 0.0001, 0.6000/*, gamuts3, gamutl3*/)); setExpandAlignProperties(aPrimariesGreenY, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - aPrimariesBlueX = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_PRIM_BLUX"), 0.0001, 0.1600, 0.0001, 0.1500/*, gamutl4, gamuts4*/)); + aPrimariesBlueX = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_PRIM_BLUX"), -0.1, 0.3000, 0.0001, 0.1500/*, gamutl4, gamuts4*/)); setExpandAlignProperties(aPrimariesBlueX, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - aPrimariesBlueY = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_PRIM_BLUY"), -0.0800, 0.0700, 0.0001, 0.060/*, gamutl5, gamuts5*/)); + aPrimariesBlueY = Gtk::manage(new Adjuster(M("ICCPROFCREATOR_PRIM_BLUY"), -0.100, 0.4000, 0.0001, 0.060/*, gamutl5, gamuts5*/)); setExpandAlignProperties(aPrimariesBlueY, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); primariesGrid->attach(*aPrimariesRedX, 0, 0, 1, 1); From c01166441c1820628aba067ce8722226c6d5018b Mon Sep 17 00:00:00 2001 From: Desmis Date: Sat, 29 May 2021 11:39:06 +0200 Subject: [PATCH 112/135] Wavelet levels - and denoise - crash in some cases - issue 6264 (#6265) * Change order levwav for denoise * Intialize to zero multipliers contrast if not used * Forgotten commit * Clean code --- rtengine/ipwavelet.cc | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index caec5ec22..7abc7a48d 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -448,7 +448,11 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const for (int m = 0; m < maxmul; m++) { cp.mulC[m] = waparams.ch[m]; } - + for (int m = maxmul; m < 10; m++) { + cp.mulC[m] = 0.f; + } + +//printf("maxmul=%i\n", maxmul); cp.factor = WaveletParams::LABGRID_CORR_MAX * 3.276f; cp.scaling = WaveletParams::LABGRID_CORR_SCALE; cp.scaledirect = WaveletParams::LABGRIDL_DIRECT_SCALE; @@ -536,6 +540,9 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const for (int m = 0; m < maxmul; m++) { cp.mul[m] = waparams.c[m]; } + for (int m = maxmul; m < 10; m++) { + cp.mul[m] = 0.f; + } cp.mul[9] = (float) waparams.sup; @@ -1038,13 +1045,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const cp.mul[0] = 0.01f; } } - - - if (!exblurL && cp.contrast == 0.f && cp.blurres == 0.f && !cp.noiseena && !cp.tonemap && !cp.resena && !cp.chromena && !cp.toningena && !cp.finena && !cp.edgeena && cp.conres == 0.f && cp.conresH == 0.f && cp.val == 0 && !ref0 && params->wavelet.CLmethod == "all") { // no processing of residual L or edge=> we probably can reduce the number of levels - while (levwavL > 0 && cp.mul[levwavL - 1] == 0.f) { // cp.mul[level] == 0.f means no changes to level - levwavL--; - } - } + // printf("cp4=%f cpmul5=%f cp6=%f cp7=%f cp8=%f\n", (double)cp.mul[4], (double)cp.mul[5],(double)cp.mul[6],(double)cp.mul[7],(double)cp.mul[8]); if (levwavL == 6 && cp.noiseena && cp.chromfi == 0.f) { cp.chromfi = 0.01f; @@ -1055,12 +1056,17 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const levwavL = 7; } } - bool isdenoisL = (cp.lev0n > 0.1f || cp.lev1n > 0.1f || cp.lev2n > 0.1f || cp.lev3n > 0.1f || cp.lev4n > 0.1f); - if (levwavL < 5 && cp.noiseena) { levwavL = 6; //to allow edge and denoise => I always allocate 3 (4) levels..because if user select wavelet it is to do something !! } + if (!exblurL && cp.contrast == 0.f && cp.blurres == 0.f && !cp.noiseena && !cp.tonemap && !cp.resena && !cp.chromena && !cp.toningena && !cp.finena && !cp.edgeena && cp.conres == 0.f && cp.conresH == 0.f && cp.val == 0 && !ref0 && params->wavelet.CLmethod == "all") { // no processing of residual L or edge=> we probably can reduce the number of levels + while (levwavL > 0 && cp.mul[levwavL - 1] == 0.f) { // cp.mul[level] == 0.f means no changes to level + levwavL--; + } + } + bool isdenoisL = (cp.lev0n > 0.1f || cp.lev1n > 0.1f || cp.lev2n > 0.1f || cp.lev3n > 0.1f || cp.lev4n > 0.1f); + /* if(cp.denoicurvh || cp.levdenhigh > 0.01f) { From ef49d9eefd2a20b0dea22460163c0dada9c0c5f8 Mon Sep 17 00:00:00 2001 From: Desmis Date: Sun, 30 May 2021 07:53:19 +0200 Subject: [PATCH 113/135] Disable masks when tool is disable --- rtengine/iplocallab.cc | 2 +- rtgui/locallabtools.cc | 51 ++++++++++++++++++++++++++--------------- rtgui/locallabtools2.cc | 42 ++++++++++++++++++++++----------- 3 files changed, 61 insertions(+), 34 deletions(-) diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 00b379271..5b7160b83 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -4418,6 +4418,7 @@ void ImProcFunctions::retinex_pde(const float * datain, float * dataout, int bfw */ // BENCHFUN + #ifdef RT_FFTW3F_OMP if (multiThread) { fftwf_init_threads(); @@ -14140,7 +14141,6 @@ void ImProcFunctions::Lab_Local( if (lp.softmet == 0) { ImProcFunctions::softLight(bufexpfin.get(), softLightParams); } else if (lp.softmet == 1) { - const std::unique_ptr datain(new float[bfwr * bfhr]); const std::unique_ptr dataout(new float[bfwr * bfhr]); const std::unique_ptr dE(new float[bfwr * bfhr]); diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc index 371c1892b..45262bce3 100644 --- a/rtgui/locallabtools.cc +++ b/rtgui/locallabtools.cc @@ -2294,9 +2294,10 @@ void LocallabColor::showmaskcolMethodChanged() if (locToolListener) { locToolListener->resetOtherMaskView(this); } - - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } @@ -2311,9 +2312,10 @@ void LocallabColor::showmaskcolMethodChangedinv() if (locToolListener) { locToolListener->resetOtherMaskView(this); } - - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } @@ -3709,8 +3711,10 @@ void LocallabExposure::showmaskexpMethodChanged() locToolListener->resetOtherMaskView(this); } - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } @@ -3726,8 +3730,10 @@ void LocallabExposure::showmaskexpMethodChangedinv() locToolListener->resetOtherMaskView(this); } - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } @@ -4851,8 +4857,10 @@ void LocallabShadow::showmaskSHMethodChanged() locToolListener->resetOtherMaskView(this); } - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } @@ -4868,8 +4876,10 @@ void LocallabShadow::showmaskSHMethodChangedinv() locToolListener->resetOtherMaskView(this); } - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } @@ -5882,8 +5892,10 @@ void LocallabVibrance::showmaskvibMethodChanged() locToolListener->resetOtherMaskView(this); } - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } @@ -6289,9 +6301,10 @@ void LocallabSoft::showmasksoftMethodChanged() if (locToolListener) { locToolListener->resetOtherMaskView(this); } - - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } diff --git a/rtgui/locallabtools2.cc b/rtgui/locallabtools2.cc index f49667ff8..a4bce7301 100644 --- a/rtgui/locallabtools2.cc +++ b/rtgui/locallabtools2.cc @@ -741,8 +741,10 @@ void LocallabTone::showmasktmMethodChanged() locToolListener->resetOtherMaskView(this); } - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } @@ -1864,8 +1866,10 @@ void LocallabRetinex::showmaskretiMethodChanged() locToolListener->resetOtherMaskView(this); } - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } @@ -2318,8 +2322,10 @@ void LocallabSharp::showmasksharMethodChanged() locToolListener->resetOtherMaskView(this); } - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } @@ -4242,8 +4248,10 @@ void LocallabContrast::showmasklcMethodChanged() locToolListener->resetOtherMaskView(this); } - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } @@ -5073,8 +5081,10 @@ void LocallabCBDL::showmaskcbMethodChanged() locToolListener->resetOtherMaskView(this); } - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } @@ -5938,8 +5948,10 @@ void LocallabLog::showmaskLMethodChanged() locToolListener->resetOtherMaskView(this); } - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } @@ -7226,8 +7238,10 @@ void LocallabMask::showmask_MethodChanged() locToolListener->resetOtherMaskView(this); } - if (listener) { - listener->panelChanged(EvlocallabshowmaskMethod, ""); + if(exp->getEnabled()) { + if (listener) { + listener->panelChanged(EvlocallabshowmaskMethod, ""); + } } } From 5f88cf240e6412e8f1c1b1817867d2761c1070ad Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 30 May 2021 11:51:49 -0700 Subject: [PATCH 114/135] Use enums for on-preview geometry --- rtgui/controllines.cc | 130 +++++++++++++++++++++++++++++++----------- rtgui/controllines.h | 9 ++- rtgui/gradient.cc | 76 +++++++++++++----------- rtgui/spot.cc | 104 +++++++++++++++++++++------------ 4 files changed, 212 insertions(+), 107 deletions(-) diff --git a/rtgui/controllines.cc b/rtgui/controllines.cc index d321abd07..14454e2ef 100644 --- a/rtgui/controllines.cc +++ b/rtgui/controllines.cc @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include #include #include "controllines.h" @@ -27,6 +28,53 @@ using namespace rtengine; +enum GeometryIndex { + MO_CANVAS, + MO_OBJECT_COUNT, + + VISIBLE_OBJECT_COUNT = 0 +}; + +/** + * Offsets for mouse-over geometry that can be compared to the mouse-over object + * ID modded with the control line object count. + */ +enum GeometryOffset { + OFFSET_LINE = (MO_OBJECT_COUNT + ::ControlLine::LINE) % ::ControlLine::OBJECT_COUNT, + OFFSET_ICON = (MO_OBJECT_COUNT + ::ControlLine::ICON) % ::ControlLine::OBJECT_COUNT, + OFFSET_BEGIN = (MO_OBJECT_COUNT + ::ControlLine::BEGIN) % ::ControlLine::OBJECT_COUNT, + OFFSET_END = (MO_OBJECT_COUNT + ::ControlLine::END) % ::ControlLine::OBJECT_COUNT, +}; + +namespace +{ + +/** + * Returns true if the object matches the offset. + */ +constexpr bool checkOffset(int object_id, enum GeometryOffset offset) +{ + return object_id % ::ControlLine::OBJECT_COUNT == offset; +} + +/** + * Converts a control line mouse-over geometry ID to the visible geometry ID. + */ +constexpr int mouseOverIdToVisibleId(int mouse_over_id) +{ + return mouse_over_id - MO_OBJECT_COUNT + VISIBLE_OBJECT_COUNT; +} + +/** + * Converts a control line mouse-over geometry ID to the control line ID. + */ +constexpr int mouseOverIdToLineId(int mouse_over_id) +{ + return (mouse_over_id - MO_OBJECT_COUNT) / ::ControlLine::OBJECT_COUNT; +} + +} + ::ControlLine::~ControlLine() = default; ControlLineManager::ControlLineManager(): @@ -96,8 +144,8 @@ bool ControlLineManager::button1Pressed(int modifierKey) const int object = dataProvider->getObject(); - if (object > 0) { // A control line. - if (object % ::ControlLine::OBJ_COUNT == 2) { // Icon. + if (object >= MO_OBJECT_COUNT) { // A control line. + if (checkOffset(object, OFFSET_ICON)) { // Icon. action = Action::PICKING; } else { selected_object = object; @@ -109,7 +157,7 @@ bool ControlLineManager::button1Pressed(int modifierKey) } addLine(dataProvider->posImage, dataProvider->posImage); drawing_line = true; - selected_object = mouseOverGeometry.size() - 1; // Select endpoint. + selected_object = mouseOverGeometry.size() - ::ControlLine::OBJECT_COUNT + ::ControlLine::END; // Select endpoint. action = Action::DRAGGING; } @@ -120,7 +168,7 @@ bool ControlLineManager::button1Released(void) { action = Action::NONE; - if (selected_object > 0) { + if (selected_object >= MO_OBJECT_COUNT) { mouseOverGeometry[selected_object]->state = Geometry::NORMAL; } @@ -137,7 +185,7 @@ bool ControlLineManager::button3Pressed(int modifierKey) action = Action::NONE; - if (!provider || provider->getObject() < 1) { + if (!provider || provider->getObject() < MO_OBJECT_COUNT) { return false; } @@ -155,14 +203,13 @@ bool ControlLineManager::pick1(bool picked) EditDataProvider* provider = getEditProvider(); - if (!provider || provider->getObject() % ::ControlLine::OBJ_COUNT != 2) { + if (!provider || !checkOffset(provider->getObject(), OFFSET_ICON)) { return false; } // Change line type. int object_id = provider->getObject(); - ::ControlLine& line = - *control_lines[(object_id - 1) / ::ControlLine::OBJ_COUNT]; + ::ControlLine& line = *control_lines[mouseOverIdToLineId(object_id)]; if (line.type == rtengine::ControlLine::HORIZONTAL) { line.icon = line.icon_v; @@ -172,7 +219,7 @@ bool ControlLineManager::pick1(bool picked) line.type = rtengine::ControlLine::HORIZONTAL; } - visibleGeometry[object_id - 1] = line.icon.get(); + visibleGeometry[mouseOverIdToVisibleId(object_id)] = line.icon.get(); edited = true; callbacks->lineChanged(); @@ -194,7 +241,7 @@ bool ControlLineManager::pick3(bool picked) return false; } - removeLine((provider->getObject() - 1) / ::ControlLine::OBJ_COUNT); + removeLine(mouseOverIdToLineId(provider->getObject())); prev_obj = -1; selected_object = -1; return true; @@ -208,28 +255,28 @@ bool ControlLineManager::drag1(int modifierKey) EditDataProvider* provider = getEditProvider(); - if (!provider || selected_object < 1) { + if (!provider || selected_object < MO_OBJECT_COUNT) { return false; } ::ControlLine& control_line = - *control_lines[(selected_object - 1) / ::ControlLine::OBJ_COUNT]; + *control_lines[mouseOverIdToLineId(selected_object)]; // 0 == end, 1 == line, 2 == icon, 3 == begin - int component = selected_object % ::ControlLine::OBJ_COUNT; + int component = selected_object % ::ControlLine::OBJECT_COUNT; Coord mouse = provider->posImage + provider->deltaImage; Coord delta = provider->deltaImage - drag_delta; int ih, iw; provider->getImageSize(iw, ih); switch (component) { - case (0): // end + case (OFFSET_END): // end control_line.end->center = mouse; control_line.end->center.clip(iw, ih); control_line.line->end = control_line.end->center; control_line.end->state = Geometry::DRAGGED; break; - case (1): { // line + case (OFFSET_LINE): { // line // Constrain delta so the end stays above the image. Coord new_delta = control_line.end->center + delta; new_delta.clip(iw, ih); @@ -248,7 +295,7 @@ bool ControlLineManager::drag1(int modifierKey) break; } - case (3): // begin + case (OFFSET_BEGIN): // begin control_line.begin->center = mouse; control_line.begin->center.clip(iw, ih); control_line.line->begin = control_line.begin->center; @@ -274,11 +321,11 @@ void ControlLineManager::releaseEdit(void) { action = Action::NONE; - if (selected_object > 0) { + if (selected_object >= MO_OBJECT_COUNT) { mouseOverGeometry[selected_object]->state = Geometry::NORMAL; } - if (prev_obj > 0) { - visibleGeometry[prev_obj - 1]->state = Geometry::NORMAL; + if (prev_obj >= MO_OBJECT_COUNT) { + visibleGeometry[mouseOverIdToVisibleId(prev_obj)]->state = Geometry::NORMAL; } edited = true; @@ -307,7 +354,7 @@ bool ControlLineManager::mouseOver(int modifierKey) int cur_obj = provider->getObject(); - if (cur_obj == 0) { // Canvas + if (cur_obj == MO_CANVAS) { // Canvas if (draw_mode && modifierKey & GDK_CONTROL_MASK) { cursor = CSCrosshair; } else { @@ -315,16 +362,16 @@ bool ControlLineManager::mouseOver(int modifierKey) } } else if (cur_obj < 0) { // Nothing cursor = CSArrow; - } else if (cur_obj % ::ControlLine::OBJ_COUNT == 2) { // Icon - visibleGeometry[cur_obj - 1]->state = Geometry::PRELIGHT; + } else if (checkOffset(cur_obj, OFFSET_ICON)) { // Icon + visibleGeometry[mouseOverIdToVisibleId(cur_obj)]->state = Geometry::PRELIGHT; cursor = CSArrow; } else { // Object - visibleGeometry[cur_obj - 1]->state = Geometry::PRELIGHT; + visibleGeometry[mouseOverIdToVisibleId(cur_obj)]->state = Geometry::PRELIGHT; cursor = CSMove2D; } - if (prev_obj != cur_obj && prev_obj > 0) { - visibleGeometry[prev_obj - 1]->state = Geometry::NORMAL; + if (prev_obj != cur_obj && prev_obj >= MO_OBJECT_COUNT) { + visibleGeometry[mouseOverIdToVisibleId(prev_obj)]->state = Geometry::NORMAL; } prev_obj = cur_obj; @@ -418,14 +465,29 @@ void ControlLineManager::addLine(Coord begin, Coord end, control_line->line = std::move(line); control_line->type = type; + auto assertEqual = [](size_t a, int b) { + assert(b >= 0); + assert(a == static_cast(b)); + }; + + const int base_visible_offset = VISIBLE_OBJECT_COUNT + ::ControlLine::OBJECT_COUNT * control_lines.size(); + assertEqual(visibleGeometry.size(), base_visible_offset + ::ControlLine::LINE); EditSubscriber::visibleGeometry.push_back(control_line->line.get()); + assertEqual(visibleGeometry.size(), base_visible_offset + ::ControlLine::ICON); EditSubscriber::visibleGeometry.push_back(control_line->icon.get()); + assertEqual(visibleGeometry.size(), base_visible_offset + ::ControlLine::BEGIN); EditSubscriber::visibleGeometry.push_back(control_line->begin.get()); + assertEqual(visibleGeometry.size(), base_visible_offset + ::ControlLine::END); EditSubscriber::visibleGeometry.push_back(control_line->end.get()); + const int base_mo_count = MO_OBJECT_COUNT + ::ControlLine::OBJECT_COUNT * control_lines.size(); + assertEqual(mouseOverGeometry.size(), base_mo_count + ::ControlLine::LINE); EditSubscriber::mouseOverGeometry.push_back(control_line->line.get()); + assertEqual(mouseOverGeometry.size(), base_mo_count + ::ControlLine::ICON); EditSubscriber::mouseOverGeometry.push_back(control_line->icon.get()); + assertEqual(mouseOverGeometry.size(), base_mo_count + ::ControlLine::BEGIN); EditSubscriber::mouseOverGeometry.push_back(control_line->begin.get()); + assertEqual(mouseOverGeometry.size(), base_mo_count + ::ControlLine::END); EditSubscriber::mouseOverGeometry.push_back(control_line->end.get()); control_lines.push_back(std::move(control_line)); @@ -433,7 +495,7 @@ void ControlLineManager::addLine(Coord begin, Coord end, void ControlLineManager::autoSetLineType(int object_id) { - int line_id = (object_id - 1) / ::ControlLine::OBJ_COUNT; + int line_id = mouseOverIdToLineId(object_id); ::ControlLine& line = *control_lines[line_id]; int dx = line.begin->center.x - line.end->center.x; @@ -461,7 +523,8 @@ void ControlLineManager::autoSetLineType(int object_id) if (type != line.type) { // Need to update line type. line.type = type; line.icon = icon; - visibleGeometry[line_id * ::ControlLine::OBJ_COUNT + 1] = + visibleGeometry[line_id * ::ControlLine::OBJECT_COUNT ++ VISIBLE_OBJECT_COUNT + ::ControlLine::ICON] = line.icon.get(); } } @@ -469,7 +532,7 @@ void ControlLineManager::autoSetLineType(int object_id) void ControlLineManager::removeAll(void) { visibleGeometry.clear(); - mouseOverGeometry.erase(mouseOverGeometry.begin() + 1, + mouseOverGeometry.erase(mouseOverGeometry.begin() + MO_OBJECT_COUNT, mouseOverGeometry.end()); control_lines.clear(); prev_obj = -1; @@ -485,14 +548,13 @@ void ControlLineManager::removeLine(size_t line_id) } visibleGeometry.erase( - visibleGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id, - visibleGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id - + ::ControlLine::OBJ_COUNT + visibleGeometry.begin() + ::ControlLine::OBJECT_COUNT * line_id + VISIBLE_OBJECT_COUNT, + visibleGeometry.begin() + ::ControlLine::OBJECT_COUNT * line_id + VISIBLE_OBJECT_COUNT + + ::ControlLine::OBJECT_COUNT ); mouseOverGeometry.erase( - mouseOverGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id + 1, - mouseOverGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id - + ::ControlLine::OBJ_COUNT + 1 + mouseOverGeometry.begin() + ::ControlLine::OBJECT_COUNT * line_id + MO_OBJECT_COUNT, + mouseOverGeometry.begin() + ::ControlLine::OBJECT_COUNT * line_id + MO_OBJECT_COUNT + ::ControlLine::OBJECT_COUNT ); control_lines.erase(control_lines.begin() + line_id); diff --git a/rtgui/controllines.h b/rtgui/controllines.h index a045eedd7..a05fb8b00 100644 --- a/rtgui/controllines.h +++ b/rtgui/controllines.h @@ -30,7 +30,14 @@ class Rectangle; class RTSurface; struct ControlLine { - static constexpr int OBJ_COUNT = 4; + enum ObjectIndex { + LINE, + ICON, + BEGIN, + END, + OBJECT_COUNT + }; + std::unique_ptr line; std::shared_ptr icon; std::shared_ptr icon_h, icon_v; diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc index cfe626ca7..af6503b45 100644 --- a/rtgui/gradient.cc +++ b/rtgui/gradient.cc @@ -12,6 +12,14 @@ using namespace rtengine; using namespace rtengine::procparams; +enum GeometryIndex { + H_LINE, + V_LINE, + FEATHER_LINE_1, + FEATHER_LINE_2, + CENTER_CIRCLE, +}; + Gradient::Gradient () : FoldableToolPanel(this, "gradient", M("TP_GRADIENT_LABEL"), false, true), EditSubscriber(ET_OBJECTS), lastObject(-1), draggedPointOldAngle(-1000.) { @@ -191,24 +199,24 @@ void Gradient::updateGeometry(const int centerX, const int centerY, const double }; // update horizontal line - updateLine (visibleGeometry.at(0), 1500., 0., 180.); - updateLine (mouseOverGeometry.at(0), 1500., 0., 180.); + updateLine (visibleGeometry.at(H_LINE), 1500., 0., 180.); + updateLine (mouseOverGeometry.at(H_LINE), 1500., 0., 180.); // update vertical line - updateLine (visibleGeometry.at(1), 700., 90., 270.); - updateLine (mouseOverGeometry.at(1), 700., 90., 270.); + updateLine (visibleGeometry.at(V_LINE), 700., 90., 270.); + updateLine (mouseOverGeometry.at(V_LINE), 700., 90., 270.); // update upper feather line - updateLineWithDecay (visibleGeometry.at(2), 350., 270.); - updateLineWithDecay (mouseOverGeometry.at(2), 350., 270.); + updateLineWithDecay (visibleGeometry.at(FEATHER_LINE_1), 350., 270.); + updateLineWithDecay (mouseOverGeometry.at(FEATHER_LINE_1), 350., 270.); // update lower feather line - updateLineWithDecay (visibleGeometry.at(3), 350., 90.); - updateLineWithDecay (mouseOverGeometry.at(3), 350., 90.); + updateLineWithDecay (visibleGeometry.at(FEATHER_LINE_2), 350., 90.); + updateLineWithDecay (mouseOverGeometry.at(FEATHER_LINE_2), 350., 90.); // update circle's position - updateCircle (visibleGeometry.at(4)); - updateCircle (mouseOverGeometry.at(4)); + updateCircle (visibleGeometry.at(CENTER_CIRCLE)); + updateCircle (mouseOverGeometry.at(CENTER_CIRCLE)); } void Gradient::write (ProcParams* pp, ParamsEdited* pedited) @@ -333,12 +341,12 @@ void Gradient::editToggled () CursorShape Gradient::getCursor(int objectID, int xPos, int yPos) const { switch (objectID) { - case (0): - case (1): + case (H_LINE): + case (V_LINE): return CSMoveRotate; - case (2): - case (3): { + case (FEATHER_LINE_1): + case (FEATHER_LINE_2): { int angle = degree->getIntValue(); if (angle < -135 || (angle >= -45 && angle <= 45) || angle > 135) { @@ -348,7 +356,7 @@ CursorShape Gradient::getCursor(int objectID, int xPos, int yPos) const return CSMove1DH; } - case (4): + case (CENTER_CIRCLE): return CSMove2D; default: @@ -362,18 +370,18 @@ bool Gradient::mouseOver(int modifierKey) if (editProvider && editProvider->getObject() != lastObject) { if (lastObject > -1) { - if (lastObject == 2 || lastObject == 3) { - EditSubscriber::visibleGeometry.at(2)->state = Geometry::NORMAL; - EditSubscriber::visibleGeometry.at(3)->state = Geometry::NORMAL; + if (lastObject == FEATHER_LINE_1 || lastObject == FEATHER_LINE_2) { + EditSubscriber::visibleGeometry.at(FEATHER_LINE_1)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at(FEATHER_LINE_2)->state = Geometry::NORMAL; } else { EditSubscriber::visibleGeometry.at(lastObject)->state = Geometry::NORMAL; } } if (editProvider->getObject() > -1) { - if (editProvider->getObject() == 2 || editProvider->getObject() == 3) { - EditSubscriber::visibleGeometry.at(2)->state = Geometry::PRELIGHT; - EditSubscriber::visibleGeometry.at(3)->state = Geometry::PRELIGHT; + if (editProvider->getObject() == FEATHER_LINE_1 || editProvider->getObject() == FEATHER_LINE_2) { + EditSubscriber::visibleGeometry.at(FEATHER_LINE_1)->state = Geometry::PRELIGHT; + EditSubscriber::visibleGeometry.at(FEATHER_LINE_2)->state = Geometry::PRELIGHT; } else { EditSubscriber::visibleGeometry.at(editProvider->getObject())->state = Geometry::PRELIGHT; } @@ -415,7 +423,7 @@ bool Gradient::button1Pressed(int modifierKey) //printf("\ndraggedPointOldAngle=%.3f\n\n", draggedPointOldAngle); draggedPointAdjusterAngle = degree->getValue(); - if (lastObject == 2 || lastObject == 3) { + if (lastObject == FEATHER_LINE_1 || lastObject == FEATHER_LINE_2) { // Dragging a line to change the angle PolarCoord draggedPoint; rtengine::Coord currPos; @@ -431,7 +439,7 @@ bool Gradient::button1Pressed(int modifierKey) // compute the projected value of the dragged point draggedFeatherOffset = draggedPoint.radius * sin((draggedPoint.angle - degree->getValue()) / 180.*rtengine::RT_PI); - if (lastObject == 3) { + if (lastObject == FEATHER_LINE_2) { draggedFeatherOffset = -draggedFeatherOffset; } @@ -442,9 +450,9 @@ bool Gradient::button1Pressed(int modifierKey) return false; } else { // should theoretically always be true // this will let this class ignore further drag events - if (lastObject == 2 || lastObject == 3) { - EditSubscriber::visibleGeometry.at(2)->state = Geometry::NORMAL; - EditSubscriber::visibleGeometry.at(3)->state = Geometry::NORMAL; + if (lastObject == FEATHER_LINE_1 || lastObject == FEATHER_LINE_2) { + EditSubscriber::visibleGeometry.at(FEATHER_LINE_1)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at(FEATHER_LINE_2)->state = Geometry::NORMAL; } else { EditSubscriber::visibleGeometry.at(lastObject)->state = Geometry::NORMAL; } @@ -472,7 +480,7 @@ bool Gradient::drag1(int modifierKey) double halfSizeW = imW / 2.; double halfSizeH = imH / 2.; - if (lastObject == 0 || lastObject == 1) { + if (lastObject == H_LINE || lastObject == V_LINE) { // Dragging a line to change the angle PolarCoord draggedPoint; @@ -516,7 +524,7 @@ bool Gradient::drag1(int modifierKey) return true; } - } else if (lastObject == 2 || lastObject == 3) { + } else if (lastObject == FEATHER_LINE_1 || lastObject == FEATHER_LINE_2) { // Dragging the upper or lower feather bar PolarCoord draggedPoint; rtengine::Coord currPos; @@ -533,11 +541,11 @@ bool Gradient::drag1(int modifierKey) draggedPoint = currPos - centerPos; double currDraggedFeatherOffset = draggedPoint.radius * sin((draggedPoint.angle - degree->getValue()) / 180.*rtengine::RT_PI); - if (lastObject == 2) + if (lastObject == FEATHER_LINE_1) // Dragging the upper feather bar { currDraggedFeatherOffset -= draggedFeatherOffset; - } else if (lastObject == 3) + } else if (lastObject == FEATHER_LINE_2) // Dragging the lower feather bar { currDraggedFeatherOffset = -currDraggedFeatherOffset + draggedFeatherOffset; @@ -555,7 +563,7 @@ bool Gradient::drag1(int modifierKey) return true; } - } else if (lastObject == 4) { + } else if (lastObject == CENTER_CIRCLE) { // Dragging the circle to change the center rtengine::Coord currPos; draggedCenter += provider->deltaPrevImage; @@ -583,9 +591,9 @@ bool Gradient::drag1(int modifierKey) void Gradient::releaseEdit() { if (lastObject >= 0) { - if (lastObject == 2 || lastObject == 3) { - EditSubscriber::visibleGeometry.at(2)->state = Geometry::NORMAL; - EditSubscriber::visibleGeometry.at(3)->state = Geometry::NORMAL; + if (lastObject == FEATHER_LINE_1 || lastObject == FEATHER_LINE_2) { + EditSubscriber::visibleGeometry.at(FEATHER_LINE_1)->state = Geometry::NORMAL; + EditSubscriber::visibleGeometry.at(FEATHER_LINE_2)->state = Geometry::NORMAL; } else { EditSubscriber::visibleGeometry.at(lastObject)->state = Geometry::NORMAL; } diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 16e8cf391..3845751c9 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -29,8 +29,23 @@ using namespace rtengine; using namespace rtengine::procparams; -#define STATIC_VISIBLE_OBJ_NBR 6 -#define STATIC_MO_OBJ_NBR 6 +enum GeometryIndex { + MO_TARGET_DISK, + MO_SOURCE_DISC, + MO_TARGET_CIRCLE, + MO_SOURCE_CIRCLE, + MO_TARGET_FEATHER_CIRCLE, + MO_SOURCE_FEATHER_CIRCLE, + MO_OBJECT_COUNT, + + VISIBLE_SOURCE_ICON = 0, + VISIBLE_SOURCE_FEATHER_CIRCLE, + VISIBLE_LINK, + VISIBLE_SOURCE_CIRCLE, + VISIBLE_TARGET_FEATHER_CIRCLE, + VISIBLE_TARGET_CIRCLE, + VISIBLE_OBJECT_COUNT +}; Spot::Spot() : FoldableToolPanel(this, "spot", M ("TP_SPOT_LABEL"), true, true), @@ -106,7 +121,7 @@ Spot::~Spot() { // delete all dynamically allocated geometry if (EditSubscriber::visibleGeometry.size()) { - for (size_t i = 0; i < EditSubscriber::visibleGeometry.size() - STATIC_VISIBLE_OBJ_NBR; ++i) { // static visible geometry at the end if the list + for (size_t i = 0; i < EditSubscriber::visibleGeometry.size() - VISIBLE_OBJECT_COUNT; ++i) { // static visible geometry at the end of the list delete EditSubscriber::visibleGeometry.at (i); } } @@ -271,16 +286,16 @@ Geometry* Spot::getVisibleGeometryFromMO (int MOID) return nullptr; } - if (MOID == 0) { + if (MOID == MO_TARGET_DISK) { return getActiveSpotIcon(); } - if (MOID == 1) { // sourceMODisc + if (MOID == MO_SOURCE_DISC) { return &sourceIcon; } - if (MOID > STATIC_MO_OBJ_NBR) { - return EditSubscriber::visibleGeometry.at(MOID - STATIC_MO_OBJ_NBR); + if (MOID > MO_OBJECT_COUNT) { + return EditSubscriber::visibleGeometry.at(MOID - MO_OBJECT_COUNT); } return EditSubscriber::mouseOverGeometry.at (MOID); @@ -296,30 +311,36 @@ void Spot::createGeometry () //printf("CreateGeometry(%d)\n", nbrEntry); // delete all dynamically allocated geometry - if (EditSubscriber::visibleGeometry.size() > STATIC_VISIBLE_OBJ_NBR) - for (size_t i = 0; i < EditSubscriber::visibleGeometry.size() - STATIC_VISIBLE_OBJ_NBR; ++i) { // static visible geometry at the end if the list + if (EditSubscriber::visibleGeometry.size() > VISIBLE_OBJECT_COUNT) + for (size_t i = 0; i < EditSubscriber::visibleGeometry.size() - VISIBLE_OBJECT_COUNT; ++i) { // static visible geometry at the end of the list delete EditSubscriber::visibleGeometry.at (i); } // mouse over geometry starts with the static geometry, then the spot's icon geometry - EditSubscriber::mouseOverGeometry.resize (STATIC_MO_OBJ_NBR + nbrEntry); + EditSubscriber::mouseOverGeometry.resize (MO_OBJECT_COUNT + nbrEntry); // visible geometry starts with the spot's icon geometry, then the static geometry - EditSubscriber::visibleGeometry.resize (nbrEntry + STATIC_VISIBLE_OBJ_NBR); + EditSubscriber::visibleGeometry.resize (nbrEntry + VISIBLE_OBJECT_COUNT); size_t i = 0, j = 0; - EditSubscriber::mouseOverGeometry.at (i++) = &targetMODisc; // STATIC_MO_OBJ_NBR + 0 - EditSubscriber::mouseOverGeometry.at (i++) = &sourceMODisc; // STATIC_MO_OBJ_NBR + 1 - EditSubscriber::mouseOverGeometry.at (i++) = &targetCircle; // STATIC_MO_OBJ_NBR + 2 - EditSubscriber::mouseOverGeometry.at (i++) = &sourceCircle; // STATIC_MO_OBJ_NBR + 3 - EditSubscriber::mouseOverGeometry.at (i++) = &targetFeatherCircle; // STATIC_MO_OBJ_NBR + 4 - EditSubscriber::mouseOverGeometry.at (i++) = &sourceFeatherCircle; // STATIC_MO_OBJ_NBR + 5 + assert(i == MO_TARGET_DISK); + EditSubscriber::mouseOverGeometry.at (i++) = &targetMODisc; // MO_OBJECT_COUNT + 0 + assert(i == MO_SOURCE_DISC); + EditSubscriber::mouseOverGeometry.at (i++) = &sourceMODisc; // MO_OBJECT_COUNT + 1 + assert(i == MO_TARGET_CIRCLE); + EditSubscriber::mouseOverGeometry.at (i++) = &targetCircle; // MO_OBJECT_COUNT + 2 + assert(i == MO_SOURCE_CIRCLE); + EditSubscriber::mouseOverGeometry.at (i++) = &sourceCircle; // MO_OBJECT_COUNT + 3 + assert(i == MO_TARGET_FEATHER_CIRCLE); + EditSubscriber::mouseOverGeometry.at (i++) = &targetFeatherCircle; // MO_OBJECT_COUNT + 4 + assert(i == MO_SOURCE_FEATHER_CIRCLE); + EditSubscriber::mouseOverGeometry.at (i++) = &sourceFeatherCircle; // MO_OBJECT_COUNT + 5 // recreate all spots geometry Cairo::RefPtr normalImg = sourceIcon.getNormalImg(); Cairo::RefPtr prelightImg = sourceIcon.getPrelightImg(); Cairo::RefPtr activeImg = sourceIcon.getActiveImg(); - for (; j < EditSubscriber::visibleGeometry.size() - STATIC_VISIBLE_OBJ_NBR; ++i, ++j) { + for (; j < EditSubscriber::visibleGeometry.size() - VISIBLE_OBJECT_COUNT; ++i, ++j) { EditSubscriber::mouseOverGeometry.at (i) = EditSubscriber::visibleGeometry.at (j) = new OPIcon (normalImg, activeImg, prelightImg, Cairo::RefPtr (nullptr), Cairo::RefPtr (nullptr), Geometry::DP_CENTERCENTER); EditSubscriber::visibleGeometry.at (j)->setActive (true); EditSubscriber::visibleGeometry.at (j)->datum = Geometry::IMAGE; @@ -327,12 +348,19 @@ void Spot::createGeometry () //printf("mouseOverGeometry.at(%d) = %p\n", (unsigned int)i, (void*)EditSubscriber::mouseOverGeometry.at(i)); } - EditSubscriber::visibleGeometry.at (j++) = &sourceIcon; // STATIC_VISIBLE_OBJ_NBR + 0 - EditSubscriber::visibleGeometry.at (j++) = &sourceFeatherCircle; // STATIC_VISIBLE_OBJ_NBR + 1 - EditSubscriber::visibleGeometry.at (j++) = &link; // STATIC_VISIBLE_OBJ_NBR + 2 - EditSubscriber::visibleGeometry.at (j++) = &sourceCircle; // STATIC_VISIBLE_OBJ_NBR + 3 - EditSubscriber::visibleGeometry.at (j++) = &targetFeatherCircle; // STATIC_VISIBLE_OBJ_NBR + 4 - EditSubscriber::visibleGeometry.at (j++) = &targetCircle; // STATIC_VISIBLE_OBJ_NBR + 5 + int visibleOffset = j; + assert(j - visibleOffset == VISIBLE_SOURCE_ICON); + EditSubscriber::visibleGeometry.at (j++) = &sourceIcon; // VISIBLE_OBJECT_COUNT + 0 + assert(j - visibleOffset == VISIBLE_SOURCE_FEATHER_CIRCLE); + EditSubscriber::visibleGeometry.at (j++) = &sourceFeatherCircle; // VISIBLE_OBJECT_COUNT + 1 + assert(j - visibleOffset == VISIBLE_LINK); + EditSubscriber::visibleGeometry.at (j++) = &link; // VISIBLE_OBJECT_COUNT + 2 + assert(j - visibleOffset == VISIBLE_SOURCE_CIRCLE); + EditSubscriber::visibleGeometry.at (j++) = &sourceCircle; // VISIBLE_OBJECT_COUNT + 3 + assert(j - visibleOffset == VISIBLE_TARGET_FEATHER_CIRCLE); + EditSubscriber::visibleGeometry.at (j++) = &targetFeatherCircle; // VISIBLE_OBJECT_COUNT + 4 + assert(j - visibleOffset == VISIBLE_TARGET_CIRCLE); + EditSubscriber::visibleGeometry.at (j++) = &targetCircle; // VISIBLE_OBJECT_COUNT + 5 } void Spot::updateGeometry() @@ -440,7 +468,7 @@ void Spot::addNewEntry() se.sourcePos = se.targetPos; spots.push_back (se); // this make a copy of se ... activeSpot = spots.size() - 1; - lastObject = 1; + lastObject = MO_SOURCE_DISC; //printf("ActiveSpot = %d\n", activeSpot); @@ -487,11 +515,11 @@ CursorShape Spot::getCursor (int objectID, int xPos, int yPos) const return CSEmpty; } - if (objectID == 0 || objectID == 1) { + if (objectID == MO_TARGET_DISK || objectID == MO_SOURCE_DISC) { return CSMove2D; } - if (objectID >= 2 && objectID <= 5) { - Coord delta(Coord(xPos, yPos) - ((objectID == 3 || objectID == 5) ? spots.at(activeSpot).sourcePos : spots.at(activeSpot).targetPos)); + if (objectID >= MO_TARGET_CIRCLE && objectID <= MO_SOURCE_FEATHER_CIRCLE) { + Coord delta(Coord(xPos, yPos) - ((objectID == MO_SOURCE_CIRCLE || objectID == MO_SOURCE_FEATHER_CIRCLE) ? spots.at(activeSpot).sourcePos : spots.at(activeSpot).targetPos)); PolarCoord polarPos(delta); if (polarPos.angle < 0.) { polarPos.angle += 180.; @@ -529,19 +557,19 @@ bool Spot::mouseOver (int modifierKey) if (editProvider->getObject() > -1) { getVisibleGeometryFromMO (editProvider->getObject())->state = Geometry::PRELIGHT; - if (editProvider->getObject() >= STATIC_MO_OBJ_NBR) { + if (editProvider->getObject() >= MO_OBJECT_COUNT) { // a Spot is being edited int oldActiveSpot = activeSpot; - activeSpot = editProvider->getObject() - STATIC_MO_OBJ_NBR; + activeSpot = editProvider->getObject() - MO_OBJECT_COUNT; if (activeSpot != oldActiveSpot) { if (oldActiveSpot > -1) { EditSubscriber::visibleGeometry.at (oldActiveSpot)->state = Geometry::NORMAL; - EditSubscriber::mouseOverGeometry.at (oldActiveSpot + STATIC_MO_OBJ_NBR)->state = Geometry::NORMAL; + EditSubscriber::mouseOverGeometry.at (oldActiveSpot + MO_OBJECT_COUNT)->state = Geometry::NORMAL; } EditSubscriber::visibleGeometry.at (activeSpot)->state = Geometry::PRELIGHT; - EditSubscriber::mouseOverGeometry.at (activeSpot + STATIC_MO_OBJ_NBR)->state = Geometry::PRELIGHT; + EditSubscriber::mouseOverGeometry.at (activeSpot + MO_OBJECT_COUNT)->state = Geometry::PRELIGHT; //printf("ActiveSpot = %d (was %d before)\n", activeSpot, oldActiveSpot); } } @@ -550,7 +578,7 @@ bool Spot::mouseOver (int modifierKey) lastObject = editProvider->getObject(); if (lastObject > -1 && EditSubscriber::mouseOverGeometry.at (lastObject) == getActiveSpotIcon()) { - lastObject = 0; // targetMODisc + lastObject = MO_TARGET_DISK; } updateGeometry(); @@ -578,7 +606,7 @@ bool Spot::button1Pressed (int modifierKey) EditSubscriber::action = EditSubscriber::Action::DRAGGING; return true; } else if (lastObject > -1) { - draggedSide = lastObject == 0 ? DraggedSide::TARGET : lastObject == 1 ? DraggedSide::SOURCE : DraggedSide::NONE; + draggedSide = lastObject == MO_TARGET_DISK ? DraggedSide::TARGET : lastObject == MO_SOURCE_DISC ? DraggedSide::SOURCE : DraggedSide::NONE; getVisibleGeometryFromMO (lastObject)->state = Geometry::DRAGGED; EditSubscriber::action = EditSubscriber::Action::DRAGGING; return true; @@ -630,8 +658,8 @@ bool Spot::button3Pressed (int modifierKey) return false; } - if ((modifierKey & GDK_CONTROL_MASK) && (EditSubscriber::mouseOverGeometry.at (lastObject) == &targetMODisc || lastObject >= STATIC_MO_OBJ_NBR)) { - lastObject = 1; // sourceMODisc + if ((modifierKey & GDK_CONTROL_MASK) && (EditSubscriber::mouseOverGeometry.at (lastObject) == &targetMODisc || lastObject >= MO_OBJECT_COUNT)) { + lastObject = MO_SOURCE_DISC; sourceIcon.state = Geometry::DRAGGED; EditSubscriber::action = EditSubscriber::Action::DRAGGING; draggedSide = DraggedSide::SOURCE; @@ -687,8 +715,8 @@ bool Spot::drag1 (int modifierKey) modified = true; } - EditSubscriber::mouseOverGeometry.at (activeSpot + STATIC_MO_OBJ_NBR)->state = Geometry::DRAGGED; - } else if (loGeom == &targetMODisc || lastObject >= STATIC_MO_OBJ_NBR) { + EditSubscriber::mouseOverGeometry.at (activeSpot + MO_OBJECT_COUNT)->state = Geometry::DRAGGED; + } else if (loGeom == &targetMODisc || lastObject >= MO_OBJECT_COUNT) { //printf("targetMODisc / deltaPrevImage = %d / %d\n", editProvider->deltaPrevImage.x, editProvider->deltaPrevImage.y); rtengine::Coord currPos = spots.at (activeSpot).targetPos; spots.at (activeSpot).targetPos += editProvider->deltaPrevImage; From 3c7e20b6897baffc3c88e16a2bcccf07e3974521 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 30 May 2021 12:05:51 -0700 Subject: [PATCH 115/135] Refactor rtgui/spot.cc --- rtgui/spot.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 3845751c9..d9a6be6b7 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -208,14 +208,14 @@ void Spot::releaseEdit() { Geometry *loGeom = getVisibleGeometryFromMO (lastObject); + EditSubscriber::action = EditSubscriber::Action::NONE; + if (!loGeom) { - EditSubscriber::action = EditSubscriber::Action::NONE; return; } loGeom->state = Geometry::NORMAL; sourceIcon.state = Geometry::NORMAL; - EditSubscriber::action = EditSubscriber::Action::NONE; draggedSide = DraggedSide::NONE; updateGeometry(); } @@ -686,8 +686,6 @@ bool Spot::button3Released() updateGeometry(); EditSubscriber::action = EditSubscriber::Action::NONE; return true; - - return false; } bool Spot::drag1 (int modifierKey) From 2c1e6a8ca165374cd505b8c8f5b0b3447e89c39a Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 30 May 2021 18:02:29 -0700 Subject: [PATCH 116/135] Make control lines buttons react to line counts Set the "apply" and "delete all" button sensitivity based on the number of control lines. Add extra tooltip text to the apply button when editing and there is not enough lines. The text explains there must be enough vertical or horizontal control lines. --- rtdata/languages/default | 1 + rtgui/controllines.cc | 33 +++++++++++++++++++++++++++++++++ rtgui/controllines.h | 5 +++++ rtgui/perspective.cc | 23 +++++++++++++++++++++++ rtgui/perspective.h | 1 + 5 files changed, 63 insertions(+) diff --git a/rtdata/languages/default b/rtdata/languages/default index 773f7768b..821a6fb60 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -3320,6 +3320,7 @@ TP_PCVIGNETTE_ROUNDNESS_TOOLTIP;Roundness:\n0 = rectangle,\n50 = fitted ellipse, TP_PCVIGNETTE_STRENGTH;Strength TP_PCVIGNETTE_STRENGTH_TOOLTIP;Filter strength in stops (reached in corners). TP_PDSHARPENING_LABEL;Capture Sharpening +TP_PERSPECTIVE_CONTROL_LINE_APPLY_INVALID_TOOLTIP;At least two horizontal or two vertical control lines required. TP_PERSPECTIVE_CAMERA_CROP_FACTOR;Crop factor TP_PERSPECTIVE_CAMERA_FOCAL_LENGTH;Focal length TP_PERSPECTIVE_CAMERA_FRAME;Correction diff --git a/rtgui/controllines.cc b/rtgui/controllines.cc index c078b4322..e4ef9e9f7 100644 --- a/rtgui/controllines.cc +++ b/rtgui/controllines.cc @@ -36,6 +36,7 @@ ControlLineManager::ControlLineManager(): draw_mode(false), drawing_line(false), edited(false), + horizontalCount(0), verticalCount(0), prev_obj(-1), selected_object(-1) { @@ -84,6 +85,16 @@ size_t ControlLineManager::size(void) const return control_lines.size(); } +size_t ControlLineManager::getHorizontalCount(void) const +{ + return horizontalCount; +} + +size_t ControlLineManager::getVerticalCount(void) const +{ + return verticalCount; +} + bool ControlLineManager::button1Pressed(int modifierKey) { EditDataProvider* dataProvider = getEditProvider(); @@ -164,9 +175,13 @@ bool ControlLineManager::pick1(bool picked) if (line.type == rtengine::ControlLine::HORIZONTAL) { line.icon = line.icon_v; line.type = rtengine::ControlLine::VERTICAL; + horizontalCount--; + verticalCount++; } else if (line.type == rtengine::ControlLine::VERTICAL) { line.icon = line.icon_h; line.type = rtengine::ControlLine::HORIZONTAL; + horizontalCount++; + verticalCount--; } visibleGeometry[object_id - 1] = line.icon.get(); @@ -405,6 +420,11 @@ void ControlLineManager::addLine(Coord begin, Coord end, EditSubscriber::mouseOverGeometry.push_back(control_line->end.get()); control_lines.push_back(std::move(control_line)); + if (type == rtengine::ControlLine::HORIZONTAL) { + horizontalCount++; + } else { + verticalCount++; + } } void ControlLineManager::autoSetLineType(int object_id) @@ -437,6 +457,13 @@ void ControlLineManager::autoSetLineType(int object_id) if (type != line.type) { // Need to update line type. line.type = type; line.icon = icon; + if (type == rtengine::ControlLine::HORIZONTAL) { + horizontalCount++; + verticalCount--; + } else { + horizontalCount--; + verticalCount++; + } visibleGeometry[line_id * ::ControlLine::OBJ_COUNT + 1] = line.icon.get(); } @@ -448,6 +475,7 @@ void ControlLineManager::removeAll(void) mouseOverGeometry.erase(mouseOverGeometry.begin() + 1, mouseOverGeometry.end()); control_lines.clear(); + horizontalCount = verticalCount = 0; prev_obj = -1; selected_object = -1; edited = true; @@ -470,6 +498,11 @@ void ControlLineManager::removeLine(size_t line_id) mouseOverGeometry.begin() + ::ControlLine::OBJ_COUNT * line_id + ::ControlLine::OBJ_COUNT + 1 ); + if (control_lines[line_id]->type == rtengine::ControlLine::HORIZONTAL) { + horizontalCount--; + } else { + verticalCount--; + } control_lines.erase(control_lines.begin() + line_id); edited = true; diff --git a/rtgui/controllines.h b/rtgui/controllines.h index 2b2d179a4..578118eb7 100644 --- a/rtgui/controllines.h +++ b/rtgui/controllines.h @@ -52,6 +52,7 @@ protected: bool draw_mode; bool drawing_line; bool edited; + size_t horizontalCount, verticalCount; Cairo::RefPtr line_icon_h, line_icon_v; Cairo::RefPtr line_icon_h_prelight, line_icon_v_prelight; int prev_obj; @@ -87,6 +88,10 @@ public: ~ControlLineManager(); bool getEdited(void) const; + /** Returns the number of horizontal control lines. */ + size_t getHorizontalCount(void) const; + /** Returns the number of vertical control lines. */ + size_t getVerticalCount(void) const; void removeAll(void); /** Sets whether or not the lines are visible and interact-able. */ void setActive(bool active); diff --git a/rtgui/perspective.cc b/rtgui/perspective.cc index 8db91ee2e..e77c622cd 100644 --- a/rtgui/perspective.cc +++ b/rtgui/perspective.cc @@ -351,6 +351,8 @@ void PerspCorrection::read (const ProcParams* pp, const ParamsEdited* pedited) method->set_active (1); } + updateApplyDeleteButtons(); + enableListener (); } @@ -739,11 +741,29 @@ void PerspCorrection::setEditProvider(EditDataProvider* provider) void PerspCorrection::lineChanged(void) { + updateApplyDeleteButtons(); + if (listener) { listener->panelChanged(EvPerspControlLines, M("HISTORY_CHANGED")); } } +void PerspCorrection::updateApplyDeleteButtons(void) +{ + if (batchMode) { + return; + } + + bool edit_mode = lines_button_edit->get_active(); + bool enough_lines = lines->getHorizontalCount() >= 2 || lines->getVerticalCount() >= 2; + const auto &tooltip = M("GENERAL_APPLY") + + ((edit_mode && !enough_lines) ? "\n\n" + M("TP_PERSPECTIVE_CONTROL_LINE_APPLY_INVALID_TOOLTIP") : ""); + + lines_button_apply->set_sensitive(edit_mode && enough_lines); + lines_button_apply->set_tooltip_text(tooltip); + lines_button_erase->set_sensitive(edit_mode && lines->size() > 0); +} + void PerspCorrection::linesApplyButtonPressed(void) { if (method->get_active_row_number() == 1) { @@ -784,6 +804,7 @@ void PerspCorrection::linesEditButtonPressed(void) panel_listener->controlLineEditModeChanged(false); } } + updateApplyDeleteButtons(); } void PerspCorrection::linesEraseButtonPressed(void) @@ -795,6 +816,8 @@ void PerspCorrection::requestApplyControlLines(void) { if (lines_button_apply->is_sensitive()) { linesApplyButtonPressed(); + } else if (lines_button_edit->get_active()) { + lines_button_edit->set_active(false); } } diff --git a/rtgui/perspective.h b/rtgui/perspective.h index 6f4a4ff52..3368b6282 100644 --- a/rtgui/perspective.h +++ b/rtgui/perspective.h @@ -96,6 +96,7 @@ protected: void tweakParams(rtengine::procparams::ProcParams &pparams) override; void setCamBasedEventsActive (bool active = true); void setFocalLengthValue (const rtengine::procparams::ProcParams* pparams, const rtengine::FramesMetaData* metadata); + void updateApplyDeleteButtons(void); public: From e7e6dd1cb5882bbef714396b301af001470c3795 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Mon, 31 May 2021 11:20:01 -0700 Subject: [PATCH 117/135] Clean up rtgui perspective.* and controllines.* Change size_t to std::size_t, remove void from function parameters, use constants to represent the minimum required number of control lines, and change const auto & to const auto. --- rtgui/controllines.cc | 8 ++++---- rtgui/controllines.h | 10 +++++----- rtgui/perspective.cc | 20 +++++++------------- rtgui/perspective.h | 7 ++++++- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/rtgui/controllines.cc b/rtgui/controllines.cc index e4ef9e9f7..84175af28 100644 --- a/rtgui/controllines.cc +++ b/rtgui/controllines.cc @@ -80,17 +80,17 @@ void ControlLineManager::setDrawMode(bool draw) draw_mode = draw; } -size_t ControlLineManager::size(void) const +std::size_t ControlLineManager::size() const { return control_lines.size(); } -size_t ControlLineManager::getHorizontalCount(void) const +std::size_t ControlLineManager::getHorizontalCount() const { return horizontalCount; } -size_t ControlLineManager::getVerticalCount(void) const +std::size_t ControlLineManager::getVerticalCount() const { return verticalCount; } @@ -482,7 +482,7 @@ void ControlLineManager::removeAll(void) callbacks->lineChanged(); } -void ControlLineManager::removeLine(size_t line_id) +void ControlLineManager::removeLine(std::size_t line_id) { if (line_id >= control_lines.size()) { return; diff --git a/rtgui/controllines.h b/rtgui/controllines.h index 578118eb7..81c4c7b8a 100644 --- a/rtgui/controllines.h +++ b/rtgui/controllines.h @@ -52,7 +52,7 @@ protected: bool draw_mode; bool drawing_line; bool edited; - size_t horizontalCount, verticalCount; + std::size_t horizontalCount, verticalCount; Cairo::RefPtr line_icon_h, line_icon_v; Cairo::RefPtr line_icon_h_prelight, line_icon_v_prelight; int prev_obj; @@ -68,7 +68,7 @@ protected: * line, inclusive, the line type is set to vertical. Otherwise, horizontal. */ void autoSetLineType(int object_id); - void removeLine(size_t line_id); + void removeLine(std::size_t line_id); public: class Callbacks @@ -89,9 +89,9 @@ public: bool getEdited(void) const; /** Returns the number of horizontal control lines. */ - size_t getHorizontalCount(void) const; + std::size_t getHorizontalCount() const; /** Returns the number of vertical control lines. */ - size_t getVerticalCount(void) const; + std::size_t getVerticalCount() const; void removeAll(void); /** Sets whether or not the lines are visible and interact-able. */ void setActive(bool active); @@ -101,7 +101,7 @@ public: void setEditProvider(EditDataProvider* provider); void setLines(const std::vector& lines); /** Returns the number of lines. */ - size_t size(void) const; + std::size_t size() const; /** * Allocates a new array and populates it with copies of the control lines. */ diff --git a/rtgui/perspective.cc b/rtgui/perspective.cc index e77c622cd..c845c272b 100644 --- a/rtgui/perspective.cc +++ b/rtgui/perspective.cc @@ -519,22 +519,16 @@ void PerspCorrection::applyControlLines(void) } std::vector control_lines; - int h_count = 0, v_count = 0; double rot = camera_roll->getValue(); double pitch = camera_pitch->getValue(); double yaw = camera_yaw->getValue(); lines->toControlLines(control_lines); - for (unsigned int i = 0; i < lines->size(); i++) { - if (control_lines[i].type == rtengine::ControlLine::HORIZONTAL) { - h_count++; - } else if (control_lines[i].type == rtengine::ControlLine::VERTICAL) { - v_count++; - } - } - lens_geom_listener->autoPerspRequested(v_count > 1, h_count > 1, rot, pitch, - yaw, &control_lines); + lens_geom_listener->autoPerspRequested( + lines->getVerticalCount() >= MIN_VERT_LINES, + lines->getHorizontalCount() >= MIN_HORIZ_LINES, + rot, pitch, yaw, &control_lines); disableListener(); camera_pitch->setValue(pitch); @@ -748,15 +742,15 @@ void PerspCorrection::lineChanged(void) } } -void PerspCorrection::updateApplyDeleteButtons(void) +void PerspCorrection::updateApplyDeleteButtons() { if (batchMode) { return; } bool edit_mode = lines_button_edit->get_active(); - bool enough_lines = lines->getHorizontalCount() >= 2 || lines->getVerticalCount() >= 2; - const auto &tooltip = M("GENERAL_APPLY") + bool enough_lines = lines->getHorizontalCount() >= MIN_HORIZ_LINES || lines->getVerticalCount() >= MIN_VERT_LINES; + const auto tooltip = M("GENERAL_APPLY") + ((edit_mode && !enough_lines) ? "\n\n" + M("TP_PERSPECTIVE_CONTROL_LINE_APPLY_INVALID_TOOLTIP") : ""); lines_button_apply->set_sensitive(edit_mode && enough_lines); diff --git a/rtgui/perspective.h b/rtgui/perspective.h index 3368b6282..404b02010 100644 --- a/rtgui/perspective.h +++ b/rtgui/perspective.h @@ -96,10 +96,15 @@ protected: void tweakParams(rtengine::procparams::ProcParams &pparams) override; void setCamBasedEventsActive (bool active = true); void setFocalLengthValue (const rtengine::procparams::ProcParams* pparams, const rtengine::FramesMetaData* metadata); - void updateApplyDeleteButtons(void); + void updateApplyDeleteButtons(); public: + /** Minimum number of horizontal lines for horizontal/full correction. */ + static constexpr std::size_t MIN_HORIZ_LINES = 2; + /** Minimum number of vertical lines for vertical/full correction. */ + static constexpr std::size_t MIN_VERT_LINES = 2; + PerspCorrection (); void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; From 726f1c1f26ec0e7747276b28aa1ac8af36253861 Mon Sep 17 00:00:00 2001 From: rom9 <4711834+rom9@users.noreply.github.com> Date: Thu, 3 Jun 2021 19:57:28 +0200 Subject: [PATCH 118/135] FilmNeg tool: used a single luminance reference when sampling white balance spot several times in sequence, to avoid luminance drift. Fixes #6257 --- rtgui/filmnegative.cc | 43 +++++++++++++++++++++++++++++++++++++++++-- rtgui/filmnegative.h | 11 +++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/rtgui/filmnegative.cc b/rtgui/filmnegative.cc index c57d404c1..068575a96 100644 --- a/rtgui/filmnegative.cc +++ b/rtgui/filmnegative.cc @@ -194,6 +194,7 @@ FilmNegative::FilmNegative() : evFilmNegativeColorSpace(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_COLORSPACE")), refInputValues({0.f, 0.f, 0.f}), paramsUpgraded(false), + refLuminance({{0.f, 0.f, 0.f}, 0.f}), fnp(nullptr), colorSpace(Gtk::manage(new MyComboBoxText())), greenExp(createExponentAdjuster(this, M("TP_FILMNEGATIVE_GREEN"), 0.3, 4, 0.01, 1.5)), // master exponent (green channel) @@ -343,6 +344,9 @@ void FilmNegative::read(const rtengine::procparams::ProcParams* pp, const Params setEnabled(pp->filmNegative.enabled); + // Reset luminance reference each time params are read + refLuminance.lum = 0.f; + colorSpace->set_active(CLAMP((int)pp->filmNegative.colorSpace, 0, 1)); redRatio->setValue(pp->filmNegative.redRatio); greenExp->setValue(pp->filmNegative.greenExp); @@ -471,6 +475,9 @@ void FilmNegative::adjusterChanged(Adjuster* a, double newval) ); } else if (a == outputLevel || a == greenBalance || a == blueBalance) { + // Reset luminance reference when output level/color sliders are changed + refLuminance.lum = 0.f; + listener->panelChanged( evFilmNegativeBalance, Glib::ustring::compose( @@ -606,12 +613,44 @@ bool FilmNegative::button1Pressed(int modifierKey) } else if (refSpotButton->get_active()) { + disableListener(); + + // If the luminance reference is not set, copy the current reference input + // values, and the corresponding output luminance + if(refLuminance.lum <= 0.f) { + RGB out; + readOutputSliders(out); + refLuminance.input = refInputValues; + refLuminance.lum = rtengine::Color::rgbLuminance(out.r, out.g, out.b); + } + RGB refOut; fnp->getFilmNegativeSpot(provider->posImage, 32, refInputValues, refOut); - disableListener(); + // Output luminance of the sampled spot + float spotLum = rtengine::Color::rgbLuminance(refOut.r, refOut.g, refOut.b); + + float rexp = -(greenExp->getValue() * redRatio->getValue()); + float gexp = -greenExp->getValue(); + float bexp = -(greenExp->getValue() * blueRatio->getValue()); + + RGB mult = { + spotLum / pow_F(rtengine::max(refInputValues.r, 1.f), rexp), + spotLum / pow_F(rtengine::max(refInputValues.g, 1.f), gexp), + spotLum / pow_F(rtengine::max(refInputValues.b, 1.f), bexp) + }; + + // Calculate the new luminance of the initial luminance reference spot, by + // applying current multipliers + float newRefLum = rtengine::Color::rgbLuminance( + mult.r * pow_F(rtengine::max(refLuminance.input.r, 1.f), rexp), + mult.g * pow_F(rtengine::max(refLuminance.input.g, 1.f), gexp), + mult.b * pow_F(rtengine::max(refLuminance.input.b, 1.f), bexp)); + + // Choose a suitable gray value for the sampled spot, so that luminance + // of the initial reference spot is preserved. + float gray = spotLum * (refLuminance.lum / newRefLum); - float gray = rtengine::Color::rgbLuminance(refOut.r, refOut.g, refOut.b); writeOutputSliders({gray, gray, gray}); refInputLabel->set_text( diff --git a/rtgui/filmnegative.h b/rtgui/filmnegative.h index 64ec572d3..21a7dce5c 100644 --- a/rtgui/filmnegative.h +++ b/rtgui/filmnegative.h @@ -99,6 +99,17 @@ private: RGB refInputValues; bool paramsUpgraded; + /** + * Luminance reference: these input RGB values must produce this output luminance. + * This allows keeping constant luminance when picking several white balance spot + * samples in sequence; values are set on the initial white balance spot sampling, + * and reset every time params are read, or the output sliders are changed. + */ + struct { + RGB input; + float lum; + } refLuminance; + FilmNegProvider* fnp; MyComboBoxText* const colorSpace; From 3f58095b600becae988222e2a3402fc864178da7 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Fri, 4 Jun 2021 01:36:06 +0200 Subject: [PATCH 119/135] Updated generatePngIcons The script is now compatible with Inkscape 1.0 --- tools/generatePngIcons | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/generatePngIcons b/tools/generatePngIcons index 70ee3ee1b..9fee79c52 100755 --- a/tools/generatePngIcons +++ b/tools/generatePngIcons @@ -1,6 +1,7 @@ #!/usr/bin/env bash # By Maciej Dworak -# Version 2018-07-21 +# Version 2021-06-04 +# Compatible with Inkscape 1.0 # This script generates PNG icons from SVG files using Inkscape. # If pngquant is installed, it will automatically use it to compress the PNGs. # @@ -96,17 +97,17 @@ printf '%s\n' "Output folder: ${outDir}" "" convertSvg() { if [[ ${OSTYPE^^} = "MSYS" ]]; then "/c/Program Files/Inkscape/inkscape.exe" \ - --without-gui \ --export-area-page \ --export-background-opacity="0" \ - --export-png="$1" \ + --export-type=png \ + --export-filename="$1" \ "$2" else inkscape \ - --without-gui \ --export-area-page \ --export-background-opacity="0" \ - --export-png="$1" \ + --export-type=png \ + --export-filename="$1" \ "$2" fi From d86888e93f3c3999261cc5b32143449fc325a606 Mon Sep 17 00:00:00 2001 From: Bezierr <38507161+Bezierr@users.noreply.github.com> Date: Sat, 5 Jun 2021 05:37:09 +0000 Subject: [PATCH 120/135] Add resizing options "long edge" and "short edge" (#6263) Introduces "long edge" and "short edge" options to resize an image. The GUI is made such that the relevant spinboxes only appear for the selected option. Unrelated values (e.g. for box-mode) are not updated. --- rtdata/languages/default | 6 + rtengine/imagedata.cc | 1 - rtengine/ipresize.cc | 20 ++++ rtengine/procparams.cc | 8 ++ rtengine/procparams.h | 2 + rtengine/refreshmap.cc | 2 +- rtgui/filecatalog.cc | 4 + rtgui/options.cc | 12 ++ rtgui/options.h | 2 + rtgui/paramsedited.cc | 12 ++ rtgui/paramsedited.h | 2 + rtgui/resize.cc | 252 +++++++++++++++++++++++++++++++++++---- rtgui/resize.h | 16 ++- 13 files changed, 311 insertions(+), 28 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 69cc6adc3..792bd7fda 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1387,6 +1387,8 @@ HISTORY_MSG_RAWCACORR_AUTOIT;Raw CA Correction - Iterations HISTORY_MSG_RAWCACORR_COLORSHIFT;Raw CA Correction - Avoid color shift HISTORY_MSG_RAW_BORDER;Raw border HISTORY_MSG_RESIZE_ALLOWUPSCALING;Resize - Allow upscaling +HISTORY_MSG_RESIZE_LONGEDGE;Resize - Long Edge +HISTORY_MSG_RESIZE_SHORTEDGE;Resize - Short Edge HISTORY_MSG_SHARPENING_BLUR;Sharpening - Blur radius HISTORY_MSG_SHARPENING_CONTRAST;Sharpening - Contrast threshold HISTORY_MSG_SH_COLORSPACE;S/H - Colorspace @@ -3472,10 +3474,14 @@ TP_RESIZE_H;Height: TP_RESIZE_HEIGHT;Height TP_RESIZE_LABEL;Resize TP_RESIZE_LANCZOS;Lanczos +TP_RESIZE_LE;Long Edge: +TP_RESIZE_LONG;Long Edge TP_RESIZE_METHOD;Method: TP_RESIZE_NEAREST;Nearest TP_RESIZE_SCALE;Scale TP_RESIZE_SPECIFY;Specify: +TP_RESIZE_SE;Short Edge: +TP_RESIZE_SHORT;Short Edge TP_RESIZE_W;Width: TP_RESIZE_WIDTH;Width TP_RETINEX_CONTEDIT_HSL;HSL histogram diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 16b6a4c91..5ecfa8414 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -339,7 +339,6 @@ FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* iso_speed = isoTag->toDouble(); } } - } if (lens == "Unknown") { diff --git a/rtengine/ipresize.cc b/rtengine/ipresize.cc index b9e234b63..b6bdc5ede 100644 --- a/rtengine/ipresize.cc +++ b/rtengine/ipresize.cc @@ -379,6 +379,26 @@ float ImProcFunctions::resizeScale (const ProcParams* params, int fw, int fh, in dScale = (dScale > 1.0 && !params->resize.allowUpscaling) ? 1.0 : dScale; break; + + case (4): + + // Long Edge + if (refw > refh) { + dScale = (double)params->resize.longedge / (double)refw; + } else { + dScale = (double)params->resize.longedge / (double)refh; + } + break; + + case (5): + + // Short Edge + if (refw > refh) { + dScale = (double)params->resize.shortedge / (double)refh; + } else { + dScale = (double)params->resize.shortedge / (double)refw; + } + break; default: // Scale diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 26c51e3c6..870a9a71e 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2228,6 +2228,8 @@ ResizeParams::ResizeParams() : dataspec(3), width(900), height(900), + longedge(900), + shortedge(900), allowUpscaling(false) { } @@ -2242,6 +2244,8 @@ bool ResizeParams::operator ==(const ResizeParams& other) const && dataspec == other.dataspec && width == other.width && height == other.height + && longedge == other.longedge + && shortedge == other.shortedge && allowUpscaling == other.allowUpscaling; } @@ -6540,6 +6544,8 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->resize.dataspec, "Resize", "DataSpecified", resize.dataspec, keyFile); saveToKeyfile(!pedited || pedited->resize.width, "Resize", "Width", resize.width, keyFile); saveToKeyfile(!pedited || pedited->resize.height, "Resize", "Height", resize.height, keyFile); + saveToKeyfile(!pedited || pedited->resize.longedge, "Resize", "LongEdge", resize.longedge, keyFile); + saveToKeyfile(!pedited || pedited->resize.shortedge, "Resize", "ShortEdge", resize.shortedge, keyFile); saveToKeyfile(!pedited || pedited->resize.allowUpscaling, "Resize", "AllowUpscaling", resize.allowUpscaling, keyFile); // Post demosaic sharpening @@ -8574,6 +8580,8 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Resize", "DataSpecified", pedited, resize.dataspec, pedited->resize.dataspec); assignFromKeyfile(keyFile, "Resize", "Width", pedited, resize.width, pedited->resize.width); assignFromKeyfile(keyFile, "Resize", "Height", pedited, resize.height, pedited->resize.height); + assignFromKeyfile(keyFile, "Resize", "LongEdge", pedited, resize.longedge, pedited->resize.longedge); + assignFromKeyfile(keyFile, "Resize", "ShortEdge", pedited, resize.shortedge, pedited->resize.shortedge); if (ppVersion >= 339) { assignFromKeyfile(keyFile, "Resize", "AllowUpscaling", pedited, resize.allowUpscaling, pedited->resize.allowUpscaling); } else { diff --git a/rtengine/procparams.h b/rtengine/procparams.h index c9695a4ad..b0e7f9cd4 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1690,6 +1690,8 @@ struct ResizeParams { int dataspec; int width; int height; + int longedge; + int shortedge; bool allowUpscaling; ResizeParams(); diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 451164b8c..722898642 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -74,7 +74,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { 0, // EvLDNEdgeTolerance: obsolete, 0, // EvCDNEnabled:obsolete, 0, // free entry - RGBCURVE | M_AUTOEXP, // EvDCPToneCurve, + RGBCURVE | M_AUTOEXP, // EvDCPToneCurve, ALLNORAW, // EvDCPIlluminant, LUMINANCECURVE, // EvSHEnabled, LUMINANCECURVE, // EvSHHighlights, diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index c45fc154f..58c1bbc1b 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1215,9 +1215,13 @@ void FileCatalog::developRequested(const std::vector& tbe, bo if (params.resize.enabled) { params.resize.width = rtengine::min(params.resize.width, options.fastexport_resize_width); params.resize.height = rtengine::min(params.resize.height, options.fastexport_resize_height); + params.resize.longedge = rtengine::min(params.resize.longedge, options.fastexport_resize_longedge); + params.resize.shortedge = rtengine::min(params.resize.shortedge, options.fastexport_resize_shortedge); } else { params.resize.width = options.fastexport_resize_width; params.resize.height = options.fastexport_resize_height; + params.resize.longedge = options.fastexport_resize_longedge; + params.resize.shortedge = options.fastexport_resize_shortedge; } params.resize.enabled = options.fastexport_resize_enabled; diff --git a/rtgui/options.cc b/rtgui/options.cc index 1b6d09f4c..ec36eb166 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -539,6 +539,8 @@ void Options::setDefaults() fastexport_resize_dataspec = 3; fastexport_resize_width = 900; fastexport_resize_height = 900; + fastexport_resize_longedge = 900; + fastexport_resize_shortedge = 900; fastexport_use_fast_pipeline = true; clutsDir = "./cluts"; @@ -2018,6 +2020,14 @@ void Options::readFromFile(Glib::ustring fname) fastexport_resize_height = keyFile.get_integer("Fast Export", "fastexport_resize_height"); } + if (keyFile.has_key("Fast Export", "fastexport_resize_longedge")) { + fastexport_resize_longedge = keyFile.get_integer("Fast Export", "fastexport_resize_longedge"); + } + + if (keyFile.has_key("Fast Export", "fastexport_resize_shortedge")) { + fastexport_resize_shortedge = keyFile.get_integer("Fast Export", "fastexport_resize_shortedge"); + } + if (keyFile.has_key("Fast Export", "fastexport_use_fast_pipeline")) { fastexport_use_fast_pipeline = keyFile.get_integer("Fast Export", "fastexport_use_fast_pipeline"); } @@ -2454,6 +2464,8 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_integer("Fast Export", "fastexport_resize_dataspec", fastexport_resize_dataspec); keyFile.set_integer("Fast Export", "fastexport_resize_width", fastexport_resize_width); keyFile.set_integer("Fast Export", "fastexport_resize_height", fastexport_resize_height); + keyFile.set_integer("Fast Export", "fastexport_resize_longedge", fastexport_resize_longedge); + keyFile.set_integer("Fast Export", "fastexport_resize_shortedge", fastexport_resize_shortedge); keyFile.set_integer("Fast Export", "fastexport_use_fast_pipeline", fastexport_use_fast_pipeline); keyFile.set_string("Dialogs", "LastIccDir", lastIccDir); diff --git a/rtgui/options.h b/rtgui/options.h index 52e1c0270..19963ba39 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -424,6 +424,8 @@ public: int fastexport_resize_dataspec; int fastexport_resize_width; int fastexport_resize_height; + int fastexport_resize_longedge; + int fastexport_resize_shortedge; bool fastexport_use_fast_pipeline; std::vector favorites; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index a28d666b4..ada149b95 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -425,6 +425,8 @@ void ParamsEdited::set(bool v) resize.dataspec = v; resize.width = v; resize.height = v; + resize.longedge = v; + resize.shortedge = v; resize.enabled = v; spot.enabled = v; @@ -1718,6 +1720,8 @@ void ParamsEdited::initFrom(const std::vector& resize.dataspec = resize.dataspec && p.resize.dataspec == other.resize.dataspec; resize.width = resize.width && p.resize.width == other.resize.width; resize.height = resize.height && p.resize.height == other.resize.height; + resize.longedge = resize.longedge && p.resize.longedge == other.resize.longedge; + resize.shortedge = resize.shortedge && p.resize.shortedge == other.resize.shortedge; resize.enabled = resize.enabled && p.resize.enabled == other.resize.enabled; spot.enabled = spot.enabled && p.spot.enabled == other.spot.enabled; spot.entries = spot.entries && p.spot.entries == other.spot.entries; @@ -5718,6 +5722,14 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.resize.height = mods.resize.height; } + if (resize.longedge) { + toEdit.resize.longedge = mods.resize.longedge; + } + + if (resize.shortedge) { + toEdit.resize.shortedge = mods.resize.shortedge; + } + if (resize.enabled) { toEdit.resize.enabled = mods.resize.enabled; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index a422b653e..87f510e64 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -1083,6 +1083,8 @@ struct ResizeParamsEdited { bool dataspec; bool width; bool height; + bool longedge; + bool shortedge; bool enabled; bool allowUpscaling; }; diff --git a/rtgui/resize.cc b/rtgui/resize.cc index 314377049..55764d085 100644 --- a/rtgui/resize.cc +++ b/rtgui/resize.cc @@ -33,6 +33,8 @@ Resize::Resize () : FoldableToolPanel(this, "resize", M("TP_RESIZE_LABEL"), fals { auto m = ProcEventMapper::getInstance(); EvResizeAllowUpscaling = m->newEvent(RESIZE, "HISTORY_MSG_RESIZE_ALLOWUPSCALING"); + EvResizeLongedge = m->newEvent (RESIZE, "HISTORY_MSG_RESIZE_LONGEDGE"); + EvResizeShortedge = m->newEvent (RESIZE, "HISTORY_MSG_RESIZE_SHORTEDGE"); cropw = 0; croph = 0; @@ -70,6 +72,8 @@ Resize::Resize () : FoldableToolPanel(this, "resize", M("TP_RESIZE_LABEL"), fals spec->append (M("TP_RESIZE_WIDTH")); spec->append (M("TP_RESIZE_HEIGHT")); spec->append (M("TP_RESIZE_FITBOX")); + spec->append (M("TP_RESIZE_LONG")); + spec->append (M("TP_RESIZE_SHORT")); spec->set_active (0); spec->set_hexpand(); spec->set_halign(Gtk::ALIGN_FILL); @@ -91,19 +95,46 @@ Resize::Resize () : FoldableToolPanel(this, "resize", M("TP_RESIZE_LABEL"), fals Gtk::Box* sbox = Gtk::manage (new Gtk::Box ()); Gtk::Box* wbox = Gtk::manage (new Gtk::Box ()); Gtk::Box* hbox = Gtk::manage (new Gtk::Box ()); + Gtk::Box* ebox = Gtk::manage (new Gtk::Box ()); + Gtk::Box* lebox = Gtk::manage (new Gtk::Box ()); + Gtk::Box* sebox = Gtk::manage (new Gtk::Box ()); + w = Gtk::manage (new MySpinButton ()); + w->set_width_chars(5); + setExpandAlignProperties(w, false, false, Gtk::ALIGN_END, Gtk::ALIGN_CENTER); h = Gtk::manage (new MySpinButton ()); - wbox->set_spacing(3); + h->set_width_chars(5); + setExpandAlignProperties(h, false, false, Gtk::ALIGN_END, Gtk::ALIGN_CENTER); + le = Gtk::manage (new MySpinButton ()); + le->set_width_chars(5); + setExpandAlignProperties(le, false, false, Gtk::ALIGN_END, Gtk::ALIGN_CENTER); + se = Gtk::manage (new MySpinButton ()); + se->set_width_chars(5); + setExpandAlignProperties(se, false, false, Gtk::ALIGN_END, Gtk::ALIGN_CENTER); + wbox->pack_start (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_W"))), Gtk::PACK_SHRINK, 0); wbox->pack_start (*w); hbox->set_spacing(3); hbox->pack_start (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_H"))), Gtk::PACK_SHRINK, 0); hbox->pack_start (*h); + lebox->set_spacing(3); + lebox->pack_start (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_LE"))), Gtk::PACK_SHRINK, 0); + lebox->pack_start (*le); + sebox->set_spacing(3); + sebox->pack_start (*Gtk::manage (new Gtk::Label (M("TP_RESIZE_SE"))), Gtk::PACK_SHRINK, 0); + sebox->pack_start (*se); + sbox->set_spacing(4); sbox->pack_start (*wbox); sbox->pack_start (*hbox); - + sbox->set_homogeneous(); + ebox->set_spacing(4); + ebox->pack_start (*lebox); + ebox->pack_start (*sebox); + ebox->set_homogeneous(); + sizeBox->pack_start (*sbox, Gtk::PACK_SHRINK, 0); + sizeBox->pack_start (*ebox, Gtk::PACK_SHRINK, 0); sizeBox->show_all (); sizeBox->reference (); @@ -113,16 +144,28 @@ Resize::Resize () : FoldableToolPanel(this, "resize", M("TP_RESIZE_LABEL"), fals w->set_digits (0); w->set_increments (1, 100); - w->set_value (800); w->set_range (32, MAX_SCALE * maxw); + w->set_value (800); // Doesn't seem to have any effect (overwritten in Resize::read) h->set_digits (0); h->set_increments (1, 100); - h->set_value (600); h->set_range (32, MAX_SCALE * maxh); + h->set_value (600); // Doesn't seem to have any effect (overwritten in Resize::read) + + le->set_digits (0); + le->set_increments (1, 100); + le->set_range (32, MAX_SCALE * maxw); + le->set_value (900); + + se->set_digits (0); + se->set_increments (1, 100); + se->set_range (32, MAX_SCALE * maxh); + se->set_value (900); wconn = w->signal_value_changed().connect ( sigc::mem_fun(*this, &Resize::entryWChanged), true); hconn = h->signal_value_changed().connect ( sigc::mem_fun(*this, &Resize::entryHChanged), true); + leconn = le->signal_value_changed().connect ( sigc::mem_fun(*this, &Resize::entryLEChanged), true); + seconn = se->signal_value_changed().connect ( sigc::mem_fun(*this, &Resize::entrySEChanged), true); aconn = appliesTo->signal_changed().connect ( sigc::mem_fun(*this, &Resize::appliesToChanged) ); method->signal_changed().connect ( sigc::mem_fun(*this, &Resize::methodChanged) ); sconn = spec->signal_changed().connect ( sigc::mem_fun(*this, &Resize::specChanged) ); @@ -149,15 +192,20 @@ void Resize::read (const ProcParams* pp, const ParamsEdited* pedited) aconn.block (true); wconn.block (true); hconn.block (true); + leconn.block (true); + seconn.block (true); sconn.block (true); scale->block(true); scale->setValue (pp->resize.scale); w->set_value (pp->resize.width); h->set_value (pp->resize.height); + le->set_value (pp->resize.longedge); + se->set_value (pp->resize.shortedge); setEnabled (pp->resize.enabled); spec->set_active (pp->resize.dataspec); allowUpscaling->set_active(pp->resize.allowUpscaling); + setDimensions(); // Sets Width/Height in the GUI according to value of Specify after loading a .pp3 profile (same behavior as if changed manually) updateGUI(); appliesTo->set_active (0); @@ -178,10 +226,14 @@ void Resize::read (const ProcParams* pp, const ParamsEdited* pedited) wDirty = false; hDirty = false; + leDirty = false; + seDirty = false; if (pedited) { wDirty = pedited->resize.width; hDirty = pedited->resize.height; + leDirty = pedited->resize.longedge; + seDirty = pedited->resize.shortedge; scale->setEditedState (pedited->resize.scale ? Edited : UnEdited); if (!pedited->resize.appliesTo) { @@ -193,7 +245,7 @@ void Resize::read (const ProcParams* pp, const ParamsEdited* pedited) } if (!pedited->resize.dataspec) { - spec->set_active (4); + spec->set_active (6); } allowUpscaling->set_inconsistent(!pedited->resize.allowUpscaling); @@ -204,6 +256,8 @@ void Resize::read (const ProcParams* pp, const ParamsEdited* pedited) sconn.block (false); wconn.block (false); hconn.block (false); + leconn.block (false); + seconn.block (false); aconn.block (false); enableListener (); } @@ -211,7 +265,7 @@ void Resize::read (const ProcParams* pp, const ParamsEdited* pedited) void Resize::write (ProcParams* pp, ParamsEdited* pedited) { int dataSpec = spec->get_active_row_number(); - + pp->resize.scale = scale->getValue(); pp->resize.appliesTo = "Cropped area"; @@ -233,6 +287,8 @@ void Resize::write (ProcParams* pp, ParamsEdited* pedited) pp->resize.dataspec = dataSpec; pp->resize.width = w->get_value_as_int (); pp->resize.height = h->get_value_as_int (); + pp->resize.longedge = le->get_value_as_int (); + pp->resize.shortedge = se->get_value_as_int (); pp->resize.enabled = getEnabled (); //printf(" L:%d H:%d\n", pp->resize.width, pp->resize.height); @@ -240,7 +296,7 @@ void Resize::write (ProcParams* pp, ParamsEdited* pedited) if (pedited) { pedited->resize.enabled = !get_inconsistent(); - pedited->resize.dataspec = dataSpec != MAX_SCALE; + pedited->resize.dataspec = dataSpec != 6; pedited->resize.appliesTo = appliesTo->get_active_row_number() != 2; pedited->resize.method = method->get_active_row_number() != 3; @@ -248,10 +304,14 @@ void Resize::write (ProcParams* pp, ParamsEdited* pedited) pedited->resize.scale = scale->getEditedState (); pedited->resize.width = wDirty; pedited->resize.height = hDirty; + pedited->resize.longedge = leDirty; + pedited->resize.shortedge = seDirty; } else { pedited->resize.scale = false; pedited->resize.width = false; pedited->resize.height = false; + pedited->resize.longedge = false; + pedited->resize.shortedge = false; } pedited->resize.allowUpscaling = !allowUpscaling->get_inconsistent(); } @@ -285,31 +345,31 @@ void Resize::adjusterChanged(Adjuster* a, double newval) } } -int Resize::getComputedWidth() +int Resize::getComputedWidth(double height) { if (cropw && appliesTo->get_active_row_number() == 0) // we use the crop dimensions { - return (int)((double)(cropw) * (h->get_value() / (double)(croph)) + 0.5); + return (int)((double)(cropw) * (height / (double)(croph)) + 0.5); } else // we use the image dimensions { - return (int)((double)(maxw) * (h->get_value() / (double)(maxh)) + 0.5); + return (int)((double)(maxw) * (height / (double)(maxh)) + 0.5); } } -int Resize::getComputedHeight() +int Resize::getComputedHeight(double width) { if (croph && appliesTo->get_active_row_number() == 0) // we use the crop dimensions { - return (int)((double)(croph) * (w->get_value() / (double)(cropw)) + 0.5); + return (int)((double)(croph) * (width / (double)(cropw)) + 0.5); } else // we use the image dimensions { - return (int)((double)(maxh) * (w->get_value() / (double)(maxw)) + 0.5); + return (int)((double)(maxh) * (width / (double)(maxw)) + 0.5); } } @@ -379,8 +439,10 @@ void Resize::setDimensions () { wconn.block(true); hconn.block(true); + leconn.block(true); + seconn.block(true); scale->block(true); - + int refw, refh; if (appliesTo->get_active_row_number() == 0 && cropw) { @@ -431,6 +493,34 @@ void Resize::setDimensions () break; } + case 4: { + // Long edge mode + if (refw > refh) { + const double tmp_scale = le->get_value() / static_cast(refw); + scale->setValue(tmp_scale); + se->set_value(static_cast(static_cast(static_cast(refh) * tmp_scale + 0.5))); + } else { + const double tmp_scale = le->get_value() / static_cast(refh); + scale->setValue(tmp_scale); + se->set_value(static_cast(static_cast(static_cast(refw) * tmp_scale + 0.5))); + } + break; + } + + case 5: { + // Short edge mode + if (refw > refh) { + const double tmp_scale = se->get_value() / static_cast(refh); + scale->setValue(tmp_scale); + le->set_value(static_cast(static_cast(static_cast(refw) * tmp_scale + 0.5))); + } else { + const double tmp_scale = se->get_value() / static_cast(refw); + scale->setValue(tmp_scale); + le->set_value(static_cast(static_cast(static_cast(refh) * tmp_scale + 0.5))); + } + break; + } + default: { break; } @@ -439,6 +529,8 @@ void Resize::setDimensions () scale->block(false); wconn.block(false); hconn.block(false); + leconn.block(false); + seconn.block(false); return false; } @@ -489,7 +581,7 @@ void Resize::entryWChanged () hconn.block (true); scale->block (true); - h->set_value ((double)(getComputedHeight())); + h->set_value ((double)(getComputedHeight(w->get_value()))); scale->setValue (w->get_value () / (cropw && appliesTo->get_active_row_number() == 0 ? (double)cropw : (double)maxw)); scale->block (false); @@ -522,7 +614,7 @@ void Resize::entryHChanged () wconn.block (true); scale->block (true); - w->set_value ((double)(getComputedWidth())); + w->set_value ((double)(getComputedWidth(h->get_value()))); scale->setValue (h->get_value () / (croph && appliesTo->get_active_row_number() == 0 ? (double)croph : (double)maxh)); scale->block (false); @@ -541,25 +633,107 @@ void Resize::entryHChanged () } } +void Resize::entryLEChanged () +{ + + leDirty = true; + + // updating long edge + if (!batchMode && listener) { + int refw, refh; + + seconn.block (true); + scale->block (true); + + if (cropw && appliesTo->get_active_row_number() == 0) { + // we use the crop dimensions + refw = cropw; + refh = croph; + } else { + // we use the image dimensions + refw = maxw; + refh = maxh; + } + + if (refw > refh) { + se->set_value ((double) (getComputedHeight(le->get_value()))); + scale->setValue (le->get_value () / (cropw && appliesTo->get_active_row_number() == 0 ? (double)cropw : (double)maxw)); + } else { + se->set_value ((double)(getComputedWidth(le->get_value()))); + scale->setValue (le->get_value () / (croph && appliesTo->get_active_row_number() == 0 ? (double)croph : (double)maxh)); + } + + scale->block (false); + seconn.block (false); + } + + if (listener) { + if (getEnabled () || batchMode) { + listener->panelChanged (EvResizeLongedge, Glib::ustring::format (le->get_value_as_int())); + } + } +} + +void Resize::entrySEChanged () +{ + + seDirty = true; + + // updating short edge + if (!batchMode && listener) { + int refw, refh; + + leconn.block (true); + scale->block (true); + + if (cropw && appliesTo->get_active_row_number() == 0) { + // we use the crop dimensions + refw = cropw; + refh = croph; + } else { + // we use the image dimensions + refw = maxw; + refh = maxh; + } + + if (refw > refh) { + le->set_value ((double)(getComputedWidth(se->get_value()))); + scale->setValue (se->get_value () / (croph && appliesTo->get_active_row_number() == 0 ? (double)croph : (double)maxh)); + } else { + le->set_value ((double)(getComputedHeight(se->get_value()))); + scale->setValue (se->get_value () / (cropw && appliesTo->get_active_row_number() == 0 ? (double)cropw : (double)maxw)); + } + + scale->block (false); + leconn.block (false); + } + + if (listener) { + if (getEnabled () || batchMode) { + listener->panelChanged (EvResizeShortedge, Glib::ustring::format (se->get_value_as_int())); + } + } +} + void Resize::specChanged () { switch (spec->get_active_row_number()) { case (0): // Scale mode - scale->sliderChanged (); + scale->sliderChanged(); break; case (1): // Width mode - w->set_value((double)(getComputedWidth())); - entryWChanged (); + w->set_value((double)(getComputedWidth(h->get_value()))); + entryWChanged(); break; case (2): // Height mode - h->set_value((double)(getComputedHeight())); - entryHChanged (); + h->set_value((double)(getComputedHeight(w->get_value()))); + entryHChanged(); break; case (3): @@ -567,6 +741,16 @@ void Resize::specChanged () notifyBBox(); break; + case (4): + // Long edge mode + entryLEChanged(); + break; + + case (5): + // Short edge mode + entrySEChanged(); + break; + default: break; } @@ -593,6 +777,8 @@ void Resize::updateGUI () reorder_child(*allowUpscaling, 4); w->set_sensitive (true); h->set_sensitive (false); + w->get_parent()->get_parent()->show(); + le->get_parent()->get_parent()->hide(); break; case (2): @@ -601,6 +787,8 @@ void Resize::updateGUI () reorder_child(*allowUpscaling, 4); w->set_sensitive (false); h->set_sensitive (true); + w->get_parent()->get_parent()->show(); + le->get_parent()->get_parent()->hide(); break; case (3): @@ -609,6 +797,28 @@ void Resize::updateGUI () reorder_child(*allowUpscaling, 4); w->set_sensitive (true); h->set_sensitive (true); + w->get_parent()->get_parent()->show(); + le->get_parent()->get_parent()->hide(); + break; + + case (4): + // Long edge mode + pack_start (*sizeBox, Gtk::PACK_SHRINK, 4); + reorder_child(*allowUpscaling, 4); + le->set_sensitive (true); + se->set_sensitive (false); + w->get_parent()->get_parent()->hide(); + le->get_parent()->get_parent()->show(); + break; + + case (5): + // Short edge mode + pack_start (*sizeBox, Gtk::PACK_SHRINK, 4); + reorder_child(*allowUpscaling, 4); + le->set_sensitive (false); + se->set_sensitive (true); + w->get_parent()->get_parent()->hide(); + le->get_parent()->get_parent()->show(); break; default: diff --git a/rtgui/resize.h b/rtgui/resize.h index ec4907fd1..d13bf8aa4 100644 --- a/rtgui/resize.h +++ b/rtgui/resize.h @@ -48,6 +48,8 @@ public: void adjusterChanged (Adjuster* a, double newval) override; void entryWChanged (); void entryHChanged (); + void entryLEChanged (); + void entrySEChanged (); void appliesToChanged (); void methodChanged (); void specChanged (); @@ -62,25 +64,29 @@ public: private: void fitBoxScale (); - int getComputedWidth (); - int getComputedHeight (); + int getComputedWidth (double height); + int getComputedHeight (double width); void notifyBBox (); void updateGUI (); void allowUpscalingChanged(); rtengine::ProcEvent EvResizeAllowUpscaling; + rtengine::ProcEvent EvResizeLongedge; + rtengine::ProcEvent EvResizeShortedge; Adjuster* scale; - Gtk::Box* sizeBox; + Gtk::Box* sizeBox; MyComboBoxText* appliesTo; MyComboBoxText* method; MyComboBoxText* spec; MySpinButton* w; MySpinButton* h; + MySpinButton* le; + MySpinButton* se; Gtk::CheckButton *allowUpscaling; int maxw, maxh; int cropw, croph; - sigc::connection sconn, aconn, wconn, hconn; - bool wDirty, hDirty; + sigc::connection sconn, aconn, wconn, hconn, leconn, seconn; + bool wDirty, hDirty, leDirty, seDirty; ToolParamBlock* packBox; IdleRegister idle_register; From 9d052e267da7117fc91c9e24d1b1eaf52d11fe8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Mon, 7 Jun 2021 15:12:09 +0200 Subject: [PATCH 121/135] Fix "unused variable" warning on release builds --- rtgui/spot.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index d9a6be6b7..35028415b 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -361,6 +361,7 @@ void Spot::createGeometry () EditSubscriber::visibleGeometry.at (j++) = &targetFeatherCircle; // VISIBLE_OBJECT_COUNT + 4 assert(j - visibleOffset == VISIBLE_TARGET_CIRCLE); EditSubscriber::visibleGeometry.at (j++) = &targetCircle; // VISIBLE_OBJECT_COUNT + 5 + static_cast(visibleOffset); } void Spot::updateGeometry() From d02ed52e0087b0b3f9df0085b5cd55953ae9bb30 Mon Sep 17 00:00:00 2001 From: Desmis Date: Tue, 8 Jun 2021 07:38:47 +0200 Subject: [PATCH 122/135] Local adjustments - improve exposure - issue 6274 (#6277) * Various change to improve LA exposure * Removed pow_Fr - clean code * Remove unused code --- rtengine/iplocallab.cc | 7 ------- rtengine/opthelper.h | 2 +- rtengine/sleef.h | 1 - 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 5b7160b83..7bca595ea 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -1647,13 +1647,6 @@ static void calcLocalParams(int sp, int oW, int oH, const LocallabParams& locall lp.hlcomp = locallab.spots.at(sp).hlcompr; lp.hlcompthr = locallab.spots.at(sp).hlcomprthresh; lp.expcomp = LIM(locallab.spots.at(sp).expcomp, -2.0, 4.0); //to prevent crash with Old pp3 with integer - //increase sensitivity for low values - float proexp = lp.expcomp; - if (std::fabs(proexp) < 0.6f) { - float interm = std::fabs(proexp) / 0.6f; - interm = pow(interm, 3.f); - lp.expcomp = proexp * interm; - } lp.expchroma = locallab.spots.at(sp).expchroma / 100.; lp.sensex = local_sensiex; lp.war = local_warm; diff --git a/rtengine/opthelper.h b/rtengine/opthelper.h index f431c0ec9..8de3b781b 100644 --- a/rtengine/opthelper.h +++ b/rtengine/opthelper.h @@ -20,7 +20,7 @@ //////////////////////////////////////////////////////////////// #pragma once -#define pow_F(a,b) (xexpf(b*xlogf(a))) +#define pow_F(a,b) (xexpf((b)*xlogf(a))) #ifdef __SSE2__ #include "sleefsseavx.h" diff --git a/rtengine/sleef.h b/rtengine/sleef.h index 8611e2fc7..e630d882d 100644 --- a/rtengine/sleef.h +++ b/rtengine/sleef.h @@ -26,7 +26,6 @@ #define L2U .69314718055966295651160180568695068359375 #define L2L .28235290563031577122588448175013436025525412068e-12 #define R_LN2 1.442695040888963407359924681001892137426645954152985934135449406931 -#define pow_F(a,b) (xexpf(b*xlogf(a))) __inline int64_t doubleToRawLongBits(double d) { union { From a2c5fd0f919f4a75ccb5b7537ae12ac55391e7d9 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 12 Jun 2021 11:37:38 -0700 Subject: [PATCH 123/135] Fix drag position after alternate button press When a button is released and the edit state is not "dragging", reset the drag delta to zero. There was a problem with the spot removal spots being dragged. If a spot is deleted while being dragged, dragging another spot will cause a jump. --- rtgui/cropwindow.cc | 7 +++++++ rtgui/spot.cc | 1 + 2 files changed, 8 insertions(+) diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index b612de2e7..2927cdf32 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -794,6 +794,13 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y) iarea->setToolHand (); } + if (state != SEditDrag1 && state != SEditDrag2 && state != SEditDrag3) { + iarea->deltaImage.set(0, 0); + iarea->deltaScreen.set(0, 0); + iarea->deltaPrevImage.set(0, 0); + iarea->deltaPrevScreen.set(0, 0); + } + if (cropgl && (state == SCropSelecting || state == SResizeH1 || state == SResizeH2 || state == SResizeW1 || state == SResizeW2 || state == SResizeTL || state == SResizeTR || state == SResizeBL || state == SResizeBR || state == SCropMove)) { cropgl->cropManipReady (); iarea->setToolHand (); diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 35028415b..4f2d700cc 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -667,6 +667,7 @@ bool Spot::button3Pressed (int modifierKey) return true; } else if (! (modifierKey & (GDK_SHIFT_MASK | GDK_SHIFT_MASK))) { EditSubscriber::action = EditSubscriber::Action::PICKING; + return true; } return false; From c13cc02768e17271e8a93fde34790fcec0865c3b Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 12 Jun 2021 11:46:54 -0700 Subject: [PATCH 124/135] Un-highlight spot removal spots after deletion --- rtgui/spot.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 4f2d700cc..07425ee4b 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -428,6 +428,11 @@ void Spot::updateGeometry() sourceCircle.setVisible(draggedSide != DraggedSide::SOURCE); targetCircle.setVisible(draggedSide != DraggedSide::TARGET); } else { + targetCircle.state = Geometry::NORMAL; + sourceCircle.state = Geometry::NORMAL; + targetFeatherCircle.state = Geometry::NORMAL; + sourceFeatherCircle.state = Geometry::NORMAL; + targetCircle.setActive (false); targetMODisc.setActive (false); sourceIcon.setActive (false); From 3248e6b0035fd6fff88d8f228990ba51ca16bbc6 Mon Sep 17 00:00:00 2001 From: Jonathan Bieler Date: Sat, 12 Jun 2021 21:07:44 +0200 Subject: [PATCH 125/135] Reduce artifacts in parametric curve calculation (#6219) --- rtengine/curves.h | 15 +++++++++++++++ rtengine/diagonalcurves.cc | 28 ++++++++++++++++------------ 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/rtengine/curves.h b/rtengine/curves.h index 8800e54db..02503aff2 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -142,11 +142,19 @@ protected: double lx = xlog(x); return m2 * x + (1.0 - m2) * (2.0 - xexp(k * lx)) * xexp(l * lx); } + static inline double basel_alt(double x) + { + return (2.0 - x) * x * x * x; + } // 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); } + static inline double baseu_alt(double x) + { + return x * (2.0 + (x - 2.0) * x * x); + } // 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) { @@ -448,6 +456,13 @@ protected: { 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); } + static inline double pfull_alt(double x, double sh, double hl) + { + double t = (1.0 - sh) * (1.0 - hl) * CurveFactory::basel_alt(x) + sh * hl * CurveFactory::baseu_alt(x); + return x <= 0.5 + ? t + (1.0 - sh) * hl * CurveFactory::basel_alt(2.0 * x) * 0.5 + sh * (1.0 - hl) * CurveFactory::baseu_alt(2.0 * x) * 0.5 + : t + (1.0 - sh) * hl * (0.5 + CurveFactory::baseu_alt(2.0 * x - 1.0) * 0.5) + sh * (1.0 - hl) * (0.5 + CurveFactory::basel_alt(2.0 * x - 1.0) * 0.5); + } void fillHash(); void fillDyByDx(); diff --git a/rtengine/diagonalcurves.cc b/rtengine/diagonalcurves.cc index 622683ea2..8a1c6ccbb 100644 --- a/rtengine/diagonalcurves.cc +++ b/rtengine/diagonalcurves.cc @@ -116,8 +116,8 @@ DiagonalCurve::DiagonalCurve (const std::vector& p, int poly_pn) } mc = -xlog(2.0) / xlog(x[2]); - double mbase = pfull (0.5, x[8], x[6], x[5]); - mfc = mbase <= 1e-14 ? 0.0 : xexp(xlog(mbase) / mc); // value of the curve at the center point + double mbase = pfull_alt (0.5, x[6], x[5]); + mfc = xexp(xlog(mbase) / mc); // value of the curve at the center point msc = -xlog(2.0) / xlog(x[1] / x[2]); mhc = -xlog(2.0) / xlog((x[3] - x[2]) / (1 - x[2])); } @@ -424,7 +424,6 @@ void DiagonalCurve::catmull_rom_set() /*****************************************************************************/ - double DiagonalCurve::getVal (double t) const { @@ -435,20 +434,25 @@ double DiagonalCurve::getVal (double t) const return 0.0; } - double tv = xexp(mc * xlog(t)); - double base = pfull (tv, x[8], x[6], x[5]); - double stretched = base <= 1e-14 ? 0.0 : xexp(xlog(base) / mc); + double tv = xexp(max(mc * xlog(t),-236.0)); // prevents numerical issues when calling pfull, at the cost of minor artifacts + double base = pfull_alt (tv, x[6], x[5]); + double stretched = xexp(xlog(base) / mc); if (t < x[2]) { // add shadows effect: - double stv = xexp(msc * xlog(stretched / mfc)); - double sbase = pfull (stv, x[8], x[7], 0.5); - return mfc * (sbase <= 1e-14 ? 0.0 : xexp(xlog(sbase) / msc)); + double stv = xexp(max(msc * xlog(stretched / mfc),-236.0)); + double sbase = pfull_alt (stv, x[7], 0.5); + return mfc * xexp(xlog(sbase) / msc); } else { // add highlights effect: - double htv = xexp(mhc * xlog((stretched - mfc) / (1 - mfc))); - double hbase = pfull (htv, x[8], 0.5, x[4]); - return mfc + (1 - mfc) * (hbase <= 1e-14 ? 0.0 : xexp(xlog(hbase) / mhc)); + double htv = xexp(max(mhc * xlog((stretched - mfc) / (1.0 - mfc)),-236.0)); + double hbase = pfull_alt (htv, 0.5, x[4]); + //this part of the curve isn't affected by highlight, return the base curve + if (hbase < 1e-6 ){ + return stretched; + } else { + return mfc + (1.0 - mfc) * xexp(xlog(hbase) / mhc); + } } break; From 869ac542425676eabdded25893aabdb2ed5d38d9 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Sat, 12 Jun 2021 21:11:45 +0200 Subject: [PATCH 126/135] Minor update to the parametric curve fix --- rtengine/diagonalcurves.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rtengine/diagonalcurves.cc b/rtengine/diagonalcurves.cc index 8a1c6ccbb..1173f8803 100644 --- a/rtengine/diagonalcurves.cc +++ b/rtengine/diagonalcurves.cc @@ -446,11 +446,10 @@ double DiagonalCurve::getVal (double t) const } else { // add highlights effect: double htv = xexp(max(mhc * xlog((stretched - mfc) / (1.0 - mfc)),-236.0)); - double hbase = pfull_alt (htv, 0.5, x[4]); - //this part of the curve isn't affected by highlight, return the base curve - if (hbase < 1e-6 ){ - return stretched; + if (htv < 1e-6) { + return stretched; // this part of the curve isn't affected by highlight, return the base curve } else { + double hbase = pfull_alt (htv, 0.5, x[4]); return mfc + (1.0 - mfc) * xexp(xlog(hbase) / mhc); } } From c937e09e632a9ff6b5db0523ca5d9e5c1fe2a4c7 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Wed, 16 Jun 2021 19:26:30 +0200 Subject: [PATCH 127/135] Fix raw crop for Canon EOS R5 --- rtengine/camconst.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 0d50b35f7..157bef8a4 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1211,7 +1211,7 @@ Camera constants: { // Quality C "make_model": "Canon EOS R5", "dcraw_matrix" : [9766, -2953, -1254, -4276, 12116, 2433, -437, 1336, 5131], - "raw_crop" : [ 124, 92, 8220, 5486 ], + "raw_crop" : [ 128, 96, 8224, 5490 ], "masked_areas" : [ 94, 20, 5578, 122 ], "ranges" : { "white" : 16382 } }, From b35e0d82694c3d5a80c5decdcd2ddb096f505a07 Mon Sep 17 00:00:00 2001 From: Desmis Date: Fri, 18 Jun 2021 08:45:29 +0200 Subject: [PATCH 128/135] Fixed bad behavior GUI in inverse Dynamic Range --- rtgui/locallabtools.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc index 45262bce3..bcdda8317 100644 --- a/rtgui/locallabtools.cc +++ b/rtgui/locallabtools.cc @@ -3816,6 +3816,8 @@ void LocallabExposure::updateExposureGUI3() expcomp->setLabel(M("TP_LOCALLAB_EXPCOMPINV")); exprecove->hide(); reparexp->hide(); + expfat->hide(); + exppde->hide(); // Manage specific case where expMethod is different from 0 if (expMethod->get_active_row_number() > 0) { @@ -3838,6 +3840,8 @@ void LocallabExposure::updateExposureGUI3() } else { expMethod->show(); expcomp->setLabel(M("TP_LOCALLAB_EXPCOMP")); + expfat->show(); + exppde->show(); if (mode == Expert || mode == Normal) { // Keep widgets hidden in Simple mode softradiusexp->show(); From a6a8ee0e4074205cceab2df3c76fb79e2dee3d93 Mon Sep 17 00:00:00 2001 From: Desmis Date: Sat, 19 Jun 2021 10:36:30 +0200 Subject: [PATCH 129/135] Others fix bad behavior Dynamic range and exposure --- rtengine/iplocallab.cc | 5 +++++ rtgui/locallabtools.cc | 24 ++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 7bca595ea..fcc8a9462 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -3003,6 +3003,7 @@ void ImProcFunctions::exlabLocal(local_params& lp, float strlap, int bfh, int bf const bool exec = (lp.expmet == 1 && linear > 0.f && lp.laplacexp > 0.1f); if(!exec) {//for standard exposure + const float cexp_scale = std::pow(2.f, lp.expcomp); const float ccomp = (rtengine::max(0.f, lp.expcomp) + 1.f) * lp.hlcomp / 100.f; const float cshoulder = ((maxran / rtengine::max(1.0f, cexp_scale)) * (lp.hlcompthr / 200.f)) + 0.1f; @@ -14896,6 +14897,10 @@ void ImProcFunctions::Lab_Local( } else { + if (lp.expcomp == 0.f && (lp.linear > 0.01f && lp.laplacexp > 0.1f)) { + lp.expcomp = 0.001f;// to enabled + } + if (lp.expcomp != 0.f ) { // || lp.laplacexp > 0.1f if(lp.laplacexp <= 0.1f) { lp.laplacexp = 0.2f; //force to use Laplacian wth very small values diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc index bcdda8317..d0d24967f 100644 --- a/rtgui/locallabtools.cc +++ b/rtgui/locallabtools.cc @@ -3570,10 +3570,14 @@ void LocallabExposure::updateGUIToMode(const modeType new_type) fatanchor->show(); // Specific Simple mode widgets are shown in Normal mode + softradiusexp->hide(); + blurexpde->hide(); + if (!inversex->get_active()) { // Keep widget hidden when invers is toggled expgradexp->show(); softradiusexp->show(); exprecove->show(); + blurexpde->show(); } expmaskexp->show(); @@ -3583,7 +3587,8 @@ void LocallabExposure::updateGUIToMode(const modeType new_type) case Expert: // Show widgets hidden in Normal and Simple mode - if (!inversex->get_active()) { // Keep widget hidden when invers is toggled + structexp->hide(); + if (!inversex->get_active()) { // Keep widget hidden when invers is toggled structexp->show(); } @@ -3591,11 +3596,15 @@ void LocallabExposure::updateGUIToMode(const modeType new_type) norm->show(); fatlevel->show(); fatanchor->show(); + softradiusexp->hide(); + blurexpde->hide(); if (!inversex->get_active()) { // Keep widget hidden when invers is toggled expgradexp->show(); softradiusexp->show(); exprecove->show(); + blurexpde->show(); + } if (enaExpMask->get_active()) { maskusablee->show(); @@ -3818,6 +3827,8 @@ void LocallabExposure::updateExposureGUI3() reparexp->hide(); expfat->hide(); exppde->hide(); + structexp->hide(); + blurexpde->hide(); // Manage specific case where expMethod is different from 0 if (expMethod->get_active_row_number() > 0) { @@ -3843,11 +3854,20 @@ void LocallabExposure::updateExposureGUI3() expfat->show(); exppde->show(); - if (mode == Expert || mode == Normal) { // Keep widgets hidden in Simple mode + if (mode == Normal) { // Keep widgets hidden in Simple mode softradiusexp->show(); expgradexp->show(); exprecove->show(); + blurexpde->show(); } + if (mode == Expert) { // Keep widgets hidden in Simple mode + softradiusexp->show(); + expgradexp->show(); + exprecove->show(); + structexp->show(); + blurexpde->show(); + } + reparexp->show(); showmaskexpMethodinv->hide(); From 31e178a4dd1188cc41f76ef83cb33482f4ccc6d9 Mon Sep 17 00:00:00 2001 From: Desmis Date: Sat, 19 Jun 2021 18:36:20 +0200 Subject: [PATCH 130/135] Change loop limit for cp.mulC ipwavlet.cc --- rtengine/ipwavelet.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index 7abc7a48d..19ff01d92 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -448,7 +448,7 @@ void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int kall, const for (int m = 0; m < maxmul; m++) { cp.mulC[m] = waparams.ch[m]; } - for (int m = maxmul; m < 10; m++) { + for (int m = maxmul; m < 9; m++) { cp.mulC[m] = 0.f; } From 7e36240f3af05bdb17e33db135c0e0ea0bef0bb3 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Mon, 21 Jun 2021 08:02:42 +0200 Subject: [PATCH 131/135] Fix the incorrect rendering of Leica M8 DNGs by removing white level in camconst --- rtengine/camconst.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 157bef8a4..4b56a2643 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1549,7 +1549,7 @@ Camera constants: { // Quality C "make_model": "LEICA M8", "dcraw_matrix": [ 7675, -2196, -305, -5860, 14119, 1855, -2425, 4006, 6578 ], // DNG - "ranges": { "white": 16383 } + // Do not set white level, probably special handling by dcraw (see #6237) }, { // Quality C From 491b57bee7c09f679c27310417d0b26d585fdfae Mon Sep 17 00:00:00 2001 From: Pandagrapher Date: Mon, 21 Jun 2021 21:22:14 +0200 Subject: [PATCH 132/135] Improves RT window position management, fixes #6233 (#6239) * Improves RT window events detection and RT window position computation * Fixes some limitations in specific cases for Windows and MacOS * Fixes RT window not restoring saved position at startup - When maximized at startup, RT window position wasn't restored from options file. So when unmaximazing RT, position was set to up left corner instead of restored one - Other fix: Removed some uses of deprecated Gtk functions * Improves RT window management for independant edit window mode Other fixes: - Monitor ID wasn't correctly computed - Removes some other deprecated functions uses - Removes debug printf * Fixes editor window aspects not restored in MEOW mode on Linux Other fixes: - Removes some Gtk warnings when adding a new editor panel in MEOW mode - Adds robustness to avoid RT windows outside screen at startup loading corrupted options file with negative position values * Fixes incorrect max position saturation in dual screen configurations --- rtgui/editwindow.cc | 196 +++++++++++++++++++++++++++++++------------- rtgui/editwindow.h | 14 +++- rtgui/options.cc | 6 -- rtgui/options.h | 1 - rtgui/rtwindow.cc | 113 +++++++++++++++++-------- rtgui/rtwindow.h | 3 + 6 files changed, 232 insertions(+), 101 deletions(-) mode change 100644 => 100755 rtgui/rtwindow.cc mode change 100644 => 100755 rtgui/rtwindow.h diff --git a/rtgui/editwindow.cc b/rtgui/editwindow.cc index 3ae3e47fa..d0e53d730 100644 --- a/rtgui/editwindow.cc +++ b/rtgui/editwindow.cc @@ -31,11 +31,17 @@ extern Glib::ustring argv0; // Check if the system has more than one display and option is set bool EditWindow::isMultiDisplayEnabled() { - return options.multiDisplayMode > 0 && Gdk::Screen::get_default()->get_n_monitors() > 1; + const auto screen = Gdk::Screen::get_default(); + + if (screen) { + return options.multiDisplayMode > 0 && screen->get_display()->get_n_monitors() > 1; + } else { + return false; // There is no default screen + } } -// Should only be created once, auto-creates window on correct display -EditWindow* EditWindow::getInstance(RTWindow* p, bool restore) +// Should only be created once +EditWindow* EditWindow::getInstance(RTWindow* p) { struct EditWindowInstance { @@ -47,13 +53,15 @@ EditWindow* EditWindow::getInstance(RTWindow* p, bool restore) }; static EditWindowInstance instance_(p); - if(restore) { - instance_.editWnd.restoreWindow(); - } return &instance_.editWnd; } -EditWindow::EditWindow (RTWindow* p) : resolution(RTScalable::baseDPI), parent(p) , isFullscreen(false), isClosed(true) +EditWindow::EditWindow (RTWindow* p) + : resolution(RTScalable::baseDPI) + , parent(p) + , isFullscreen(false) + , isClosed(true) + , isMinimized(false) { updateResolution(); @@ -70,6 +78,8 @@ EditWindow::EditWindow (RTWindow* p) : resolution(RTScalable::baseDPI), parent(p mainNB->signal_switch_page().connect_notify(sigc::mem_fun(*this, &EditWindow::on_mainNB_switch_page)); signal_key_press_event().connect(sigc::mem_fun(*this, &EditWindow::keyPressed)); + signal_window_state_event().connect(sigc::mem_fun(*this, &EditWindow::on_window_state_event)); + onConfEventConn = signal_configure_event().connect(sigc::mem_fun(*this, &EditWindow::on_configure_event)); Gtk::Box* mainBox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); mainBox->pack_start(*mainNB); @@ -78,43 +88,74 @@ EditWindow::EditWindow (RTWindow* p) : resolution(RTScalable::baseDPI), parent(p } -void EditWindow::restoreWindow() { +void EditWindow::restoreWindow() +{ + if (isClosed) { + onConfEventConn.block(true); // Avoid getting size and position while window is being moved, maximized, ... - if(isClosed) { - int meowMonitor = 0; - if(isMultiDisplayEnabled()) { - if(options.meowMonitor >= 0) { // use display from last session if available - meowMonitor = std::min(options.meowMonitor, Gdk::Screen::get_default()->get_n_monitors() - 1); - } else { // Determine the other display - const Glib::RefPtr< Gdk::Window >& wnd = parent->get_window(); - meowMonitor = parent->get_screen()->get_monitor_at_window(wnd) == 0 ? 1 : 0; + int meowMonitor = 0; // By default, set to main monitor + const auto display = get_screen()->get_display(); + + if (isMultiDisplayEnabled()) { + if (options.meowMonitor >= 0) { // Use display from last session if available + meowMonitor = std::max(0, std::min(options.meowMonitor, display->get_n_monitors() - 1)); + } else { // Determine the main RT window display + const Glib::RefPtr &wnd = parent->get_window(); + + // Retrieve window monitor ID + const int monitor_nb = display->get_n_monitors(); + + for (int id = 0; id < monitor_nb; id++) { + if (display->get_monitor_at_window(wnd) == display->get_monitor(id)) { + meowMonitor = id; + break; + } + } } } Gdk::Rectangle lMonitorRect; - get_screen()->get_monitor_geometry(meowMonitor, lMonitorRect); - if(options.meowMaximized) { + display->get_monitor(meowMonitor)->get_geometry(lMonitorRect); + +#ifdef __APPLE__ + // Get macOS menu bar height + Gdk::Rectangle lWorkAreaRect; + display->get_monitor(std::min(meowMonitor, display->get_n_monitors() - 1))->get_workarea(lWorkAreaRect); + const int macMenuBarHeight = lWorkAreaRect.get_y(); + + // Place RT window to saved one in options file + if (options.meowX <= lMonitorRect.get_x() + lMonitorRect.get_width() + && options.meowX >= 0 + && options.meowY <= lMonitorRect.get_y() + lMonitorRect.get_height() - macMenuBarHeight + && options.meowY >= 0) { + move(options.meowX, options.meowY + macMenuBarHeight); + } else { + move(lMonitorRect.get_x(), lMonitorRect.get_y() + macMenuBarHeight); + } +#else + // Place RT window to saved one in options file + if (options.meowX <= lMonitorRect.get_x() + lMonitorRect.get_width() + && options.meowX >= 0 + && options.meowY <= lMonitorRect.get_y() + lMonitorRect.get_height() + && options.meowY >= 0) { + move(options.meowX, options.meowY); + } else { move(lMonitorRect.get_x(), lMonitorRect.get_y()); + } +#endif + + // Maximize RT window according to options file + if (options.meowMaximized) { maximize(); } else { + unmaximize(); resize(options.meowWidth, options.meowHeight); - if(options.meowX <= lMonitorRect.get_x() + lMonitorRect.get_width() && options.meowY <= lMonitorRect.get_y() + lMonitorRect.get_height()) { - move(options.meowX, options.meowY); - } else { - move(lMonitorRect.get_x(), lMonitorRect.get_y()); - } - } - show_all(); - - isFullscreen = options.meowFullScreen; - - if(isFullscreen) { - fullscreen(); } isClosed = false; - } + onConfEventConn.block(false); + } } void EditWindow::on_realize () @@ -174,27 +215,23 @@ bool EditWindow::on_configure_event(GdkEventConfigure* event) setAppIcon(); } - if (get_realized() && is_visible()) { - if(!is_maximized()) { - get_position(options.meowX, options.meowY); - get_size(options.meowWidth, options.meowHeight); - } - options.meowMaximized = is_maximized(); + if (!options.meowMaximized && !isFullscreen && !isMinimized) { + get_position(options.meowX, options.meowY); + get_size(options.meowWidth, options.meowHeight); } return Gtk::Widget::on_configure_event(event); } -/* HOMBRE: Disabling this since it's maximized when opened anyway. - * Someday, the EditorWindow might save its own position and state, so it'll have to be uncommented bool EditWindow::on_window_state_event(GdkEventWindowState* event) { - if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) { - options.windowMaximized = event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED; - } + // Retrieve RT window states + options.meowMaximized = event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED; + isMinimized = event->new_window_state & GDK_WINDOW_STATE_ICONIFIED; + isFullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN; return Gtk::Widget::on_window_state_event(event); -}*/ +} void EditWindow::on_mainNB_switch_page(Gtk::Widget* widget, guint page_num) { @@ -241,7 +278,8 @@ void EditWindow::addEditorPanel (EditorPanel* ep, const std::string &name) epanels[ name ] = ep; filesEdited.insert ( name ); parent->fpanel->refreshEditedState (filesEdited); - ep->setAspect(); + + show_all(); } void EditWindow::remEditorPanel (EditorPanel* ep) @@ -281,10 +319,20 @@ bool EditWindow::selectEditorPanel(const std::string &name) void EditWindow::toFront () { - // when using the secondary window on the same monitor as the primary window we need to present the secondary window. + // When using the secondary window on the same monitor as the primary window we need to present the secondary window. // If we don't, it will stay in background when opening 2nd, 3rd... editor, which is annoying // It will also deiconify the window - present(); + // To avoid unexpected behavior while window is being updated, present() function is called after at idle + idle_register.add( + [this]()-> bool + { + onConfEventConn.block(true); // Avoid getting size and position while window is being moved, maximized, ... + present(); + onConfEventConn.block(false); + + return false; + } + ); } bool EditWindow::keyPressed (GdkEventKey* event) @@ -308,27 +356,63 @@ bool EditWindow::keyPressed (GdkEventKey* event) return false; } - } -void EditWindow::toggleFullscreen () +void EditWindow::toggleFullscreen() { + onConfEventConn.block(true); // Avoid getting size and position while window is getting fullscreen + isFullscreen ? unfullscreen() : fullscreen(); - options.meowFullScreen = isFullscreen = !isFullscreen; + + onConfEventConn.block(false); } -void EditWindow::writeOptions() { +void EditWindow::get_position(int& x, int& y) const +{ + // Call native function + Gtk::Window::get_position(x, y); - if(is_visible()) { - if(isMultiDisplayEnabled()) { - options.meowMonitor = get_screen()->get_monitor_at_window(get_window()); + // Retrieve display (concatenation of all monitors) size + int width = 0, height = 0; + const auto display = get_screen()->get_display(); + const int nbMonitors = display->get_n_monitors(); + + for (int i = 0; i < nbMonitors; i++) { + Gdk::Rectangle lMonitorRect; + display->get_monitor(i)->get_geometry(lMonitorRect); + width = std::max(width, lMonitorRect.get_x() + lMonitorRect.get_width()); + height = std::max(height, lMonitorRect.get_y() + lMonitorRect.get_height()); + } + + // Saturate position at monitor limits to avoid unexpected behavior (fixes #6233) + x = std::min(width, std::max(0, x)); + y = std::min(height, std::max(0, y)); +} + +void EditWindow::writeOptions() +{ + if (is_visible()) { + if (isMultiDisplayEnabled()) { + // Retrieve window monitor ID + options.meowMonitor = 0; + const auto display = get_screen()->get_display(); + const int monitor_nb = display->get_n_monitors(); + + for (int id = 0; id < monitor_nb; id++) { + if (display->get_monitor_at_window(get_window()) == display->get_monitor(id)) { + options.windowMonitor = id; + break; + } + } } - options.meowMaximized = is_maximized(); - get_position(options.meowX, options.meowY); - get_size(options.meowWidth,options.meowHeight); + if (!options.meowMaximized && !isFullscreen && !isMinimized) { + get_position(options.meowX, options.meowY); + get_size(options.meowWidth, options.meowHeight); + } } } + bool EditWindow::on_delete_event(GdkEventAny* event) { diff --git a/rtgui/editwindow.h b/rtgui/editwindow.h index f4ada571d..b8eeaee82 100644 --- a/rtgui/editwindow.h +++ b/rtgui/editwindow.h @@ -21,6 +21,7 @@ #include #include "rtimage.h" +#include "guiutils.h" class EditorPanel; class RTWindow; @@ -40,17 +41,20 @@ private: bool isFullscreen; bool isClosed; + bool isMinimized; + sigc::connection onConfEventConn; void toggleFullscreen (); - void restoreWindow(); bool updateResolution(); void setAppIcon(); + IdleRegister idle_register; + public: // Check if the system has more than one display and option is set static bool isMultiDisplayEnabled(); - // Should only be created once, auto-creates window on correct display - static EditWindow* getInstance(RTWindow* p, bool restore = true); + // Should only be created once + static EditWindow* getInstance(RTWindow* p); explicit EditWindow (RTWindow* p); @@ -65,8 +69,10 @@ public: bool keyPressed (GdkEventKey* event); bool on_configure_event(GdkEventConfigure* event) override; bool on_delete_event(GdkEventAny* event) override; - //bool on_window_state_event(GdkEventWindowState* event); + bool on_window_state_event(GdkEventWindowState* event) override; void on_mainNB_switch_page(Gtk::Widget* page, guint page_num); void set_title_decorated(Glib::ustring fname); void on_realize () override; + void get_position(int& x, int& y) const; + void restoreWindow(); }; diff --git a/rtgui/options.cc b/rtgui/options.cc index ec36eb166..4e6beb7f4 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -298,7 +298,6 @@ void Options::setDefaults() windowMaximized = true; windowMonitor = 0; meowMonitor = -1; - meowFullScreen = false; meowMaximized = true; meowWidth = 1200; meowHeight = 680; @@ -1244,10 +1243,6 @@ void Options::readFromFile(Glib::ustring fname) meowMonitor = keyFile.get_integer("GUI", "MeowMonitor"); } - if (keyFile.has_key("GUI", "MeowFullScreen")) { - meowFullScreen = keyFile.get_boolean("GUI", "MeowFullScreen"); - } - if (keyFile.has_key("GUI", "MeowMaximized")) { meowMaximized = keyFile.get_boolean("GUI", "MeowMaximized"); } @@ -2270,7 +2265,6 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_integer("GUI", "WindowY", windowY); keyFile.set_integer("GUI", "WindowMonitor", windowMonitor); keyFile.set_integer("GUI", "MeowMonitor", meowMonitor); - keyFile.set_boolean("GUI", "MeowFullScreen", meowFullScreen); keyFile.set_boolean("GUI", "MeowMaximized", meowMaximized); keyFile.set_integer("GUI", "MeowWidth", meowWidth); keyFile.set_integer("GUI", "MeowHeight", meowHeight); diff --git a/rtgui/options.h b/rtgui/options.h index 19963ba39..bc5e41c91 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -219,7 +219,6 @@ public: bool windowMaximized; int windowMonitor; int meowMonitor; - bool meowFullScreen; bool meowMaximized; int meowWidth; int meowHeight; diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc old mode 100644 new mode 100755 index cf77374ce..7f87d4ec4 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -282,8 +282,10 @@ RTWindow::RTWindow () on_delete_has_run = false; is_fullscreen = false; + is_minimized = false; property_destroy_with_parent().set_value (false); signal_window_state_event().connect ( sigc::mem_fun (*this, &RTWindow::on_window_state_event) ); + onConfEventConn = signal_configure_event().connect ( sigc::mem_fun (*this, &RTWindow::on_configure_event) ); signal_key_press_event().connect ( sigc::mem_fun (*this, &RTWindow::keyPressed) ); signal_key_release_event().connect(sigc::mem_fun(*this, &RTWindow::keyReleased)); @@ -522,7 +524,7 @@ void RTWindow::showErrors() bool RTWindow::on_configure_event (GdkEventConfigure* event) { - if (!is_maximized() && is_visible()) { + if (!options.windowMaximized && !is_fullscreen && !is_minimized) { get_size (options.windowWidth, options.windowHeight); get_position (options.windowX, options.windowY); } @@ -535,10 +537,11 @@ bool RTWindow::on_configure_event (GdkEventConfigure* event) bool RTWindow::on_window_state_event (GdkEventWindowState* event) { - if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED) { - options.windowMaximized = event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED; - } - + // Retrieve RT window states + options.windowMaximized = event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED; + is_minimized = event->new_window_state & GDK_WINDOW_STATE_ICONIFIED; + is_fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN; + return Gtk::Widget::on_window_state_event (event); } @@ -577,8 +580,10 @@ void RTWindow::addEditorPanel (EditorPanel* ep, const std::string &name) { if (options.multiDisplayMode > 0) { EditWindow * wndEdit = EditWindow::getInstance (this); - wndEdit->show(); wndEdit->addEditorPanel (ep, name); + wndEdit->show_all(); + wndEdit->restoreWindow(); // Need to be called after RTWindow creation to work with all OS Windows Manager + ep->setAspect(); wndEdit->toFront(); } else { ep->setParent (this); @@ -795,7 +800,7 @@ bool RTWindow::on_delete_event (GdkEventAny* event) if (isSingleTabMode() || simpleEditor) { isProcessing = epanel->getIsProcessing(); } else if (options.multiDisplayMode > 0) { - editWindow = EditWindow::getInstance (this, false); + editWindow = EditWindow::getInstance (this); isProcessing = editWindow->isProcessing(); } else { int pageCount = mainNB->get_n_pages(); @@ -863,12 +868,22 @@ bool RTWindow::on_delete_event (GdkEventAny* event) FileBrowserEntry::hdr.reset(); FileBrowserEntry::ps.reset(); - if (!options.windowMaximized) { + if (!options.windowMaximized && !is_fullscreen && !is_minimized) { get_size (options.windowWidth, options.windowHeight); get_position (options.windowX, options.windowY); } - options.windowMonitor = get_screen()->get_monitor_at_window (get_window()); + // Retrieve window monitor ID + options.windowMonitor = 0; + const auto display = get_screen()->get_display(); + const int monitor_nb = display->get_n_monitors(); + + for (int id = 0; id < monitor_nb; id++) { + if (display->get_monitor_at_window(get_window()) == display->get_monitor(id)) { + options.windowMonitor = id; + break; + } + } try { Options::save (); @@ -981,25 +996,25 @@ void RTWindow::error(const Glib::ustring& descr) void RTWindow::toggle_fullscreen () { + onConfEventConn.block(true); // Avoid getting size and position while window is getting fullscreen + if (is_fullscreen) { unfullscreen(); - is_fullscreen = false; if (btn_fullscreen) { - //btn_fullscreen->set_label(M("MAIN_BUTTON_FULLSCREEN")); btn_fullscreen->set_tooltip_markup (M ("MAIN_BUTTON_FULLSCREEN")); btn_fullscreen->set_image (*iFullscreen); } } else { fullscreen(); - is_fullscreen = true; if (btn_fullscreen) { - //btn_fullscreen->set_label(M("MAIN_BUTTON_UNFULLSCREEN")); btn_fullscreen->set_tooltip_markup (M ("MAIN_BUTTON_UNFULLSCREEN")); btn_fullscreen->set_image (*iFullscreen_exit); } } + + onConfEventConn.block(false); } void RTWindow::SetEditorCurrent() @@ -1105,40 +1120,70 @@ bool RTWindow::splashClosed (GdkEventAny* event) void RTWindow::setWindowSize () { + onConfEventConn.block(true); // Avoid getting size and position while window is being moved, maximized, ... + Gdk::Rectangle lMonitorRect; - get_screen()->get_monitor_geometry (std::min (options.windowMonitor, Gdk::Screen::get_default()->get_n_monitors() - 1), lMonitorRect); + const auto display = get_screen()->get_display(); + display->get_monitor (std::min (options.windowMonitor, display->get_n_monitors() - 1))->get_geometry(lMonitorRect); #ifdef __APPLE__ // Get macOS menu bar height - const Gdk::Rectangle lWorkAreaRect = get_screen()->get_monitor_workarea (std::min (options.windowMonitor, Gdk::Screen::get_default()->get_n_monitors() - 1)); + Gdk::Rectangle lWorkAreaRect; + display->get_monitor (std::min (options.windowMonitor, display->get_n_monitors() - 1))->get_workarea(lWorkAreaRect); const int macMenuBarHeight = lWorkAreaRect.get_y(); + + // Place RT window to saved one in options file + if (options.windowX <= lMonitorRect.get_x() + lMonitorRect.get_width() + && options.windowX >= 0 + && options.windowY <= lMonitorRect.get_y() + lMonitorRect.get_height() - macMenuBarHeight + && options.windowY >= 0) { + move (options.windowX, options.windowY + macMenuBarHeight); + } else { + move (lMonitorRect.get_x(), lMonitorRect.get_y() + macMenuBarHeight); + } +#else + // Place RT window to saved one in options file + if (options.windowX <= lMonitorRect.get_x() + lMonitorRect.get_width() + && options.windowX >= 0 + && options.windowY <= lMonitorRect.get_y() + lMonitorRect.get_height() + && options.windowY >= 0) { + move (options.windowX, options.windowY); + } else { + move (lMonitorRect.get_x(), lMonitorRect.get_y()); + } #endif + // Maximize RT window according to options file if (options.windowMaximized) { -#ifdef __APPLE__ - move (lMonitorRect.get_x(), lMonitorRect.get_y() + macMenuBarHeight); -#else - move (lMonitorRect.get_x(), lMonitorRect.get_y()); -#endif maximize(); } else { unmaximize(); resize (options.windowWidth, options.windowHeight); - -#ifdef __APPLE__ - if (options.windowX <= lMonitorRect.get_x() + lMonitorRect.get_width() && options.windowY <= lMonitorRect.get_y() + lMonitorRect.get_height() - macMenuBarHeight) { - move (options.windowX, options.windowY + macMenuBarHeight); - } else { - move (lMonitorRect.get_x(), lMonitorRect.get_y() + macMenuBarHeight); - } -#else - if (options.windowX <= lMonitorRect.get_x() + lMonitorRect.get_width() && options.windowY <= lMonitorRect.get_y() + lMonitorRect.get_height()) { - move (options.windowX, options.windowY); - } else { - move (lMonitorRect.get_x(), lMonitorRect.get_y()); - } -#endif } + + onConfEventConn.block(false); +} + +void RTWindow::get_position(int& x, int& y) const +{ + // Call native function + Gtk::Window::get_position (x, y); + + // Retrieve display (concatenation of all monitors) size + int width = 0, height = 0; + const auto display = get_screen()->get_display(); + const int nbMonitors = display->get_n_monitors(); + + for (int i = 0; i < nbMonitors; i++) { + Gdk::Rectangle lMonitorRect; + display->get_monitor(i)->get_geometry(lMonitorRect); + width = std::max(width, lMonitorRect.get_x() + lMonitorRect.get_width()); + height = std::max(height, lMonitorRect.get_y() + lMonitorRect.get_height()); + } + + // Saturate position at monitor limits to avoid unexpected behavior (fixes #6233) + x = std::min(width, std::max(0, x)); + y = std::min(height, std::max(0, y)); } void RTWindow::set_title_decorated (Glib::ustring fname) diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h old mode 100644 new mode 100755 index aa1830d89..0c1cd2572 --- a/rtgui/rtwindow.h +++ b/rtgui/rtwindow.h @@ -51,6 +51,8 @@ private: Gtk::ProgressBar prProgBar; PLDBridge* pldBridge; bool is_fullscreen; + bool is_minimized; + sigc::connection onConfEventConn; bool on_delete_has_run; Gtk::Button * btn_fullscreen; @@ -96,6 +98,7 @@ public: void showPreferences (); void on_realize () override; void toggle_fullscreen (); + void get_position(int& x, int& y) const; void setProgress(double p) override; void setProgressStr(const Glib::ustring& str) override; From 4d171141265c1e49e0042d4f712a681c83184bad Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Tue, 22 Jun 2021 05:35:31 +0200 Subject: [PATCH 133/135] Remove errant comma. Should fix #6289 --- rtengine/camconst.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 4b56a2643..4aae51a29 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1548,7 +1548,7 @@ Camera constants: { // Quality C "make_model": "LEICA M8", - "dcraw_matrix": [ 7675, -2196, -305, -5860, 14119, 1855, -2425, 4006, 6578 ], // DNG + "dcraw_matrix": [ 7675, -2196, -305, -5860, 14119, 1855, -2425, 4006, 6578 ] // DNG // Do not set white level, probably special handling by dcraw (see #6237) }, From 3cf3562505ccef559bf3e5a755a163d157e629b3 Mon Sep 17 00:00:00 2001 From: Desmis Date: Wed, 23 Jun 2021 13:49:53 +0200 Subject: [PATCH 134/135] LA small change GUI vibrance --- rtgui/locallabtools.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc index d0d24967f..14a3a43c4 100644 --- a/rtgui/locallabtools.cc +++ b/rtgui/locallabtools.cc @@ -5073,7 +5073,7 @@ LocallabVibrance::LocallabVibrance(): Color::hsv2rgb01(0.92f, 0.45f, 0.6f, R, G, B); mskinTonesCurve.emplace_back(0.0, R, G, B); Color::hsv2rgb01(0.14056f, 0.45f, 0.6f, R, G, B); - mskinTonesCurve.emplace_back(0.0, R, G, B); + mskinTonesCurve.emplace_back(1.0, R, G, B); skinTonesCurve->setBottomBarBgGradient(mskinTonesCurve); skinTonesCurve->setLeftBarBgGradient(mskinTonesCurve); skinTonesCurve->setRangeLabels( From 4ab54c9fda8ec9e18603ec768e2b039d1f2c9217 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Thu, 24 Jun 2021 12:01:18 +0200 Subject: [PATCH 135/135] Crash when moving crop window using SHIFT+Mouse, fixes #6290 --- rtgui/rtwindow.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index 7f87d4ec4..baa44cabe 100755 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -764,7 +764,7 @@ bool RTWindow::keyPressed (GdkEventKey* event) bool RTWindow::keyReleased(GdkEventKey *event) { - if (mainNB->get_current_page() == mainNB->page_num(*fpanel)) { + if (fpanel && mainNB->get_current_page() == mainNB->page_num(*fpanel)) { return fpanel->handleShortcutKeyRelease(event); } return false;