From d080bba351f3db0135fe7efa931af39a16aa0eec Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Mon, 18 Feb 2019 03:10:58 +0100 Subject: [PATCH 01/36] Center selected thumb in Filmstrip #5174 When opening an image, selecting the next/previous image or syncing the Filmstrip, the newly selected thumbnail is centered, unless it lies within the visible area more than 1 thumbnails-width away from either edge, in which case centering does not occur. --- rtgui/editorpanel.cc | 8 ++-- rtgui/filebrowser.cc | 105 ++++++++++++++++++++++--------------------- rtgui/filebrowser.h | 7 +-- 3 files changed, 61 insertions(+), 59 deletions(-) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 684d362b0..6e390cf42 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -1057,14 +1057,14 @@ void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) } else { Gtk::Allocation alloc; iareapanel->imageArea->on_resized (alloc); + + // When passing a photo as an argument to the RawTherapee executable, the user wants + // this auto-loaded photo's thumbnail to be selected and visible in the Filmstrip. + EditorPanel::syncFileBrowser(); } history->resetSnapShotNumber(); navigator->setInvalid(ipc->getFullWidth(),ipc->getFullHeight()); - - // When passing a photo as an argument to the RawTherapee executable, the user wants - // this auto-loaded photo's thumbnail to be selected and visible in the Filmstrip. - EditorPanel::syncFileBrowser(); } void EditorPanel::close () diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index d489bb1d3..9f267be4e 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -1727,62 +1727,62 @@ void FileBrowser::buttonPressed (LWButton* button, int actionCode, void* actionD } } -void FileBrowser::openNextImage () +void FileBrowser::openNextImage() { MYWRITERLOCK(l, entryRW); if (!fd.empty() && selected.size() > 0 && !options.tabbedUI) { - for (size_t i = 0; i < fd.size() - 1; i++) { if (selected[0]->thumbnail->getFileName() == fd[i]->filename) { // located 1-st image in current selection if (i < fd.size() && tbl) { // find the first not-filtered-out (next) image for (size_t k = i + 1; k < fd.size(); k++) { if (!fd[k]->filtered/*checkFilter (fd[k])*/) { + // clear current selection for (size_t j = 0; j < selected.size(); j++) { selected[j]->selected = false; } - selected.clear (); + selected.clear(); // set new selection fd[k]->selected = true; - selected.push_back (fd[k]); - //queue_draw (); + selected.push_back(fd[k]); + //queue_draw(); MYWRITERLOCK_RELEASE(l); // this will require a read access - notifySelectionListener (); + notifySelectionListener(); MYWRITERLOCK_ACQUIRE(l); - // scroll to the selected position - double h1, v1; - getScrollPosition(h1, v1); + // scroll to the selected position, centered horizontally in the container + double x1, y1; + getScrollPosition(x1, y1); - double h2 = selected[0]->getStartX(); - double v2 = selected[0]->getStartY(); + double x2 = selected[0]->getStartX(); + double y2 = selected[0]->getStartY(); Thumbnail* thumb = (static_cast(fd[k]))->thumbnail; - int minWidth = get_width() - fd[k]->getMinimalWidth(); + int tw = fd[k]->getMinimalWidth(); // thumb width + + int ww = get_width(); // window width MYWRITERLOCK_RELEASE(l); // scroll only when selected[0] is outside of the displayed bounds - if (h2 + minWidth - h1 > get_width()) { - setScrollPosition(h2 - minWidth, v2); - } - - if (h1 > h2) { - setScrollPosition(h2, v2); + // or less than a thumbnail's width from either edge. + if ((x2 > x1 + ww - 2 * tw) || (x2 - tw < x1)) { + setScrollPosition(x2 - (ww - tw) / 2, y2); } // open the selected image std::vector entries; - entries.push_back (thumb); - tbl->openRequested (entries); + entries.push_back(thumb); + tbl->openRequested(entries); + return; } } @@ -1792,62 +1792,62 @@ void FileBrowser::openNextImage () } } -void FileBrowser::openPrevImage () +void FileBrowser::openPrevImage() { MYWRITERLOCK(l, entryRW); if (!fd.empty() && selected.size() > 0 && !options.tabbedUI) { - for (size_t i = 1; i < fd.size(); i++) { if (selected[0]->thumbnail->getFileName() == fd[i]->filename) { // located 1-st image in current selection if (i > 0 && tbl) { // find the first not-filtered-out (previous) image for (ssize_t k = (ssize_t)i - 1; k >= 0; k--) { if (!fd[k]->filtered/*checkFilter (fd[k])*/) { + // clear current selection for (size_t j = 0; j < selected.size(); j++) { selected[j]->selected = false; } - selected.clear (); + selected.clear(); // set new selection fd[k]->selected = true; - selected.push_back (fd[k]); - //queue_draw (); + selected.push_back(fd[k]); + //queue_draw(); MYWRITERLOCK_RELEASE(l); // this will require a read access - notifySelectionListener (); + notifySelectionListener(); MYWRITERLOCK_ACQUIRE(l); - // scroll to the selected position - double h1, v1; - getScrollPosition(h1, v1); + // scroll to the selected position, centered horizontally in the container + double x1, y1; + getScrollPosition(x1, y1); - double h2 = selected[0]->getStartX(); - double v2 = selected[0]->getStartY(); + double x2 = selected[0]->getStartX(); + double y2 = selected[0]->getStartY(); Thumbnail* thumb = (static_cast(fd[k]))->thumbnail; - int minWidth = get_width() - fd[k]->getMinimalWidth(); + int tw = fd[k]->getMinimalWidth(); // thumb width + + int ww = get_width(); // window width MYWRITERLOCK_RELEASE(l); // scroll only when selected[0] is outside of the displayed bounds - if (h2 + minWidth - h1 > get_width()) { - setScrollPosition(h2 - minWidth, v2); - } - - if (h1 > h2) { - setScrollPosition(h2, v2); + // or less than a thumbnail's width from either edge. + if ((x2 > x1 + ww - 2 * tw) || (x2 - tw < x1)) { + setScrollPosition(x2 - (ww - tw) / 2, y2); } // open the selected image std::vector entries; - entries.push_back (thumb); - tbl->openRequested (entries); + entries.push_back(thumb); + tbl->openRequested(entries); + return; } } @@ -1857,11 +1857,8 @@ void FileBrowser::openPrevImage () } } - -void FileBrowser::selectImage (Glib::ustring fname) +void FileBrowser::selectImage(Glib::ustring fname) { - - // need to clear the filter in filecatalog MYWRITERLOCK(l, entryRW); if (!fd.empty() && !options.tabbedUI) { @@ -1874,27 +1871,31 @@ void FileBrowser::selectImage (Glib::ustring fname) selected[j]->selected = false; } - selected.clear (); + selected.clear(); // set new selection fd[i]->selected = true; - selected.push_back (fd[i]); - queue_draw (); + selected.push_back(fd[i]); + queue_draw(); MYWRITERLOCK_RELEASE(l); // this will require a read access - notifySelectionListener (); + notifySelectionListener(); MYWRITERLOCK_ACQUIRE(l); - // scroll to the selected position - double h = selected[0]->getStartX(); - double v = selected[0]->getStartY(); + // scroll to the selected position, centered horizontally in the container + double x = selected[0]->getStartX(); + double y = selected[0]->getStartY(); + + int tw = fd[i]->getMinimalWidth(); // thumb width + + int ww = get_width(); // window width MYWRITERLOCK_RELEASE(l); - setScrollPosition(h, v); + setScrollPosition(x - (ww - tw) / 2, y); return; } diff --git a/rtgui/filebrowser.h b/rtgui/filebrowser.h index f876872eb..44646ab17 100644 --- a/rtgui/filebrowser.h +++ b/rtgui/filebrowser.h @@ -181,12 +181,13 @@ public: return tbl ? tbl->isInTabMode() : false; } - void openNextImage (); - void openPrevImage (); + void openNextImage(); + void openPrevImage(); + void selectImage(Glib::ustring fname); + void copyProfile (); void pasteProfile (); void partPasteProfile (); - void selectImage (Glib::ustring fname); void openNextPreviousEditorImage (Glib::ustring fname, eRTNav eNextPrevious); #ifdef WIN32 From 0cbc4923bc47db40b4be1432cf8fb2617254c1ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Thu, 28 Feb 2019 20:44:50 +0100 Subject: [PATCH 02/36] Relax dependency from `procparams.h` --- rtengine/FTblockDN.cc | 1 + rtengine/PF_correct_RT.cc | 1 + rtengine/ahd_demosaic_RT.cc | 3 +- rtengine/amaze_demosaic_RT.cc | 1 + rtengine/clutstore.cc | 1 + rtengine/curves.cc | 1 + rtengine/curves.h | 1 - rtengine/dcrop.cc | 9 +- rtengine/dual_demosaic_RT.cc | 1 + rtengine/gamutwarning.h | 2 + rtengine/histmatching.cc | 11 +- rtengine/hphd_demosaic_RT.cc | 1 + rtengine/iimage.cc | 1 + rtengine/iimage.h | 16 +- rtengine/imagedata.cc | 2 + rtengine/imagedata.h | 1 - rtengine/imagefloat.cc | 1 + rtengine/imageio.cc | 27 +- rtengine/imageio.h | 12 +- rtengine/imagesource.h | 31 +- rtengine/improccoordinator.cc | 574 ++++++++++++++++++-------------- rtengine/improccoordinator.h | 16 +- rtengine/improcfun.cc | 25 +- rtengine/improcfun.h | 27 +- rtengine/init.cc | 1 + rtengine/ipdehaze.cc | 10 +- rtengine/iplab2rgb.cc | 2 + rtengine/iplabregions.cc | 1 + rtengine/iplocalcontrast.cc | 5 +- rtengine/ipresize.cc | 1 + rtengine/ipretinex.cc | 12 +- rtengine/ipshadowshighlights.cc | 6 +- rtengine/ipsharpen.cc | 1 + rtengine/ipsoftlight.cc | 2 + rtengine/iptransform.cc | 1 + rtengine/ipwavelet.cc | 1 + rtengine/lcp.cc | 1 + rtengine/previewimage.cc | 6 +- rtengine/processingjob.h | 1 + rtengine/procparams.cc | 32 +- rtengine/procparams.h | 133 ++++++-- rtengine/profilestore.cc | 2 + rtengine/profilestore.h | 14 +- rtengine/rawimagesource.cc | 2 + rtengine/rawimagesource.h | 39 ++- rtengine/rcd_demosaic.cc | 1 + rtengine/rtengine.h | 19 +- rtengine/rtlensfun.cc | 1 + rtengine/rtlensfun.h | 10 +- rtengine/rtthumbnail.cc | 3 +- rtengine/rtthumbnail.h | 1 - rtengine/settings.h | 6 +- rtengine/simpleprocess.cc | 3 +- rtengine/stdimagesource.cc | 8 +- rtengine/tmo_fattal02.cc | 1 + rtengine/vng4_demosaic_RT.cc | 1 + rtexif/rtexif.cc | 2 + rtexif/rtexif.h | 11 +- rtgui/batchqueue.cc | 6 +- rtgui/batchqueueentry.cc | 6 +- rtgui/batchqueueentry.h | 4 +- rtgui/cacheimagedata.cc | 6 + rtgui/cacheimagedata.h | 2 +- rtgui/crophandler.cc | 12 +- rtgui/crophandler.h | 5 +- rtgui/cropwindow.cc | 287 ++++++++-------- rtgui/exifpanel.cc | 2 +- rtgui/exportpanel.cc | 2 + rtgui/filebrowserentry.cc | 236 ++++++------- rtgui/filebrowserentry.h | 3 +- rtgui/filecatalog.cc | 2 +- rtgui/guiutils.cc | 1 + rtgui/imagearea.cc | 3 +- rtgui/iptcpanel.cc | 2 +- rtgui/options.cc | 2 + rtgui/options.h | 2 +- rtgui/partialpastedlg.h | 2 + rtgui/preferences.cc | 2 +- rtgui/previewhandler.cc | 15 +- rtgui/previewhandler.h | 8 +- rtgui/previewwindow.cc | 2 + rtgui/thumbimageupdater.cc | 2 + rtgui/thumbnail.cc | 158 +++++---- rtgui/thumbnail.h | 45 +-- rtgui/tonecurve.cc | 26 +- rtgui/tonecurve.h | 4 +- 86 files changed, 1139 insertions(+), 814 deletions(-) diff --git a/rtengine/FTblockDN.cc b/rtengine/FTblockDN.cc index 2a1a9fcb4..4e62e1c1f 100644 --- a/rtengine/FTblockDN.cc +++ b/rtengine/FTblockDN.cc @@ -38,6 +38,7 @@ #include "cplx_wavelet_dec.h" #include "median.h" #include "iccstore.h" +#include "procparams.h" #ifdef _OPENMP #include #endif diff --git a/rtengine/PF_correct_RT.cc b/rtengine/PF_correct_RT.cc index 57e4c2225..fe89a7b65 100644 --- a/rtengine/PF_correct_RT.cc +++ b/rtengine/PF_correct_RT.cc @@ -36,6 +36,7 @@ #include "median.h" #include "jaggedarray.h" #include "StopWatch.h" +#include "procparams.h" namespace rtengine { diff --git a/rtengine/ahd_demosaic_RT.cc b/rtengine/ahd_demosaic_RT.cc index 7931bf17d..d67c7b76b 100644 --- a/rtengine/ahd_demosaic_RT.cc +++ b/rtengine/ahd_demosaic_RT.cc @@ -27,6 +27,7 @@ #include "rtengine.h" #include "rawimagesource.h" #include "rt_math.h" +#include "procparams.h" #include "../rtgui/multilangmgr.h" #include "median.h" //#define BENCHMARK @@ -223,4 +224,4 @@ void RawImageSource::ahd_demosaic() } #undef TS -} \ No newline at end of file +} diff --git a/rtengine/amaze_demosaic_RT.cc b/rtengine/amaze_demosaic_RT.cc index 31419022d..8b8e6ca57 100644 --- a/rtengine/amaze_demosaic_RT.cc +++ b/rtengine/amaze_demosaic_RT.cc @@ -33,6 +33,7 @@ #include "sleef.c" #include "opthelper.h" #include "median.h" +#include "procparams.h" #include "StopWatch.h" namespace rtengine diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc index 1a425d21b..9ee976907 100644 --- a/rtengine/clutstore.cc +++ b/rtengine/clutstore.cc @@ -5,6 +5,7 @@ #include "iccstore.h" #include "imagefloat.h" #include "opthelper.h" +#include "procparams.h" #include "rt_math.h" #include "stdimagesource.h" diff --git a/rtengine/curves.cc b/rtengine/curves.cc index ecd38d4aa..71e128495 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -37,6 +37,7 @@ #include "ciecam02.h" #include "color.h" #include "iccstore.h" +#include "procparams.h" #undef CLIPD #define CLIPD(a) ((a)>0.0f?((a)<1.0f?(a):1.0f):0.0f) diff --git a/rtengine/curves.h b/rtengine/curves.h index b88a3bdc4..c924321fa 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -30,7 +30,6 @@ #include "../rtgui/myflatcurve.h" #include "../rtgui/mydiagonalcurve.h" #include "color.h" -#include "procparams.h" #include "pipettebuffer.h" #include "LUT.h" diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index e49e03329..0872049d8 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -17,9 +17,10 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "dcrop.h" #include "curves.h" +#include "dcrop.h" #include "mytime.h" +#include "procparams.h" #include "refreshmap.h" #include "rt_math.h" @@ -131,7 +132,7 @@ void Crop::update(int todo) { MyMutex::MyLock cropLock(cropMutex); - ProcParams& params = parent->params; + ProcParams& params = *parent->params; // CropGUIListener* cropgl; // No need to update todo here, since it has already been changed in ImprocCoordinator::updatePreviewImage, @@ -1116,7 +1117,7 @@ void Crop::freeAll() namespace { -bool check_need_larger_crop_for_lcp_distortion(int fw, int fh, int x, int y, int w, int h, const ProcParams ¶ms) +bool check_need_larger_crop_for_lcp_distortion(int fw, int fh, int x, int y, int w, int h, const procparams::ProcParams ¶ms) { if (x == 0 && y == 0 && w == fw && h == fh) { return false; @@ -1177,7 +1178,7 @@ bool Crop::setCropSizes(int rcx, int rcy, int rcw, int rch, int skip, bool inter parent->ipf.transCoord(parent->fw, parent->fh, bx1, by1, bw, bh, orx, ory, orw, orh); - if (check_need_larger_crop_for_lcp_distortion(parent->fw, parent->fh, orx, ory, orw, orh, parent->params)) { + if (check_need_larger_crop_for_lcp_distortion(parent->fw, parent->fh, orx, ory, orw, orh, *parent->params)) { // TODO - this is an estimate of the max distortion relative to the image size. ATM it is hardcoded to be 15%, which seems enough. If not, need to revise int dW = int (double (parent->fw) * 0.15 / (2 * skip)); int dH = int (double (parent->fh) * 0.15 / (2 * skip)); diff --git a/rtengine/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc index 790275d7e..9df3369bd 100644 --- a/rtengine/dual_demosaic_RT.cc +++ b/rtengine/dual_demosaic_RT.cc @@ -27,6 +27,7 @@ #include "rtengine.h" #include "rawimagesource.h" #include "rt_math.h" +#include "procparams.h" //#define BENCHMARK #include "StopWatch.h" #include "rt_algo.h" diff --git a/rtengine/gamutwarning.h b/rtengine/gamutwarning.h index be6d7b61b..19a27cdfd 100644 --- a/rtengine/gamutwarning.h +++ b/rtengine/gamutwarning.h @@ -31,6 +31,8 @@ namespace rtengine { +enum RenderingIntent : int; + class GamutWarning: public NonCopyable { public: GamutWarning(cmsHPROFILE iprof, cmsHPROFILE gamutprof, RenderingIntent intent, bool bpc); diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index 1b6dd133f..614e5368a 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -24,6 +24,7 @@ #include "color.h" #include "rt_math.h" #include "iccstore.h" +#include "procparams.h" #include "../rtgui/mydiagonalcurve.h" #include "improcfun.h" //#define BENCHMARK @@ -248,7 +249,7 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st && a.dcpIlluminant == b.dcpIlluminant); }; - if (!histMatchingCache.empty() && same_profile(histMatchingParams, cp)) { + if (!histMatchingCache.empty() && same_profile(*histMatchingParams, cp)) { if (settings->verbose) { std::cout << "tone curve found in cache" << std::endl; } @@ -286,14 +287,14 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st std::cout << "histogram matching: no thumbnail found, generating a neutral curve" << std::endl; } histMatchingCache = outCurve; - histMatchingParams = cp; + *histMatchingParams = cp; return; } else if (w * 10 < fw) { if (settings->verbose) { std::cout << "histogram matching: the embedded thumbnail is too small: " << w << "x" << h << std::endl; } histMatchingCache = outCurve; - histMatchingParams = cp; + *histMatchingParams = cp; return; } skip = LIM(skip * fh / h, 6, 10); // adjust the skip factor -- the larger the thumbnail, the less we should skip to get a good match @@ -316,7 +317,7 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st std::cout << "histogram matching: raw decoding failed, generating a neutral curve" << std::endl; } histMatchingCache = outCurve; - histMatchingParams = cp; + *histMatchingParams = cp; return; } target.reset(thumb->processImage(neutral, sensor_type, fh / skip, TI_Nearest, getMetaData(), scale, false, true)); @@ -388,7 +389,7 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st } histMatchingCache = outCurve; - histMatchingParams = cp; + *histMatchingParams = cp; } } // namespace rtengine diff --git a/rtengine/hphd_demosaic_RT.cc b/rtengine/hphd_demosaic_RT.cc index 5c15469ca..1d9aa0dd0 100644 --- a/rtengine/hphd_demosaic_RT.cc +++ b/rtengine/hphd_demosaic_RT.cc @@ -23,6 +23,7 @@ #include "jaggedarray.h" #include "rawimage.h" #include "rt_math.h" +#include "procparams.h" #include "../rtgui/multilangmgr.h" #include "opthelper.h" //#define BENCHMARK diff --git a/rtengine/iimage.cc b/rtengine/iimage.cc index adda06162..c9a4f223a 100644 --- a/rtengine/iimage.cc +++ b/rtengine/iimage.cc @@ -17,6 +17,7 @@ * along with RawTherapee. If not, see . */ +#include "procparams.h" #include "rtengine.h" const char rtengine::sImage8[] = "Image8"; diff --git a/rtengine/iimage.h b/rtengine/iimage.h index 3b518e223..5ce93605b 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -26,7 +26,6 @@ #include "imagedimensions.h" #include "LUT.h" #include "coord2d.h" -#include "procparams.h" #include "color.h" #include "../rtgui/threadutils.h" @@ -43,12 +42,21 @@ namespace rtengine { +namespace procparams +{ + + class CoarseTransformParams; + +} + +class ProgressListener; +class Color; + extern const char sImage8[]; extern const char sImage16[]; extern const char sImagefloat[]; -int getCoarseBitMask( const procparams::CoarseTransformParams &coarse); -class ProgressListener; -class Color; + +int getCoarseBitMask(const procparams::CoarseTransformParams& coarse); enum TypeInterpolation { TI_Nearest, TI_Bilinear }; diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 9b2de3e3b..cbb8aa5c0 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -25,6 +25,8 @@ #include "iptcpairs.h" #include "imagesource.h" #include "rt_math.h" +#include "procparams.h" + #pragma GCC diagnostic warning "-Wextra" #define PRINT_HDR_PS_DETECTION 0 diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index 7aa4812d0..c6889e653 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -25,7 +25,6 @@ #include #include #include "../rtexif/rtexif.h" -#include "procparams.h" #include #include "rtengine.h" diff --git a/rtengine/imagefloat.cc b/rtengine/imagefloat.cc index 74233741c..d98a817a2 100644 --- a/rtengine/imagefloat.cc +++ b/rtengine/imagefloat.cc @@ -27,6 +27,7 @@ #include "alignedbuffer.h" #include "rt_math.h" #include "color.h" +#include "procparams.h" using namespace rtengine; diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 76a6417ff..f1fa8dbef 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -26,6 +26,7 @@ #include #include #include "rt_math.h" +#include "procparams.h" #include "../rtgui/options.h" #include "../rtgui/version.h" @@ -103,8 +104,8 @@ void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const rtengine::pr { // store exif info - exifChange.clear(); - exifChange = exif; + exifChange->clear(); + *exifChange = exif; if (exifRoot != nullptr) { delete exifRoot; @@ -185,6 +186,22 @@ void ImageIO::setOutputProfile (const char* pdata, int plen) profileLength = plen; } +ImageIO::ImageIO() : + pl(nullptr), + embProfile(nullptr), + profileData(nullptr), + profileLength(0), + loadedProfileData(nullptr), + loadedProfileDataJpg(false), + loadedProfileLength(0), + exifChange(new procparams::ExifPairs), + iptc(nullptr), + exifRoot(nullptr), + sampleFormat(IIOSF_UNKNOWN), + sampleArrangement(IIOSA_UNKNOWN) +{ +} + ImageIO::~ImageIO () { @@ -1055,7 +1072,7 @@ int ImageIO::savePNG (const Glib::ustring &fname, int bps) const iptcdata = nullptr; } - int size = rtexif::ExifManager::createPNGMarker(exifRoot, exifChange, width, height, bps, (char*)iptcdata, iptclen, buffer, bufferSize); + int size = rtexif::ExifManager::createPNGMarker(exifRoot, *exifChange, width, height, bps, (char*)iptcdata, iptclen, buffer, bufferSize); if (iptcdata) { iptc_data_free_buf (iptc, iptcdata); @@ -1205,7 +1222,7 @@ int ImageIO::saveJPEG (const Glib::ustring &fname, int quality, int subSamp) con // assemble and write exif marker if (exifRoot) { - int size = rtexif::ExifManager::createJPEGMarker (exifRoot, exifChange, cinfo.image_width, cinfo.image_height, buffer); + int size = rtexif::ExifManager::createJPEGMarker (exifRoot, *exifChange, cinfo.image_width, cinfo.image_height, buffer); if (size > 0 && size < 65530) { jpeg_write_marker(&cinfo, JPEG_APP0 + 1, buffer, size); @@ -1361,7 +1378,7 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u // ------------------ Apply list of change ----------------- - for (auto currExifChange : exifChange) { + for (auto currExifChange : *exifChange) { cl->applyChange (currExifChange.first, currExifChange.second); } diff --git a/rtengine/imageio.h b/rtengine/imageio.h index 60bf6bc43..f3428b759 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -28,11 +28,12 @@ #define IMIO_FILETYPENOTSUPPORTED 6 #define IMIO_CANNOTWRITEFILE 7 +#include + #include #include #include "rtengine.h" #include "imageformat.h" -#include "procparams.h" #include "../rtexif/rtexif.h" #include "imagedimensions.h" #include "iimage.h" @@ -55,7 +56,7 @@ protected: char* loadedProfileData; bool loadedProfileDataJpg; int loadedProfileLength; - procparams::ExifPairs exifChange; + std::unique_ptr exifChange; IptcData* iptc; const rtexif::TagDirectory* exifRoot; MyMutex imutex; @@ -68,11 +69,8 @@ private: public: static Glib::ustring errorMsg[6]; - ImageIO () : pl (nullptr), embProfile(nullptr), profileData(nullptr), profileLength(0), loadedProfileData(nullptr), loadedProfileDataJpg(false), - loadedProfileLength(0), iptc(nullptr), exifRoot (nullptr), sampleFormat(IIOSF_UNKNOWN), - sampleArrangement(IIOSA_UNKNOWN) {} - - ~ImageIO () override; + ImageIO(); + ~ImageIO() override; void setProgressListener (ProgressListener* l); void setSampleFormat(IIOSampleFormat sFormat); diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 6c39d8d42..a18cca9d7 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -23,7 +23,6 @@ #include #include "rtengine.h" #include "colortemp.h" -#include "procparams.h" #include "coord2d.h" #include "dcp.h" #include "LUT.h" @@ -35,7 +34,17 @@ namespace rtengine { -using namespace procparams; +namespace procparams +{ + +struct CoarseTransformParams; +struct ColorManagementParams; +struct LensProfParams; +struct RAWParams; +struct RetinexParams; +struct ToneCurveParams; + +} class ImageMatrices { @@ -67,14 +76,14 @@ public: ~ImageSource () override {} virtual int load (const Glib::ustring &fname) = 0; - virtual void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse, bool prepareDenoise = true) {}; - virtual void demosaic (const RAWParams &raw, bool autoContrast, double &contrastThreshold) {}; - virtual void retinex (const ColorManagementParams& cmp, const RetinexParams &deh, const ToneCurveParams& Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) {}; - virtual void retinexPrepareCurves (const RetinexParams &retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, RetinexgaintransmissionCurve &retinexgaintransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) {}; - virtual void retinexPrepareBuffers (const ColorManagementParams& cmp, const RetinexParams &retinexParams, multi_array2D &conversionBuffer, LUTu &lhist16RETI) {}; + virtual void preprocess (const procparams::RAWParams &raw, const procparams::LensProfParams &lensProf, const procparams::CoarseTransformParams& coarse, bool prepareDenoise = true) {}; + virtual void demosaic (const procparams::RAWParams &raw, bool autoContrast, double &contrastThreshold) {}; + virtual void retinex (const procparams::ColorManagementParams& cmp, const procparams::RetinexParams &deh, const procparams::ToneCurveParams& Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) {}; + virtual void retinexPrepareCurves (const procparams::RetinexParams &retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, RetinexgaintransmissionCurve &retinexgaintransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) {}; + virtual void retinexPrepareBuffers (const procparams::ColorManagementParams& cmp, const procparams::RetinexParams &retinexParams, multi_array2D &conversionBuffer, LUTu &lhist16RETI) {}; virtual void flushRawData () {}; virtual void flushRGB () {}; - virtual void HLRecovery_Global (const ToneCurveParams &hrp) {}; + virtual void HLRecovery_Global (const procparams::ToneCurveParams &hrp) {}; virtual void HLRecovery_inpaint (float** red, float** green, float** blue) {}; virtual bool isRGBSourceModified () const = 0; // tracks whether cached rgb output of demosaic has been modified @@ -86,7 +95,7 @@ public: // use right after demosaicing image, add coarse transformation and put the result in the provided Imagefloat* - virtual void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hlp, const RAWParams &raw) = 0; + virtual void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hlp, const RAWParams &raw) = 0; virtual eSensorType getSensorType () const = 0; virtual bool isMono () const = 0; // true is ready to provide the AutoWB, i.e. when the image has been demosaiced for RawImageSource @@ -111,7 +120,7 @@ public: virtual ImageMatrices* getImageMatrices () = 0; virtual bool isRAW () const = 0; - virtual DCPProfile* getDCP (const ColorManagementParams &cmp, DCPProfile::ApplyState &as) + virtual DCPProfile* getDCP (const procparams::ColorManagementParams &cmp, DCPProfile::ApplyState &as) { return nullptr; }; @@ -140,7 +149,7 @@ public: } // for RAW files, compute a tone curve using histogram matching on the embedded thumbnail - virtual void getAutoMatchedToneCurve(const ColorManagementParams &cp, std::vector &outCurve) + virtual void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, std::vector &outCurve) { outCurve = { 0.0 }; } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 12ef0c226..d0f4df6d3 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -24,6 +24,7 @@ #include "colortemp.h" #include "improcfun.h" #include "iccstore.h" +#include "procparams.h" #include #include #include @@ -36,70 +37,121 @@ namespace rtengine extern const Settings* settings; -ImProcCoordinator::ImProcCoordinator() - : orig_prev(nullptr), oprevi(nullptr), oprevl(nullptr), nprevl(nullptr), fattal_11_dcrop_cache(nullptr), previmg(nullptr), workimg(nullptr), - ncie (nullptr), imgsrc (nullptr), lastAwbEqual (0.), lastAwbTempBias (0.0), ipf (¶ms, true), monitorIntent (RI_RELATIVE), - softProof(false), gamutCheck(false), sharpMask(false), scale(10), highDetailPreprocessComputed(false), highDetailRawComputed(false), - allocated(false), bwAutoR(-9000.f), bwAutoG(-9000.f), bwAutoB(-9000.f), CAMMean(NAN), +ImProcCoordinator::ImProcCoordinator() : + orig_prev(nullptr), + oprevi(nullptr), + oprevl(nullptr), + nprevl(nullptr), + fattal_11_dcrop_cache(nullptr), + previmg(nullptr), + workimg(nullptr), + ncie (nullptr), + imgsrc (nullptr), + lastAwbEqual (0.), + lastAwbTempBias (0.0), + monitorIntent (RI_RELATIVE), + softProof(false), + gamutCheck(false), + sharpMask(false), + scale(10), + highDetailPreprocessComputed(false), + highDetailRawComputed(false), + allocated(false), + bwAutoR(-9000.f), + bwAutoG(-9000.f), + bwAutoB(-9000.f), + CAMMean(NAN), + hltonecurve(65536), + shtonecurve(65536), + tonecurve(65536, 0), //,1); + lumacurve(32770, 0), // lumacurve[32768] and lumacurve[32769] will be set to 32768 and 32769 later to allow linear interpolation + chroma_acurve(65536, 0), + chroma_bcurve(65536, 0), + satcurve(65536, 0), + lhskcurve(65536, 0), + clcurve(65536, 0), + conversionBuffer(1, 1), + wavclCurve(65536, 0), + clToningcurve(65536, 0), + cl2Toningcurve(65536, 0), + Noisecurve(65536, 0), + NoiseCCcurve(65536, 0), + vhist16(65536), vhist16bw(65536), + lhist16CAM(65536), + lhist16CCAM(65536), + lhist16RETI(), + lhist16LClad(65536), + histRed(256), histRedRaw(256), + histGreen(256), histGreenRaw(256), + histBlue(256), histBlueRaw(256), + histLuma(256), + histToneCurve(256), + histToneCurveBW(256), + histLCurve(256), + histCCurve(256), + histLLCurve(256), - hltonecurve(65536), - shtonecurve(65536), - tonecurve(65536, 0), //,1); - lumacurve(32770, 0), // lumacurve[32768] and lumacurve[32769] will be set to 32768 and 32769 later to allow linear interpolation - chroma_acurve(65536, 0), - chroma_bcurve(65536, 0), - satcurve(65536, 0), - lhskcurve(65536, 0), - clcurve(65536, 0), - conversionBuffer(1, 1), - wavclCurve(65536, 0), - clToningcurve(65536, 0), - cl2Toningcurve(65536, 0), - Noisecurve(65536, 0), - NoiseCCcurve(65536, 0), - vhist16(65536), vhist16bw(65536), - lhist16CAM(65536), - lhist16CCAM(65536), - lhist16RETI(), - lhist16LClad(65536), - histRed(256), histRedRaw(256), - histGreen(256), histGreenRaw(256), - histBlue(256), histBlueRaw(256), - histLuma(256), - histToneCurve(256), - histToneCurveBW(256), - histLCurve(256), - histCCurve(256), - histLLCurve(256), + histLCAM(256), + histCCAM(256), + histClad(256), + bcabhist(256), + histChroma(256), - histLCAM(256), - histCCAM(256), - histClad(256), - bcabhist(256), - histChroma(256), + histLRETI(256), - histLRETI(256), + CAMBrightCurveJ(), CAMBrightCurveQ(), - CAMBrightCurveJ(), CAMBrightCurveQ(), - - rCurve(), - gCurve(), - bCurve(), - ctColorCurve(), - rcurvehist(256), rcurvehistCropped(256), rbeforehist(256), - gcurvehist(256), gcurvehistCropped(256), gbeforehist(256), - bcurvehist(256), bcurvehistCropped(256), bbeforehist(256), - fw(0), fh(0), tr(0), - fullw(1), fullh(1), - pW(-1), pH(-1), - plistener(nullptr), imageListener(nullptr), aeListener(nullptr), acListener(nullptr), abwListener(nullptr), awbListener(nullptr), flatFieldAutoClipListener(nullptr), bayerAutoContrastListener(nullptr), xtransAutoContrastListener(nullptr), frameCountListener(nullptr), imageTypeListener(nullptr), actListener(nullptr), adnListener(nullptr), awavListener(nullptr), dehaListener(nullptr), hListener(nullptr), - resultValid(false), lastOutputProfile("BADFOOD"), lastOutputIntent(RI__COUNT), lastOutputBPC(false), thread(nullptr), changeSinceLast(0), updaterRunning(false), destroying(false), utili(false), autili(false), - butili(false), ccutili(false), cclutili(false), clcutili(false), opautili(false), wavcontlutili(false), colourToningSatLimit(0.f), colourToningSatLimitOpacity(0.f), highQualityComputed(false), customTransformIn(nullptr), customTransformOut(nullptr) -{} - -void ImProcCoordinator::assign(ImageSource* imgsrc) + rCurve(), + gCurve(), + bCurve(), + ctColorCurve(), + rcurvehist(256), rcurvehistCropped(256), rbeforehist(256), + gcurvehist(256), gcurvehistCropped(256), gbeforehist(256), + bcurvehist(256), bcurvehistCropped(256), bbeforehist(256), + fw(0), fh(0), tr(0), + fullw(1), fullh(1), + pW(-1), pH(-1), + plistener(nullptr), + imageListener(nullptr), + aeListener(nullptr), + acListener(nullptr), + abwListener(nullptr), + awbListener(nullptr), + flatFieldAutoClipListener(nullptr), + bayerAutoContrastListener(nullptr), + xtransAutoContrastListener(nullptr), + frameCountListener(nullptr), + imageTypeListener(nullptr), + actListener(nullptr), + adnListener(nullptr), + awavListener(nullptr), + dehaListener(nullptr), + hListener(nullptr), + resultValid(false), + params(new procparams::ProcParams), + lastOutputProfile("BADFOOD"), + lastOutputIntent(RI__COUNT), + lastOutputBPC(false), + thread(nullptr), + changeSinceLast(0), + updaterRunning(false), + nextParams(new procparams::ProcParams), + destroying(false), + utili(false), + autili(false), + butili(false), + ccutili(false), + cclutili(false), + clcutili(false), + opautili(false), + wavcontlutili(false), + colourToningSatLimit(0.f), + colourToningSatLimitOpacity(0.f), + highQualityComputed(false), + customTransformIn(nullptr), + customTransformOut(nullptr), + ipf(params.get(), true) { - this->imgsrc = imgsrc; } ImProcCoordinator::~ImProcCoordinator() @@ -142,6 +194,16 @@ ImProcCoordinator::~ImProcCoordinator() updaterThreadStart.unlock(); } +void ImProcCoordinator::assign(ImageSource* imgsrc) +{ + this->imgsrc = imgsrc; +} + +void ImProcCoordinator::getParams(procparams::ProcParams* dst) +{ + *dst = *params; +} + DetailedCrop* ImProcCoordinator::createCrop(::EditDataProvider *editDataProvider, bool isDetailWindow) { @@ -177,9 +239,9 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) todo |= TRANSFORM; // Change about Crop does affect TRANSFORM } - RAWParams rp = params.raw; - ColorManagementParams cmp = params.icm; - LCurveParams lcur = params.labCurve; + RAWParams rp = params->raw; + ColorManagementParams cmp = params->icm; + LCurveParams lcur = params->labCurve; if (!highDetailNeeded) { // if below 100% magnification, take a fast path @@ -201,14 +263,14 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) progress("Applying white balance, color correction & sRGB conversion...", 100 * readyphase / numofphases); if (frameCountListener) { - frameCountListener->FrameCountChanged(imgsrc->getFrameCount(), params.raw.bayersensor.imageNum); + frameCountListener->FrameCountChanged(imgsrc->getFrameCount(), params->raw.bayersensor.imageNum); } // raw auto CA is bypassed if no high detail is needed, so we have to compute it when high detail is needed if ((todo & M_PREPROC) || (!highDetailPreprocessComputed && highDetailNeeded)) { - imgsrc->setCurrentFrame(params.raw.bayersensor.imageNum); + imgsrc->setCurrentFrame(params->raw.bayersensor.imageNum); - imgsrc->preprocess(rp, params.lensProf, params.coarse); + imgsrc->preprocess(rp, params->lensProf, params->coarse); if (flatFieldAutoClipListener && rp.ff_AutoClipControl) { flatFieldAutoClipListener->flatFieldAutoClipValueChanged(imgsrc->getFlatFieldAutoClipValue()); } @@ -235,8 +297,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if ((todo & M_RAW) || (!highDetailRawComputed && highDetailNeeded) - || (params.toneCurve.hrenabled && params.toneCurve.method != "Color" && imgsrc->isRGBSourceModified()) - || (!params.toneCurve.hrenabled && params.toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) { + || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified()) + || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) { if (settings->verbose) { if (imgsrc->getSensorType() == ST_BAYER) { @@ -246,14 +308,14 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } if(imgsrc->getSensorType() == ST_BAYER) { - if(params.raw.bayersensor.method != RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::PIXELSHIFT)) { - imgsrc->setBorder(params.raw.bayersensor.border); + if(params->raw.bayersensor.method != RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::PIXELSHIFT)) { + imgsrc->setBorder(params->raw.bayersensor.border); } else { - imgsrc->setBorder(std::max(params.raw.bayersensor.border, 2)); + imgsrc->setBorder(std::max(params->raw.bayersensor.border, 2)); } } - bool autoContrast = imgsrc->getSensorType() == ST_BAYER ? params.raw.bayersensor.dualDemosaicAutoContrast : params.raw.xtranssensor.dualDemosaicAutoContrast; - double contrastThreshold = imgsrc->getSensorType() == ST_BAYER ? params.raw.bayersensor.dualDemosaicContrast : params.raw.xtranssensor.dualDemosaicContrast; + bool autoContrast = imgsrc->getSensorType() == ST_BAYER ? params->raw.bayersensor.dualDemosaicAutoContrast : params->raw.xtranssensor.dualDemosaicAutoContrast; + double contrastThreshold = imgsrc->getSensorType() == ST_BAYER ? params->raw.bayersensor.dualDemosaicContrast : params->raw.xtranssensor.dualDemosaicContrast; imgsrc->demosaic(rp, autoContrast, contrastThreshold); //enabled demosaic if (imgsrc->getSensorType() == ST_BAYER && bayerAutoContrastListener && autoContrast) { @@ -272,24 +334,24 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) highDetailRawComputed = false; } - if (params.retinex.enabled) { + if (params->retinex.enabled) { lhist16RETI(32768); lhist16RETI.clear(); - imgsrc->retinexPrepareBuffers(params.icm, params.retinex, conversionBuffer, lhist16RETI); + imgsrc->retinexPrepareBuffers(params->icm, params->retinex, conversionBuffer, lhist16RETI); } } - if ((todo & (M_RETINEX | M_INIT)) && params.retinex.enabled) { + if ((todo & (M_RETINEX | M_INIT)) && params->retinex.enabled) { bool dehacontlutili = false; bool mapcontlutili = false; bool useHsl = false; LUTf cdcurve(65536, 0); LUTf mapcurve(65536, 0); - imgsrc->retinexPrepareCurves(params.retinex, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, dehacontlutili, mapcontlutili, useHsl, lhist16RETI, histLRETI); + imgsrc->retinexPrepareCurves(params->retinex, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, dehacontlutili, mapcontlutili, useHsl, lhist16RETI, histLRETI); float minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax; - imgsrc->retinex(params.icm, params.retinex, params.toneCurve, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, histLRETI); //enabled Retinex + imgsrc->retinex(params->icm, params->retinex, params->toneCurve, cdcurve, mapcurve, dehatransmissionCurve, dehagaintransmissionCurve, conversionBuffer, dehacontlutili, mapcontlutili, useHsl, minCD, maxCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax, histLRETI); //enabled Retinex if (dehaListener) { dehaListener->minmaxChanged(maxCD, minCD, mini, maxi, Tmean, Tsigma, Tmin, Tmax); @@ -299,32 +361,32 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (todo & (M_INIT | M_LINDENOISE | M_HDR)) { MyMutex::MyLock initLock(minit); // Also used in crop window - imgsrc->HLRecovery_Global(params.toneCurve); // this handles Color HLRecovery + imgsrc->HLRecovery_Global(params->toneCurve); // this handles Color HLRecovery if (settings->verbose) { printf("Applying white balance, color correction & sRBG conversion...\n"); } - currWB = ColorTemp(params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method); + currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method); - if (!params.wb.enabled) { + if (!params->wb.enabled) { currWB = ColorTemp(); - } else if (params.wb.method == "Camera") { + } else if (params->wb.method == "Camera") { currWB = imgsrc->getWB(); - } else if (params.wb.method == "Auto") { - if (lastAwbEqual != params.wb.equal || lastAwbTempBias != params.wb.tempBias) { + } else if (params->wb.method == "Auto") { + if (lastAwbEqual != params->wb.equal || lastAwbTempBias != params->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, params->wb.equal, params->wb.tempBias); + lastAwbEqual = params->wb.equal; + lastAwbTempBias = params->wb.tempBias; } else { lastAwbEqual = -1.; lastAwbTempBias = 0.0; - autoWB.useDefaults(params.wb.equal); + autoWB.useDefaults(params->wb.equal); } //double rr,gg,bb; @@ -334,19 +396,19 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) currWB = autoWB; } - if (params.wb.enabled) { - params.wb.temperature = currWB.getTemp(); - params.wb.green = currWB.getGreen(); + if (params->wb.enabled) { + params->wb.temperature = currWB.getTemp(); + params->wb.green = currWB.getGreen(); } - if (params.wb.method == "Auto" && awbListener && params.wb.enabled) { - awbListener->WBChanged(params.wb.temperature, params.wb.green); + if (params->wb.method == "Auto" && awbListener && params->wb.enabled) { + awbListener->WBChanged(params->wb.temperature, params->wb.green); } /* GammaValues g_a; - double pwr = 1.0 / params.icm.gampos; - double ts = params.icm.slpos; + double pwr = 1.0 / params->icm.gampos; + double ts = params->icm.slpos; int mode = 0; @@ -367,7 +429,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } fou.close(); */ - int tr = getCoarseBitMask(params.coarse); + int tr = getCoarseBitMask(params->coarse); imgsrc->getFullSize(fw, fh, tr); @@ -377,13 +439,13 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // 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.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); /* Issue 2785, disabled some 1:1 tools if (todo & M_LINDENOISE) { - DirPyrDenoiseParams denoiseParams = params.dirpyrDenoise; + DirPyrDenoiseParams denoiseParams = params->dirpyrDenoise; if (denoiseParams.enabled && (scale==1)) { Imagefloat *calclum = NULL ; @@ -414,7 +476,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) calclum->b(ii>>1,jj>>1) = orig_prev->b(ii,jj); } } - imgsrc->convertColorSpace(calclum, params.icm, currWB);//calculate values after colorspace conversion + imgsrc->convertColorSpace(calclum, params->icm, currWB);//calculate values after colorspace conversion } int kall=1; @@ -422,14 +484,14 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } */ - imgsrc->convertColorSpace(orig_prev, params.icm, currWB); + imgsrc->convertColorSpace(orig_prev, params->icm, currWB); - ipf.firstAnalysis(orig_prev, params, vhist16); + ipf.firstAnalysis(orig_prev, *params, vhist16); } readyphase++; - if ((todo & M_HDR) && (params.fattal.enabled || params.dehaze.enabled)) { + 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; @@ -449,7 +511,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // Remove transformation if unneeded bool needstransform = ipf.needsTransform(); - if ((needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled))) { + if ((needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled && !params->colorappearance.enabled))) { assert(oprevi); Imagefloat *op = oprevi; oprevi = new Imagefloat(pW, pH); @@ -462,13 +524,13 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } - if ((todo & (M_TRANSFORM | M_RGBCURVE)) && params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled) { + if ((todo & (M_TRANSFORM | M_RGBCURVE)) && params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled && !params->colorappearance.enabled) { const int W = oprevi->getWidth(); const int H = oprevi->getHeight(); LabImage labcbdl(W, H); - ipf.rgb2lab(*oprevi, labcbdl, params.icm.workingProfile); + ipf.rgb2lab(*oprevi, labcbdl, params->icm.workingProfile); ipf.dirpyrequalizer(&labcbdl, scale); - ipf.lab2rgb(labcbdl, *oprevi, params.icm.workingProfile); + ipf.lab2rgb(labcbdl, *oprevi, params->icm.workingProfile); } readyphase++; @@ -477,37 +539,37 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) readyphase++; if (todo & M_AUTOEXP) { - if (params.toneCurve.autoexp) { + if (params->toneCurve.autoexp) { LUTu aehist; int aehistcompr; imgsrc->getAutoExpHistogram(aehist, aehistcompr); - ipf.getAutoExp(aehist, aehistcompr, params.toneCurve.clip, params.toneCurve.expcomp, - params.toneCurve.brightness, params.toneCurve.contrast, params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh); + ipf.getAutoExp(aehist, aehistcompr, params->toneCurve.clip, params->toneCurve.expcomp, + params->toneCurve.brightness, params->toneCurve.contrast, params->toneCurve.black, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh); if (aeListener) - aeListener->autoExpChanged(params.toneCurve.expcomp, params.toneCurve.brightness, params.toneCurve.contrast, - params.toneCurve.black, params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, params.toneCurve.hrenabled); + aeListener->autoExpChanged(params->toneCurve.expcomp, params->toneCurve.brightness, params->toneCurve.contrast, + params->toneCurve.black, params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, params->toneCurve.hrenabled); } - if (params.toneCurve.histmatching) { - if (!params.toneCurve.fromHistMatching) { - imgsrc->getAutoMatchedToneCurve(params.icm, params.toneCurve.curve); + if (params->toneCurve.histmatching) { + if (!params->toneCurve.fromHistMatching) { + imgsrc->getAutoMatchedToneCurve(params->icm, params->toneCurve.curve); } - if (params.toneCurve.autoexp) { - params.toneCurve.expcomp = 0.0; + if (params->toneCurve.autoexp) { + params->toneCurve.expcomp = 0.0; } - params.toneCurve.autoexp = false; - params.toneCurve.curveMode = ToneCurveParams::TcMode::FILMLIKE; - params.toneCurve.curve2 = { 0 }; - params.toneCurve.brightness = 0; - params.toneCurve.contrast = 0; - params.toneCurve.black = 0; - params.toneCurve.fromHistMatching = true; + params->toneCurve.autoexp = false; + params->toneCurve.curveMode = ToneCurveMode::FILMLIKE; + params->toneCurve.curve2 = { 0 }; + params->toneCurve.brightness = 0; + params->toneCurve.contrast = 0; + params->toneCurve.black = 0; + params->toneCurve.fromHistMatching = true; if (aeListener) { - aeListener->autoMatchedToneCurveChanged(params.toneCurve.curveMode, params.toneCurve.curve); + aeListener->autoMatchedToneCurveChanged(params->toneCurve.curveMode, params->toneCurve.curve); } } } @@ -515,13 +577,13 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) progress("Exposure curve & CIELAB conversion...", 100 * readyphase / numofphases); if (todo & (M_AUTOEXP | M_RGBCURVE)) { - if (params.icm.workingTRC == "Custom") { //exec TRC IN free + if (params->icm.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; + 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(); @@ -531,13 +593,13 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) cmsDeleteTransform(customTransformIn); customTransformIn = nullptr; } - ipf.workingtrc(oprevi, oprevi, cw, ch, -5, params.icm.workingProfile, 2.4, 12.92310, customTransformIn, true, false, true); + 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); + ipf.workingtrc(oprevi, oprevi, cw, ch, 5, params->icm.workingProfile, params->icm.workingTRCGamma, params->icm.workingTRCSlope, customTransformOut, false, true, true); } } } @@ -547,43 +609,43 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // if (hListener) oprevi->calcCroppedHistogram(params, scale, histCropped); //complexCurve also calculated pre-curves histogram depending on crop - CurveFactory::complexCurve(params.toneCurve.expcomp, params.toneCurve.black / 65535.0, - params.toneCurve.hlcompr, params.toneCurve.hlcomprthresh, - params.toneCurve.shcompr, params.toneCurve.brightness, params.toneCurve.contrast, - params.toneCurve.curve, params.toneCurve.curve2, + CurveFactory::complexCurve(params->toneCurve.expcomp, params->toneCurve.black / 65535.0, + params->toneCurve.hlcompr, params->toneCurve.hlcomprthresh, + params->toneCurve.shcompr, params->toneCurve.brightness, params->toneCurve.contrast, + params->toneCurve.curve, params->toneCurve.curve2, vhist16, hltonecurve, shtonecurve, tonecurve, histToneCurve, customToneCurve1, customToneCurve2, 1); - CurveFactory::RGBCurve(params.rgbCurves.rcurve, rCurve, 1); - CurveFactory::RGBCurve(params.rgbCurves.gcurve, gCurve, 1); - CurveFactory::RGBCurve(params.rgbCurves.bcurve, bCurve, 1); + CurveFactory::RGBCurve(params->rgbCurves.rcurve, rCurve, 1); + CurveFactory::RGBCurve(params->rgbCurves.gcurve, gCurve, 1); + CurveFactory::RGBCurve(params->rgbCurves.bcurve, bCurve, 1); opautili = false; - if (params.colorToning.enabled) { - TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params.icm.workingProfile); + if (params->colorToning.enabled) { + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); double wp[3][3] = { {wprof[0][0], wprof[0][1], wprof[0][2]}, {wprof[1][0], wprof[1][1], wprof[1][2]}, {wprof[2][0], wprof[2][1], wprof[2][2]} }; - params.colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, opautili); - CurveFactory::curveToning(params.colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16); - CurveFactory::curveToning(params.colorToning.cl2curve, cl2Toningcurve, scale == 1 ? 1 : 16); + params->colorToning.getCurves(ctColorCurve, ctOpacityCurve, wp, opautili); + CurveFactory::curveToning(params->colorToning.clcurve, clToningcurve, scale == 1 ? 1 : 16); + CurveFactory::curveToning(params->colorToning.cl2curve, cl2Toningcurve, scale == 1 ? 1 : 16); } - if (params.blackwhite.enabled) { - CurveFactory::curveBW(params.blackwhite.beforeCurve, params.blackwhite.afterCurve, vhist16bw, histToneCurveBW, beforeToneCurveBW, afterToneCurveBW, 1); + if (params->blackwhite.enabled) { + CurveFactory::curveBW(params->blackwhite.beforeCurve, params->blackwhite.afterCurve, vhist16bw, histToneCurveBW, beforeToneCurveBW, afterToneCurveBW, 1); } - colourToningSatLimit = float (params.colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f; - colourToningSatLimitOpacity = 1.f - (float (params.colorToning.saturatedOpacity) / 100.f); + colourToningSatLimit = float (params->colorToning.satProtectionThreshold) / 100.f * 0.7f + 0.3f; + colourToningSatLimitOpacity = 1.f - (float (params->colorToning.saturatedOpacity) / 100.f); int satTH = 80; int satPR = 30; int indi = 0; - if (params.colorToning.enabled && params.colorToning.autosat && params.colorToning.method != "LabGrid") { //for colortoning evaluation of saturation settings + if (params->colorToning.enabled && params->colorToning.autosat && params->colorToning.method != "LabGrid") { //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 @@ -607,21 +669,21 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) satPR = (int) 100.f * (moyS - 0.85f * eqty); } - if (actListener && params.colorToning.enabled) { - if (params.blackwhite.enabled && params.colorToning.autosat) { + if (actListener && params->colorToning.enabled) { + if (params->blackwhite.enabled && params->colorToning.autosat) { actListener->autoColorTonChanged(0, satTH, satPR); //hide sliders only if autosat indi = 0; } else { - if (params.colorToning.autosat) { - if (params.colorToning.method == "Lab") { + if (params->colorToning.autosat) { + if (params->colorToning.method == "Lab") { indi = 1; - } else if (params.colorToning.method == "RGBCurves") { + } else if (params->colorToning.method == "RGBCurves") { indi = 1; - } else if (params.colorToning.method == "RGBSliders") { + } else if (params->colorToning.method == "RGBSliders") { indi = 1; - } else if (params.colorToning.method == "Splico") { + } else if (params->colorToning.method == "Splico") { indi = 2; - } else if (params.colorToning.method == "Splitlr") { + } else if (params->colorToning.method == "Splitlr") { indi = 2; } } @@ -636,12 +698,12 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) double bbm = 33.; DCPProfile::ApplyState as; - DCPProfile *dcpProf = imgsrc->getDCP(params.icm, as); + DCPProfile *dcpProf = imgsrc->getDCP(params->icm, as); - ipf.rgbProc (oprevi, oprevl, nullptr, hltonecurve, shtonecurve, tonecurve, params.toneCurve.saturation, - rCurve, gCurve, bCurve, colourToningSatLimit, colourToningSatLimitOpacity, 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, as, histToneCurve); + ipf.rgbProc (oprevi, oprevl, nullptr, hltonecurve, shtonecurve, tonecurve, params->toneCurve.saturation, + rCurve, gCurve, bCurve, colourToningSatLimit, colourToningSatLimitOpacity, 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, as, histToneCurve); - if (params.blackwhite.enabled && params.blackwhite.autoc && abwListener) { + if (params->blackwhite.enabled && params->blackwhite.autoc && abwListener) { if (settings->verbose) { printf("ImProcCoordinator / Auto B&W coefs: R=%.2f G=%.2f B=%.2f\n", bwAutoR, bwAutoG, bwAutoB); } @@ -649,7 +711,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) abwListener->BWChanged((float) rrm, (float) ggm, (float) bbm); } - if (params.colorToning.enabled && params.colorToning.autosat && actListener) { + if (params->colorToning.enabled && params->colorToning.autosat && actListener) { actListener->autoColorTonChanged(indi, (int) colourToningSatLimit, (int)colourToningSatLimitOpacity); //change sliders autosat } @@ -658,7 +720,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // compute L channel histogram int x1, y1, x2, y2; - params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); + params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); } readyphase++; @@ -691,15 +753,15 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) #ifdef _OPENMP static_cast(numThreads); // to silence cppcheck warning #endif - CurveFactory::complexLCurve(params.labCurve.brightness, params.labCurve.contrast, params.labCurve.lcurve, lhist16, lumacurve, histLCurve, scale == 1 ? 1 : 16, utili); + CurveFactory::complexLCurve(params->labCurve.brightness, params->labCurve.contrast, params->labCurve.lcurve, lhist16, lumacurve, histLCurve, scale == 1 ? 1 : 16, utili); } if (todo & M_LUMACURVE) { - CurveFactory::curveCL(clcutili, params.labCurve.clcurve, clcurve, scale == 1 ? 1 : 16); + CurveFactory::curveCL(clcutili, params->labCurve.clcurve, clcurve, scale == 1 ? 1 : 16); - CurveFactory::complexsgnCurve(autili, butili, ccutili, cclutili, params.labCurve.acurve, params.labCurve.bcurve, params.labCurve.cccurve, - params.labCurve.lccurve, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, scale == 1 ? 1 : 16); + CurveFactory::complexsgnCurve(autili, butili, ccutili, cclutili, params->labCurve.acurve, params->labCurve.bcurve, params->labCurve.cccurve, + params->labCurve.lccurve, chroma_acurve, chroma_bcurve, satcurve, lhskcurve, scale == 1 ? 1 : 16); } if (todo & (M_LUMINANCE + M_COLOR)) { @@ -713,7 +775,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) ipf.vibrance(nprevl); ipf.labColorCorrectionRegions(nprevl); - if ((params.colorappearance.enabled && !params.colorappearance.tonecie) || (!params.colorappearance.enabled)) { + if ((params->colorappearance.enabled && !params->colorappearance.tonecie) || (!params->colorappearance.enabled)) { ipf.EPDToneMap(nprevl, 5, scale); } @@ -722,29 +784,29 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) /* Issue 2785, disabled some 1:1 tools if (scale==1) { - if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ + if((params->colorappearance.enabled && !settings->autocielab) || (!params->colorappearance.enabled)){ progress ("Denoising luminance impulse...",100*readyphase/numofphases); ipf.impulsedenoise (nprevl); readyphase++; } - if((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ + if((params->colorappearance.enabled && !settings->autocielab) || (!params->colorappearance.enabled)){ progress ("Defringing...",100*readyphase/numofphases); ipf.defringe (nprevl); readyphase++; } - if (params.sharpenEdge.enabled) { + if (params->sharpenEdge.enabled) { progress ("Edge sharpening...",100*readyphase/numofphases); ipf.MLsharpen (nprevl); readyphase++; } - if (params.sharpenMicro.enabled) { - if(( params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)){ + if (params->sharpenMicro.enabled) { + if(( params->colorappearance.enabled && !settings->autocielab) || (!params->colorappearance.enabled)){ progress ("Microcontrast...",100*readyphase/numofphases); ipf.MLmicrocontrast (nprevl); readyphase++; } } - if(((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled)) && params.sharpening.enabled) { + if(((params->colorappearance.enabled && !settings->autocielab) || (!params->colorappearance.enabled)) && params->sharpening.enabled) { progress ("Sharpening...",100*readyphase/numofphases); float **buffer = new float*[pH]; @@ -760,8 +822,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } */ - if (params.dirpyrequalizer.cbdlMethod == "aft") { - if (((params.colorappearance.enabled && !settings->autocielab) || (!params.colorappearance.enabled))) { + if (params->dirpyrequalizer.cbdlMethod == "aft") { + if (((params->colorappearance.enabled && !settings->autocielab) || (!params->colorappearance.enabled))) { progress("Pyramid wavelet...", 100 * readyphase / numofphases); ipf.dirpyrequalizer(nprevl, scale); //ipf.Lanczoslab (ip_wavelet(LabImage * lab, LabImage * dst, const procparams::EqualizerParams & eqparams), nprevl, 1.f/scale); @@ -771,12 +833,12 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) wavcontlutili = false; - //CurveFactory::curveWavContL ( wavcontlutili,params.wavelet.lcurve, wavclCurve, LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,int skip); - CurveFactory::curveWavContL(wavcontlutili, params.wavelet.wavclCurve, wavclCurve, scale == 1 ? 1 : 16); + //CurveFactory::curveWavContL ( wavcontlutili,params->wavelet.lcurve, wavclCurve, LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,int skip); + CurveFactory::curveWavContL(wavcontlutili, params->wavelet.wavclCurve, wavclCurve, scale == 1 ? 1 : 16); - if ((params.wavelet.enabled)) { - WaveletParams WaveParams = params.wavelet; + if ((params->wavelet.enabled)) { + WaveletParams WaveParams = params->wavelet; // WaveParams.getCurves(wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY); WaveParams.getCurves(wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL); @@ -789,15 +851,15 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) ipf.softLight(nprevl); - if (params.colorappearance.enabled) { + 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 int x1, y1, x2, y2; - params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); + params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); lhist16CAM.clear(); lhist16CCAM.clear(); - if (!params.colorappearance.datacie) { + if (!params->colorappearance.datacie) { for (int x = 0; x < pH; x++) for (int y = 0; y < pW; y++) { int pos = CLIP((int)(nprevl->L[x][y])); @@ -807,7 +869,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } - CurveFactory::curveLightBrightColor(params.colorappearance.curve, params.colorappearance.curve2, params.colorappearance.curve3, + CurveFactory::curveLightBrightColor(params->colorappearance.curve, params->colorappearance.curve2, params->colorappearance.curve3, lhist16CAM, histLCAM, lhist16CCAM, histCCAM, customColCurve1, customColCurve2, customColCurve3, 1); @@ -816,9 +878,9 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (imgsrc->isRAW()) { if (imgsrc->getSensorType() == ST_BAYER) { - imgNum = rtengine::LIM(params.raw.bayersensor.imageNum, 0, metaData->getFrameCount() - 1); + imgNum = rtengine::LIM(params->raw.bayersensor.imageNum, 0, metaData->getFrameCount() - 1); } else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) { - //imgNum = rtengine::LIM(params.raw.xtranssensor.imageNum, 0, metaData->getFrameCount() - 1); + //imgNum = rtengine::LIM(params->raw.xtranssensor.imageNum, 0, metaData->getFrameCount() - 1); } } @@ -832,8 +894,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) adap = 2000.; } else { double E_V = fcomp + log2(double ((fnum * fnum) / fspeed / (fiso / 100.f))); - E_V += params.toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV - E_V += log2(params.raw.expos); // exposure raw white point ; log2 ==> linear to EV + E_V += params->toneCurve.expcomp;// exposure compensation in tonecurve ==> direct EV + E_V += log2(params->raw.expos); // exposure raw white point ; log2 ==> linear to EV adap = powf(2.f, E_V - 3.f); // cd / m2 // end calculation adaptation scene luminosity } @@ -845,11 +907,11 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) ncie = new CieImage(pW, pH); } - if (!CAMBrightCurveJ && (params.colorappearance.algo == "JC" || params.colorappearance.algo == "JS" || params.colorappearance.algo == "ALL")) { + if (!CAMBrightCurveJ && (params->colorappearance.algo == "JC" || params->colorappearance.algo == "JS" || params->colorappearance.algo == "ALL")) { CAMBrightCurveJ(32768, 0); } - if (!CAMBrightCurveQ && (params.colorappearance.algo == "QM" || params.colorappearance.algo == "ALL")) { + if (!CAMBrightCurveQ && (params->colorappearance.algo == "QM" || params->colorappearance.algo == "ALL")) { CAMBrightCurveQ(32768, 0); } @@ -858,17 +920,17 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) CAMBrightCurveJ.dirty = true; CAMBrightCurveQ.dirty = true; - ipf.ciecam_02float(ncie, float (adap), pW, 2, nprevl, ¶ms, customColCurve1, customColCurve2, customColCurve3, histLCAM, histCCAM, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, scale, execsharp, d, dj, yb, 1); + ipf.ciecam_02float(ncie, float (adap), pW, 2, nprevl, params.get(), customColCurve1, customColCurve2, customColCurve3, histLCAM, histCCAM, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, scale, execsharp, d, dj, yb, 1); - if ((params.colorappearance.autodegree || params.colorappearance.autodegreeout) && acListener && params.colorappearance.enabled) { + if ((params->colorappearance.autodegree || params->colorappearance.autodegreeout) && acListener && params->colorappearance.enabled) { acListener->autoCamChanged(100.* (double)d, 100.* (double)dj); } - if (params.colorappearance.autoadapscen && acListener && params.colorappearance.enabled) { + if (params->colorappearance.autoadapscen && acListener && params->colorappearance.enabled) { acListener->adapCamChanged(adap); //real value of adapt scene } - if (params.colorappearance.autoybscen && acListener && params.colorappearance.enabled) { + if (params->colorappearance.autoybscen && acListener && params->colorappearance.enabled) { acListener->ybCamChanged((int) yb); //real value Yb scene } @@ -892,10 +954,10 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } // 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; - lastOutputIntent = params.icm.outputIntent; - lastOutputBPC = params.icm.outputBPC; + if ((todo & M_MONITOR) || (lastOutputProfile != params->icm.outputProfile) || lastOutputIntent != params->icm.outputIntent || lastOutputBPC != params->icm.outputBPC) { + lastOutputProfile = params->icm.outputProfile; + lastOutputIntent = params->icm.outputIntent; + lastOutputBPC = params->icm.outputBPC; ipf.updateColorProfiles(monitorProfile, monitorIntent, softProof, gamutCheck); } } @@ -918,7 +980,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // Computing the internal image for analysis, i.e. conversion from WCS->Output profile delete workimg; - workimg = ipf.lab2rgb(nprevl, 0, 0, pW, pH, params.icm); + workimg = ipf.lab2rgb(nprevl, 0, 0, pW, pH, params->icm); } catch (char * str) { progress("Error converting file...", 0); return; @@ -929,14 +991,14 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) resultValid = true; if (imageListener) { - imageListener->setImage(previmg, scale, params.crop); + imageListener->setImage(previmg, scale, params->crop); } } if (imageListener) // TODO: The WB tool should be advertised too in order to get the AutoWB's temp and green values { - imageListener->imageReady(params.crop); + imageListener->imageReady(params->crop); } readyphase++; @@ -999,7 +1061,7 @@ void ImProcCoordinator::freeAll() void ImProcCoordinator::setScale(int prevscale) { - tr = getCoarseBitMask(params.coarse); + tr = getCoarseBitMask(params->coarse); int nW, nH; imgsrc->getFullSize(fw, fh, tr); @@ -1046,7 +1108,7 @@ void ImProcCoordinator::updateLRGBHistograms() { int x1, y1, x2, y2; - params.crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); + params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); #ifdef _OPENMP #pragma omp parallel sections @@ -1168,10 +1230,10 @@ void ImProcCoordinator::getSpotWB(int x, int y, int rect, double& temp, double& ipf.transCoord(fw, fh, points, red, green, blue); - int tr = getCoarseBitMask(params.coarse); + int tr = getCoarseBitMask(params->coarse); - ret = imgsrc->getSpotWB(red, green, blue, tr, params.wb.equal); - currWB = ColorTemp(params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method); + ret = imgsrc->getSpotWB(red, green, blue, tr, params->wb.equal); + currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method); //double rr,gg,bb; //currWB.getMultipliers(rr,gg,bb); @@ -1193,11 +1255,11 @@ void ImProcCoordinator::getAutoCrop(double ratio, int &x, int &y, int &w, int &h LensCorrection *pLCPMap = nullptr; - if (params.lensProf.useLcp() && imgsrc->getMetaData()->getFocalLen() > 0) { - const std::shared_ptr pLCPProf = LCPStore::getInstance()->getProfile(params.lensProf.lcpFile); + if (params->lensProf.useLcp() && imgsrc->getMetaData()->getFocalLen() > 0) { + const std::shared_ptr pLCPProf = LCPStore::getInstance()->getProfile(params->lensProf.lcpFile); if (pLCPProf) pLCPMap = new LCPMapper(pLCPProf, imgsrc->getMetaData()->getFocalLen(), imgsrc->getMetaData()->getFocalLen35mm(), imgsrc->getMetaData()->getFocusDist(), - 0, false, params.lensProf.useDist, fullw, fullh, params.coarse, imgsrc->getRotateDegree()); + 0, false, params->lensProf.useDist, fullw, fullh, params->coarse, imgsrc->getRotateDegree()); } double fillscale = ipf.getTransformAutoFill(fullw, fullh, pLCPMap); @@ -1255,34 +1317,34 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a int fW, fH; - int tr = getCoarseBitMask(params.coarse); + int tr = getCoarseBitMask(params->coarse); imgsrc->getFullSize(fW, fH, tr); PreviewProps pp(0, 0, fW, fH, 1); - ProcParams ppar = params; + ProcParams ppar = *params; 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(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method); - if (params.wb.method == "Camera") { + if (params->wb.method == "Camera") { currWB = imgsrc->getWB(); - } else if (params.wb.method == "Auto") { - if (lastAwbEqual != params.wb.equal || lastAwbTempBias != params.wb.tempBias) { + } else if (params->wb.method == "Auto") { + if (lastAwbEqual != params->wb.equal || lastAwbTempBias != params->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, params->wb.equal, params->wb.tempBias); + lastAwbEqual = params->wb.equal; + lastAwbTempBias = params->wb.tempBias; } else { lastAwbEqual = -1.; lastAwbTempBias = 0.0; - autoWB.useDefaults(params.wb.equal); + autoWB.useDefaults(params->wb.equal); } } @@ -1304,12 +1366,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 (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; #ifdef _OPENMP #pragma omp parallel for #endif @@ -1340,7 +1402,7 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a } int imw, imh; - double tmpScale = ipf.resizeScale(¶ms, fW, fH, imw, imh); + double tmpScale = ipf.resizeScale(params.get(), fW, fH, imw, imh); if (tmpScale != 1.0) { Imagefloat* tempImage = new Imagefloat(imw, imh); @@ -1413,41 +1475,41 @@ void ImProcCoordinator::process() while (changeSinceLast) { const bool panningRelatedChange = - params.toneCurve != nextParams.toneCurve - || params.labCurve != nextParams.labCurve - || params.localContrast != nextParams.localContrast - || params.rgbCurves != nextParams.rgbCurves - || params.colorToning != nextParams.colorToning - || params.vibrance != nextParams.vibrance - || params.wb != nextParams.wb - || params.colorappearance != nextParams.colorappearance - || params.epd != nextParams.epd - || params.fattal != nextParams.fattal - || params.sh != nextParams.sh - || params.crop != nextParams.crop - || params.coarse != nextParams.coarse - || params.commonTrans != nextParams.commonTrans - || params.rotate != nextParams.rotate - || params.distortion != nextParams.distortion - || params.lensProf != nextParams.lensProf - || params.perspective != nextParams.perspective - || params.gradient != nextParams.gradient - || params.pcvignette != nextParams.pcvignette - || params.cacorrection != nextParams.cacorrection - || params.vignetting != nextParams.vignetting - || params.chmixer != nextParams.chmixer - || params.blackwhite != nextParams.blackwhite - || params.icm != nextParams.icm - || params.hsvequalizer != nextParams.hsvequalizer - || params.filmSimulation != nextParams.filmSimulation - || params.softlight != nextParams.softlight - || params.raw != nextParams.raw - || params.retinex != nextParams.retinex - || params.wavelet != nextParams.wavelet - || params.dirpyrequalizer != nextParams.dirpyrequalizer - || params.dehaze != nextParams.dehaze; + params->toneCurve != nextParams->toneCurve + || params->labCurve != nextParams->labCurve + || params->localContrast != nextParams->localContrast + || params->rgbCurves != nextParams->rgbCurves + || params->colorToning != nextParams->colorToning + || params->vibrance != nextParams->vibrance + || params->wb != nextParams->wb + || params->colorappearance != nextParams->colorappearance + || params->epd != nextParams->epd + || params->fattal != nextParams->fattal + || params->sh != nextParams->sh + || params->crop != nextParams->crop + || params->coarse != nextParams->coarse + || params->commonTrans != nextParams->commonTrans + || params->rotate != nextParams->rotate + || params->distortion != nextParams->distortion + || params->lensProf != nextParams->lensProf + || params->perspective != nextParams->perspective + || params->gradient != nextParams->gradient + || params->pcvignette != nextParams->pcvignette + || params->cacorrection != nextParams->cacorrection + || params->vignetting != nextParams->vignetting + || params->chmixer != nextParams->chmixer + || params->blackwhite != nextParams->blackwhite + || params->icm != nextParams->icm + || params->hsvequalizer != nextParams->hsvequalizer + || params->filmSimulation != nextParams->filmSimulation + || params->softlight != nextParams->softlight + || params->raw != nextParams->raw + || params->retinex != nextParams->retinex + || params->wavelet != nextParams->wavelet + || params->dirpyrequalizer != nextParams->dirpyrequalizer + || params->dehaze != nextParams->dehaze; - params = nextParams; + *params = *nextParams; int change = changeSinceLast; changeSinceLast = 0; paramsUpdateMutex.unlock(); @@ -1472,7 +1534,7 @@ ProcParams* ImProcCoordinator::beginUpdateParams() { paramsUpdateMutex.lock(); - return &nextParams; + return nextParams.get(); } void ImProcCoordinator::endUpdateParams(ProcEvent change) diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index fb3012f62..8ae5bc669 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -19,6 +19,8 @@ #ifndef _IMPROCCOORDINATOR_H_ #define _IMPROCCOORDINATOR_H_ +#include + #include "rtengine.h" #include "improcfun.h" #include "image8.h" @@ -70,8 +72,6 @@ protected: double lastAwbEqual; double lastAwbTempBias; - ImProcFunctions ipf; - Glib::ustring monitorProfile; RenderingIntent monitorIntent; bool softProof; @@ -185,7 +185,7 @@ protected: void updatePreviewImage (int todo, bool panningRelatedChange); MyMutex mProcessing; - ProcParams params; + std::unique_ptr params; // for optimization purpose, the output profile, output rendering intent and // output BPC will trigger a regeneration of the profile on parameter change only @@ -200,7 +200,7 @@ protected: MyMutex paramsUpdateMutex; int changeSinceLast; bool updaterRunning; - ProcParams nextParams; + std::unique_ptr nextParams; bool destroying; bool utili; bool autili; @@ -217,16 +217,16 @@ protected: bool highQualityComputed; cmsHTRANSFORM customTransformIn; cmsHTRANSFORM customTransformOut; + + ImProcFunctions ipf; + public: ImProcCoordinator (); ~ImProcCoordinator () override; void assign (ImageSource* imgsrc); - void getParams (procparams::ProcParams* dst) override - { - *dst = params; - } + void getParams (procparams::ProcParams* dst) override; void startProcessing (int changeCode) override; ProcParams* beginUpdateParams () override; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 465e3ffe8..60d80ecd6 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -41,6 +41,7 @@ #include "clutstore.h" #include "ciecam02.h" #include "StopWatch.h" +#include "procparams.h" #include "../rtgui/ppversion.h" #include "../rtgui/guiutils.h" @@ -205,33 +206,33 @@ void proPhotoBlue(float *rtemp, float *gtemp, float *btemp, int istart, int tH, } } -void customToneCurve(const ToneCurve &customToneCurve, ToneCurveParams::TcMode curveMode, float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize, PerceptualToneCurveState ptcApplyState) { +void customToneCurve(const ToneCurve &customToneCurve, ToneCurveMode curveMode, float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize, PerceptualToneCurveState ptcApplyState) { - if (curveMode == ToneCurveParams::TcMode::STD) { // Standard + if (curveMode == ToneCurveMode::STD) { // Standard const StandardToneCurve& userToneCurve = static_cast (customToneCurve); for (int i = istart, ti = 0; i < tH; i++, ti++) { userToneCurve.BatchApply(0, tW - jstart, &rtemp[ti * tileSize], >emp[ti * tileSize], &btemp[ti * tileSize]); } - } else if (curveMode == ToneCurveParams::TcMode::FILMLIKE) { // Adobe like + } else if (curveMode == ToneCurveMode::FILMLIKE) { // Adobe like const AdobeToneCurve& userToneCurve = static_cast (customToneCurve); for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { userToneCurve.Apply(rtemp[ti * tileSize + tj], gtemp[ti * tileSize + tj], btemp[ti * tileSize + tj]); } } - } else if (curveMode == ToneCurveParams::TcMode::SATANDVALBLENDING) { // apply the curve on the saturation and value channels + } else if (curveMode == ToneCurveMode::SATANDVALBLENDING) { // apply the curve on the saturation and value channels const SatAndValueBlendingToneCurve& userToneCurve = static_cast (customToneCurve); for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { userToneCurve.Apply(rtemp[ti * tileSize + tj], gtemp[ti * tileSize + tj], btemp[ti * tileSize + tj]); } } - } else if (curveMode == ToneCurveParams::TcMode::WEIGHTEDSTD) { // apply the curve to the rgb channels, weighted + } else if (curveMode == ToneCurveMode::WEIGHTEDSTD) { // apply the curve to the rgb channels, weighted const WeightedStdToneCurve& userToneCurve = static_cast (customToneCurve); for (int i = istart, ti = 0; i < tH; i++, ti++) { userToneCurve.BatchApply(0, tW - jstart, &rtemp[ti * tileSize], >emp[ti * tileSize], &btemp[ti * tileSize]); } - } else if (curveMode == ToneCurveParams::TcMode::LUMINANCE) { // apply the curve to the luminance channel + } else if (curveMode == ToneCurveMode::LUMINANCE) { // apply the curve to the luminance channel const LuminanceToneCurve& userToneCurve = static_cast (customToneCurve); for (int i = istart, ti = 0; i < tH; i++, ti++) { @@ -239,7 +240,7 @@ void customToneCurve(const ToneCurve &customToneCurve, ToneCurveParams::TcMode c userToneCurve.Apply(rtemp[ti * tileSize + tj], gtemp[ti * tileSize + tj], btemp[ti * tileSize + tj]); } } - } else if (curveMode == ToneCurveParams::TcMode::PERCEPTUAL) { // apply curve while keeping color appearance constant + } else if (curveMode == ToneCurveMode::PERCEPTUAL) { // apply curve while keeping color appearance constant const PerceptualToneCurve& userToneCurve = static_cast (customToneCurve); for (int i = istart, ti = 0; i < tH; i++, ti++) { userToneCurve.BatchApply(0, tW - jstart, &rtemp[ti * tileSize], >emp[ti * tileSize], &btemp[ti * tileSize], ptcApplyState); @@ -322,7 +323,7 @@ void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, if (settings->printerBPC) { flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; } - outIntent = settings->printerIntent; + outIntent = RenderingIntent(settings->printerIntent); } else { oprof = ICCStore::getInstance()->getProfile(params->icm.outputProfile); if (params->icm.outputBPC) { @@ -2225,8 +2226,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer const float hlrange = 65536.0 - shoulder; const bool isProPhoto = (params->icm.workingProfile == "ProPhoto"); // extracting datas from 'params' to avoid cache flush (to be confirmed) - ToneCurveParams::TcMode curveMode = params->toneCurve.curveMode; - ToneCurveParams::TcMode curveMode2 = params->toneCurve.curveMode2; + ToneCurveMode curveMode = params->toneCurve.curveMode; + ToneCurveMode curveMode2 = params->toneCurve.curveMode2; bool highlight = params->toneCurve.hrenabled;//Get the value if "highlight reconstruction" is activated bool hasToneCurve1 = bool (customToneCurve1); bool hasToneCurve2 = bool (customToneCurve2); @@ -2238,12 +2239,12 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer PerceptualToneCurveState ptc1ApplyState, ptc2ApplyState; - if (hasToneCurve1 && curveMode == ToneCurveParams::TcMode::PERCEPTUAL) { + if (hasToneCurve1 && curveMode == ToneCurveMode::PERCEPTUAL) { const PerceptualToneCurve& userToneCurve = static_cast (customToneCurve1); userToneCurve.initApplyState (ptc1ApplyState, params->icm.workingProfile); } - if (hasToneCurve2 && curveMode2 == ToneCurveParams::TcMode::PERCEPTUAL) { + if (hasToneCurve2 && curveMode2 == ToneCurveMode::PERCEPTUAL) { const PerceptualToneCurve& userToneCurve = static_cast (customToneCurve2); userToneCurve.initApplyState (ptc2ApplyState, params->icm.workingProfile); } diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 3e583958b..dde94166f 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -22,7 +22,6 @@ #include "imagefloat.h" #include "image16.h" #include "image8.h" -#include "procparams.h" #include "shmap.h" #include "coord2d.h" #include "color.h" @@ -39,12 +38,22 @@ namespace rtengine { -using namespace procparams; +namespace procparams +{ + +class ProcParams; + +struct DirPyrDenoiseParams; +struct SharpeningParams; +struct VignettingParams; +struct WaveletParams; + +} + +enum RenderingIntent : int; class ImProcFunctions { - - cmsHTRANSFORM monitorTransform; std::unique_ptr gamutWarning; @@ -52,7 +61,7 @@ class ImProcFunctions double scale; bool multiThread; - void calcVignettingParams(int oW, int oH, const VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul); + void calcVignettingParams(int oW, int oH, const procparams::VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul); void transformLuminanceOnly(Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH, int fW, int fH); void transformGeneral(bool highQuality, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LensCorrection *pLCPMap); @@ -203,7 +212,7 @@ public: bool needsTransform(); bool needsPCVignetting(); - void firstAnalysis(const Imagefloat* const working, const ProcParams ¶ms, LUTu & vhist16); + void firstAnalysis(const Imagefloat* const working, const procparams::ProcParams ¶ms, LUTu & vhist16); void updateColorProfiles(const Glib::ustring& monitorProfile, RenderingIntent monitorIntent, bool softProof, bool gamutCheck); void rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, LUTf & hltonecurve, LUTf & shtonecurve, LUTf & tonecurve, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clcurve, LUTf & cl2curve, const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, @@ -230,7 +239,7 @@ public: void chromiLuminanceCurve(PipetteBuffer *pipetteBuffer, int pW, LabImage* lold, LabImage* lnew, LUTf &acurve, LUTf &bcurve, LUTf & satcurve, LUTf & satclcurve, LUTf &clcurve, LUTf &curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histLurve); void vibrance(LabImage* lab); //Jacques' vibrance // void colorCurve (LabImage* lold, LabImage* lnew); - void sharpening(LabImage* lab, const SharpeningParams &sharpenParam, bool showMask = false); + void sharpening(LabImage* lab, const procparams::SharpeningParams &sharpenParam, bool showMask = false); void sharpeningcam(CieImage* ncie, float** buffer, bool showMask = false); void transform(Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const FramesMetaData *metadata, int rawRotationDeg, bool fullImage); float resizeScale(const ProcParams* params, int fw, int fh, int &imw, int &imh); @@ -239,7 +248,7 @@ public: void Lanczos(const LabImage* src, LabImage* dst, float scale); void Lanczos(const Imagefloat* src, Imagefloat* dst, float scale); - void deconvsharpening(float** luminance, float** buffer, int W, int H, const SharpeningParams &sharpenParam); + void deconvsharpening(float** luminance, float** buffer, int W, int H, const procparams::SharpeningParams &sharpenParam); void MLsharpen(LabImage* lab); // Manuel's clarity / sharpening void MLmicrocontrast(float** luminance, int W, int H); //Manuel's microcontrast void MLmicrocontrast(LabImage* lab); //Manuel's microcontrast @@ -262,7 +271,7 @@ public: void EPDToneMapCIE(CieImage *ncie, float a_w, float c_, int Wid, int Hei, float minQ, float maxQ, unsigned int Iterates = 0, int skip = 1); // pyramid denoise - procparams::DirPyrDenoiseParams dnparams; +// procparams::DirPyrDenoiseParams dnparams; void dirpyr(LabImage* data_fine, LabImage* data_coarse, int level, LUTf &rangefn_L, LUTf &rangefn_ab, int pitch, int scale, const int luma, int chroma); void idirpyr(LabImage* data_coarse, LabImage* data_fine, int level, LUTf &rangefn_L, LUTf & nrwt_l, LUTf & nrwt_ab, diff --git a/rtengine/init.cc b/rtengine/init.cc index 7d944fc0b..ee092ae8f 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -32,6 +32,7 @@ #include "profilestore.h" #include "../rtgui/threadutils.h" #include "rtlensfun.h" +#include "procparams.h" namespace rtengine { diff --git a/rtengine/ipdehaze.cc b/rtengine/ipdehaze.cc index 54dfa0cf6..c1092e335 100644 --- a/rtengine/ipdehaze.cc +++ b/rtengine/ipdehaze.cc @@ -28,13 +28,15 @@ * */ -#include "improcfun.h" -#include "guidedfilter.h" -#include "rt_math.h" -#include "rt_algo.h" #include #include +#include "guidedfilter.h" +#include "improcfun.h" +#include "procparams.h" +#include "rt_algo.h" +#include "rt_math.h" + extern Options options; namespace rtengine { diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index 04358f6af..8790f003c 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -26,6 +26,8 @@ #include "curves.h" #include "alignedbuffer.h" #include "color.h" +#include "procparams.h" + namespace rtengine { diff --git a/rtengine/iplabregions.cc b/rtengine/iplabregions.cc index 28e7ddad3..5945398d2 100644 --- a/rtengine/iplabregions.cc +++ b/rtengine/iplabregions.cc @@ -24,6 +24,7 @@ #include "improcfun.h" #include "guidedfilter.h" +#include "procparams.h" //#define BENCHMARK #include "StopWatch.h" #include "sleef.c" diff --git a/rtengine/iplocalcontrast.cc b/rtengine/iplocalcontrast.cc index aa1eeff7d..1bf21829e 100644 --- a/rtengine/iplocalcontrast.cc +++ b/rtengine/iplocalcontrast.cc @@ -26,9 +26,10 @@ #include #endif -#include "improcfun.h" -#include "gauss.h" #include "array2D.h" +#include "gauss.h" +#include "improcfun.h" +#include "procparams.h" namespace rtengine { diff --git a/rtengine/ipresize.cc b/rtengine/ipresize.cc index a14115120..823beb23e 100644 --- a/rtengine/ipresize.cc +++ b/rtengine/ipresize.cc @@ -22,6 +22,7 @@ #include "alignedbuffer.h" #include "opthelper.h" #include "rt_math.h" +#include "procparams.h" #include "sleef.c" //#define PROFILE diff --git a/rtengine/ipretinex.cc b/rtengine/ipretinex.cc index 6239575d6..9d94e9326 100644 --- a/rtengine/ipretinex.cc +++ b/rtengine/ipretinex.cc @@ -36,16 +36,18 @@ */ -#include -#include #include +#include +#include #include -#include "rtengine.h" + #include "gauss.h" -#include "rawimagesource.h" #include "improcfun.h" -#include "opthelper.h" #include "median.h" +#include "opthelper.h" +#include "procparams.h" +#include "rawimagesource.h" +#include "rtengine.h" #include "StopWatch.h" #define clipretinex( val, minv, maxv ) (( val = (val < minv ? minv : val ) ) > maxv ? maxv : val ) diff --git a/rtengine/ipshadowshighlights.cc b/rtengine/ipshadowshighlights.cc index 450aac221..6ce66d9b3 100644 --- a/rtengine/ipshadowshighlights.cc +++ b/rtengine/ipshadowshighlights.cc @@ -19,10 +19,12 @@ */ #include "improcfun.h" + #include "gauss.h" -#include "sleef.c" -#include "opthelper.h" #include "guidedfilter.h" +#include "opthelper.h" +#include "procparams.h" +#include "sleef.c" namespace rtengine { diff --git a/rtengine/ipsharpen.cc b/rtengine/ipsharpen.cc index 84068ced9..9d7358fa9 100644 --- a/rtengine/ipsharpen.cc +++ b/rtengine/ipsharpen.cc @@ -22,6 +22,7 @@ #include "bilateral2.h" #include "jaggedarray.h" #include "rt_math.h" +#include "procparams.h" #include "sleef.c" #include "opthelper.h" //#define BENCHMARK diff --git a/rtengine/ipsoftlight.cc b/rtengine/ipsoftlight.cc index 74fb543aa..6aca9b8eb 100644 --- a/rtengine/ipsoftlight.cc +++ b/rtengine/ipsoftlight.cc @@ -24,6 +24,8 @@ #include "improcfun.h" +#include "procparams.h" + namespace rtengine { namespace { diff --git a/rtengine/iptransform.cc b/rtengine/iptransform.cc index 8c06252c1..beca624a8 100644 --- a/rtengine/iptransform.cc +++ b/rtengine/iptransform.cc @@ -18,6 +18,7 @@ */ #include "rtengine.h" #include "improcfun.h" +#include "procparams.h" #ifdef _OPENMP #include #endif diff --git a/rtengine/ipwavelet.cc b/rtengine/ipwavelet.cc index 860823b3a..d3595b42c 100644 --- a/rtengine/ipwavelet.cc +++ b/rtengine/ipwavelet.cc @@ -40,6 +40,7 @@ #include "median.h" #include "EdgePreservingDecomposition.h" #include "iccstore.h" +#include "procparams.h" #ifdef _OPENMP #include diff --git a/rtengine/lcp.cc b/rtengine/lcp.cc index 34ad7a545..7156f17e2 100644 --- a/rtengine/lcp.cc +++ b/rtengine/lcp.cc @@ -29,6 +29,7 @@ #include "lcp.h" +#include "procparams.h" #include "settings.h" namespace rtengine diff --git a/rtengine/previewimage.cc b/rtengine/previewimage.cc index 1538ae5fa..e62a1adea 100644 --- a/rtengine/previewimage.cc +++ b/rtengine/previewimage.cc @@ -18,11 +18,13 @@ */ #include "previewimage.h" + #include "iimage.h" -#include "utils.h" #include "iimage.h" -#include "rtthumbnail.h" +#include "procparams.h" #include "rawimagesource.h" +#include "rtthumbnail.h" +#include "utils.h" using namespace rtengine; using namespace procparams; diff --git a/rtengine/processingjob.h b/rtengine/processingjob.h index 026bd4924..b2a81e4c2 100644 --- a/rtengine/processingjob.h +++ b/rtengine/processingjob.h @@ -20,6 +20,7 @@ #define _PROCESSINGJOB_ #include "rtengine.h" +#include "procparams.h" namespace rtengine { diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 33ea7e5cc..890e86c72 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -315,8 +315,8 @@ ToneCurveParams::ToneCurveParams() : curve2{ DCT_Linear }, - curveMode(ToneCurveParams::TcMode::STD), - curveMode2(ToneCurveParams::TcMode::STD), + curveMode(ToneCurveMode::STD), + curveMode2(ToneCurveMode::STD), brightness(0), black(0), contrast(0), @@ -2875,13 +2875,13 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->toneCurve.hrenabled, "HLRecovery", "Enabled", toneCurve.hrenabled, keyFile); saveToKeyfile(!pedited || pedited->toneCurve.method, "HLRecovery", "Method", toneCurve.method, keyFile); - const std::map tc_mapping = { - {ToneCurveParams::TcMode::STD, "Standard"}, - {ToneCurveParams::TcMode::FILMLIKE, "FilmLike"}, - {ToneCurveParams::TcMode::SATANDVALBLENDING, "SatAndValueBlending"}, - {ToneCurveParams::TcMode::WEIGHTEDSTD, "WeightedStd"}, - {ToneCurveParams::TcMode::LUMINANCE, "Luminance"}, - {ToneCurveParams::TcMode::PERCEPTUAL, "Perceptual"} + const std::map tc_mapping = { + {ToneCurveMode::STD, "Standard"}, + {ToneCurveMode::FILMLIKE, "FilmLike"}, + {ToneCurveMode::SATANDVALBLENDING, "SatAndValueBlending"}, + {ToneCurveMode::WEIGHTEDSTD, "WeightedStd"}, + {ToneCurveMode::LUMINANCE, "Luminance"}, + {ToneCurveMode::PERCEPTUAL, "Perceptual"} }; saveToKeyfile(!pedited || pedited->toneCurve.curveMode, "Exposure", "CurveMode", tc_mapping, toneCurve.curveMode, keyFile); @@ -3659,13 +3659,13 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) toneCurve.shcompr = 100; // older pp3 files can have values above 100. } - const std::map tc_mapping = { - {"Standard", ToneCurveParams::TcMode::STD}, - {"FilmLike", ToneCurveParams::TcMode::FILMLIKE}, - {"SatAndValueBlending", ToneCurveParams::TcMode::SATANDVALBLENDING}, - {"WeightedStd", ToneCurveParams::TcMode::WEIGHTEDSTD}, - {"Luminance", ToneCurveParams::TcMode::LUMINANCE}, - {"Perceptual", ToneCurveParams::TcMode::PERCEPTUAL} + const std::map tc_mapping = { + {"Standard", ToneCurveMode::STD}, + {"FilmLike", ToneCurveMode::FILMLIKE}, + {"SatAndValueBlending", ToneCurveMode::SATANDVALBLENDING}, + {"WeightedStd", ToneCurveMode::WEIGHTEDSTD}, + {"Luminance", ToneCurveMode::LUMINANCE}, + {"Perceptual", ToneCurveMode::PERCEPTUAL} }; assignFromKeyfile(keyFile, "Exposure", "CurveMode", pedited, tc_mapping, toneCurve.curveMode, pedited->toneCurve.curveMode); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index d79fc5ae4..37f428c8a 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -44,7 +44,7 @@ class WavOpacityCurveRG; class WavOpacityCurveW; class WavOpacityCurveWL; -enum RenderingIntent { +enum RenderingIntent : int { RI_PERCEPTUAL = INTENT_PERCEPTUAL, RI_RELATIVE = INTENT_RELATIVE_COLORIMETRIC, RI_SATURATION = INTENT_SATURATION, @@ -249,35 +249,35 @@ private: bool is_double; }; +enum class ToneCurveMode : int { + STD, // Standard modes, the curve is applied on all component individually + WEIGHTEDSTD, // Weighted standard mode + FILMLIKE, // Film-like mode, as defined in Adobe's reference code + SATANDVALBLENDING, // Modify the Saturation and Value channel + LUMINANCE, // Modify the Luminance channel with coefficients from Rec 709's + PERCEPTUAL // Keep color appearance constant using perceptual modeling +}; + /** * Parameters of the tone curve */ struct ToneCurveParams { - enum class TcMode { - STD, // Standard modes, the curve is applied on all component individually - WEIGHTEDSTD, // Weighted standard mode - FILMLIKE, // Film-like mode, as defined in Adobe's reference code - SATANDVALBLENDING, // Modify the Saturation and Value channel - LUMINANCE, // Modify the Luminance channel with coefficients from Rec 709's - PERCEPTUAL // Keep color appearance constant using perceptual modeling - }; - - bool autoexp; - double clip; - bool hrenabled; // Highlight Reconstruction enabled - Glib::ustring method; // Highlight Reconstruction's method - double expcomp; - std::vector curve; - std::vector curve2; - TcMode curveMode; - TcMode curveMode2; - int brightness; - int black; - int contrast; - int saturation; - int shcompr; - int hlcompr; // Highlight Recovery's compression - int hlcomprthresh; // Highlight Recovery's threshold + bool autoexp; + double clip; + bool hrenabled; // Highlight Reconstruction enabled + Glib::ustring method; // Highlight Reconstruction's method + double expcomp; + std::vector curve; + std::vector curve2; + ToneCurveMode curveMode; + ToneCurveMode curveMode2; + int brightness; + int black; + int contrast; + int saturation; + int shcompr; + int hlcompr; // Highlight Recovery's compression + int hlcomprthresh; // Highlight Recovery's threshold bool histmatching; // histogram matching bool fromHistMatching; bool clampOOG; // clamp out of gamut colours @@ -1076,14 +1076,89 @@ struct MetaDataParams { /** - * Typedef for representing a key/value for the exif metadata information + * Minimal wrapper allowing forward declaration for representing a key/value for the exif metadata information */ -typedef std::map ExifPairs; +class ExifPairs final +{ +public: + using const_iterator = std::map::const_iterator; + + const_iterator begin() const + { + return pairs.begin(); + } + + const_iterator end() const + { + return pairs.end(); + } + + void clear() + { + pairs.clear(); + } + + Glib::ustring& operator[](const Glib::ustring& key) + { + return pairs[key]; + } + + bool operator ==(const ExifPairs& other) const + { + return pairs == other.pairs; + } + +private: + std::map pairs; +}; /** * The IPTC key/value pairs */ -typedef std::map> IPTCPairs; +class IPTCPairs final +{ +public: + using iterator = std::map>::iterator; + using const_iterator = std::map>::const_iterator; + + iterator find(const Glib::ustring& key) + { + return pairs.find(key); + } + + const_iterator begin() const + { + return pairs.begin(); + } + + const_iterator end() const + { + return pairs.end(); + } + + bool empty() const + { + return pairs.empty(); + } + + void clear() + { + pairs.clear(); + } + + std::vector& operator[](const Glib::ustring& key) + { + return pairs[key]; + } + + bool operator ==(const IPTCPairs& other) const + { + return pairs == other.pairs; + } + +private: + std::map> pairs; +}; struct WaveletParams { std::vector ccwcurve; diff --git a/rtengine/profilestore.cc b/rtengine/profilestore.cc index ec57fc669..437ef6ec6 100644 --- a/rtengine/profilestore.cc +++ b/rtengine/profilestore.cc @@ -19,6 +19,8 @@ #include "profilestore.h" #include "dynamicprofile.h" +#include "procparams.h" + #include "../rtgui/options.h" #include "../rtgui/multilangmgr.h" diff --git a/rtengine/profilestore.h b/rtengine/profilestore.h index d79e5691f..5b4c94b20 100644 --- a/rtengine/profilestore.h +++ b/rtengine/profilestore.h @@ -27,8 +27,20 @@ #include "noncopyable.h" #include "dynamicprofile.h" - // forward decl +namespace rtengine +{ + +namespace procparams +{ + +class AutoPartialProfile; +class PartialProfile; + +} + +} + class DynamicProfileRule; class DynamicProfileRules; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index b7f90ba3a..1a774db39 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -36,6 +36,7 @@ #include "rtlensfun.h" #include "pdaflinesfilter.h" #include "camconst.h" +#include "procparams.h" #ifdef _OPENMP #include #endif @@ -452,6 +453,7 @@ RawImageSource::RawImageSource () , red(0, 0) , blue(0, 0) , rawDirty(true) + , histMatchingParams(new procparams::ColorManagementParams) { camProfile = nullptr; embProfile = nullptr; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index acf2deccb..15d030cca 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -19,13 +19,16 @@ #ifndef _RAWIMAGESOURCE_ #define _RAWIMAGESOURCE_ -#include "imagesource.h" -#include "dcp.h" -#include "array2D.h" -#include "curves.h" -#include "color.h" -#include "iimage.h" #include +#include + +#include "array2D.h" +#include "color.h" +#include "curves.h" +#include "dcp.h" +#include "iimage.h" +#include "imagesource.h" + #define HR_SCALE 2 namespace rtengine @@ -39,7 +42,7 @@ private: static DiagonalCurve *phaseOneIccCurveInv; static LUTf invGrad; // for fast_demosaic static LUTf initInvGrad (); - static void colorSpaceConversion_ (Imagefloat* im, const ColorManagementParams& cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName); + static void colorSpaceConversion_ (Imagefloat* im, const procparams::ColorManagementParams& cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName); int defTransform (int tran); protected: @@ -91,7 +94,7 @@ protected: float psBlueBrightness[4]; std::vector histMatchingCache; - ColorManagementParams histMatchingParams; + std::unique_ptr histMatchingParams; void processFalseColorCorrectionThread (Imagefloat* im, array2D &rbconv_Y, array2D &rbconv_I, array2D &rbconv_Q, array2D &rbout_I, array2D &rbout_Q, const int row_from, const int row_to); void hlRecovery (const std::string &method, float* red, float* green, float* blue, int width, float* hlmax); @@ -112,14 +115,14 @@ public: int load(const Glib::ustring &fname) override { return load(fname, false); } int load(const Glib::ustring &fname, bool firstFrameOnly); - void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse, bool prepareDenoise = true) override; - void demosaic (const RAWParams &raw, bool autoContrast, double &contrastThreshold) override; - void retinex (const ColorManagementParams& cmp, const RetinexParams &deh, const ToneCurveParams& Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) override; - void retinexPrepareCurves (const RetinexParams &retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, RetinexgaintransmissionCurve &retinexgaintransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) override; - void retinexPrepareBuffers (const ColorManagementParams& cmp, const RetinexParams &retinexParams, multi_array2D &conversionBuffer, LUTu &lhist16RETI) override; + void preprocess (const procparams::RAWParams &raw, const procparams::LensProfParams &lensProf, const procparams::CoarseTransformParams& coarse, bool prepareDenoise = true) override; + void demosaic (const procparams::RAWParams &raw, bool autoContrast, double &contrastThreshold) override; + void retinex (const procparams::ColorManagementParams& cmp, const procparams::RetinexParams &deh, const procparams::ToneCurveParams& Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) override; + void retinexPrepareCurves (const procparams::RetinexParams &retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, RetinexgaintransmissionCurve &retinexgaintransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) override; + void retinexPrepareBuffers (const procparams::ColorManagementParams& cmp, const procparams::RetinexParams &retinexParams, multi_array2D &conversionBuffer, LUTu &lhist16RETI) override; void flushRawData () override; void flushRGB () override; - void HLRecovery_Global (const ToneCurveParams &hrp) override; + void HLRecovery_Global (const procparams::ToneCurveParams &hrp) override; void refinement_lassus (int PassCount); void refinement(int PassCount); void setBorder(unsigned int rawBorder) override {border = rawBorder;} @@ -133,7 +136,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, array2D &rawData); // raw for cblack - void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw) override; + void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw) override; eSensorType getSensorType () const override { return ri != nullptr ? ri->getSensorType() : ST_NONE; @@ -180,10 +183,10 @@ public: } void getAutoExpHistogram (LUTu & histogram, int& histcompr) override; void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) override; - void getAutoMatchedToneCurve(const ColorManagementParams &cp, std::vector &outCurve) override; - DCPProfile *getDCP(const ColorManagementParams &cmp, DCPProfile::ApplyState &as) override; + void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, std::vector &outCurve) override; + DCPProfile *getDCP(const procparams::ColorManagementParams &cmp, DCPProfile::ApplyState &as) override; - void convertColorSpace(Imagefloat* image, const ColorManagementParams &cmp, const ColorTemp &wb) override; + void convertColorSpace(Imagefloat* image, const procparams::ColorManagementParams &cmp, const ColorTemp &wb) override; static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in); static void colorSpaceConversion (Imagefloat* im, const ColorManagementParams& cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName) { diff --git a/rtengine/rcd_demosaic.cc b/rtengine/rcd_demosaic.cc index 01430a894..8513f4796 100644 --- a/rtengine/rcd_demosaic.cc +++ b/rtengine/rcd_demosaic.cc @@ -20,6 +20,7 @@ #include "rawimagesource.h" #include "rt_math.h" +#include "procparams.h" #include "../rtgui/multilangmgr.h" #include "opthelper.h" #include "StopWatch.h" diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index bc8c12fec..6264d43ae 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -21,7 +21,6 @@ #include "imageformat.h" #include "rt_math.h" -#include "procparams.h" #include "procevents.h" #include #include @@ -45,6 +44,22 @@ class EditDataProvider; namespace rtengine { +enum RenderingIntent : int; + +namespace procparams +{ + +class ProcParams; +class IPTCPairs; + +struct RAWParams; +struct ColorManagementParams; +struct CropParams; + +enum class ToneCurveMode : int; + +} + class IImage8; class IImage16; class IImagefloat; @@ -315,7 +330,7 @@ public: * @param hlrecons set to true if HighLight Reconstruction is enabled */ virtual void autoExpChanged(double brightness, int bright, int contrast, int black, int hlcompr, int hlcomprthresh, bool hlrecons) = 0; - virtual void autoMatchedToneCurveChanged(procparams::ToneCurveParams::TcMode curveMode, const std::vector& curve) = 0; + virtual void autoMatchedToneCurveChanged(procparams::ToneCurveMode curveMode, const std::vector& curve) = 0; }; class AutoCamListener diff --git a/rtengine/rtlensfun.cc b/rtengine/rtlensfun.cc index 4856909f7..3cea8c484 100644 --- a/rtengine/rtlensfun.cc +++ b/rtengine/rtlensfun.cc @@ -19,6 +19,7 @@ */ #include "rtlensfun.h" +#include "procparams.h" #include "settings.h" #include diff --git a/rtengine/rtlensfun.h b/rtengine/rtlensfun.h index c196a4765..8b097b30e 100644 --- a/rtengine/rtlensfun.h +++ b/rtengine/rtlensfun.h @@ -29,10 +29,16 @@ #include "lcp.h" #include "noncopyable.h" -#include "procparams.h" namespace rtengine { +namespace procparams +{ + +struct LensProfParams; + +} + class LFModifier final : public LensCorrection, public NonCopyable @@ -113,7 +119,7 @@ public: LFCamera findCamera(const Glib::ustring &make, const Glib::ustring &model) const; LFLens findLens(const LFCamera &camera, const Glib::ustring &name) const; - static std::unique_ptr findModifier(const LensProfParams &lensProf, const FramesMetaData *idata, int width, int height, const CoarseTransformParams &coarse, int rawRotationDeg); + static std::unique_ptr findModifier(const procparams::LensProfParams &lensProf, const FramesMetaData *idata, int width, int height, const CoarseTransformParams &coarse, int rawRotationDeg); private: std::unique_ptr getModifier(const LFCamera &camera, const LFLens &lens, diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 1623ecfbf..1ee09dcf3 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -37,6 +37,7 @@ #include "../rtgui/ppversion.h" #include "improccoordinator.h" #include "settings.h" +#include "procparams.h" #include #include "StopWatch.h" #include "median.h" @@ -1220,7 +1221,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT ImProcFunctions ipf (¶ms, forHistogramMatching); // enable multithreading when forHistogramMatching is true ipf.setScale (sqrt (double (fw * fw + fh * fh)) / sqrt (double (thumbImg->getWidth() * thumbImg->getWidth() + thumbImg->getHeight() * thumbImg->getHeight()))*scale); - ipf.updateColorProfiles (ICCStore::getInstance()->getDefaultMonitorProfileName(), options.rtSettings.monitorIntent, false, false); + ipf.updateColorProfiles (ICCStore::getInstance()->getDefaultMonitorProfileName(), RenderingIntent(options.rtSettings.monitorIntent), false, false); LUTu hist16 (65536); diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index c01aa81ee..df33b892d 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -20,7 +20,6 @@ #define _THUMBPROCESSINGPARAMETERS_ #include "rawmetadatalocation.h" -#include "procparams.h" #include #include #include "image8.h" diff --git a/rtengine/settings.h b/rtengine/settings.h index 3f5a5d1fe..1fc3b222c 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -19,8 +19,6 @@ #ifndef _RTSETTINGS_ #define _RTSETTINGS_ -#include "procparams.h" - namespace rtengine { @@ -39,10 +37,10 @@ public: int leveldnautsimpl; // STD or EXPERT Glib::ustring printerProfile; ///< ICC profile name used for soft-proofing a printer output - RenderingIntent printerIntent; ///< Colorimetric intent used with the above profile + int printerIntent; ///< Colorimetric intent used with the above profile bool printerBPC; ///< Black Point Compensation for the Labimage->Printer->Monitor transform Glib::ustring monitorProfile; ///< ICC profile name used for the monitor - RenderingIntent monitorIntent; ///< Colorimetric intent used with the above profile + int monitorIntent; ///< Colorimetric intent used with the above profile bool monitorBPC; ///< Black Point Compensation for the Labimage->Monitor transform (directly, i.e. not soft-proofing and no WCS in between) bool autoMonitorProfile; ///< Try to auto-determine the correct monitor color profile bool autocielab; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 46f1a91c8..8dfaf9b25 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -24,6 +24,7 @@ #include "iccstore.h" #include "clutstore.h" #include "processingjob.h" +#include "procparams.h" #include #include "../rtgui/options.h" #include "rawimagesource.h" @@ -768,7 +769,7 @@ private: } params.toneCurve.autoexp = false; - params.toneCurve.curveMode = ToneCurveParams::TcMode::FILMLIKE; + params.toneCurve.curveMode = ToneCurveMode::FILMLIKE; params.toneCurve.curve2 = { 0 }; params.toneCurve.brightness = 0; params.toneCurve.contrast = 0; diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index 298cf16ef..6ca3091a3 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -17,11 +17,13 @@ * along with RawTherapee. If not, see . */ #include "stdimagesource.h" -#include "mytime.h" + +#include "color.h" +#include "curves.h" #include "iccstore.h" #include "imageio.h" -#include "curves.h" -#include "color.h" +#include "mytime.h" +#include "procparams.h" #undef THREAD_PRIORITY_NORMAL diff --git a/rtengine/tmo_fattal02.cc b/rtengine/tmo_fattal02.cc index e4788f3f8..32755319e 100644 --- a/rtengine/tmo_fattal02.cc +++ b/rtengine/tmo_fattal02.cc @@ -74,6 +74,7 @@ #include "opthelper.h" #include "rt_algo.h" #include "rescale.h" +#include "procparams.h" namespace rtengine { diff --git a/rtengine/vng4_demosaic_RT.cc b/rtengine/vng4_demosaic_RT.cc index 1c7f27dea..0f35389fb 100644 --- a/rtengine/vng4_demosaic_RT.cc +++ b/rtengine/vng4_demosaic_RT.cc @@ -22,6 +22,7 @@ #include "rtengine.h" #include "rawimagesource.h" +#include "procparams.h" #include "../rtgui/multilangmgr.h" //#define BENCHMARK #include "StopWatch.h" diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc index 39d85ace9..33fc84106 100644 --- a/rtexif/rtexif.cc +++ b/rtexif/rtexif.cc @@ -32,6 +32,8 @@ #include "rtexif.h" +#include "../rtengine/procparams.h" + #include "../rtgui/cacheimagedata.h" #include "../rtgui/version.h" #include "../rtgui/ppversion.h" diff --git a/rtexif/rtexif.h b/rtexif/rtexif.h index 242e02dea..5df0bae2d 100644 --- a/rtexif/rtexif.h +++ b/rtexif/rtexif.h @@ -32,10 +32,19 @@ #include -#include "../rtengine/procparams.h" #include "../rtengine/noncopyable.h" #include "../rtengine/rawmetadatalocation.h" +namespace rtengine +{ + +namespace procparams +{ + class ExifPairs; +} + +} + class CacheImageData; namespace rtexif diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index f6c598df7..540215478 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -197,7 +197,7 @@ void BatchQueue::addEntries (const std::vector& entries, bool // recovery save const auto tempFile = getTempFilenameForParams (entry->filename); - if (!entry->params.save (tempFile)) + if (!entry->params->save (tempFile)) entry->savedParamsFile = tempFile; entry->selected = false; @@ -642,7 +642,7 @@ void BatchQueue::error(const Glib::ustring& descr) bqbs->setButtonListener (this); processing->addButtonSet (bqbs); processing->processing = false; - processing->job = rtengine::ProcessingJob::create(processing->filename, processing->thumbnail->getType() == FT_Raw, processing->params); + processing->job = rtengine::ProcessingJob::create(processing->filename, processing->thumbnail->getType() == FT_Raw, *processing->params); processing = nullptr; redraw (); } @@ -706,7 +706,7 @@ rtengine::ProcessingJob* BatchQueue::imageReady(rtengine::IImagefloat* img) // We keep the extension to avoid overwriting the profile when we have // the same output filename with different extension //processing->params.save (removeExtension(fname) + paramFileExtension); - processing->params.save (fname + ".out" + paramFileExtension); + processing->params->save (fname + ".out" + paramFileExtension); } if (processing->thumbnail) { diff --git a/rtgui/batchqueueentry.cc b/rtgui/batchqueueentry.cc index b5383205f..0ce71b043 100644 --- a/rtgui/batchqueueentry.cc +++ b/rtgui/batchqueueentry.cc @@ -26,6 +26,8 @@ #include "multilangmgr.h" #include "thumbbrowserbase.h" +#include "../rtengine/procparams.h" + bool BatchQueueEntry::iconsLoaded(false); Glib::RefPtr BatchQueueEntry::savedAsIcon; @@ -36,7 +38,7 @@ BatchQueueEntry::BatchQueueEntry (rtengine::ProcessingJob* pjob, const rtengine: origph(prevh), opreviewDone(false), job(pjob), - params(pparams), + params(new rtengine::procparams::ProcParams(pparams)), progress(0), outFileName(""), sequence(0), @@ -93,7 +95,7 @@ void BatchQueueEntry::refreshThumbnailImage () // creating the image buffer first //if (!opreview) opreview = new guint8[(origpw+1) * origph * 3]; // this will asynchronously compute the original preview and land at this.updateImage - batchQueueEntryUpdater.process (nullptr, origpw, origph, preh, this, ¶ms, thumbnail); + batchQueueEntryUpdater.process (nullptr, origpw, origph, preh, this, params.get(), thumbnail); } else { // this will asynchronously land at this.updateImage batchQueueEntryUpdater.process (opreview, origpw, origph, preh, this); diff --git a/rtgui/batchqueueentry.h b/rtgui/batchqueueentry.h index 2b75922b7..e14581285 100644 --- a/rtgui/batchqueueentry.h +++ b/rtgui/batchqueueentry.h @@ -19,6 +19,8 @@ #ifndef _BATCHQUEUEENTRY_ #define _BATCHQUEUEENTRY_ +#include + #include #include "../rtengine/rtengine.h" #include "thumbbrowserentrybase.h" @@ -46,7 +48,7 @@ public: static Glib::RefPtr savedAsIcon; rtengine::ProcessingJob* job; - rtengine::procparams::ProcParams params; + std::unique_ptr params; Glib::ustring savedParamsFile; double progress; Glib::ustring outFileName; diff --git a/rtgui/cacheimagedata.cc b/rtgui/cacheimagedata.cc index dbb3b2946..35aeb6c91 100644 --- a/rtgui/cacheimagedata.cc +++ b/rtgui/cacheimagedata.cc @@ -22,6 +22,8 @@ #include "version.h" #include +#include "../rtengine/procparams.h" + CacheImageData::CacheImageData () : md5(""), supported(false), format(FT_Invalid), rankOld(-1), inTrashOld(false), recentlySaved(false), timeValid(false), year(0), month(0), day(0), hour(0), min(0), sec(0), exifValid(false), frameCount(1), @@ -301,3 +303,7 @@ int CacheImageData::save (const Glib::ustring& fname) } } +rtengine::procparams::IPTCPairs CacheImageData::getIPTCData(unsigned int frame) const +{ + return {}; +} diff --git a/rtgui/cacheimagedata.h b/rtgui/cacheimagedata.h index f146f2ce0..d3aea803b 100644 --- a/rtgui/cacheimagedata.h +++ b/rtgui/cacheimagedata.h @@ -94,7 +94,7 @@ public: rtexif::TagDirectory* getFrameExifData (unsigned int frame = 0) const override { return nullptr; } rtexif::TagDirectory* getBestExifData (rtengine::ImageSource *imgSource, rtengine::procparams::RAWParams *rawParams) const override { return nullptr; } bool hasIPTC (unsigned int frame = 0) const override { return false; } - rtengine::procparams::IPTCPairs getIPTCData (unsigned int frame = 0) const override { return rtengine::procparams::IPTCPairs(); } + rtengine::procparams::IPTCPairs getIPTCData (unsigned int frame = 0) const override; tm getDateTime (unsigned int frame = 0) const override { return tm{}; } time_t getDateTimeAsTS(unsigned int frame = 0) const override { return time_t(-1); } int getISOSpeed (unsigned int frame = 0) const override { return iso; } diff --git a/rtgui/crophandler.cc b/rtgui/crophandler.cc index fdb920269..ab2f3626c 100644 --- a/rtgui/crophandler.cc +++ b/rtgui/crophandler.cc @@ -23,13 +23,17 @@ #include "guiutils.h" #include "cropwindow.h" #include "imagearea.h" + #include "../rtengine/dcrop.h" +#include "../rtengine/procparams.h" #include "../rtengine/refreshmap.h" #include "../rtengine/rt_math.h" using namespace rtengine; CropHandler::CropHandler() : + cropParams(new procparams::CropParams), + colorParams(new procparams::ColorManagementParams), zoom(100), ww(0), wh(0), @@ -123,8 +127,8 @@ bool CropHandler::isFullDisplay () double CropHandler::getFitCropZoom () { - double z1 = (double) wh / cropParams.h; - double z2 = (double) ww / cropParams.w; + double z1 = (double) wh / cropParams->h; + double z2 = (double) ww / cropParams->w; return z1 < z2 ? z1 : z2; } @@ -312,8 +316,8 @@ void CropHandler::setDetailedCrop( cimg.lock (); - cropParams = cp; - colorParams = cmp; + *cropParams = cp; + *colorParams = cmp; if (!cropimg.empty()) { cropimg.clear(); diff --git a/rtgui/crophandler.h b/rtgui/crophandler.h index 2690ca002..f0e121e5e 100644 --- a/rtgui/crophandler.h +++ b/rtgui/crophandler.h @@ -21,6 +21,7 @@ #include #include +#include #include @@ -105,8 +106,8 @@ public: void update (); - rtengine::procparams::CropParams cropParams; - rtengine::procparams::ColorManagementParams colorParams; + std::unique_ptr cropParams; + std::unique_ptr colorParams; Glib::RefPtr cropPixbuf; // image displayed on monitor, using the monitor profile (i.e. lab to monitor profile) Glib::RefPtr cropPixbuftrue; // internal image in output color space for analysis (i.e. lab to either Working profile or Output profile, depending on options.rtSettings.HistogramWorking) diff --git a/rtgui/cropwindow.cc b/rtgui/cropwindow.cc index 0e6530882..46227709d 100644 --- a/rtgui/cropwindow.cc +++ b/rtgui/cropwindow.cc @@ -16,21 +16,22 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "cropwindow.h" - #include -#include "../rtengine/mytime.h" -#include "../rtengine/rt_math.h" -#include "../rtengine/dcrop.h" +#include "cropwindow.h" -#include "guiutils.h" -#include "threadutils.h" -#include "rtimage.h" #include "cursormanager.h" -#include "options.h" +#include "guiutils.h" #include "imagearea.h" #include "lockablecolorpicker.h" +#include "options.h" +#include "rtimage.h" +#include "threadutils.h" + +#include "../rtengine/dcrop.h" +#include "../rtengine/mytime.h" +#include "../rtengine/procparams.h" +#include "../rtengine/rt_math.h" using namespace rtengine; @@ -352,8 +353,8 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) } else { if (onArea (CropImage, x, y)) { // events inside of the image domain crop_custom_ratio = 0.f; - if ((bstate & GDK_SHIFT_MASK) && cropHandler.cropParams.w > 0 && cropHandler.cropParams.h > 0) { - crop_custom_ratio = float(cropHandler.cropParams.w) / float(cropHandler.cropParams.h); + if ((bstate & GDK_SHIFT_MASK) && cropHandler.cropParams->w > 0 && cropHandler.cropParams->h > 0) { + crop_custom_ratio = float(cropHandler.cropParams->w) / float(cropHandler.cropParams->h); } if (iarea->getToolMode () == TMColorPicker) { @@ -373,7 +374,7 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) // Add a new Color Picker rtengine::Coord imgPos; screenCoordToImage(x, y, imgPos.x, imgPos.y); - LockableColorPicker *newPicker = new LockableColorPicker(this, &cropHandler.colorParams.outputProfile, &cropHandler.colorParams.workingProfile); + LockableColorPicker *newPicker = new LockableColorPicker(this, &cropHandler.colorParams->outputProfile, &cropHandler.colorParams->workingProfile); colorPickers.push_back(newPicker); hoveredPicker = newPicker; updateHoveredPicker(&imgPos); @@ -387,49 +388,49 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) } else if (onArea (CropTopLeft, x, y)) { state = SResizeTL; press_x = x; - action_x = cropHandler.cropParams.x; + action_x = cropHandler.cropParams->x; press_y = y; - action_y = cropHandler.cropParams.y; + action_y = cropHandler.cropParams->y; } else if (onArea (CropTopRight, x, y)) { state = SResizeTR; press_x = x; - action_x = cropHandler.cropParams.w; + action_x = cropHandler.cropParams->w; press_y = y; - action_y = cropHandler.cropParams.y; + action_y = cropHandler.cropParams->y; } else if (onArea (CropBottomLeft, x, y)) { state = SResizeBL; press_x = x; - action_x = cropHandler.cropParams.x; + action_x = cropHandler.cropParams->x; press_y = y; - action_y = cropHandler.cropParams.h; + action_y = cropHandler.cropParams->h; } else if (onArea (CropBottomRight, x, y)) { state = SResizeBR; press_x = x; - action_x = cropHandler.cropParams.w; + action_x = cropHandler.cropParams->w; press_y = y; - action_y = cropHandler.cropParams.h; + action_y = cropHandler.cropParams->h; } else if (onArea (CropTop, x, y)) { state = SResizeH1; press_y = y; - action_y = cropHandler.cropParams.y; + action_y = cropHandler.cropParams->y; } else if (onArea (CropBottom, x, y)) { state = SResizeH2; press_y = y; - action_y = cropHandler.cropParams.h; + action_y = cropHandler.cropParams->h; } else if (onArea (CropLeft, x, y)) { state = SResizeW1; press_x = x; - action_x = cropHandler.cropParams.x; + action_x = cropHandler.cropParams->x; } else if (onArea (CropRight, x, y)) { state = SResizeW2; press_x = x; - action_x = cropHandler.cropParams.w; + action_x = cropHandler.cropParams->w; } else if ((bstate & GDK_SHIFT_MASK) && onArea (CropInside, x, y)) { state = SCropMove; press_x = x; press_y = y; - action_x = cropHandler.cropParams.x; - action_y = cropHandler.cropParams.y; + action_x = cropHandler.cropParams->x; + action_y = cropHandler.cropParams->y; } else if (onArea (CropObserved, x, y)) { state = SObservedMove; press_x = x; @@ -450,11 +451,11 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y) } else if (iarea->getToolMode () == TMCropSelect && cropgl) { state = SCropSelecting; screenCoordToImage (x, y, press_x, press_y); - cropHandler.cropParams.enabled = true; - cropHandler.cropParams.x = press_x; - cropHandler.cropParams.y = press_y; - cropHandler.cropParams.w = cropHandler.cropParams.h = 1; - cropgl->cropInit (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h); + cropHandler.cropParams->enabled = true; + cropHandler.cropParams->x = press_x; + cropHandler.cropParams->y = press_y; + cropHandler.cropParams->w = cropHandler.cropParams->h = 1; + 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))) || editSubscriber->getEditingType() == ET_OBJECTS) { @@ -827,57 +828,57 @@ void CropWindow::pointerMoved (int bstate, int x, int y) action_y = y; iarea->redraw (); } else if (state == SResizeH1 && cropgl) { - int oy = cropHandler.cropParams.y; - cropHandler.cropParams.y = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; - cropHandler.cropParams.h += oy - cropHandler.cropParams.y; - cropgl->cropHeight1Resized (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h, crop_custom_ratio); + int oy = cropHandler.cropParams->y; + cropHandler.cropParams->y = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; + cropHandler.cropParams->h += oy - cropHandler.cropParams->y; + cropgl->cropHeight1Resized (cropHandler.cropParams->x, cropHandler.cropParams->y, cropHandler.cropParams->w, cropHandler.cropParams->h, crop_custom_ratio); iarea->redraw (); } else if (state == SResizeH2 && cropgl) { - cropHandler.cropParams.h = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; - cropgl->cropHeight2Resized (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h, crop_custom_ratio); + cropHandler.cropParams->h = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; + cropgl->cropHeight2Resized (cropHandler.cropParams->x, cropHandler.cropParams->y, cropHandler.cropParams->w, cropHandler.cropParams->h, crop_custom_ratio); iarea->redraw (); } else if (state == SResizeW1 && cropgl) { - int ox = cropHandler.cropParams.x; - cropHandler.cropParams.x = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; - cropHandler.cropParams.w += ox - cropHandler.cropParams.x; - cropgl->cropWidth1Resized (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h, crop_custom_ratio); + int ox = cropHandler.cropParams->x; + cropHandler.cropParams->x = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; + cropHandler.cropParams->w += ox - cropHandler.cropParams->x; + cropgl->cropWidth1Resized (cropHandler.cropParams->x, cropHandler.cropParams->y, cropHandler.cropParams->w, cropHandler.cropParams->h, crop_custom_ratio); iarea->redraw (); } else if (state == SResizeW2 && cropgl) { - cropHandler.cropParams.w = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; - cropgl->cropWidth2Resized (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h, crop_custom_ratio); + cropHandler.cropParams->w = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; + cropgl->cropWidth2Resized (cropHandler.cropParams->x, cropHandler.cropParams->y, cropHandler.cropParams->w, cropHandler.cropParams->h, crop_custom_ratio); iarea->redraw (); } else if (state == SResizeTL && cropgl) { - int ox = cropHandler.cropParams.x; - cropHandler.cropParams.x = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; - cropHandler.cropParams.w += ox - cropHandler.cropParams.x; - int oy = cropHandler.cropParams.y; - cropHandler.cropParams.y = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; - cropHandler.cropParams.h += oy - cropHandler.cropParams.y; - cropgl->cropTopLeftResized (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h, crop_custom_ratio); + int ox = cropHandler.cropParams->x; + cropHandler.cropParams->x = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; + cropHandler.cropParams->w += ox - cropHandler.cropParams->x; + int oy = cropHandler.cropParams->y; + cropHandler.cropParams->y = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; + cropHandler.cropParams->h += oy - cropHandler.cropParams->y; + cropgl->cropTopLeftResized (cropHandler.cropParams->x, cropHandler.cropParams->y, cropHandler.cropParams->w, cropHandler.cropParams->h, crop_custom_ratio); iarea->redraw (); } else if (state == SResizeTR && cropgl) { - cropHandler.cropParams.w = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; - int oy = cropHandler.cropParams.y; - cropHandler.cropParams.y = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; - cropHandler.cropParams.h += oy - cropHandler.cropParams.y; - cropgl->cropTopRightResized (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h, crop_custom_ratio); + cropHandler.cropParams->w = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; + int oy = cropHandler.cropParams->y; + cropHandler.cropParams->y = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; + cropHandler.cropParams->h += oy - cropHandler.cropParams->y; + cropgl->cropTopRightResized (cropHandler.cropParams->x, cropHandler.cropParams->y, cropHandler.cropParams->w, cropHandler.cropParams->h, crop_custom_ratio); iarea->redraw (); } else if (state == SResizeBL && cropgl) { - int ox = cropHandler.cropParams.x; - cropHandler.cropParams.x = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; - cropHandler.cropParams.w += ox - cropHandler.cropParams.x; - cropHandler.cropParams.h = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; - cropgl->cropBottomLeftResized (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h, crop_custom_ratio); + int ox = cropHandler.cropParams->x; + cropHandler.cropParams->x = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; + cropHandler.cropParams->w += ox - cropHandler.cropParams->x; + cropHandler.cropParams->h = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; + cropgl->cropBottomLeftResized (cropHandler.cropParams->x, cropHandler.cropParams->y, cropHandler.cropParams->w, cropHandler.cropParams->h, crop_custom_ratio); iarea->redraw (); } else if (state == SResizeBR && cropgl) { - cropHandler.cropParams.w = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; - cropHandler.cropParams.h = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; - cropgl->cropBottomRightResized (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h, crop_custom_ratio); + cropHandler.cropParams->w = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; + cropHandler.cropParams->h = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; + cropgl->cropBottomRightResized (cropHandler.cropParams->x, cropHandler.cropParams->y, cropHandler.cropParams->w, cropHandler.cropParams->h, crop_custom_ratio); iarea->redraw (); } else if (state == SCropMove && cropgl) { - cropHandler.cropParams.x = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; - cropHandler.cropParams.y = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; - cropgl->cropMoved (cropHandler.cropParams.x, cropHandler.cropParams.y, cropHandler.cropParams.w, cropHandler.cropParams.h); + cropHandler.cropParams->x = action_x + (x - press_x) / zoomSteps[cropZoom].zoom; + cropHandler.cropParams->y = action_y + (y - press_y) / zoomSteps[cropZoom].zoom; + cropgl->cropMoved (cropHandler.cropParams->x, cropHandler.cropParams->y, cropHandler.cropParams->w, cropHandler.cropParams->h); iarea->redraw (); } else if (state == SCropSelecting && cropgl) { screenCoordToImage (x, y, action_x, action_y); @@ -886,19 +887,19 @@ void CropWindow::pointerMoved (int bstate, int x, int y) cropgl->cropResized (cx1, cy1, cx2, cy2); if (cx2 > cx1) { - cropHandler.cropParams.x = cx1; - cropHandler.cropParams.w = cx2 - cx1 + 1; + cropHandler.cropParams->x = cx1; + cropHandler.cropParams->w = cx2 - cx1 + 1; } else { - cropHandler.cropParams.x = cx2; - cropHandler.cropParams.w = cx1 - cx2 + 1; + cropHandler.cropParams->x = cx2; + cropHandler.cropParams->w = cx1 - cx2 + 1; } if (cy2 > cy1) { - cropHandler.cropParams.y = cy1; - cropHandler.cropParams.h = cy2 - cy1 + 1; + cropHandler.cropParams->y = cy1; + cropHandler.cropParams->h = cy2 - cy1 + 1; } else { - cropHandler.cropParams.y = cy2; - cropHandler.cropParams.h = cy1 - cy2 + 1; + cropHandler.cropParams->y = cy2; + cropHandler.cropParams->h = cy1 - cy2 + 1; } iarea->redraw (); @@ -1018,17 +1019,17 @@ void CropWindow::pointerMoved (int bstate, int x, int y) if (!onArea (CropImage, x, y) || !cropHandler.cropPixbuftrue) { cropHandler.getFullImageSize(mx, my); - // pmlistener->pointerMoved (false, cropHandler.colorParams.working, mx, my, -1, -1, -1); - // if (pmhlistener) pmhlistener->pointerMoved (false, cropHandler.colorParams.working, mx, my, -1, -1, -1); + // pmlistener->pointerMoved (false, cropHandler.colorParams->working, mx, my, -1, -1, -1); + // if (pmhlistener) pmhlistener->pointerMoved (false, cropHandler.colorParams->working, mx, my, -1, -1, -1); /* Glib::ustring outputProfile; - outputProfile =cropHandler.colorParams.output ; + outputProfile =cropHandler.colorParams->output ; printf("Using \"%s\" output\n", outputProfile.c_str()); if(outputProfile==options.rtSettings.srgb) printf("OK SRGB2"); */ - pmlistener->pointerMoved (false, cropHandler.colorParams.outputProfile, cropHandler.colorParams.workingProfile, mx, my, -1, -1, -1); + pmlistener->pointerMoved (false, cropHandler.colorParams->outputProfile, cropHandler.colorParams->workingProfile, mx, my, -1, -1, -1); if (pmhlistener) { - pmhlistener->pointerMoved (false, cropHandler.colorParams.outputProfile, cropHandler.colorParams.workingProfile, mx, my, -1, -1, -1); + pmhlistener->pointerMoved (false, cropHandler.colorParams->outputProfile, cropHandler.colorParams->workingProfile, mx, my, -1, -1, -1); } } else { @@ -1075,11 +1076,11 @@ void CropWindow::pointerMoved (int bstate, int x, int y) // Updates the Navigator // TODO: possible double color conversion if rval, gval, bval come from cropHandler.cropPixbuftrue ? see issue #4583 - pmlistener->pointerMoved (true, cropHandler.colorParams.outputProfile, cropHandler.colorParams.workingProfile, mx, my, rval, gval, bval, isRaw); + pmlistener->pointerMoved (true, cropHandler.colorParams->outputProfile, cropHandler.colorParams->workingProfile, mx, my, rval, gval, bval, isRaw); if (pmhlistener) { // Updates the HistogramRGBArea - pmhlistener->pointerMoved (true, cropHandler.colorParams.outputProfile, cropHandler.colorParams.workingProfile, mx, my, rval, gval, bval); + pmhlistener->pointerMoved (true, cropHandler.colorParams->outputProfile, cropHandler.colorParams->workingProfile, mx, my, rval, gval, bval); } } } @@ -1119,87 +1120,87 @@ bool CropWindow::onArea (CursorArea a, int x, int y) case CropTopLeft: screenCoordToImage (x, y, x1, y1); - return cropHandler.cropParams.enabled && - y1 >= cropHandler.cropParams.y - CROPRESIZEBORDER && - y1 <= cropHandler.cropParams.y + CROPRESIZEBORDER && + return cropHandler.cropParams->enabled && + y1 >= cropHandler.cropParams->y - CROPRESIZEBORDER && + y1 <= cropHandler.cropParams->y + CROPRESIZEBORDER && y >= ypos + imgY && - x1 >= cropHandler.cropParams.x - CROPRESIZEBORDER && - x1 <= cropHandler.cropParams.x + CROPRESIZEBORDER && + x1 >= cropHandler.cropParams->x - CROPRESIZEBORDER && + x1 <= cropHandler.cropParams->x + CROPRESIZEBORDER && x >= xpos + imgX; case CropTopRight: screenCoordToImage (x, y, x1, y1); - return cropHandler.cropParams.enabled && - y1 >= cropHandler.cropParams.y - CROPRESIZEBORDER && - y1 <= cropHandler.cropParams.y + CROPRESIZEBORDER && + return cropHandler.cropParams->enabled && + y1 >= cropHandler.cropParams->y - CROPRESIZEBORDER && + y1 <= cropHandler.cropParams->y + CROPRESIZEBORDER && y >= ypos + imgY && - x1 >= cropHandler.cropParams.x + cropHandler.cropParams.w - 1 - CROPRESIZEBORDER && - x1 <= cropHandler.cropParams.x + cropHandler.cropParams.w - 1 + CROPRESIZEBORDER && + x1 >= cropHandler.cropParams->x + cropHandler.cropParams->w - 1 - CROPRESIZEBORDER && + x1 <= cropHandler.cropParams->x + cropHandler.cropParams->w - 1 + CROPRESIZEBORDER && x < xpos + imgX + imgW; case CropBottomLeft: screenCoordToImage (x, y, x1, y1); - return cropHandler.cropParams.enabled && - y1 >= cropHandler.cropParams.y + cropHandler.cropParams.h - 1 - CROPRESIZEBORDER && - y1 <= cropHandler.cropParams.y + cropHandler.cropParams.h - 1 + CROPRESIZEBORDER && + return cropHandler.cropParams->enabled && + y1 >= cropHandler.cropParams->y + cropHandler.cropParams->h - 1 - CROPRESIZEBORDER && + y1 <= cropHandler.cropParams->y + cropHandler.cropParams->h - 1 + CROPRESIZEBORDER && y < ypos + imgY + imgH && - x1 >= cropHandler.cropParams.x - CROPRESIZEBORDER && - x1 <= cropHandler.cropParams.x + CROPRESIZEBORDER && + x1 >= cropHandler.cropParams->x - CROPRESIZEBORDER && + x1 <= cropHandler.cropParams->x + CROPRESIZEBORDER && x >= xpos + imgX; case CropBottomRight: screenCoordToImage (x, y, x1, y1); - return cropHandler.cropParams.enabled && - y1 >= cropHandler.cropParams.y + cropHandler.cropParams.h - 1 - CROPRESIZEBORDER && - y1 <= cropHandler.cropParams.y + cropHandler.cropParams.h - 1 + CROPRESIZEBORDER && + return cropHandler.cropParams->enabled && + y1 >= cropHandler.cropParams->y + cropHandler.cropParams->h - 1 - CROPRESIZEBORDER && + y1 <= cropHandler.cropParams->y + cropHandler.cropParams->h - 1 + CROPRESIZEBORDER && y < ypos + imgY + imgH && - x1 >= cropHandler.cropParams.x + cropHandler.cropParams.w - 1 - CROPRESIZEBORDER && - x1 <= cropHandler.cropParams.x + cropHandler.cropParams.w - 1 + CROPRESIZEBORDER && + x1 >= cropHandler.cropParams->x + cropHandler.cropParams->w - 1 - CROPRESIZEBORDER && + x1 <= cropHandler.cropParams->x + cropHandler.cropParams->w - 1 + CROPRESIZEBORDER && x < xpos + imgX + imgW; case CropTop: screenCoordToImage (x, y, x1, y1); - return cropHandler.cropParams.enabled && - x1 > cropHandler.cropParams.x + CROPRESIZEBORDER && - x1 < cropHandler.cropParams.x + cropHandler.cropParams.w - 1 - CROPRESIZEBORDER && - y1 > cropHandler.cropParams.y - CROPRESIZEBORDER && - y1 < cropHandler.cropParams.y + CROPRESIZEBORDER && + return cropHandler.cropParams->enabled && + x1 > cropHandler.cropParams->x + CROPRESIZEBORDER && + x1 < cropHandler.cropParams->x + cropHandler.cropParams->w - 1 - CROPRESIZEBORDER && + y1 > cropHandler.cropParams->y - CROPRESIZEBORDER && + y1 < cropHandler.cropParams->y + CROPRESIZEBORDER && y >= ypos + imgY; case CropBottom: screenCoordToImage (x, y, x1, y1); - return cropHandler.cropParams.enabled && - x1 > cropHandler.cropParams.x + CROPRESIZEBORDER && - x1 < cropHandler.cropParams.x + cropHandler.cropParams.w - 1 - CROPRESIZEBORDER && - y1 > cropHandler.cropParams.y + cropHandler.cropParams.h - 1 - CROPRESIZEBORDER && - y1 < cropHandler.cropParams.y + cropHandler.cropParams.h - 1 + CROPRESIZEBORDER && + return cropHandler.cropParams->enabled && + x1 > cropHandler.cropParams->x + CROPRESIZEBORDER && + x1 < cropHandler.cropParams->x + cropHandler.cropParams->w - 1 - CROPRESIZEBORDER && + y1 > cropHandler.cropParams->y + cropHandler.cropParams->h - 1 - CROPRESIZEBORDER && + y1 < cropHandler.cropParams->y + cropHandler.cropParams->h - 1 + CROPRESIZEBORDER && y < ypos + imgY + imgH; case CropLeft: screenCoordToImage (x, y, x1, y1); - return cropHandler.cropParams.enabled && - y1 > cropHandler.cropParams.y + CROPRESIZEBORDER && - y1 < cropHandler.cropParams.y + cropHandler.cropParams.h - 1 - CROPRESIZEBORDER && - x1 > cropHandler.cropParams.x - CROPRESIZEBORDER && - x1 < cropHandler.cropParams.x + CROPRESIZEBORDER && + return cropHandler.cropParams->enabled && + y1 > cropHandler.cropParams->y + CROPRESIZEBORDER && + y1 < cropHandler.cropParams->y + cropHandler.cropParams->h - 1 - CROPRESIZEBORDER && + x1 > cropHandler.cropParams->x - CROPRESIZEBORDER && + x1 < cropHandler.cropParams->x + CROPRESIZEBORDER && x >= xpos + imgX; case CropRight: screenCoordToImage (x, y, x1, y1); - return cropHandler.cropParams.enabled && - y1 > cropHandler.cropParams.y + CROPRESIZEBORDER && - y1 < cropHandler.cropParams.y + cropHandler.cropParams.h - 1 - CROPRESIZEBORDER && - x1 > cropHandler.cropParams.x + cropHandler.cropParams.w - 1 - CROPRESIZEBORDER && - x1 < cropHandler.cropParams.x + cropHandler.cropParams.w - 1 + CROPRESIZEBORDER && + return cropHandler.cropParams->enabled && + y1 > cropHandler.cropParams->y + CROPRESIZEBORDER && + y1 < cropHandler.cropParams->y + cropHandler.cropParams->h - 1 - CROPRESIZEBORDER && + x1 > cropHandler.cropParams->x + cropHandler.cropParams->w - 1 - CROPRESIZEBORDER && + x1 < cropHandler.cropParams->x + cropHandler.cropParams->w - 1 + CROPRESIZEBORDER && x < xpos + imgX + imgW; case CropInside: screenCoordToImage (x, y, x1, y1); - return cropHandler.cropParams.enabled && - y1 > cropHandler.cropParams.y && - y1 < cropHandler.cropParams.y + cropHandler.cropParams.h - 1 && - x1 > cropHandler.cropParams.x && - x1 < cropHandler.cropParams.x + cropHandler.cropParams.w - 1; + return cropHandler.cropParams->enabled && + y1 > cropHandler.cropParams->y && + y1 < cropHandler.cropParams->y + cropHandler.cropParams->h - 1 && + x1 > cropHandler.cropParams->x && + x1 < cropHandler.cropParams->x + cropHandler.cropParams->w - 1; case CropResize: return decorated && x >= xpos + width - 16 && y >= ypos + height - 16 && x < xpos + width && y < ypos + height; @@ -1367,7 +1368,7 @@ void CropWindow::expose (Cairo::RefPtr cr) Gdk::Cairo::set_source_pixbuf(cr, rough, posX, posY); cr->rectangle(posX, posY, rtengine::min (rough->get_width (), imgAreaW-imgX), rtengine::min (rough->get_height (), imgAreaH-imgY)); cr->fill(); -// if (cropHandler.cropParams.enabled) +// if (cropHandler.cropParams->enabled) // drawCrop (cr, x+imgX, y+imgY, imgW, imgH, cropX, cropY, zoomSteps[cropZoom].zoom, cropHandler.cropParams); } @@ -1375,7 +1376,7 @@ void CropWindow::expose (Cairo::RefPtr cr) drawObservedFrame (cr); } } else { - CropParams cropParams = cropHandler.cropParams; + CropParams cropParams = *cropHandler.cropParams; if (state == SNormal) { switch (options.cropGuides) { case Options::CROP_GUIDE_NONE: @@ -1805,7 +1806,7 @@ void CropWindow::expose (Cairo::RefPtr cr) cr->fill(); } - if (cropHandler.cropParams.enabled) { + if (cropHandler.cropParams->enabled) { int cropX, cropY; cropHandler.getPosition (cropX, cropY); drawCrop (cr, x + imgAreaX + imgX, y + imgAreaY + imgY, imgW, imgH, cropX, cropY, zoomSteps[cropZoom].zoom, cropParams, (this == iarea->mainCropWindow), useBgColor, cropHandler.isFullDisplay ()); @@ -1888,7 +1889,7 @@ void CropWindow::expose (Cairo::RefPtr cr) cr->rectangle(posX, posY, rtengine::min (rough->get_width (), imgAreaW-imgX), rtengine::min (rough->get_height (), imgAreaH-imgY)); cr->fill(); - if (cropHandler.cropParams.enabled) { + if (cropHandler.cropParams->enabled) { drawCrop (cr, x + imgAreaX + imgX, y + imgAreaY + imgY, rough->get_width(), rough->get_height(), cropX, cropY, zoomSteps[cropZoom].zoom, cropParams, (this == iarea->mainCropWindow), useBgColor, cropHandler.isFullDisplay ()); } @@ -1947,9 +1948,9 @@ void CropWindow::zoomIn (bool toCursor, int cursorX, int cursorY) y = cursorY; } else { if (zoomSteps[cropZoom].zoom <= cropHandler.getFitZoom()) { - if (cropHandler.cropParams.enabled) { - x = cropHandler.cropParams.x + cropHandler.cropParams.w / 2; - y = cropHandler.cropParams.y + cropHandler.cropParams.h / 2; + if (cropHandler.cropParams->enabled) { + x = cropHandler.cropParams->x + cropHandler.cropParams->w / 2; + y = cropHandler.cropParams->y + cropHandler.cropParams->h / 2; } else { int fw, fh; cropHandler.getFullImageSize(fw, fh); @@ -1961,11 +1962,11 @@ void CropWindow::zoomIn (bool toCursor, int cursorX, int cursorY) } else if (zoomVersion != exposeVersion) { screenCoordToImage(xpos + imgX + imgW / 2, ypos + imgY + imgH / 2, x, y); - if (cropHandler.cropParams.enabled) { + if (cropHandler.cropParams->enabled) { // add some gravity towards crop center - int x1 = cropHandler.cropParams.x + cropHandler.cropParams.w / 2; - int y1 = cropHandler.cropParams.y + cropHandler.cropParams.h / 2; - double cropd = sqrt(cropHandler.cropParams.h * cropHandler.cropParams.h + cropHandler.cropParams.w * cropHandler.cropParams.w) * zoomSteps[cropZoom].zoom; + int x1 = cropHandler.cropParams->x + cropHandler.cropParams->w / 2; + int y1 = cropHandler.cropParams->y + cropHandler.cropParams->h / 2; + double cropd = sqrt(cropHandler.cropParams->h * cropHandler.cropParams->h + cropHandler.cropParams->w * cropHandler.cropParams->w) * zoomSteps[cropZoom].zoom; double imd = sqrt(imgW * imgW + imgH * imgH); double d; @@ -2023,9 +2024,9 @@ void CropWindow::zoom11 (bool notify) int y = -1; if (zoomSteps[cropZoom].zoom <= cropHandler.getFitZoom()) { - if (cropHandler.cropParams.enabled) { - x = cropHandler.cropParams.x + cropHandler.cropParams.w / 2; - y = cropHandler.cropParams.y + cropHandler.cropParams.h / 2; + if (cropHandler.cropParams->enabled) { + x = cropHandler.cropParams->x + cropHandler.cropParams->w / 2; + y = cropHandler.cropParams->y + cropHandler.cropParams->h / 2; } else { int fw, fh; cropHandler.getFullImageSize(fw, fh); @@ -2114,7 +2115,7 @@ void CropWindow::zoomFit () void CropWindow::zoomFitCrop () { - if(cropHandler.cropParams.enabled) { + if(cropHandler.cropParams->enabled) { double z = cropHandler.getFitCropZoom (); int cz = int(zoomSteps.size())-1; @@ -2129,8 +2130,8 @@ void CropWindow::zoomFitCrop () zoomVersion = exposeVersion; int centerX, centerY; - centerX = cropHandler.cropParams.x + cropHandler.cropParams.w / 2; - centerY = cropHandler.cropParams.y + cropHandler.cropParams.h / 2; + centerX = cropHandler.cropParams->x + cropHandler.cropParams->w / 2; + centerY = cropHandler.cropParams->y + cropHandler.cropParams->h / 2; setCropAnchorPosition(centerX, centerY); changeZoom (cz, true, centerX, centerY); fitZoom = options.cropAutoFit; diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index 20416c549..be5d5dc4c 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -684,7 +684,7 @@ void ExifPanel::updateChangeList () void ExifPanel::applyChangeList () { - for (rtengine::procparams::ExifPairs::iterator i = changeList.begin(); i != changeList.end(); ++i) { + for (rtengine::procparams::ExifPairs::const_iterator i = changeList.begin(); i != changeList.end(); ++i) { editTag (exifTreeModel->children(), i->first, i->second); } } diff --git a/rtgui/exportpanel.cc b/rtgui/exportpanel.cc index 3a74d3ca3..9a4c930d5 100644 --- a/rtgui/exportpanel.cc +++ b/rtgui/exportpanel.cc @@ -22,6 +22,8 @@ #include "options.h" #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc index 70d2fc128..a55e2ffca 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -18,15 +18,17 @@ */ #include "filebrowserentry.h" -#include #include +#include -#include "guiutils.h" -#include "threadutils.h" -#include "rtimage.h" #include "cursormanager.h" -#include "thumbbrowserbase.h" +#include "guiutils.h" #include "inspector.h" +#include "rtimage.h" +#include "threadutils.h" +#include "thumbbrowserbase.h" + +#include "../rtengine/procparams.h" #define CROPRESIZEBORDER 4 @@ -40,7 +42,7 @@ Glib::RefPtr FileBrowserEntry::hdr; Glib::RefPtr FileBrowserEntry::ps; FileBrowserEntry::FileBrowserEntry (Thumbnail* thm, const Glib::ustring& fname) - : ThumbBrowserEntryBase (fname), wasInside(false), iatlistener(nullptr), press_x(0), press_y(0), action_x(0), action_y(0), rot_deg(0.0), landscape(true), cropgl(nullptr), state(SNormal), crop_custom_ratio(0.f) + : ThumbBrowserEntryBase (fname), wasInside(false), iatlistener(nullptr), press_x(0), press_y(0), action_x(0), action_y(0), rot_deg(0.0), landscape(true), cropParams(new rtengine::procparams::CropParams), cropgl(nullptr), state(SNormal), crop_custom_ratio(0.f) { thumbnail = thm; @@ -163,9 +165,9 @@ std::vector > FileBrowserEntry::getSpecificityIconsOnI void FileBrowserEntry::customBackBufferUpdate (Cairo::RefPtr c) { - if(scale != 1.0 && cropParams.enabled) { // somewhere in pipeline customBackBufferUpdate is called when scale == 1.0, which is nonsense for a thumb + if(scale != 1.0 && cropParams->enabled) { // somewhere in pipeline customBackBufferUpdate is called when scale == 1.0, which is nonsense for a thumb if (state == SCropSelecting || state == SResizeH1 || state == SResizeH2 || state == SResizeW1 || state == SResizeW2 || state == SResizeTL || state == SResizeTR || state == SResizeBL || state == SResizeBR || state == SCropMove) { - drawCrop (c, prex, prey, prew, preh, 0, 0, scale, cropParams, true, false); + drawCrop (c, prex, prey, prew, preh, 0, 0, scale, *cropParams, true, false); } else { rtengine::procparams::CropParams cparams = thumbnail->getProcParams().crop; switch (options.cropGuides) { @@ -246,7 +248,7 @@ void FileBrowserEntry::_updateImage(rtengine::IImage8* img, double s, const rten redrawRequests--; scale = s; - this->cropParams = cropParams; + *this->cropParams = cropParams; bool newLandscape = img->getWidth() > img->getHeight(); bool rotated = false; @@ -319,65 +321,65 @@ bool FileBrowserEntry::motionNotify (int x, int y) action_y = y; parent->redrawNeeded (this); } else if (state == SResizeH1 && cropgl) { - int oy = cropParams.y; - cropParams.y = action_y + (y - press_y) / scale; - cropParams.h += oy - cropParams.y; - cropgl->cropHeight1Resized (cropParams.x, cropParams.y, cropParams.w, cropParams.h, crop_custom_ratio); + int oy = cropParams->y; + cropParams->y = action_y + (y - press_y) / scale; + cropParams->h += oy - cropParams->y; + cropgl->cropHeight1Resized (cropParams->x, cropParams->y, cropParams->w, cropParams->h, crop_custom_ratio); updateBackBuffer (); parent->redrawNeeded (this); } else if (state == SResizeH2 && cropgl) { - cropParams.h = action_y + (y - press_y) / scale; - cropgl->cropHeight2Resized (cropParams.x, cropParams.y, cropParams.w, cropParams.h, crop_custom_ratio); + cropParams->h = action_y + (y - press_y) / scale; + cropgl->cropHeight2Resized (cropParams->x, cropParams->y, cropParams->w, cropParams->h, crop_custom_ratio); updateBackBuffer (); parent->redrawNeeded (this); } else if (state == SResizeW1 && cropgl) { - int ox = cropParams.x; - cropParams.x = action_x + (x - press_x) / scale; - cropParams.w += ox - cropParams.x; - cropgl->cropWidth1Resized (cropParams.x, cropParams.y, cropParams.w, cropParams.h, crop_custom_ratio); + int ox = cropParams->x; + cropParams->x = action_x + (x - press_x) / scale; + cropParams->w += ox - cropParams->x; + cropgl->cropWidth1Resized (cropParams->x, cropParams->y, cropParams->w, cropParams->h, crop_custom_ratio); updateBackBuffer (); parent->redrawNeeded (this); } else if (state == SResizeW2 && cropgl) { - cropParams.w = action_x + (x - press_x) / scale; - cropgl->cropWidth2Resized (cropParams.x, cropParams.y, cropParams.w, cropParams.h, crop_custom_ratio); + cropParams->w = action_x + (x - press_x) / scale; + cropgl->cropWidth2Resized (cropParams->x, cropParams->y, cropParams->w, cropParams->h, crop_custom_ratio); updateBackBuffer (); parent->redrawNeeded (this); } else if (state == SResizeTL && cropgl) { - int ox = cropParams.x; - cropParams.x = action_x + (x - press_x) / scale; - cropParams.w += ox - cropParams.x; - int oy = cropParams.y; - cropParams.y = action_y + (y - press_y) / scale; - cropParams.h += oy - cropParams.y; - cropgl->cropTopLeftResized (cropParams.x, cropParams.y, cropParams.w, cropParams.h, crop_custom_ratio); + int ox = cropParams->x; + cropParams->x = action_x + (x - press_x) / scale; + cropParams->w += ox - cropParams->x; + int oy = cropParams->y; + cropParams->y = action_y + (y - press_y) / scale; + cropParams->h += oy - cropParams->y; + cropgl->cropTopLeftResized (cropParams->x, cropParams->y, cropParams->w, cropParams->h, crop_custom_ratio); updateBackBuffer (); parent->redrawNeeded (this); } else if (state == SResizeTR && cropgl) { - cropParams.w = action_x + (x - press_x) / scale; - int oy = cropParams.y; - cropParams.y = action_y + (y - press_y) / scale; - cropParams.h += oy - cropParams.y; - cropgl->cropTopRightResized (cropParams.x, cropParams.y, cropParams.w, cropParams.h, crop_custom_ratio); + cropParams->w = action_x + (x - press_x) / scale; + int oy = cropParams->y; + cropParams->y = action_y + (y - press_y) / scale; + cropParams->h += oy - cropParams->y; + cropgl->cropTopRightResized (cropParams->x, cropParams->y, cropParams->w, cropParams->h, crop_custom_ratio); updateBackBuffer (); parent->redrawNeeded (this); } else if (state == SResizeBL && cropgl) { - int ox = cropParams.x; - cropParams.x = action_x + (x - press_x) / scale; - cropParams.w += ox - cropParams.x; - cropParams.h = action_y + (y - press_y) / scale; - cropgl->cropBottomLeftResized (cropParams.x, cropParams.y, cropParams.w, cropParams.h, crop_custom_ratio); + int ox = cropParams->x; + cropParams->x = action_x + (x - press_x) / scale; + cropParams->w += ox - cropParams->x; + cropParams->h = action_y + (y - press_y) / scale; + cropgl->cropBottomLeftResized (cropParams->x, cropParams->y, cropParams->w, cropParams->h, crop_custom_ratio); updateBackBuffer (); parent->redrawNeeded (this); } else if (state == SResizeBR && cropgl) { - cropParams.w = action_x + (x - press_x) / scale; - cropParams.h = action_y + (y - press_y) / scale; - cropgl->cropBottomRightResized (cropParams.x, cropParams.y, cropParams.w, cropParams.h, crop_custom_ratio); + cropParams->w = action_x + (x - press_x) / scale; + cropParams->h = action_y + (y - press_y) / scale; + cropgl->cropBottomRightResized (cropParams->x, cropParams->y, cropParams->w, cropParams->h, crop_custom_ratio); updateBackBuffer (); parent->redrawNeeded (this); } else if (state == SCropMove && cropgl) { - cropParams.x = action_x + (x - press_x) / scale; - cropParams.y = action_y + (y - press_y) / scale; - cropgl->cropMoved (cropParams.x, cropParams.y, cropParams.w, cropParams.h); + cropParams->x = action_x + (x - press_x) / scale; + cropParams->y = action_y + (y - press_y) / scale; + cropgl->cropMoved (cropParams->x, cropParams->y, cropParams->w, cropParams->h); updateBackBuffer (); parent->redrawNeeded (this); } else if (state == SCropSelecting && cropgl) { @@ -386,19 +388,19 @@ bool FileBrowserEntry::motionNotify (int x, int y) cropgl->cropResized (cx1, cy1, cx2, cy2); if (cx2 > cx1) { - cropParams.x = cx1; - cropParams.w = cx2 - cx1 + 1; + cropParams->x = cx1; + cropParams->w = cx2 - cx1 + 1; } else { - cropParams.x = cx2; - cropParams.w = cx1 - cx2 + 1; + cropParams->x = cx2; + cropParams->w = cx1 - cx2 + 1; } if (cy2 > cy1) { - cropParams.y = cy1; - cropParams.h = cy2 - cy1 + 1; + cropParams->y = cy1; + cropParams->h = cy2 - cy1 + 1; } else { - cropParams.y = cy2; - cropParams.h = cy1 - cy2 + 1; + cropParams->y = cy2; + cropParams->h = cy1 - cy2 + 1; } updateBackBuffer (); @@ -429,71 +431,71 @@ bool FileBrowserEntry::pressNotify (int button, int type, int bstate, int x, i if (!b && selected && inside (x, y)) { if (button == 1 && type == GDK_BUTTON_PRESS && state == SNormal) { - if ((bstate & GDK_SHIFT_MASK) && cropParams.w > 0 && cropParams.h > 0) { - crop_custom_ratio = float(cropParams.w) / float(cropParams.h); + if ((bstate & GDK_SHIFT_MASK) && cropParams->w > 0 && cropParams->h > 0) { + crop_custom_ratio = float(cropParams->w) / float(cropParams->h); } if (onArea (CropTopLeft, ix, iy)) { state = SResizeTL; press_x = x; - action_x = cropParams.x; + action_x = cropParams->x; press_y = y; - action_y = cropParams.y; + action_y = cropParams->y; cropgl = iatlistener->startCropEditing (thumbnail); b = true; } else if (onArea (CropTopRight, ix, iy)) { state = SResizeTR; press_x = x; - action_x = cropParams.w; + action_x = cropParams->w; press_y = y; - action_y = cropParams.y; + action_y = cropParams->y; cropgl = iatlistener->startCropEditing (thumbnail); b = true; } else if (onArea (CropBottomLeft, ix, iy)) { state = SResizeBL; press_x = x; - action_x = cropParams.x; + action_x = cropParams->x; press_y = y; - action_y = cropParams.h; + action_y = cropParams->h; cropgl = iatlistener->startCropEditing (thumbnail); b = true; } else if (onArea (CropBottomRight, ix, iy)) { state = SResizeBR; press_x = x; - action_x = cropParams.w; + action_x = cropParams->w; press_y = y; - action_y = cropParams.h; + action_y = cropParams->h; cropgl = iatlistener->startCropEditing (thumbnail); b = true; } else if (onArea (CropTop, ix, iy)) { state = SResizeH1; press_y = y; - action_y = cropParams.y; + action_y = cropParams->y; cropgl = iatlistener->startCropEditing (thumbnail); b = true; } else if (onArea (CropBottom, ix, iy)) { state = SResizeH2; press_y = y; - action_y = cropParams.h; + action_y = cropParams->h; cropgl = iatlistener->startCropEditing (thumbnail); b = true; } else if (onArea (CropLeft, ix, iy)) { state = SResizeW1; press_x = x; - action_x = cropParams.x; + action_x = cropParams->x; cropgl = iatlistener->startCropEditing (thumbnail); b = true; } else if (onArea (CropRight, ix, iy)) { state = SResizeW2; press_x = x; - action_x = cropParams.w; + action_x = cropParams->w; cropgl = iatlistener->startCropEditing (thumbnail); b = true; } else if ((bstate & GDK_SHIFT_MASK) && onArea (CropInside, ix, iy)) { state = SCropMove; press_x = x; press_y = y; - action_x = cropParams.x; - action_y = cropParams.y; + action_x = cropParams->x; + action_y = cropParams->y; cropgl = iatlistener->startCropEditing (thumbnail); b = true; } else if (onArea (CropImage, ix, iy)) { @@ -513,10 +515,10 @@ bool FileBrowserEntry::pressNotify (int button, int type, int bstate, int x, i if (cropgl) { state = SCropSelecting; - press_x = cropParams.x = (ix - prex) / scale; - press_y = cropParams.y = (iy - prey) / scale; - cropParams.w = cropParams.h = 1; - cropgl->cropInit (cropParams.x, cropParams.y, cropParams.w, cropParams.h); + press_x = cropParams->x = (ix - prex) / scale; + press_y = cropParams->y = (iy - prey) / scale; + cropParams->w = cropParams->h = 1; + cropgl->cropInit (cropParams->x, cropParams->y, cropParams->w, cropParams->h); b = true; } } @@ -582,67 +584,67 @@ bool FileBrowserEntry::onArea (CursorArea a, int x, int y) return x >= prex && x < prex + prew && y >= prey && y < prey + preh; case CropTopLeft: - return cropParams.enabled && - y1 >= cropParams.y - cropResizeBorder && - y1 <= cropParams.y + cropResizeBorder && - x1 >= cropParams.x - cropResizeBorder && - x1 <= cropParams.x + cropResizeBorder; + return cropParams->enabled && + y1 >= cropParams->y - cropResizeBorder && + y1 <= cropParams->y + cropResizeBorder && + x1 >= cropParams->x - cropResizeBorder && + x1 <= cropParams->x + cropResizeBorder; case CropTopRight: - return cropParams.enabled && - y1 >= cropParams.y - cropResizeBorder && - y1 <= cropParams.y + cropResizeBorder && - x1 >= cropParams.x + cropParams.w - 1 - cropResizeBorder && - x1 <= cropParams.x + cropParams.w - 1 + cropResizeBorder; + return cropParams->enabled && + y1 >= cropParams->y - cropResizeBorder && + y1 <= cropParams->y + cropResizeBorder && + x1 >= cropParams->x + cropParams->w - 1 - cropResizeBorder && + x1 <= cropParams->x + cropParams->w - 1 + cropResizeBorder; case CropBottomLeft: - return cropParams.enabled && - y1 >= cropParams.y + cropParams.h - 1 - cropResizeBorder && - y1 <= cropParams.y + cropParams.h - 1 + cropResizeBorder && - x1 >= cropParams.x - cropResizeBorder && - x1 <= cropParams.x + cropResizeBorder; + return cropParams->enabled && + y1 >= cropParams->y + cropParams->h - 1 - cropResizeBorder && + y1 <= cropParams->y + cropParams->h - 1 + cropResizeBorder && + x1 >= cropParams->x - cropResizeBorder && + x1 <= cropParams->x + cropResizeBorder; case CropBottomRight: - return cropParams.enabled && - y1 >= cropParams.y + cropParams.h - 1 - cropResizeBorder && - y1 <= cropParams.y + cropParams.h - 1 + cropResizeBorder && - x1 >= cropParams.x + cropParams.w - 1 - cropResizeBorder && - x1 <= cropParams.x + cropParams.w - 1 + cropResizeBorder; + return cropParams->enabled && + y1 >= cropParams->y + cropParams->h - 1 - cropResizeBorder && + y1 <= cropParams->y + cropParams->h - 1 + cropResizeBorder && + x1 >= cropParams->x + cropParams->w - 1 - cropResizeBorder && + x1 <= cropParams->x + cropParams->w - 1 + cropResizeBorder; case CropTop: - return cropParams.enabled && - x1 > cropParams.x + cropResizeBorder && - x1 < cropParams.x + cropParams.w - 1 - cropResizeBorder && - y1 > cropParams.y - cropResizeBorder && - y1 < cropParams.y + cropResizeBorder; + return cropParams->enabled && + x1 > cropParams->x + cropResizeBorder && + x1 < cropParams->x + cropParams->w - 1 - cropResizeBorder && + y1 > cropParams->y - cropResizeBorder && + y1 < cropParams->y + cropResizeBorder; case CropBottom: - return cropParams.enabled && - x1 > cropParams.x + cropResizeBorder && - x1 < cropParams.x + cropParams.w - 1 - cropResizeBorder && - y1 > cropParams.y + cropParams.h - 1 - cropResizeBorder && - y1 < cropParams.y + cropParams.h - 1 + cropResizeBorder; + return cropParams->enabled && + x1 > cropParams->x + cropResizeBorder && + x1 < cropParams->x + cropParams->w - 1 - cropResizeBorder && + y1 > cropParams->y + cropParams->h - 1 - cropResizeBorder && + y1 < cropParams->y + cropParams->h - 1 + cropResizeBorder; case CropLeft: - return cropParams.enabled && - y1 > cropParams.y + cropResizeBorder && - y1 < cropParams.y + cropParams.h - 1 - cropResizeBorder && - x1 > cropParams.x - cropResizeBorder && - x1 < cropParams.x + cropResizeBorder; + return cropParams->enabled && + y1 > cropParams->y + cropResizeBorder && + y1 < cropParams->y + cropParams->h - 1 - cropResizeBorder && + x1 > cropParams->x - cropResizeBorder && + x1 < cropParams->x + cropResizeBorder; case CropRight: - return cropParams.enabled && - y1 > cropParams.y + cropResizeBorder && - y1 < cropParams.y + cropParams.h - 1 - cropResizeBorder && - x1 > cropParams.x + cropParams.w - 1 - cropResizeBorder && - x1 < cropParams.x + cropParams.w - 1 + cropResizeBorder; + return cropParams->enabled && + y1 > cropParams->y + cropResizeBorder && + y1 < cropParams->y + cropParams->h - 1 - cropResizeBorder && + x1 > cropParams->x + cropParams->w - 1 - cropResizeBorder && + x1 < cropParams->x + cropParams->w - 1 + cropResizeBorder; case CropInside: - return cropParams.enabled && - y1 > cropParams.y && - y1 < cropParams.y + cropParams.h - 1 && - x1 > cropParams.x && - x1 < cropParams.x + cropParams.w - 1; + return cropParams->enabled && + y1 > cropParams->y && + y1 < cropParams->y + cropParams->h - 1 && + x1 > cropParams->x && + x1 < cropParams->x + cropParams->w - 1; default: /* do nothing */ ; } diff --git a/rtgui/filebrowserentry.h b/rtgui/filebrowserentry.h index b1fa8c54b..770889d88 100644 --- a/rtgui/filebrowserentry.h +++ b/rtgui/filebrowserentry.h @@ -20,6 +20,7 @@ #define _FILEBROWSERENTRY_ #include +#include #include @@ -55,7 +56,7 @@ class FileBrowserEntry : public ThumbBrowserEntryBase, int press_x, press_y, action_x, action_y; double rot_deg; bool landscape; - rtengine::procparams::CropParams cropParams; + std::unique_ptr cropParams; CropGUIListener* cropgl; FileBrowserEntryIdleHelper* feih; diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc index 5ebac5e12..c400a18e3 100644 --- a/rtgui/filecatalog.cc +++ b/rtgui/filecatalog.cc @@ -1187,7 +1187,7 @@ void FileCatalog::developRequested(const std::vector& tbe, bo params.icm.inputProfile = options.fastexport_icm_input_profile; params.icm.workingProfile = options.fastexport_icm_working_profile; params.icm.outputProfile = options.fastexport_icm_output_profile; - params.icm.outputIntent = options.fastexport_icm_outputIntent; + params.icm.outputIntent = rtengine::RenderingIntent(options.fastexport_icm_outputIntent); params.icm.outputBPC = options.fastexport_icm_outputBPC; } diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index a645846d1..e2a40bcf8 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -23,6 +23,7 @@ #include "../rtengine/rt_math.h" #include "../rtengine/utils.h" #include "../rtengine/icons.h" +#include "../rtengine/procparams.h" #include "rtimage.h" #include "multilangmgr.h" diff --git a/rtgui/imagearea.cc b/rtgui/imagearea.cc index 0bdb7f11c..40a8c2ca8 100644 --- a/rtgui/imagearea.cc +++ b/rtgui/imagearea.cc @@ -23,6 +23,7 @@ #include "multilangmgr.h" #include "cropwindow.h" #include "../rtengine/refreshmap.h" +#include "../rtengine/procparams.h" #include "options.h" ImageArea::ImageArea (ImageAreaPanel* p) : parent(p), fullImageWidth(0), fullImageHeight(0) @@ -659,7 +660,7 @@ void ImageArea::initialImageArrived () } else { mainCropWindow->zoomFit(); } - } else if ((options.cropAutoFit || options.bgcolor != 0) && mainCropWindow->cropHandler.cropParams.enabled) { + } else if ((options.cropAutoFit || options.bgcolor != 0) && mainCropWindow->cropHandler.cropParams->enabled) { mainCropWindow->zoomFitCrop(); } fullImageWidth = w; diff --git a/rtgui/iptcpanel.cc b/rtgui/iptcpanel.cc index 0dafe940f..5065452b0 100644 --- a/rtgui/iptcpanel.cc +++ b/rtgui/iptcpanel.cc @@ -623,7 +623,7 @@ void IPTCPanel::applyChangeList () keyword->get_entry()->set_text (""); suppCategory->get_entry()->set_text (""); - for (rtengine::procparams::IPTCPairs::iterator i = changeList.begin(); i != changeList.end(); ++i) { + for (rtengine::procparams::IPTCPairs::const_iterator i = changeList.begin(); i != changeList.end(); ++i) { if (i->first == "Caption" && !i->second.empty()) { captionText->set_text (i->second.at(0)); } else if (i->first == "CaptionWriter" && !i->second.empty()) { diff --git a/rtgui/options.cc b/rtgui/options.cc index b38a9f689..fe3b9bf1a 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -25,6 +25,8 @@ #include "guiutils.h" #include "version.h" +#include "../rtengine/procparams.h" + #ifdef _OPENMP #include #endif diff --git a/rtgui/options.h b/rtgui/options.h index 5001306ff..43f0cbe81 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -363,7 +363,7 @@ public: Glib::ustring fastexport_icm_input_profile; Glib::ustring fastexport_icm_working_profile; Glib::ustring fastexport_icm_output_profile; - rtengine::RenderingIntent fastexport_icm_outputIntent; + int fastexport_icm_outputIntent; bool fastexport_icm_outputBPC; Glib::ustring fastexport_icm_custom_output_profile; bool fastexport_resize_enabled; diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index dbcb912e3..9f92707bb 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -22,6 +22,8 @@ #include #include "../rtengine/rtengine.h" +class ParamsEdited; + class PartialPasteDlg : public Gtk::Dialog { diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index c10c37b1f..8f1653459 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -2384,7 +2384,7 @@ void Preferences::workflowUpdate () || moptions.rtSettings.printerBPC != options.rtSettings.printerBPC || moptions.rtSettings.printerIntent != options.rtSettings.printerIntent) { // Update the position of the Histogram - parent->updateProfiles (moptions.rtSettings.printerProfile, moptions.rtSettings.printerIntent, moptions.rtSettings.printerBPC); + parent->updateProfiles (moptions.rtSettings.printerProfile, rtengine::RenderingIntent(moptions.rtSettings.printerIntent), moptions.rtSettings.printerBPC); } } diff --git a/rtgui/previewhandler.cc b/rtgui/previewhandler.cc index 2315b8c91..a1640b39c 100644 --- a/rtgui/previewhandler.cc +++ b/rtgui/previewhandler.cc @@ -19,11 +19,15 @@ #include "previewhandler.h" #include #include "../rtengine/rtengine.h" +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; -PreviewHandler::PreviewHandler () : image(nullptr), previewScale(1.) +PreviewHandler::PreviewHandler () : + image(nullptr), + cropParams(new procparams::CropParams), + previewScale(1.) { pih = new PreviewHandlerIdleHelper; @@ -72,7 +76,7 @@ void PreviewHandler::setImage(rtengine::IImage8* i, double scale, const rtengine pih->phandler->image = i; } - pih->phandler->cropParams = cp; + *pih->phandler->cropParams = cp; pih->phandler->previewScale = scale; --pih->pending; @@ -139,7 +143,7 @@ void PreviewHandler::imageReady(const rtengine::procparams::CropParams& cp) pih->phandler->previewImg = Gdk::Pixbuf::create_from_data(pih->phandler->image->getData(), Gdk::COLORSPACE_RGB, false, 8, pih->phandler->image->getWidth(), pih->phandler->image->getHeight(), 3 * pih->phandler->image->getWidth()); pih->phandler->previewImgMutex.unlock (); - pih->phandler->cropParams = cp; + *pih->phandler->cropParams = cp; pih->phandler->previewImageChanged (); --pih->pending; @@ -204,3 +208,8 @@ void PreviewHandler::previewImageChanged () (*i)->previewImageChanged (); } } + +rtengine::procparams::CropParams PreviewHandler::getCropParams() +{ + return *cropParams; +} diff --git a/rtgui/previewhandler.h b/rtgui/previewhandler.h index 81a68e05c..4c4a68afc 100644 --- a/rtgui/previewhandler.h +++ b/rtgui/previewhandler.h @@ -20,6 +20,7 @@ #define _PREVIEWHANDLER_ #include +#include #include @@ -54,7 +55,7 @@ private: protected: rtengine::IImage8* image; - rtengine::procparams::CropParams cropParams; + std::unique_ptr cropParams; double previewScale; PreviewHandlerIdleHelper* pih; std::list listeners; @@ -82,10 +83,7 @@ public: // with this function it is possible to ask for a rough approximation of a (possibly zoomed) crop of the image Glib::RefPtr getRoughImage (int x, int y, int w, int h, double zoom); Glib::RefPtr getRoughImage (int desiredW, int desiredH, double& zoom); - rtengine::procparams::CropParams getCropParams () - { - return cropParams; - } + rtengine::procparams::CropParams getCropParams (); }; #endif diff --git a/rtgui/previewwindow.cc b/rtgui/previewwindow.cc index cd4977bb1..c999ff663 100644 --- a/rtgui/previewwindow.cc +++ b/rtgui/previewwindow.cc @@ -21,6 +21,8 @@ #include "imagearea.h" #include "cursormanager.h" +#include "../rtengine/procparams.h" + PreviewWindow::PreviewWindow () : previewHandler(nullptr), mainCropWin(nullptr), imageArea(nullptr), imgX(0), imgY(0), imgW(0), imgH(0), zoom(0.0), press_x(0), press_y(0), isMoving(false), needsUpdate(false), cursor_type(CSUndefined) diff --git a/rtgui/thumbimageupdater.cc b/rtgui/thumbimageupdater.cc index f7caf5f5e..c0df751a5 100644 --- a/rtgui/thumbimageupdater.cc +++ b/rtgui/thumbimageupdater.cc @@ -27,6 +27,8 @@ #include "guiutils.h" #include "threadutils.h" +#include "../rtengine/procparams.h" + #ifdef _OPENMP #include #endif diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 7fb547aa6..b842c01dd 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -25,6 +25,7 @@ #include #include #include "../rtengine/imagedata.h" +#include "../rtengine/procparams.h" #include #include "../rtengine/dynamicprofile.h" @@ -38,7 +39,7 @@ using namespace rtengine::procparams; Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf) : fname(fname), cfs(*cf), cachemgr(cm), ref(1), enqueueNumber(0), tpp(nullptr), - pparamsValid(false), imageLoading(false), lastImg(nullptr), + pparamsValid(false), pparams(new ProcParams), imageLoading(false), lastImg(nullptr), lastW(0), lastH(0), lastScale(0), initial_(false) { @@ -66,7 +67,7 @@ Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageDa Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5) : fname(fname), cachemgr(cm), ref(1), enqueueNumber(0), tpp(nullptr), pparamsValid(false), - imageLoading(false), lastImg(nullptr), + pparams(new ProcParams), imageLoading(false), lastImg(nullptr), lastW(0), lastH(0), lastScale(0.0), initial_(true) { @@ -107,20 +108,20 @@ void Thumbnail::_generateThumbnailImage () if (ext.lowercase() == "jpg" || ext.lowercase() == "jpeg") { infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams.wb.equal); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams->wb.equal); if (tpp) { cfs.format = FT_Jpeg; } } else if (ext.lowercase() == "png") { - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams.wb.equal); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams->wb.equal); if (tpp) { cfs.format = FT_Png; } } else if (ext.lowercase() == "tif" || ext.lowercase() == "tiff") { infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams.wb.equal); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1, pparams->wb.equal); if (tpp) { cfs.format = FT_Tiff; @@ -141,7 +142,7 @@ void Thumbnail::_generateThumbnailImage () if ( tpp == nullptr ) { quick = false; - tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, sensorType, tw, th, 1, pparams.wb.equal, TRUE); + tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, sensorType, tw, th, 1, pparams->wb.equal, TRUE); } cfs.sensortype = sensorType; @@ -178,22 +179,22 @@ const ProcParams& Thumbnail::getProcParams () const ProcParams& Thumbnail::getProcParamsU () { if (pparamsValid) { - return pparams; + return *pparams; } else { - pparams = *(ProfileStore::getInstance()->getDefaultProcParams (getType() == FT_Raw)); + *pparams = *(ProfileStore::getInstance()->getDefaultProcParams (getType() == FT_Raw)); - if (pparams.wb.method == "Camera") { + if (pparams->wb.method == "Camera") { double ct; - getCamWB (ct, pparams.wb.green); - pparams.wb.temperature = ct; - } else if (pparams.wb.method == "Auto") { + getCamWB (ct, pparams->wb.green); + pparams->wb.temperature = ct; + } else if (pparams->wb.method == "Auto") { double ct; - getAutoWB (ct, pparams.wb.green, pparams.wb.equal, pparams.wb.tempBias); - pparams.wb.temperature = ct; + getAutoWB (ct, pparams->wb.green, pparams->wb.equal, pparams->wb.tempBias); + pparams->wb.temperature = ct; } } - return pparams; // there is no valid pp to return, but we have to return something + return *pparams; // there is no valid pp to return, but we have to return something } /** @brief Create default params on demand and returns a new updatable object @@ -320,27 +321,27 @@ void Thumbnail::loadProcParams () MyMutex::MyLock lock(mutex); pparamsValid = false; - pparams.setDefaults(); + pparams->setDefaults(); const PartialProfile *defaultPP = ProfileStore::getInstance()->getDefaultPartialProfile(getType() == FT_Raw); - defaultPP->applyTo(&pparams); + defaultPP->applyTo(pparams.get()); if (options.paramsLoadLocation == PLL_Input) { // try to load it from params file next to the image file - int ppres = pparams.load (fname + paramFileExtension); - pparamsValid = !ppres && pparams.ppVersion >= 220; + int ppres = pparams->load (fname + paramFileExtension); + pparamsValid = !ppres && pparams->ppVersion >= 220; // if no success, try to load the cached version of the procparams if (!pparamsValid) { - pparamsValid = !pparams.load (getCacheFileName ("profiles", paramFileExtension)); + pparamsValid = !pparams->load (getCacheFileName ("profiles", paramFileExtension)); } } else { // try to load it from cache - pparamsValid = !pparams.load (getCacheFileName ("profiles", paramFileExtension)); + pparamsValid = !pparams->load (getCacheFileName ("profiles", paramFileExtension)); // if no success, try to load it from params file next to the image file if (!pparamsValid) { - int ppres = pparams.load (fname + paramFileExtension); - pparamsValid = !ppres && pparams.ppVersion >= 220; + int ppres = pparams->load (fname + paramFileExtension); + pparamsValid = !ppres && pparams->ppVersion >= 220; } } } @@ -373,7 +374,7 @@ void Thumbnail::clearProcParams (int whoClearedIt) // probably not as this is the only option to set param values to default // reset the params to defaults - pparams.setDefaults(); + pparams->setDefaults(); // and restore rank and inTrash setRank(rank); @@ -422,42 +423,42 @@ void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoCh { const bool needsReprocessing = resetToDefault - || pparams.toneCurve != pp.toneCurve - || pparams.labCurve != pp.labCurve - || pparams.localContrast != pp.localContrast - || pparams.rgbCurves != pp.rgbCurves - || pparams.colorToning != pp.colorToning - || pparams.vibrance != pp.vibrance - || pparams.wb != pp.wb - || pparams.colorappearance != pp.colorappearance - || pparams.epd != pp.epd - || pparams.fattal != pp.fattal - || pparams.sh != pp.sh - || pparams.crop != pp.crop - || pparams.coarse != pp.coarse - || pparams.commonTrans != pp.commonTrans - || pparams.rotate != pp.rotate - || pparams.distortion != pp.distortion - || pparams.lensProf != pp.lensProf - || pparams.perspective != pp.perspective - || pparams.gradient != pp.gradient - || pparams.pcvignette != pp.pcvignette - || pparams.cacorrection != pp.cacorrection - || pparams.vignetting != pp.vignetting - || pparams.chmixer != pp.chmixer - || pparams.blackwhite != pp.blackwhite - || pparams.icm != pp.icm - || pparams.hsvequalizer != pp.hsvequalizer - || pparams.filmSimulation != pp.filmSimulation - || pparams.softlight != pp.softlight - || pparams.dehaze != pp.dehaze + || pparams->toneCurve != pp.toneCurve + || pparams->labCurve != pp.labCurve + || pparams->localContrast != pp.localContrast + || pparams->rgbCurves != pp.rgbCurves + || pparams->colorToning != pp.colorToning + || pparams->vibrance != pp.vibrance + || pparams->wb != pp.wb + || pparams->colorappearance != pp.colorappearance + || pparams->epd != pp.epd + || pparams->fattal != pp.fattal + || pparams->sh != pp.sh + || pparams->crop != pp.crop + || pparams->coarse != pp.coarse + || pparams->commonTrans != pp.commonTrans + || pparams->rotate != pp.rotate + || pparams->distortion != pp.distortion + || pparams->lensProf != pp.lensProf + || pparams->perspective != pp.perspective + || pparams->gradient != pp.gradient + || pparams->pcvignette != pp.pcvignette + || pparams->cacorrection != pp.cacorrection + || pparams->vignetting != pp.vignetting + || pparams->chmixer != pp.chmixer + || pparams->blackwhite != pp.blackwhite + || pparams->icm != pp.icm + || pparams->hsvequalizer != pp.hsvequalizer + || pparams->filmSimulation != pp.filmSimulation + || pparams->softlight != pp.softlight + || pparams->dehaze != pp.dehaze || whoChangedIt == FILEBROWSER || whoChangedIt == BATCHEDITOR; { MyMutex::MyLock lock(mutex); - if (pparams != pp) { + if (*pparams != pp) { cfs.recentlySaved = false; } else if (pparamsValid && !updateCacheNow) { // nothing to do @@ -470,9 +471,9 @@ void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoCh const int inTrash = getStage(); if (pe) { - pe->combine(pparams, pp, true); + pe->combine(*pparams, pp, true); } else { - pparams = pp; + *pparams = pp; } pparamsValid = true; @@ -506,7 +507,7 @@ void Thumbnail::imageDeveloped () cfs.save (getCacheFileName ("data", ".txt")); if (options.saveParamsCache) { - pparams.save (getCacheFileName ("profiles", paramFileExtension)); + pparams->save (getCacheFileName ("profiles", paramFileExtension)); } } @@ -574,7 +575,7 @@ void Thumbnail::getThumbnailSize (int &w, int &h, const rtengine::procparams::Pr ppCoarse -= 180; } - int thisCoarse = this->pparams.coarse.rotate; + int thisCoarse = this->pparams->coarse.rotate; if (thisCoarse >= 180) { thisCoarse -= 180; @@ -948,7 +949,7 @@ void Thumbnail::updateCache (bool updatePParams, bool updateCacheImageData) { if (updatePParams && pparamsValid) { - pparams.save ( + pparams->save ( options.saveParamsFile ? fname + paramFileExtension : "", options.saveParamsCache ? getCacheFileName ("profiles", paramFileExtension) : "", true @@ -981,6 +982,45 @@ void Thumbnail::setFileName (const Glib::ustring &fn) cfs.md5 = cachemgr->getMD5 (fname); } +int Thumbnail::getRank () const +{ + return pparams->rank; +} + +void Thumbnail::setRank (int rank) +{ + if (pparams->rank != rank) { + pparams->rank = rank; + pparamsValid = true; + } +} + +int Thumbnail::getColorLabel () const +{ + return pparams->colorlabel; +} + +void Thumbnail::setColorLabel (int colorlabel) +{ + if (pparams->colorlabel != colorlabel) { + pparams->colorlabel = colorlabel; + pparamsValid = true; + } +} + +int Thumbnail::getStage () const +{ + return pparams->inTrash; +} + +void Thumbnail::setStage (bool stage) +{ + if (pparams->inTrash != stage) { + pparams->inTrash = stage; + pparamsValid = true; + } +} + void Thumbnail::addThumbnailListener (ThumbnailListener* tnl) { diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index 28762e505..99f5279ed 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -19,7 +19,9 @@ #ifndef _THUMBNAIL_ #define _THUMBNAIL_ +#include #include + #include #include "cachemanager.h" #include "options.h" @@ -30,6 +32,8 @@ #include "threadutils.h" class CacheManager; +class ParamsEdited; + class Thumbnail { @@ -47,7 +51,7 @@ class Thumbnail float imgRatio; // hack to avoid rounding error // double scale; // portion of the sizes of the processed thumbnail image and the full scale image - rtengine::procparams::ProcParams pparams; + std::unique_ptr pparams; bool pparamsValid; bool imageLoading; @@ -160,41 +164,14 @@ public: return cfs.md5; } - int getRank () const - { - return pparams.rank; - } - void setRank (int rank) - { - if (pparams.rank != rank) { - pparams.rank = rank; - pparamsValid = true; - } - } + int getRank () const; + void setRank (int rank); - int getColorLabel () const - { - return pparams.colorlabel; - } - void setColorLabel (int colorlabel) - { - if (pparams.colorlabel != colorlabel) { - pparams.colorlabel = colorlabel; - pparamsValid = true; - } - } + int getColorLabel () const; + void setColorLabel (int colorlabel); - int getStage () const - { - return pparams.inTrash; - } - void setStage (bool stage) - { - if (pparams.inTrash != stage) { - pparams.inTrash = stage; - pparamsValid = true; - } - } + int getStage () const; + void setStage (bool stage); void addThumbnailListener (ThumbnailListener* tnl); void removeThumbnailListener (ThumbnailListener* tnl); diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index b4157e58a..9b654e387 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -347,33 +347,33 @@ void ToneCurve::write (ProcParams* pp, ParamsEdited* pedited) int tcMode = toneCurveMode->get_active_row_number(); if (tcMode == 0) { - pp->toneCurve.curveMode = ToneCurveParams::TcMode::STD; + pp->toneCurve.curveMode = ToneCurveMode::STD; } else if (tcMode == 1) { - pp->toneCurve.curveMode = ToneCurveParams::TcMode::WEIGHTEDSTD; + pp->toneCurve.curveMode = ToneCurveMode::WEIGHTEDSTD; } else if (tcMode == 2) { - pp->toneCurve.curveMode = ToneCurveParams::TcMode::FILMLIKE; + pp->toneCurve.curveMode = ToneCurveMode::FILMLIKE; } else if (tcMode == 3) { - pp->toneCurve.curveMode = ToneCurveParams::TcMode::SATANDVALBLENDING; + pp->toneCurve.curveMode = ToneCurveMode::SATANDVALBLENDING; } else if (tcMode == 4) { - pp->toneCurve.curveMode = ToneCurveParams::TcMode::LUMINANCE; + pp->toneCurve.curveMode = ToneCurveMode::LUMINANCE; } else if (tcMode == 5) { - pp->toneCurve.curveMode = ToneCurveParams::TcMode::PERCEPTUAL; + pp->toneCurve.curveMode = ToneCurveMode::PERCEPTUAL; } tcMode = toneCurveMode2->get_active_row_number(); if (tcMode == 0) { - pp->toneCurve.curveMode2 = ToneCurveParams::TcMode::STD; + pp->toneCurve.curveMode2 = ToneCurveMode::STD; } else if (tcMode == 1) { - pp->toneCurve.curveMode2 = ToneCurveParams::TcMode::WEIGHTEDSTD; + pp->toneCurve.curveMode2 = ToneCurveMode::WEIGHTEDSTD; } else if (tcMode == 2) { - pp->toneCurve.curveMode2 = ToneCurveParams::TcMode::FILMLIKE; + pp->toneCurve.curveMode2 = ToneCurveMode::FILMLIKE; } else if (tcMode == 3) { - pp->toneCurve.curveMode2 = ToneCurveParams::TcMode::SATANDVALBLENDING; + pp->toneCurve.curveMode2 = ToneCurveMode::SATANDVALBLENDING; } else if (tcMode == 4) { - pp->toneCurve.curveMode2 = ToneCurveParams::TcMode::LUMINANCE; + pp->toneCurve.curveMode2 = ToneCurveMode::LUMINANCE; } else if (tcMode == 5) { - pp->toneCurve.curveMode2 = ToneCurveParams::TcMode::PERCEPTUAL; + pp->toneCurve.curveMode2 = ToneCurveMode::PERCEPTUAL; } pp->toneCurve.histmatching = histmatching->get_active(); @@ -979,7 +979,7 @@ void ToneCurve::autoExpChanged(double expcomp, int bright, int contr, int black, ); } -void ToneCurve::autoMatchedToneCurveChanged(rtengine::procparams::ToneCurveParams::TcMode curveMode, const std::vector& curve) +void ToneCurve::autoMatchedToneCurveChanged(rtengine::procparams::ToneCurveMode curveMode, const std::vector& curve) { nextToneCurveMode = curveMode; nextToneCurve = curve; diff --git a/rtgui/tonecurve.h b/rtgui/tonecurve.h index 2cf7b9d12..47789ec01 100644 --- a/rtgui/tonecurve.h +++ b/rtgui/tonecurve.h @@ -81,7 +81,7 @@ protected: int nextHlcompr; int nextHlcomprthresh; bool nextHLRecons; - rtengine::procparams::ToneCurveParams::TcMode nextToneCurveMode; + rtengine::procparams::ToneCurveMode nextToneCurveMode; std::vector nextToneCurve; void setHistmatching(bool enabled); @@ -132,7 +132,7 @@ public: void histmatchingToggled(); void autoExpChanged(double expcomp, int bright, int contr, int black, int hlcompr, int hlcomprthresh, bool hlrecons) override; - void autoMatchedToneCurveChanged(rtengine::procparams::ToneCurveParams::TcMode curveMode, const std::vector& curve) override; + void autoMatchedToneCurveChanged(rtengine::procparams::ToneCurveMode curveMode, const std::vector& curve) override; void setRaw (bool raw); From 917cc49278a32db9d0cbdd76b0d0e622dee8eded Mon Sep 17 00:00:00 2001 From: heckflosse Date: Thu, 28 Feb 2019 22:39:40 +0100 Subject: [PATCH 03/36] xtrans: reduce border artifacts, #5198 --- rtengine/xtrans_demosaic.cc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/rtengine/xtrans_demosaic.cc b/rtengine/xtrans_demosaic.cc index 26cd9071b..c37be314f 100644 --- a/rtengine/xtrans_demosaic.cc +++ b/rtengine/xtrans_demosaic.cc @@ -197,12 +197,6 @@ void RawImageSource::xtrans_interpolate (const int passes, const bool useCieLab) const int height = H, width = W; -// if (settings->verbose) { -// printf("%d-pass X-Trans interpolation using %s conversion...\n", passes, useCieLab ? "lab" : "yuv"); -// } - - xtransborder_interpolate(6, red, green, blue); - float xyz_cam[3][3]; { float rgb_cam[3][4]; @@ -956,6 +950,7 @@ void RawImageSource::xtrans_interpolate (const int passes, const bool useCieLab) free(buffer); } + xtransborder_interpolate(8, red, green, blue); } #undef CLIP void RawImageSource::fast_xtrans_interpolate (const array2D &rawData, array2D &red, array2D &green, array2D &blue) From bd09da51f0ede7fbc1b738e2b50af8dda15ccd2b Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Fri, 1 Mar 2019 14:02:20 +0100 Subject: [PATCH 04/36] Added "Unclipped" processing profile #5199 Allows one to easily saved unclipped floating-point images. Documentation: http://rawpedia.rawtherapee.com/Unclipped --- rtdata/profiles/Unclipped.pp3 | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 rtdata/profiles/Unclipped.pp3 diff --git a/rtdata/profiles/Unclipped.pp3 b/rtdata/profiles/Unclipped.pp3 new file mode 100644 index 000000000..c0bc9ad94 --- /dev/null +++ b/rtdata/profiles/Unclipped.pp3 @@ -0,0 +1,27 @@ +[Version] +AppVersion=5.5-151-g1786731f4 +Version=346 + +[Exposure] +ClampOOG=false +Curve=0; +Curve2=0; + +[Black & White] +BeforeCurve=0; +AfterCurve=0; + +[Vibrance] +Enabled=false + +[Color appearance] +Enabled=false + +[Film Simulation] +Enabled=false + +[RGB Curves] +LumaMode=false + +[Color Management] +ApplyLookTable=false From f78f17ae6fc137d05ef2fcd366c9923866b09d5b Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 1 Mar 2019 14:36:13 +0100 Subject: [PATCH 05/36] xtransborder_interpolate: Use same weights as in fast_xtrans_interpolate, #5198 --- rtengine/xtrans_demosaic.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/rtengine/xtrans_demosaic.cc b/rtengine/xtrans_demosaic.cc index c37be314f..f32969d17 100644 --- a/rtengine/xtrans_demosaic.cc +++ b/rtengine/xtrans_demosaic.cc @@ -120,6 +120,11 @@ void RawImageSource::xtransborder_interpolate (int border, array2D &red, int xtrans[6][6]; ri->getXtransMatrix(xtrans); + const float weight[3][3] = { + {0.25f, 0.5f, 0.25f}, + {0.5f, 0.f, 0.5f}, + {0.25f, 0.5f, 0.25f} + }; for (int row = 0; row < height; row++) for (int col = 0; col < width; col++) { @@ -129,11 +134,11 @@ void RawImageSource::xtransborder_interpolate (int border, array2D &red, float sum[6] = {0.f}; - for (int y = MAX(0, row - 1); y <= MIN(row + 1, height - 1); y++) - for (int x = MAX(0, col - 1); x <= MIN(col + 1, width - 1); x++) { + for (int y = MAX(0, row - 1), v = row == 0 ? 0 : -1; y <= MIN(row + 1, height - 1); y++, v++) + for (int x = MAX(0, col - 1), h = col == 0 ? 0 : -1; x <= MIN(col + 1, width - 1); x++, h++) { int f = fcol(y, x); - sum[f] += rawData[y][x]; - sum[f + 3]++; + sum[f] += rawData[y][x] * weight[v + 1][h + 1]; + sum[f + 3] += weight[v + 1][h + 1]; } switch(fcol(row, col)) { From 520a3709bf426ebdace39a12f5dd08fee6f75feb Mon Sep 17 00:00:00 2001 From: heckflosse Date: Fri, 1 Mar 2019 14:47:55 +0100 Subject: [PATCH 06/36] Allow user defined border for xtrans, #5198 --- rtengine/improccoordinator.cc | 2 ++ rtengine/procparams.cc | 4 ++++ rtengine/procparams.h | 1 + rtengine/simpleprocess.cc | 2 ++ rtgui/paramsedited.cc | 8 +++++++- rtgui/paramsedited.h | 1 + rtgui/partialpastedlg.cc | 1 + rtgui/xtransprocess.cc | 26 +++++++++++++++++++++++++- rtgui/xtransprocess.h | 4 ++++ 9 files changed, 47 insertions(+), 2 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 12ef0c226..6f0257064 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -251,6 +251,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } else { imgsrc->setBorder(std::max(params.raw.bayersensor.border, 2)); } + } else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) { + imgsrc->setBorder(params.raw.xtranssensor.border); } bool autoContrast = imgsrc->getSensorType() == ST_BAYER ? params.raw.bayersensor.dualDemosaicAutoContrast : params.raw.xtranssensor.dualDemosaicAutoContrast; double contrastThreshold = imgsrc->getSensorType() == ST_BAYER ? params.raw.bayersensor.dualDemosaicContrast : params.raw.xtranssensor.dualDemosaicContrast; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 33ea7e5cc..3ddf26c4d 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2609,6 +2609,7 @@ RAWParams::XTransSensor::XTransSensor() : method(getMethodString(Method::THREE_PASS)), dualDemosaicAutoContrast(true), dualDemosaicContrast(20), + border(7), ccSteps(0), blackred(0.0), blackgreen(0.0), @@ -2622,6 +2623,7 @@ bool RAWParams::XTransSensor::operator ==(const XTransSensor& other) const method == other.method && dualDemosaicAutoContrast == other.dualDemosaicAutoContrast && dualDemosaicContrast == other.dualDemosaicContrast + && border == other.border && ccSteps == other.ccSteps && blackred == other.blackred && blackgreen == other.blackgreen @@ -3552,6 +3554,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->raw.xtranssensor.method, "RAW X-Trans", "Method", raw.xtranssensor.method, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.dualDemosaicAutoContrast, "RAW X-Trans", "DualDemosaicAutoContrast", raw.xtranssensor.dualDemosaicAutoContrast, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.dualDemosaicContrast, "RAW X-Trans", "DualDemosaicContrast", raw.xtranssensor.dualDemosaicContrast, keyFile); + saveToKeyfile(!pedited || pedited->raw.xtranssensor.border, "RAW X-Trans", "Border", raw.xtranssensor.border, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.ccSteps, "RAW X-Trans", "CcSteps", raw.xtranssensor.ccSteps, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.exBlackRed, "RAW X-Trans", "PreBlackRed", raw.xtranssensor.blackred, keyFile); saveToKeyfile(!pedited || pedited->raw.xtranssensor.exBlackGreen, "RAW X-Trans", "PreBlackGreen", raw.xtranssensor.blackgreen, keyFile); @@ -5099,6 +5102,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } } assignFromKeyfile(keyFile, "RAW X-Trans", "DualDemosaicContrast", pedited, raw.xtranssensor.dualDemosaicContrast, pedited->raw.xtranssensor.dualDemosaicContrast); + assignFromKeyfile(keyFile, "RAW X-Trans", "Border", pedited, raw.xtranssensor.border, pedited->raw.xtranssensor.border); assignFromKeyfile(keyFile, "RAW X-Trans", "CcSteps", pedited, raw.xtranssensor.ccSteps, pedited->raw.xtranssensor.ccSteps); assignFromKeyfile(keyFile, "RAW X-Trans", "PreBlackRed", pedited, raw.xtranssensor.blackred, pedited->raw.xtranssensor.exBlackRed); assignFromKeyfile(keyFile, "RAW X-Trans", "PreBlackGreen", pedited, raw.xtranssensor.blackgreen, pedited->raw.xtranssensor.exBlackGreen); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index d79fc5ae4..a359f1d53 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1369,6 +1369,7 @@ struct RAWParams { Glib::ustring method; bool dualDemosaicAutoContrast; double dualDemosaicContrast; + int border; int ccSteps; double blackred; double blackgreen; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 46f1a91c8..8fa79241b 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -165,6 +165,8 @@ private: } else { imgsrc->setBorder(std::max(params.raw.bayersensor.border, 2)); } + } else if (imgsrc->getSensorType() == ST_FUJI_XTRANS) { + imgsrc->setBorder(params.raw.xtranssensor.border); } imgsrc->getFullSize (fw, fh, tr); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 5d7396f19..992cb5c58 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -432,6 +432,7 @@ void ParamsEdited::set(bool v) raw.xtranssensor.method = v; raw.xtranssensor.dualDemosaicAutoContrast = v; raw.xtranssensor.dualDemosaicContrast = v; + raw.xtranssensor.border = v; raw.xtranssensor.ccSteps = v; raw.xtranssensor.exBlackRed = v; raw.xtranssensor.exBlackGreen = v; @@ -998,6 +999,7 @@ void ParamsEdited::initFrom(const std::vector& raw.xtranssensor.method = raw.xtranssensor.method && p.raw.xtranssensor.method == other.raw.xtranssensor.method; raw.xtranssensor.dualDemosaicAutoContrast = raw.xtranssensor.dualDemosaicAutoContrast && p.raw.xtranssensor.dualDemosaicAutoContrast == other.raw.xtranssensor.dualDemosaicAutoContrast; raw.xtranssensor.dualDemosaicContrast = raw.xtranssensor.dualDemosaicContrast && p.raw.xtranssensor.dualDemosaicContrast == other.raw.xtranssensor.dualDemosaicContrast; + raw.xtranssensor.border = raw.xtranssensor.border && p.raw.xtranssensor.border == other.raw.xtranssensor.border; raw.xtranssensor.ccSteps = raw.xtranssensor.ccSteps && p.raw.xtranssensor.ccSteps == other.raw.xtranssensor.ccSteps; raw.xtranssensor.exBlackRed = raw.xtranssensor.exBlackRed && p.raw.xtranssensor.blackred == other.raw.xtranssensor.blackred; raw.xtranssensor.exBlackGreen = raw.xtranssensor.exBlackGreen && p.raw.xtranssensor.blackgreen == other.raw.xtranssensor.blackgreen; @@ -2656,6 +2658,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.raw.xtranssensor.ccSteps = mods.raw.xtranssensor.ccSteps; } + if (raw.xtranssensor.border) { + toEdit.raw.xtranssensor.border = mods.raw.xtranssensor.border; + } + if (raw.xtranssensor.exBlackRed) { toEdit.raw.xtranssensor.blackred = dontforceSet && options.baBehav[ADDSET_RAWEXPOS_BLACKS] ? toEdit.raw.xtranssensor.blackred + mods.raw.xtranssensor.blackred : mods.raw.xtranssensor.blackred; } @@ -3188,7 +3194,7 @@ bool RAWParamsEdited::BayerSensor::isUnchanged() const bool RAWParamsEdited::XTransSensor::isUnchanged() const { - return method && exBlackRed && exBlackGreen && exBlackBlue && dualDemosaicAutoContrast && dualDemosaicContrast; + return method && border && exBlackRed && exBlackGreen && exBlackBlue && dualDemosaicAutoContrast && dualDemosaicContrast; } bool RAWParamsEdited::isUnchanged() const diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 0bad2ab3c..d7b4e8af4 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -790,6 +790,7 @@ public: bool method; bool dualDemosaicAutoContrast; bool dualDemosaicContrast; + bool border; bool ccSteps; bool exBlackRed; bool exBlackGreen; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index 1f3ef8b77..734f7c29b 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -841,6 +841,7 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param if (!raw_border->get_active ()) { filterPE.raw.bayersensor.border = falsePE.raw.bayersensor.border; + filterPE.raw.xtranssensor.border = falsePE.raw.xtranssensor.border; } if (!raw_imagenum->get_active ()) { diff --git a/rtgui/xtransprocess.cc b/rtgui/xtransprocess.cc index 9639ce29d..49d64bd8f 100644 --- a/rtgui/xtransprocess.cc +++ b/rtgui/xtransprocess.cc @@ -27,6 +27,7 @@ using namespace rtengine::procparams; XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP_RAW_LABEL"), true) { auto m = ProcEventMapper::getInstance(); + EvDemosaicBorder = m->newEvent(DEMOSAIC, "HISTORY_MSG_RAW_BORDER"); EvDemosaicContrast = m->newEvent(DEMOSAIC, "HISTORY_MSG_DUALDEMOSAIC_CONTRAST"); EvDemosaicAutoContrast = m->newEvent(DEMOSAIC, "HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST"); @@ -83,6 +84,18 @@ XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP dualDemosaicOptions->pack_start(*dualDemosaicContrast); pack_start( *dualDemosaicOptions, Gtk::PACK_SHRINK, 4); + borderbox = Gtk::manage(new Gtk::HBox()); + border = Gtk::manage(new Adjuster(M("TP_RAW_BORDER"), 0, 16, 1, 7)); + border->setAdjusterListener (this); + + if (border->delay < options.adjusterMaxDelay) { + border->delay = options.adjusterMaxDelay; + } + + border->show(); + borderbox->pack_start(*border); + pack_start(*borderbox, Gtk::PACK_SHRINK, 4); + pack_start( *Gtk::manage( new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0 ); ccSteps = Gtk::manage (new Adjuster (M("TP_RAW_FALSECOLOR"), 0, 5, 1, 0 )); ccSteps->setAdjusterListener (this); @@ -106,6 +119,7 @@ void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const Param disableListener (); methodconn.block (true); + border->setValue(pp->raw.xtranssensor.border); for (size_t i = 0; i < RAWParams::XTransSensor::getMethodStrings().size(); ++i) if( pp->raw.xtranssensor.method == RAWParams::XTransSensor::getMethodStrings()[i]) { method->set_active(i); @@ -114,6 +128,7 @@ void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const Param } if(pedited ) { + border->setEditedState (pedited->raw.xtranssensor.border ? Edited : UnEdited); dualDemosaicContrast->setAutoInconsistent (multiImage && !pedited->raw.xtranssensor.dualDemosaicAutoContrast); dualDemosaicContrast->setEditedState ( pedited->raw.xtranssensor.dualDemosaicContrast ? Edited : UnEdited); ccSteps->setEditedState (pedited->raw.xtranssensor.ccSteps ? Edited : UnEdited); @@ -126,7 +141,7 @@ void XTransProcess::read(const rtengine::procparams::ProcParams* pp, const Param dualDemosaicContrast->setValue (pp->raw.xtranssensor.dualDemosaicContrast); ccSteps->setValue (pp->raw.xtranssensor.ccSteps); - lastAutoContrast = pp->raw.bayersensor.dualDemosaicAutoContrast; + lastAutoContrast = pp->raw.xtranssensor.dualDemosaicAutoContrast; if (!batchMode) { dualDemosaicOptions->set_visible(pp->raw.xtranssensor.method == procparams::RAWParams::XTransSensor::getMethodString(procparams::RAWParams::XTransSensor::Method::FOUR_PASS) @@ -142,6 +157,7 @@ void XTransProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* p { pp->raw.xtranssensor.dualDemosaicAutoContrast = dualDemosaicContrast->getAutoValue(); pp->raw.xtranssensor.dualDemosaicContrast = dualDemosaicContrast->getValue(); + pp->raw.xtranssensor.border = border->getIntValue(); pp->raw.xtranssensor.ccSteps = ccSteps->getIntValue(); int currentRow = method->get_active_row_number(); @@ -151,6 +167,7 @@ void XTransProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* p } if (pedited) { + pedited->raw.xtranssensor.border = border->getEditedState (); pedited->raw.xtranssensor.method = method->get_active_text() != M("GENERAL_UNCHANGED"); pedited->raw.xtranssensor.dualDemosaicAutoContrast = !dualDemosaicContrast->getAutoInconsistent (); pedited->raw.xtranssensor.dualDemosaicContrast = dualDemosaicContrast->getEditedState (); @@ -160,6 +177,7 @@ void XTransProcess::write( rtengine::procparams::ProcParams* pp, ParamsEdited* p void XTransProcess::setAdjusterBehavior (bool falsecoloradd, bool dualDemosaicContrastAdd) { + border->setAddMode(false); dualDemosaicContrast->setAddMode(dualDemosaicContrastAdd); ccSteps->setAddMode(falsecoloradd); } @@ -170,19 +188,23 @@ void XTransProcess::setBatchMode(bool batchMode) method->set_active_text(M("GENERAL_UNCHANGED")); ToolPanel::setBatchMode (batchMode); dualDemosaicContrast->showEditedCB (); + border->showEditedCB (); ccSteps->showEditedCB (); } void XTransProcess::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited) { dualDemosaicContrast->setDefault( defParams->raw.xtranssensor.dualDemosaicContrast); + border->setDefault (defParams->raw.xtranssensor.border); ccSteps->setDefault (defParams->raw.xtranssensor.ccSteps); if (pedited) { dualDemosaicContrast->setDefaultEditedState( pedited->raw.xtranssensor.dualDemosaicContrast ? Edited : UnEdited); + border->setDefaultEditedState(pedited->raw.xtranssensor.border ? Edited : UnEdited); ccSteps->setDefaultEditedState(pedited->raw.xtranssensor.ccSteps ? Edited : UnEdited); } else { dualDemosaicContrast->setDefaultEditedState(Irrelevant ); + border->setDefaultEditedState(Irrelevant); ccSteps->setDefaultEditedState(Irrelevant ); } } @@ -194,6 +216,8 @@ void XTransProcess::adjusterChanged(Adjuster* a, double newval) listener->panelChanged (EvDemosaicFalseColorIter, a->getTextValue() ); } else if (a == dualDemosaicContrast) { listener->panelChanged (EvDemosaicContrast, a->getTextValue() ); + } else if (a == border) { + listener->panelChanged (EvDemosaicBorder, a->getTextValue() ); } } } diff --git a/rtgui/xtransprocess.h b/rtgui/xtransprocess.h index cd60337dc..e5389b566 100644 --- a/rtgui/xtransprocess.h +++ b/rtgui/xtransprocess.h @@ -32,6 +32,8 @@ class XTransProcess : public ToolParamBlock, public AdjusterListener, public Che protected: MyComboBoxText* method; + Gtk::HBox* borderbox; + Adjuster* border; Adjuster* ccSteps; Gtk::VBox *dualDemosaicOptions; Adjuster* dualDemosaicContrast; @@ -40,6 +42,8 @@ protected: int oldSelection; sigc::connection methodconn; IdleRegister idle_register; + + rtengine::ProcEvent EvDemosaicBorder; rtengine::ProcEvent EvDemosaicAutoContrast; rtengine::ProcEvent EvDemosaicContrast; From 7f4c7ee57a0bb9030a7163ffbbdac995958a3e46 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Fri, 1 Mar 2019 17:24:58 +0100 Subject: [PATCH 07/36] Removed [Version] section from Unclipped.pp3 As in 0415ee979 #4805 --- rtdata/profiles/Unclipped.pp3 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rtdata/profiles/Unclipped.pp3 b/rtdata/profiles/Unclipped.pp3 index c0bc9ad94..c112e7d88 100644 --- a/rtdata/profiles/Unclipped.pp3 +++ b/rtdata/profiles/Unclipped.pp3 @@ -1,7 +1,3 @@ -[Version] -AppVersion=5.5-151-g1786731f4 -Version=346 - [Exposure] ClampOOG=false Curve=0; From 57d030881ded0cad76b8b6ee06b5e140a250e949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Fri, 1 Mar 2019 17:40:02 +0100 Subject: [PATCH 08/36] More `procparams.h` relaxation --- rtengine/curves.cc | 1 - rtengine/dcp.h | 2 +- rtengine/iccstore.cc | 1 - rtengine/iimage.h | 2 +- rtengine/imageio.h | 2 +- rtengine/improccoordinator.h | 4 +- rtengine/ipvibrance.cc | 1 + rtengine/procparams.h | 4 +- rtengine/rawimagesource.h | 2 +- rtgui/batchqueue.cc | 1 + rtgui/batchqueueentry.h | 2 +- rtgui/bayerpreprocess.cc | 9 +- rtgui/bayerprocess.cc | 6 +- rtgui/bayerrawexposure.cc | 3 + rtgui/blackwhite.cc | 12 +- rtgui/cacorrection.cc | 6 +- rtgui/chmixer.cc | 3 + rtgui/clipboard.cc | 128 ++++++++++-- rtgui/clipboard.h | 126 +++++------ rtgui/coarsepanel.cc | 3 + rtgui/colorappearance.cc | 6 +- rtgui/crop.cc | 3 + rtgui/crophandler.h | 4 +- rtgui/darkframe.cc | 10 +- rtgui/defringe.cc | 7 +- rtgui/dehaze.cc | 10 +- rtgui/dirpyrdenoise.cc | 8 +- rtgui/distortion.cc | 6 +- rtgui/epd.cc | 7 +- rtgui/exifpanel.cc | 26 ++- rtgui/exifpanel.h | 7 +- rtgui/fattaltonemap.cc | 11 +- rtgui/filebrowser.cc | 19 +- rtgui/filebrowserentry.h | 2 +- rtgui/filmsimulation.cc | 5 +- rtgui/flatfield.cc | 10 +- rtgui/gradient.cc | 3 + rtgui/history.cc | 7 +- rtgui/hsvequalizer.cc | 3 +- rtgui/icmpanel.cc | 13 +- rtgui/impulsedenoise.cc | 6 +- rtgui/iptcpanel.cc | 71 ++++--- rtgui/iptcpanel.h | 11 +- rtgui/labcurve.cc | 8 +- rtgui/lensgeom.cc | 2 + rtgui/lensprofile.cc | 19 +- rtgui/localcontrast.cc | 10 +- rtgui/paramsedited.cc | 8 +- rtgui/paramsedited.h | 379 +++++++++------------------------- rtgui/partialpastedlg.h | 2 +- rtgui/pcvignette.cc | 2 + rtgui/perspective.cc | 3 + rtgui/preprocess.cc | 8 +- rtgui/previewhandler.h | 2 +- rtgui/profilechangelistener.h | 12 ++ rtgui/profilepanel.cc | 5 +- rtgui/profilestorecombobox.cc | 3 - rtgui/rawcacorrection.cc | 3 + rtgui/rawexposure.cc | 8 +- rtgui/resize.cc | 5 +- rtgui/rgbcurves.cc | 2 + rtgui/rotate.cc | 6 +- rtgui/sensorbayer.cc | 3 - rtgui/sensorxtrans.cc | 3 - rtgui/shadowshighlights.cc | 3 + rtgui/sharpenedge.cc | 10 +- rtgui/sharpenmicro.cc | 6 +- rtgui/softlight.cc | 10 +- rtgui/thresholdselector.cc | 3 + rtgui/thumbnail.h | 4 +- rtgui/tonecurve.cc | 13 +- rtgui/toolpanel.cc | 2 + rtgui/toolpanel.h | 1 - rtgui/vignetting.cc | 2 + rtgui/xtransprocess.cc | 7 +- rtgui/xtransrawexposure.cc | 8 +- 76 files changed, 597 insertions(+), 538 deletions(-) diff --git a/rtengine/curves.cc b/rtengine/curves.cc index 71e128495..ecd38d4aa 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -37,7 +37,6 @@ #include "ciecam02.h" #include "color.h" #include "iccstore.h" -#include "procparams.h" #undef CLIPD #define CLIPD(a) ((a)>0.0f?((a)<1.0f?(a):1.0f):0.0f) diff --git a/rtengine/dcp.h b/rtengine/dcp.h index bedc7f76d..dc6915d26 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -48,7 +48,7 @@ public: private: struct Data; - std::unique_ptr data; + const std::unique_ptr data; friend class DCPProfile; }; diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc index b0248456a..268a6b1c2 100644 --- a/rtengine/iccstore.cc +++ b/rtengine/iccstore.cc @@ -32,7 +32,6 @@ #include "iccstore.h" #include "iccmatrices.h" -#include "procparams.h" #include "../rtgui/options.h" #include "../rtgui/threadutils.h" diff --git a/rtengine/iimage.h b/rtengine/iimage.h index 5ce93605b..a67c2051e 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -45,7 +45,7 @@ namespace rtengine namespace procparams { - class CoarseTransformParams; +struct CoarseTransformParams; } diff --git a/rtengine/imageio.h b/rtengine/imageio.h index f3428b759..05a11655a 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -56,7 +56,7 @@ protected: char* loadedProfileData; bool loadedProfileDataJpg; int loadedProfileLength; - std::unique_ptr exifChange; + const std::unique_ptr exifChange; IptcData* iptc; const rtexif::TagDirectory* exifRoot; MyMutex imutex; diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 8ae5bc669..c293f0c16 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -185,7 +185,7 @@ protected: void updatePreviewImage (int todo, bool panningRelatedChange); MyMutex mProcessing; - std::unique_ptr params; + const std::unique_ptr params; // for optimization purpose, the output profile, output rendering intent and // output BPC will trigger a regeneration of the profile on parameter change only @@ -200,7 +200,7 @@ protected: MyMutex paramsUpdateMutex; int changeSinceLast; bool updaterRunning; - std::unique_ptr nextParams; + const std::unique_ptr nextParams; bool destroying; bool utili; bool autili; diff --git a/rtengine/ipvibrance.cc b/rtengine/ipvibrance.cc index 5f178b5c0..9bb4bc087 100644 --- a/rtengine/ipvibrance.cc +++ b/rtengine/ipvibrance.cc @@ -27,6 +27,7 @@ #include "../rtgui/thresholdselector.h" #include "curves.h" #include "color.h" +#include "procparams.h" #include "StopWatch.h" #ifdef _OPENMP #include diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 37f428c8a..26670c65a 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -28,7 +28,7 @@ #include "noncopyable.h" -class ParamsEdited; +struct ParamsEdited; namespace rtengine { @@ -473,7 +473,7 @@ struct ColorToningParams { }; std::vector labregions; int labregionsShowMask; - + ColorToningParams(); bool operator ==(const ColorToningParams& other) const; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 15d030cca..3c41b8742 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -94,7 +94,7 @@ protected: float psBlueBrightness[4]; std::vector histMatchingCache; - std::unique_ptr histMatchingParams; + const std::unique_ptr histMatchingParams; void processFalseColorCorrectionThread (Imagefloat* im, array2D &rbconv_Y, array2D &rbconv_I, array2D &rbconv_Q, array2D &rbout_I, array2D &rbout_Q, const int row_from, const int row_to); void hlRecovery (const std::string &method, float* red, float* green, float* blue, int width, float* hlmax); diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 540215478..9792522c7 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -21,6 +21,7 @@ #include #include #include "../rtengine/rt_math.h" +#include "../rtengine/procparams.h" #include #include diff --git a/rtgui/batchqueueentry.h b/rtgui/batchqueueentry.h index e14581285..6aecff945 100644 --- a/rtgui/batchqueueentry.h +++ b/rtgui/batchqueueentry.h @@ -48,7 +48,7 @@ public: static Glib::RefPtr savedAsIcon; rtengine::ProcessingJob* job; - std::unique_ptr params; + const std::unique_ptr params; Glib::ustring savedParamsFile; double progress; Glib::ustring outFileName; diff --git a/rtgui/bayerpreprocess.cc b/rtgui/bayerpreprocess.cc index 0720612fe..89fd6fcb6 100644 --- a/rtgui/bayerpreprocess.cc +++ b/rtgui/bayerpreprocess.cc @@ -16,11 +16,14 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "bayerpreprocess.h" -#include "guiutils.h" -#include "eventmapper.h" #include +#include "bayerpreprocess.h" +#include "eventmapper.h" +#include "guiutils.h" + +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 279e68bd6..a681023a6 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -17,9 +17,13 @@ * along with RawTherapee. If not, see . */ #include "bayerprocess.h" + #include "eventmapper.h" -#include "options.h" #include "guiutils.h" +#include "options.h" + +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/bayerrawexposure.cc b/rtgui/bayerrawexposure.cc index f284d7975..d49486511 100644 --- a/rtgui/bayerrawexposure.cc +++ b/rtgui/bayerrawexposure.cc @@ -17,8 +17,11 @@ * along with RawTherapee. If not, see . */ #include "bayerrawexposure.h" + #include "guiutils.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/blackwhite.cc b/rtgui/blackwhite.cc index dcc5c7e01..48d37ebab 100644 --- a/rtgui/blackwhite.cc +++ b/rtgui/blackwhite.cc @@ -16,13 +16,17 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "blackwhite.h" -#include "rtimage.h" -#include "../rtengine/color.h" #include #include -#include "guiutils.h" + +#include "blackwhite.h" + #include "edit.h" +#include "guiutils.h" +#include "rtimage.h" + +#include "../rtengine/color.h" +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/cacorrection.cc b/rtgui/cacorrection.cc index 4405e4ad1..c91eec145 100644 --- a/rtgui/cacorrection.cc +++ b/rtgui/cacorrection.cc @@ -16,10 +16,14 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "cacorrection.h" #include + +#include "cacorrection.h" + #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/chmixer.cc b/rtgui/chmixer.cc index e15ed89f5..4a3411e8b 100644 --- a/rtgui/chmixer.cc +++ b/rtgui/chmixer.cc @@ -17,8 +17,11 @@ * along with RawTherapee. If not, see . */ #include "chmixer.h" + #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/clipboard.cc b/rtgui/clipboard.cc index dfd78cdd1..c8eb94d7b 100644 --- a/rtgui/clipboard.cc +++ b/rtgui/clipboard.cc @@ -18,62 +18,146 @@ */ #include "clipboard.h" +#include "../rtengine/procparams.h" + Clipboard clipboard; -Clipboard::Clipboard () : _hasIPTC(false), partProfile (false), hasDiagonalCurveDataType(DCT_Empty), hasFlatCurveDataType(FCT_Empty) {} +Clipboard::Clipboard () : + _hasIPTC(false), + iptc(new rtengine::procparams::IPTCPairs), + partProfile(new rtengine::procparams::PartialProfile(false)), + hasDiagonalCurveDataType(DCT_Empty), + hasFlatCurveDataType(FCT_Empty) +{ +} Clipboard::~Clipboard () { - partProfile.deleteInstance(); + partProfile->deleteInstance(); +} + +bool Clipboard::hasIPTC() const +{ + return _hasIPTC; +} + +const rtengine::procparams::IPTCPairs& Clipboard::getIPTC() const +{ + return *iptc; +} + +void Clipboard::setIPTC(const rtengine::procparams::IPTCPairs& iptcc) +{ + *iptc = iptcc; + _hasIPTC = true; +} + +const rtengine::procparams::PartialProfile& Clipboard::getPartialProfile() const +{ + return *partProfile; } /* * set both the "pparams" and "pedited" field of the PartialProfile; each one can be NULL */ -void Clipboard::setPartialProfile (const rtengine::procparams::PartialProfile& pprofile) +void Clipboard::setPartialProfile(const rtengine::procparams::PartialProfile& pprofile) { if (pprofile.pparams) { - if (!partProfile.pparams) { - partProfile.pparams = new rtengine::procparams::ProcParams(); + if (!partProfile->pparams) { + partProfile->pparams = new rtengine::procparams::ProcParams(); } - *partProfile.pparams = *pprofile.pparams; + *partProfile->pparams = *pprofile.pparams; } else { - if (partProfile.pparams) { - delete partProfile.pparams; - partProfile.pparams = nullptr; + if (partProfile->pparams) { + delete partProfile->pparams; + partProfile->pparams = nullptr; } } if (pprofile.pedited) { - if (!partProfile.pedited) { - partProfile.pedited = new ParamsEdited(); + if (!partProfile->pedited) { + partProfile->pedited = new ParamsEdited(); } - *partProfile.pedited = *pprofile.pedited; + *partProfile->pedited = *pprofile.pedited; } else { - if (partProfile.pedited) { - delete partProfile.pedited; - partProfile.pedited = nullptr; + if (partProfile->pedited) { + delete partProfile->pedited; + partProfile->pedited = nullptr; } } } +const rtengine::procparams::ProcParams& Clipboard::getProcParams() const +{ + return *partProfile->pparams; +} + /* * this method copy the procparams to "pparams" and delete "pedited" */ -void Clipboard::setProcParams (const rtengine::procparams::ProcParams& pparams) +void Clipboard::setProcParams(const rtengine::procparams::ProcParams& pparams) { // copy procparams - if (!partProfile.pparams) { - partProfile.pparams = new rtengine::procparams::ProcParams(); + if (!partProfile->pparams) { + partProfile->pparams = new rtengine::procparams::ProcParams(); } - *partProfile.pparams = pparams; + *partProfile->pparams = pparams; // delete pedited - if (partProfile.pedited) { - delete partProfile.pedited; - partProfile.pedited = nullptr; + if (partProfile->pedited) { + delete partProfile->pedited; + partProfile->pedited = nullptr; } } + +const ParamsEdited& Clipboard::getParamsEdited() const +{ + return *partProfile->pedited; +} + +bool Clipboard::hasProcParams() const +{ + return partProfile->pparams; +} + +bool Clipboard::hasPEdited() const +{ + return partProfile->pedited; +} + +DiagonalCurveType Clipboard::hasDiagonalCurveData() const +{ + return hasDiagonalCurveDataType; +} + +const std::vector& Clipboard::getDiagonalCurveData() const +{ + return diagonalCurve; +} + +void Clipboard::setDiagonalCurveData(const std::vector& p, DiagonalCurveType type) +{ + diagonalCurve = p; + hasDiagonalCurveDataType = type; + return; +} + +FlatCurveType Clipboard::hasFlatCurveData() const +{ + return hasFlatCurveDataType; +} + +const std::vector& Clipboard:: getFlatCurveData() const +{ + return flatCurve; +} + +void Clipboard::setFlatCurveData(const std::vector& p, FlatCurveType type) +{ + flatCurve = p; + hasFlatCurveDataType = type; + return; +} diff --git a/rtgui/clipboard.h b/rtgui/clipboard.h index eff5c08c8..74c9f6770 100644 --- a/rtgui/clipboard.h +++ b/rtgui/clipboard.h @@ -19,96 +19,64 @@ #ifndef _CLIPBOARD_ #define _CLIPBOARD_ +#include #include -#include "../rtengine/rtengine.h" -#include "../rtengine/procparams.h" -#include "paramsedited.h" -#include "myflatcurve.h" + #include "mydiagonalcurve.h" +#include "myflatcurve.h" +#include "paramsedited.h" + +#include "../rtengine/rtengine.h" + +namespace rtengine +{ + +namespace procparams +{ + +class PartialProfile; + +} + +} class Clipboard { +public: + Clipboard (); + ~Clipboard (); + bool hasIPTC() const; + const rtengine::procparams::IPTCPairs& getIPTC() const; + void setIPTC(const rtengine::procparams::IPTCPairs& iptcc); + + const rtengine::procparams::PartialProfile& getPartialProfile() const; + void setPartialProfile(const rtengine::procparams::PartialProfile& pprofile); + + const rtengine::procparams::ProcParams& getProcParams() const; + void setProcParams(const rtengine::procparams::ProcParams& pparams); + + const ParamsEdited& getParamsEdited() const; + + bool hasProcParams() const; + bool hasPEdited() const; + + DiagonalCurveType hasDiagonalCurveData() const; + const std::vector& getDiagonalCurveData() const; + void setDiagonalCurveData(const std::vector& p, DiagonalCurveType type); + + void setFlatCurveData(const std::vector& p, FlatCurveType type); + const std::vector& getFlatCurveData() const; + FlatCurveType hasFlatCurveData() const; + +private: bool _hasIPTC; - rtengine::procparams::IPTCPairs iptc; - rtengine::procparams::PartialProfile partProfile; + const std::unique_ptr iptc; + const std::unique_ptr partProfile; DiagonalCurveType hasDiagonalCurveDataType; FlatCurveType hasFlatCurveDataType; std::vector diagonalCurve; std::vector flatCurve; - - -public: - void setIPTC (const rtengine::procparams::IPTCPairs& iptcc) - { - iptc = iptcc; - _hasIPTC = true; - } - const rtengine::procparams::IPTCPairs& getIPTC () - { - return iptc; - } - bool hasIPTC () - { - return _hasIPTC; - } - - void setPartialProfile (const rtengine::procparams::PartialProfile& pprofile); - const rtengine::procparams::PartialProfile& getPartialProfile () - { - return partProfile; - }; - void setProcParams (const rtengine::procparams::ProcParams& pparams); - const rtengine::procparams::ProcParams& getProcParams () - { - return *partProfile.pparams; - } - const ParamsEdited& getParamsEdited () - { - return *partProfile.pedited; - } - bool hasProcParams () - { - return partProfile.pparams; - } - bool hasPEdited () - { - return partProfile.pedited; - } - - void setDiagonalCurveData (std::vector& p, DiagonalCurveType type ) - { - diagonalCurve = p; - hasDiagonalCurveDataType = type; - return; - } - const std::vector & getDiagonalCurveData () - { - return diagonalCurve; - } - DiagonalCurveType hasDiagonalCurveData () - { - return hasDiagonalCurveDataType; - } - - void setFlatCurveData (std::vector& p, FlatCurveType type ) - { - flatCurve = p; - hasFlatCurveDataType = type; - return; - } - const std::vector & getFlatCurveData () - { - return flatCurve; - } - FlatCurveType hasFlatCurveData () - { - return hasFlatCurveDataType; - } - - Clipboard (); - ~Clipboard (); - }; extern Clipboard clipboard; diff --git a/rtgui/coarsepanel.cc b/rtgui/coarsepanel.cc index 8f927239e..92c312554 100644 --- a/rtgui/coarsepanel.cc +++ b/rtgui/coarsepanel.cc @@ -17,8 +17,11 @@ * along with RawTherapee. If not, see . */ #include "coarsepanel.h" + #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/colorappearance.cc b/rtgui/colorappearance.cc index dea55ced4..f78a1f32b 100644 --- a/rtgui/colorappearance.cc +++ b/rtgui/colorappearance.cc @@ -16,10 +16,14 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "colorappearance.h" #include + +#include "colorappearance.h" + #include "guiutils.h" + #include "../rtengine/color.h" +#include "../rtengine/procparams.h" #define MINTEMP0 2000 //1200 #define MAXTEMP0 12000 //12000 diff --git a/rtgui/crop.cc b/rtgui/crop.cc index 1cd87b80a..de693d399 100644 --- a/rtgui/crop.cc +++ b/rtgui/crop.cc @@ -17,9 +17,12 @@ * along with RawTherapee. If not, see . */ #include "crop.h" + #include "options.h" #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/crophandler.h b/rtgui/crophandler.h index f0e121e5e..e0b48d348 100644 --- a/rtgui/crophandler.h +++ b/rtgui/crophandler.h @@ -106,8 +106,8 @@ public: void update (); - std::unique_ptr cropParams; - std::unique_ptr colorParams; + const std::unique_ptr cropParams; + const std::unique_ptr colorParams; Glib::RefPtr cropPixbuf; // image displayed on monitor, using the monitor profile (i.e. lab to monitor profile) Glib::RefPtr cropPixbuftrue; // internal image in output color space for analysis (i.e. lab to either Working profile or Output profile, depending on options.rtSettings.HistogramWorking) diff --git a/rtgui/darkframe.cc b/rtgui/darkframe.cc index d0f2e9ed0..77e9c53a6 100644 --- a/rtgui/darkframe.cc +++ b/rtgui/darkframe.cc @@ -16,12 +16,16 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "darkframe.h" -#include "options.h" -#include "guiutils.h" #include + +#include "darkframe.h" + +#include "guiutils.h" +#include "options.h" #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/defringe.cc b/rtgui/defringe.cc index 6a3d11d76..7d29b8c8f 100644 --- a/rtgui/defringe.cc +++ b/rtgui/defringe.cc @@ -16,9 +16,12 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "defringe.h" -#include #include +#include + +#include "defringe.h" + +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/dehaze.cc b/rtgui/dehaze.cc index 0f0892ac6..8204210db 100644 --- a/rtgui/dehaze.cc +++ b/rtgui/dehaze.cc @@ -17,10 +17,14 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "dehaze.h" -#include "eventmapper.h" -#include #include +#include + +#include "dehaze.h" + +#include "eventmapper.h" + +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/dirpyrdenoise.cc b/rtgui/dirpyrdenoise.cc index 613dc8d44..7be07420e 100644 --- a/rtgui/dirpyrdenoise.cc +++ b/rtgui/dirpyrdenoise.cc @@ -16,12 +16,16 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "dirpyrdenoise.h" -#include #include +#include + +#include "dirpyrdenoise.h" + #include "edit.h" #include "guiutils.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; extern Options options; diff --git a/rtgui/distortion.cc b/rtgui/distortion.cc index d1d097269..0ac067ba8 100644 --- a/rtgui/distortion.cc +++ b/rtgui/distortion.cc @@ -16,10 +16,14 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "distortion.h" #include + +#include "distortion.h" + #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/epd.cc b/rtgui/epd.cc index 675a5b9b9..4b7cca10a 100644 --- a/rtgui/epd.cc +++ b/rtgui/epd.cc @@ -16,9 +16,12 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "epd.h" -#include #include +#include + +#include "epd.h" + +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/exifpanel.cc b/rtgui/exifpanel.cc index be5d5dc4c..1882f4377 100644 --- a/rtgui/exifpanel.cc +++ b/rtgui/exifpanel.cc @@ -21,13 +21,17 @@ #include "guiutils.h" #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; using namespace rtexif; -ExifPanel::ExifPanel () : idata (nullptr) +ExifPanel::ExifPanel() : + idata(nullptr), + changeList(new rtengine::procparams::ExifPairs), + defChangeList(new rtengine::procparams::ExifPairs) { - recursiveOp = true; exifTree = Gtk::manage (new Gtk::TreeView()); @@ -166,7 +170,7 @@ void ExifPanel::read (const ProcParams* pp, const ParamsEdited* pedited) disableListener (); - changeList = pp->exif; + *changeList = pp->exif; setImageData (idata); applyChangeList (); exifSelectionChanged (); @@ -178,13 +182,13 @@ void ExifPanel::write (ProcParams* pp, ParamsEdited* pedited) { // updateChangeList (); - pp->exif = changeList; + pp->exif = *changeList; } void ExifPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { - defChangeList = defParams->exif; + *defChangeList = defParams->exif; } void ExifPanel::setImageData (const FramesMetaData* id) @@ -457,7 +461,7 @@ void ExifPanel::resetAllPressed () { setImageData (idata); - changeList = defChangeList; + *changeList = *defChangeList; applyChangeList (); exifSelectionChanged (); notifyListener (); @@ -661,11 +665,11 @@ void ExifPanel::updateChangeList (Gtk::TreeModel::Children root, std::string pre for (iter = root.begin(); iter != root.end(); ++iter) { if (iter->get_value (exifColumns.edited)) { - changeList[ prefix + iter->get_value (exifColumns.field_nopango) ] = iter->get_value (exifColumns.value_nopango); + (*changeList)[ prefix + iter->get_value (exifColumns.field_nopango) ] = iter->get_value (exifColumns.value_nopango); } else if (iter->get_value (exifColumns.action) == AC_WRITE && iter->get_value (exifColumns.icon) == delicon) { - changeList[ prefix + iter->get_value (exifColumns.field_nopango) ] = "#delete"; + (*changeList)[ prefix + iter->get_value (exifColumns.field_nopango) ] = "#delete"; } else if (iter->get_value (exifColumns.action) == AC_DONTWRITE && iter->get_value (exifColumns.icon) == keepicon) { - changeList[ prefix + iter->get_value (exifColumns.field_nopango) ] = "#keep"; + (*changeList)[ prefix + iter->get_value (exifColumns.field_nopango) ] = "#keep"; } if (iter->get_value (exifColumns.icon) == keepicon) { @@ -677,14 +681,14 @@ void ExifPanel::updateChangeList (Gtk::TreeModel::Children root, std::string pre void ExifPanel::updateChangeList () { - changeList.clear (); + changeList->clear (); updateChangeList (exifTreeModel->children(), ""); } void ExifPanel::applyChangeList () { - for (rtengine::procparams::ExifPairs::const_iterator i = changeList.begin(); i != changeList.end(); ++i) { + for (rtengine::procparams::ExifPairs::const_iterator i = changeList->begin(); i != changeList->end(); ++i) { editTag (exifTreeModel->children(), i->first, i->second); } } diff --git a/rtgui/exifpanel.h b/rtgui/exifpanel.h index cd27cb780..c8597a287 100644 --- a/rtgui/exifpanel.h +++ b/rtgui/exifpanel.h @@ -19,7 +19,10 @@ #ifndef _EXIFPANEL_ #define _EXIFPANEL_ +#include + #include + #include "toolpanel.h" class ExifPanel : public Gtk::VBox, public ToolPanel @@ -27,8 +30,8 @@ class ExifPanel : public Gtk::VBox, public ToolPanel private: const rtengine::FramesMetaData* idata; - rtengine::procparams::ExifPairs changeList; - rtengine::procparams::ExifPairs defChangeList; + const std::unique_ptr changeList; + const std::unique_ptr defChangeList; bool recursiveOp; class ExifColumns : public Gtk::TreeModelColumnRecord diff --git a/rtgui/fattaltonemap.cc b/rtgui/fattaltonemap.cc index 3a6a15a4d..85d835cc7 100644 --- a/rtgui/fattaltonemap.cc +++ b/rtgui/fattaltonemap.cc @@ -17,10 +17,15 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "fattaltonemap.h" -#include "eventmapper.h" -#include #include +#include + +#include "fattaltonemap.h" + +#include "eventmapper.h" + +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index d489bb1d3..2a576013a 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -18,19 +18,24 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "filebrowser.h" #include + #include -#include "options.h" -#include "multilangmgr.h" -#include "clipboard.h" -#include "procparamchangers.h" + +#include "filebrowser.h" + #include "batchqueue.h" -#include "../rtengine/dfmanager.h" -#include "../rtengine/ffmanager.h" +#include "clipboard.h" +#include "multilangmgr.h" +#include "options.h" +#include "procparamchangers.h" #include "rtimage.h" #include "threadutils.h" +#include "../rtengine/dfmanager.h" +#include "../rtengine/ffmanager.h" +#include "../rtengine/procparams.h" + extern Options options; namespace diff --git a/rtgui/filebrowserentry.h b/rtgui/filebrowserentry.h index 770889d88..3a3d32977 100644 --- a/rtgui/filebrowserentry.h +++ b/rtgui/filebrowserentry.h @@ -56,7 +56,7 @@ class FileBrowserEntry : public ThumbBrowserEntryBase, int press_x, press_y, action_x, action_y; double rot_deg; bool landscape; - std::unique_ptr cropParams; + const std::unique_ptr cropParams; CropGUIListener* cropgl; FileBrowserEntryIdleHelper* feih; diff --git a/rtgui/filmsimulation.cc b/rtgui/filmsimulation.cc index f929048b8..e354724ba 100644 --- a/rtgui/filmsimulation.cc +++ b/rtgui/filmsimulation.cc @@ -1,12 +1,13 @@ +#include #include #include #include "filmsimulation.h" -#include - #include "options.h" + #include "../rtengine/clutstore.h" +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/flatfield.cc b/rtgui/flatfield.cc index 86d27aacf..3cbd7acf1 100644 --- a/rtgui/flatfield.cc +++ b/rtgui/flatfield.cc @@ -16,12 +16,16 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "flatfield.h" -#include "options.h" -#include "guiutils.h" #include + +#include "flatfield.h" + +#include "guiutils.h" +#include "options.h" #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc index 5091d3637..fd99e9939 100644 --- a/rtgui/gradient.cc +++ b/rtgui/gradient.cc @@ -2,7 +2,10 @@ * This file is part of RawTherapee. */ #include "gradient.h" + #include "rtimage.h" + +#include "../rtengine/procparams.h" #include "../rtengine/rt_math.h" using namespace rtengine; diff --git a/rtgui/history.cc b/rtgui/history.cc index 35f99db5b..4d435c460 100644 --- a/rtgui/history.cc +++ b/rtgui/history.cc @@ -17,10 +17,13 @@ * along with RawTherapee. If not, see . */ #include "history.h" + +#include "eventmapper.h" +#include "guiutils.h" #include "multilangmgr.h" #include "rtimage.h" -#include "guiutils.h" -#include "eventmapper.h" + +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/hsvequalizer.cc b/rtgui/hsvequalizer.cc index 1dfb017a7..7db76aa9f 100644 --- a/rtgui/hsvequalizer.cc +++ b/rtgui/hsvequalizer.cc @@ -16,9 +16,10 @@ * * 2010 Ilya Popov */ - #include "hsvequalizer.h" + #include "../rtengine/color.h" +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index bb7fdd89b..ba8bf9cef 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -17,15 +17,18 @@ * along with RawTherapee. If not, see . */ #include -#include "icmpanel.h" -#include "options.h" -#include "eventmapper.h" +#include "icmpanel.h" + +#include "eventmapper.h" #include "guiutils.h" -#include "../rtengine/iccstore.h" -#include "../rtengine/dcp.h" +#include "options.h" #include "rtimage.h" +#include "../rtengine/dcp.h" +#include "../rtengine/iccstore.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/impulsedenoise.cc b/rtgui/impulsedenoise.cc index 3e5a9a980..9203ce8a7 100644 --- a/rtgui/impulsedenoise.cc +++ b/rtgui/impulsedenoise.cc @@ -16,11 +16,15 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "impulsedenoise.h" #include #include + +#include "impulsedenoise.h" + #include "guiutils.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/iptcpanel.cc b/rtgui/iptcpanel.cc index 5065452b0..7347927a0 100644 --- a/rtgui/iptcpanel.cc +++ b/rtgui/iptcpanel.cc @@ -20,10 +20,15 @@ #include "clipboard.h" #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; -IPTCPanel::IPTCPanel () +IPTCPanel::IPTCPanel () : + changeList(new rtengine::procparams::IPTCPairs), + defChangeList(new rtengine::procparams::IPTCPairs), + embeddedData(new rtengine::procparams::IPTCPairs) { set_spacing (4); @@ -410,12 +415,12 @@ void IPTCPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { disableListener (); - changeList.clear(); + changeList->clear(); if (!pp->iptc.empty()) { - changeList = pp->iptc; + *changeList = pp->iptc; } else { - changeList = embeddedData; + *changeList = *embeddedData; } applyChangeList (); @@ -425,25 +430,25 @@ void IPTCPanel::read (const ProcParams* pp, const ParamsEdited* pedited) void IPTCPanel::write (ProcParams* pp, ParamsEdited* pedited) { - pp->iptc = changeList; + pp->iptc = *changeList; } void IPTCPanel::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { - defChangeList = defParams->iptc; + *defChangeList = defParams->iptc; } void IPTCPanel::setImageData (const FramesMetaData* id) { if (id) { - embeddedData = id->getIPTCData (); + *embeddedData = id->getIPTCData (); } else { - embeddedData.clear (); + embeddedData->clear (); } - file->set_sensitive (!embeddedData.empty()); + file->set_sensitive (!embeddedData->empty()); } void IPTCPanel::notifyListener () @@ -564,33 +569,33 @@ void IPTCPanel::delSuppCategory () void IPTCPanel::updateChangeList () { - changeList.clear (); - changeList["Caption" ].push_back (captionText->get_text ()); - changeList["CaptionWriter" ].push_back (captionWriter->get_text ()); - changeList["Headline" ].push_back (headline->get_text ()); - changeList["Instructions" ].push_back (instructions->get_text ()); + changeList->clear (); + (*changeList)["Caption" ].push_back (captionText->get_text ()); + (*changeList)["CaptionWriter" ].push_back (captionWriter->get_text ()); + (*changeList)["Headline" ].push_back (headline->get_text ()); + (*changeList)["Instructions" ].push_back (instructions->get_text ()); for (unsigned int i = 0; i < keywords->size(); i++) { - changeList["Keywords" ].push_back (keywords->get_text (i)); + (*changeList)["Keywords" ].push_back (keywords->get_text (i)); } - changeList["Category" ].push_back (category->get_entry()->get_text ()); + (*changeList)["Category" ].push_back (category->get_entry()->get_text ()); for (unsigned int i = 0; i < suppCategories->size(); i++) { - changeList["SupplementalCategories"].push_back (suppCategories->get_text (i)); + (*changeList)["SupplementalCategories"].push_back (suppCategories->get_text (i)); } - changeList["Creator" ].push_back (creator->get_text ()); - changeList["CreatorJobTitle"].push_back (creatorJobTitle->get_text ()); - changeList["Credit" ].push_back (credit->get_text ()); - changeList["Source" ].push_back (source->get_text ()); - changeList["Copyright" ].push_back (copyright->get_text ()); - changeList["City" ].push_back (city->get_text ()); - changeList["Province" ].push_back (province->get_text ()); - changeList["Country" ].push_back (country->get_text ()); - changeList["Title" ].push_back (title->get_text ()); - changeList["DateCreated" ].push_back (dateCreated->get_text ()); - changeList["TransReference" ].push_back (transReference->get_text ()); + (*changeList)["Creator" ].push_back (creator->get_text ()); + (*changeList)["CreatorJobTitle"].push_back (creatorJobTitle->get_text ()); + (*changeList)["Credit" ].push_back (credit->get_text ()); + (*changeList)["Source" ].push_back (source->get_text ()); + (*changeList)["Copyright" ].push_back (copyright->get_text ()); + (*changeList)["City" ].push_back (city->get_text ()); + (*changeList)["Province" ].push_back (province->get_text ()); + (*changeList)["Country" ].push_back (country->get_text ()); + (*changeList)["Title" ].push_back (title->get_text ()); + (*changeList)["DateCreated" ].push_back (dateCreated->get_text ()); + (*changeList)["TransReference" ].push_back (transReference->get_text ()); notifyListener (); } @@ -623,7 +628,7 @@ void IPTCPanel::applyChangeList () keyword->get_entry()->set_text (""); suppCategory->get_entry()->set_text (""); - for (rtengine::procparams::IPTCPairs::const_iterator i = changeList.begin(); i != changeList.end(); ++i) { + for (rtengine::procparams::IPTCPairs::const_iterator i = changeList->begin(); i != changeList->end(); ++i) { if (i->first == "Caption" && !i->second.empty()) { captionText->set_text (i->second.at(0)); } else if (i->first == "CaptionWriter" && !i->second.empty()) { @@ -676,7 +681,7 @@ void IPTCPanel::resetClicked () { disableListener (); - changeList = defChangeList; + *changeList = *defChangeList; applyChangeList (); enableListener (); notifyListener (); @@ -686,7 +691,7 @@ void IPTCPanel::fileClicked () { disableListener (); - changeList = embeddedData; + *changeList = *embeddedData; applyChangeList (); enableListener (); notifyListener (); @@ -695,14 +700,14 @@ void IPTCPanel::fileClicked () void IPTCPanel::copyClicked () { - clipboard.setIPTC (changeList); + clipboard.setIPTC (*changeList); } void IPTCPanel::pasteClicked () { disableListener (); - changeList = clipboard.getIPTC (); + *changeList = clipboard.getIPTC (); applyChangeList (); enableListener (); notifyListener (); diff --git a/rtgui/iptcpanel.h b/rtgui/iptcpanel.h index 5574fe884..25683ccec 100644 --- a/rtgui/iptcpanel.h +++ b/rtgui/iptcpanel.h @@ -19,17 +19,20 @@ #ifndef _IPTCPANEL_ #define _IPTCPANEL_ +#include + #include -#include "toolpanel.h" + #include "guiutils.h" +#include "toolpanel.h" class IPTCPanel : public Gtk::VBox, public ToolPanel { private: - rtengine::procparams::IPTCPairs changeList; - rtengine::procparams::IPTCPairs defChangeList; - rtengine::procparams::IPTCPairs embeddedData; + const std::unique_ptr changeList; + const std::unique_ptr defChangeList; + const std::unique_ptr embeddedData; Gtk::TextView* captionView; Glib::RefPtr captionText; diff --git a/rtgui/labcurve.cc b/rtgui/labcurve.cc index 2e851c321..e73fa31e0 100644 --- a/rtgui/labcurve.cc +++ b/rtgui/labcurve.cc @@ -16,11 +16,15 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "labcurve.h" #include -#include "../rtengine/improcfun.h" + +#include "labcurve.h" + #include "edit.h" +#include "../rtengine/improcfun.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/lensgeom.cc b/rtgui/lensgeom.cc index 898fa1105..baf816c8b 100644 --- a/rtgui/lensgeom.cc +++ b/rtgui/lensgeom.cc @@ -20,6 +20,8 @@ #include "guiutils.h" #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/lensprofile.cc b/rtgui/lensprofile.cc index d421632a9..85dcb992a 100644 --- a/rtgui/lensprofile.cc +++ b/rtgui/lensprofile.cc @@ -16,15 +16,20 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include -#include "lensprofile.h" -#include "guiutils.h" -#include "../rtengine/lcp.h" -#include -#include "rtimage.h" -#include "../rtengine/rtlensfun.h" #include #include +#include + +#include + +#include "lensprofile.h" + +#include "guiutils.h" +#include "rtimage.h" + +#include "../rtengine/lcp.h" +#include "../rtengine/procparams.h" +#include "../rtengine/rtlensfun.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/localcontrast.cc b/rtgui/localcontrast.cc index 2be811a99..93b67657d 100644 --- a/rtgui/localcontrast.cc +++ b/rtgui/localcontrast.cc @@ -17,10 +17,14 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "localcontrast.h" -#include "eventmapper.h" -#include #include +#include + +#include "localcontrast.h" + +#include "eventmapper.h" + +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 5d7396f19..b93b3123b 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -16,10 +16,14 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "paramsedited.h" #include -#include "options.h" + +#include "paramsedited.h" + #include "addsetids.h" +#include "options.h" + +#include "../rtengine/procparams.h" ParamsEdited::ParamsEdited(bool value) { diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 0bad2ab3c..49052cbdf 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -16,27 +16,19 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#ifndef _PARAMEDITED_H_ -#define _PARAMEDITED_H_ +#pragma once -#include #include -#include "../rtengine/procparams.h" + #include "../rtengine/rtengine.h" -class GeneralParamsEdited -{ - -public: +struct GeneralParamsEdited { bool rank; bool colorlabel; bool intrash; }; -class ToneCurveParamsEdited -{ - -public: +struct ToneCurveParamsEdited { bool curve; bool curve2; bool curveMode; @@ -58,9 +50,7 @@ public: bool clampOOG; }; -class RetinexParamsEdited -{ -public: +struct RetinexParamsEdited { bool enabled; bool str; bool scal; @@ -90,19 +80,17 @@ public: bool lhcurve; bool retinex; bool medianmap; - bool isUnchanged() const; bool highlights; bool htonalwidth; bool shadows; bool stonalwidth; bool radius; + bool isUnchanged() const; }; -class LCurveParamsEdited -{ -public: +struct LCurveParamsEdited { bool enabled; bool brightness; bool contrast; @@ -122,9 +110,7 @@ public: }; -class LocalContrastParamsEdited -{ -public: +struct LocalContrastParamsEdited { bool enabled; bool radius; bool amount; @@ -132,11 +118,7 @@ public: bool lightness; }; - -class RGBCurvesParamsEdited -{ - -public: +struct RGBCurvesParamsEdited { bool enabled; bool lumamode; bool rcurve; @@ -144,10 +126,7 @@ public: bool bcurve; }; -class ColorToningEdited -{ - -public: +struct ColorToningEdited { bool enabled; bool opacityCurve; bool colorCurve; @@ -182,31 +161,22 @@ public: bool labregionsShowMask; }; -class SharpenEdgeParamsEdited -{ - -public : +struct SharpenEdgeParamsEdited { bool enabled; bool passes; bool amount; bool threechannels; }; -class SharpenMicroParamsEdited -{ -public : +struct SharpenMicroParamsEdited { bool enabled; bool matrix; bool amount; bool contrast; bool uniformity; - }; -class SharpeningParamsEdited -{ - -public: +struct SharpeningParamsEdited { bool enabled; bool contrast; bool blurradius; @@ -226,10 +196,7 @@ public: bool deconvdamping; }; -class VibranceParamsEdited -{ - -public: +struct VibranceParamsEdited { bool enabled; bool pastels; bool saturated; @@ -240,19 +207,7 @@ public: bool skintonescurve; }; -/*class ColorBoostParamsEdited { - - public: - bool amount; - bool avoidclip; - bool enable_saturationlimiter; - bool rstprotection; -};*/ - -class WBParamsEdited -{ - -public: +struct WBParamsEdited { bool enabled; bool method; bool temperature; @@ -261,50 +216,19 @@ public: bool tempBias; }; -/*class ColorShiftParamsEdited { - - public: - bool a; - bool b; -};*/ - -/*class LumaDenoiseParamsEdited { - - public: - bool enabled; - bool radius; - bool edgetolerance; -};*/ - -/*class ColorDenoiseParamsEdited { - - public: - bool enabled; - bool amount; -};*/ - -class DefringeParamsEdited -{ - -public: +struct DefringeParamsEdited { bool enabled; bool radius; bool threshold; bool huecurve; }; -class ImpulseDenoiseParamsEdited -{ - -public: +struct ImpulseDenoiseParamsEdited { bool enabled; bool thresh; }; -class ColorAppearanceParamsEdited -{ - -public: +struct ColorAppearanceParamsEdited { bool curve; bool curve2; bool curve3; @@ -337,22 +261,16 @@ public: bool rstprotection; bool surrsource; bool gamut; -// bool badpix; bool datacie; bool tonecie; -// bool sharpcie; bool tempout; bool greenout; bool ybout; bool tempsc; bool greensc; - }; -class DirPyrDenoiseParamsEdited -{ - -public: +struct DirPyrDenoiseParamsEdited { bool enabled; bool enhance; bool median; @@ -365,7 +283,6 @@ public: bool lcurve; bool cccurve; -// bool perform; bool dmethod; bool Lmethod; bool Cmethod; @@ -375,12 +292,9 @@ public: bool methodmed; bool rgbmethod; bool passes; - }; -class EPDParamsEdited -{ -public: +struct EPDParamsEdited { bool enabled; bool strength; bool gamma; @@ -389,21 +303,14 @@ public: bool reweightingIterates; }; - -class FattalToneMappingParamsEdited -{ -public: +struct FattalToneMappingParamsEdited { bool enabled; bool threshold; bool amount; bool anchor; }; - -class SHParamsEdited -{ - -public: +struct SHParamsEdited { bool enabled; bool highlights; bool htonalwidth; @@ -413,10 +320,7 @@ public: bool lab; }; -class CropParamsEdited -{ - -public: +struct CropParamsEdited { bool enabled; bool x; bool y; @@ -428,58 +332,47 @@ public: bool guide; }; -class CoarseTransformParamsEdited -{ - -public: +struct CoarseTransformParamsEdited { bool rotate; bool hflip; bool vflip; }; -class CommonTransformParamsEdited -{ - -public: +struct CommonTransformParamsEdited { bool autofill; }; -class RotateParamsEdited -{ - -public: +struct RotateParamsEdited { bool degree; }; -class DistortionParamsEdited -{ - -public: +struct DistortionParamsEdited { bool amount; }; -class LensProfParamsEdited -{ -public: - bool lcpFile, useDist, useVign, useCA; - bool useLensfun, lfAutoMatch, lfCameraMake, lfCameraModel, lfLens; +struct LensProfParamsEdited { + bool lcpFile; + bool useDist; + bool useVign; + bool useCA; + + bool useLensfun; + bool lfAutoMatch; + bool lfCameraMake; + bool lfCameraModel; + bool lfLens; + bool lcMode; bool isUnchanged() const; }; -class PerspectiveParamsEdited -{ - -public: +struct PerspectiveParamsEdited { bool horizontal; bool vertical; }; -class GradientParamsEdited -{ - -public: +struct GradientParamsEdited { bool enabled; bool degree; bool feather; @@ -488,20 +381,14 @@ public: bool centerY; }; -class PCVignetteParamsEdited -{ - -public: +struct PCVignetteParamsEdited { bool enabled; bool strength; bool feather; bool roundness; }; -class VignettingParamsEdited -{ - -public: +struct VignettingParamsEdited { bool amount; bool radius; bool strength; @@ -509,20 +396,15 @@ public: bool centerY; }; -class ChannelMixerParamsEdited -{ - -public: +struct ChannelMixerParamsEdited { bool enabled; bool red[3]; bool green[3]; bool blue[3]; }; -class BlackWhiteParamsEdited -{ -public: +struct BlackWhiteParamsEdited { bool enabledcc; bool enabled; bool method; @@ -546,28 +428,14 @@ public: bool afterCurveMode; bool autoc; bool algo; - }; -class CACorrParamsEdited -{ - -public: +struct CACorrParamsEdited { bool red; bool blue; }; -/* -class HRecParamsEdited { - public: - bool enabled; - bool method; -}; -*/ -class ResizeParamsEdited -{ - -public: +struct ResizeParamsEdited { bool scale; bool appliesTo; bool method; @@ -578,10 +446,7 @@ public: bool allowUpscaling; }; -class ColorManagementParamsEdited -{ - -public: +struct ColorManagementParamsEdited { bool inputProfile; bool toneCurve; bool applyLookTable; @@ -598,10 +463,8 @@ public: bool outputIntent; bool outputBPC; }; -class WaveletParamsEdited -{ -public: +struct WaveletParamsEdited { bool enabled; bool strength; bool balance; @@ -685,13 +548,9 @@ public: bool expfinal; bool exptoning; bool expnoise; - }; -class DirPyrEqualizerParamsEdited -{ - -public: +struct DirPyrEqualizerParamsEdited { bool enabled; bool gamutlab; bool mult[6]; @@ -699,52 +558,35 @@ public: bool threshold; bool skinprotect; bool hueskin; - // bool algo; }; -class HSVEqualizerParamsEdited -{ - -public: +struct HSVEqualizerParamsEdited { bool enabled; bool hcurve; bool scurve; bool vcurve; }; -class FilmSimulationParamsEdited -{ -public: +struct FilmSimulationParamsEdited { bool enabled; bool clutFilename; bool strength; }; -class SoftLightParamsEdited -{ -public: +struct SoftLightParamsEdited { bool enabled; bool strength; }; -class DehazeParamsEdited -{ -public: +struct DehazeParamsEdited { bool enabled; bool strength; bool showDepthMap; bool depth; }; - -class RAWParamsEdited -{ - -public: - class BayerSensor - { - - public: +struct RAWParamsEdited { + struct BayerSensor { bool method; bool border; bool imageNum; @@ -774,7 +616,6 @@ public: bool pixelShiftNonGreenCross; bool pixelShiftDemosaicMethod; - //bool allEnhance; bool greenEq; bool linenoise; bool linenoiseDirection; @@ -783,10 +624,7 @@ public: bool isUnchanged() const; }; - class XTransSensor - { - - public: + struct XTransSensor { bool method; bool dualDemosaicAutoContrast; bool dualDemosaicContrast; @@ -823,66 +661,56 @@ public: }; -class MetaDataParamsEdited -{ -public: +struct MetaDataParamsEdited { bool mode; }; - -class ParamsEdited -{ - -public: - GeneralParamsEdited general; - ToneCurveParamsEdited toneCurve; - LCurveParamsEdited labCurve; - LocalContrastParamsEdited localContrast; - RGBCurvesParamsEdited rgbCurves; - ColorToningEdited colorToning; - RetinexParamsEdited retinex; - SharpeningParamsEdited sharpening; - SharpeningParamsEdited prsharpening; - SharpenEdgeParamsEdited sharpenEdge; - SharpenMicroParamsEdited sharpenMicro; - VibranceParamsEdited vibrance; - ColorAppearanceParamsEdited colorappearance; - //ColorBoostParamsEdited colorBoost; - WBParamsEdited wb; - //ColorShiftParamsEdited colorShift; - //LumaDenoiseParamsEdited lumaDenoise; - //ColorDenoiseParamsEdited colorDenoise; - DefringeParamsEdited defringe; - DirPyrDenoiseParamsEdited dirpyrDenoise; - EPDParamsEdited epd; +struct ParamsEdited { + GeneralParamsEdited general; + ToneCurveParamsEdited toneCurve; + LCurveParamsEdited labCurve; + LocalContrastParamsEdited localContrast; + RGBCurvesParamsEdited rgbCurves; + ColorToningEdited colorToning; + RetinexParamsEdited retinex; + SharpeningParamsEdited sharpening; + SharpeningParamsEdited prsharpening; + SharpenEdgeParamsEdited sharpenEdge; + SharpenMicroParamsEdited sharpenMicro; + VibranceParamsEdited vibrance; + ColorAppearanceParamsEdited colorappearance; + WBParamsEdited wb; + DefringeParamsEdited defringe; + DirPyrDenoiseParamsEdited dirpyrDenoise; + EPDParamsEdited epd; FattalToneMappingParamsEdited fattal; - ImpulseDenoiseParamsEdited impulseDenoise; - SHParamsEdited sh; - CropParamsEdited crop; - CoarseTransformParamsEdited coarse; - CommonTransformParamsEdited commonTrans; - RotateParamsEdited rotate; - DistortionParamsEdited distortion; - LensProfParamsEdited lensProf; - PerspectiveParamsEdited perspective; - GradientParamsEdited gradient; - PCVignetteParamsEdited pcvignette; - CACorrParamsEdited cacorrection; - VignettingParamsEdited vignetting; - ChannelMixerParamsEdited chmixer; - BlackWhiteParamsEdited blackwhite; - ResizeParamsEdited resize; - ColorManagementParamsEdited icm; - RAWParamsEdited raw; - DirPyrEqualizerParamsEdited dirpyrequalizer; - WaveletParamsEdited wavelet; - HSVEqualizerParamsEdited hsvequalizer; - FilmSimulationParamsEdited filmSimulation; - SoftLightParamsEdited softlight; - DehazeParamsEdited dehaze; - MetaDataParamsEdited metadata; - bool exif; - bool iptc; + ImpulseDenoiseParamsEdited impulseDenoise; + SHParamsEdited sh; + CropParamsEdited crop; + CoarseTransformParamsEdited coarse; + CommonTransformParamsEdited commonTrans; + RotateParamsEdited rotate; + DistortionParamsEdited distortion; + LensProfParamsEdited lensProf; + PerspectiveParamsEdited perspective; + GradientParamsEdited gradient; + PCVignetteParamsEdited pcvignette; + CACorrParamsEdited cacorrection; + VignettingParamsEdited vignetting; + ChannelMixerParamsEdited chmixer; + BlackWhiteParamsEdited blackwhite; + ResizeParamsEdited resize; + ColorManagementParamsEdited icm; + RAWParamsEdited raw; + DirPyrEqualizerParamsEdited dirpyrequalizer; + WaveletParamsEdited wavelet; + HSVEqualizerParamsEdited hsvequalizer; + FilmSimulationParamsEdited filmSimulation; + SoftLightParamsEdited softlight; + DehazeParamsEdited dehaze; + MetaDataParamsEdited metadata; + bool exif; + bool iptc; explicit ParamsEdited(bool value = false); @@ -890,4 +718,3 @@ public: void initFrom(const std::vector& src); void combine(rtengine::procparams::ProcParams& toEdit, const rtengine::procparams::ProcParams& mods, bool forceSet); }; -#endif diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index 9f92707bb..0325fa063 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -22,7 +22,7 @@ #include #include "../rtengine/rtengine.h" -class ParamsEdited; +struct ParamsEdited; class PartialPasteDlg : public Gtk::Dialog { diff --git a/rtgui/pcvignette.cc b/rtgui/pcvignette.cc index 3d668fed9..303ae5cfb 100644 --- a/rtgui/pcvignette.cc +++ b/rtgui/pcvignette.cc @@ -3,6 +3,8 @@ */ #include "pcvignette.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/perspective.cc b/rtgui/perspective.cc index db5e0c50b..db2f32248 100644 --- a/rtgui/perspective.cc +++ b/rtgui/perspective.cc @@ -17,8 +17,11 @@ * along with RawTherapee. If not, see . */ #include "perspective.h" + #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/preprocess.cc b/rtgui/preprocess.cc index 9ad0953af..0d8933a98 100644 --- a/rtgui/preprocess.cc +++ b/rtgui/preprocess.cc @@ -16,10 +16,14 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "preprocess.h" -#include "guiutils.h" #include +#include "preprocess.h" + +#include "guiutils.h" + +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/previewhandler.h b/rtgui/previewhandler.h index 4c4a68afc..fcd0a0c5f 100644 --- a/rtgui/previewhandler.h +++ b/rtgui/previewhandler.h @@ -55,7 +55,7 @@ private: protected: rtengine::IImage8* image; - std::unique_ptr cropParams; + const std::unique_ptr cropParams; double previewScale; PreviewHandlerIdleHelper* pih; std::list listeners; diff --git a/rtgui/profilechangelistener.h b/rtgui/profilechangelistener.h index 8e8dc99b5..e333933ea 100644 --- a/rtgui/profilechangelistener.h +++ b/rtgui/profilechangelistener.h @@ -23,6 +23,18 @@ #include "../rtengine/rtengine.h" +namespace rtengine +{ + +namespace procparams +{ + +class PartialProfile; + +} + +} + class ProfileChangeListener { public: diff --git a/rtgui/profilepanel.cc b/rtgui/profilepanel.cc index a3a0f72b7..af39695fa 100644 --- a/rtgui/profilepanel.cc +++ b/rtgui/profilepanel.cc @@ -17,12 +17,15 @@ * along with RawTherapee. If not, see . */ #include "profilepanel.h" -#include "options.h" + #include "clipboard.h" #include "multilangmgr.h" +#include "options.h" #include "profilestorecombobox.h" #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/profilestorecombobox.cc b/rtgui/profilestorecombobox.cc index e7d64f28b..96bbc32fa 100644 --- a/rtgui/profilestorecombobox.cc +++ b/rtgui/profilestorecombobox.cc @@ -24,9 +24,6 @@ #include "toolpanel.h" #include "guiutils.h" -using namespace rtengine; -using namespace rtengine::procparams; - ProfileStoreLabel::ProfileStoreLabel (const ProfileStoreEntry *entry) : Gtk::Label (entry->label), entry (entry) { set_alignment (0, 0.5); diff --git a/rtgui/rawcacorrection.cc b/rtgui/rawcacorrection.cc index 2daeb102f..57b8ff4ac 100644 --- a/rtgui/rawcacorrection.cc +++ b/rtgui/rawcacorrection.cc @@ -17,10 +17,13 @@ * along with RawTherapee. If not, see . */ #include "rawcacorrection.h" + #include "eventmapper.h" #include "guiutils.h" #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/rawexposure.cc b/rtgui/rawexposure.cc index 0c5191476..6f08e64c7 100644 --- a/rtgui/rawexposure.cc +++ b/rtgui/rawexposure.cc @@ -16,10 +16,14 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "rawexposure.h" -#include "guiutils.h" #include +#include "rawexposure.h" + +#include "guiutils.h" + +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/resize.cc b/rtgui/resize.cc index fc0f51191..4635dca50 100644 --- a/rtgui/resize.cc +++ b/rtgui/resize.cc @@ -17,8 +17,11 @@ * along with RawTherapee. If not, see . */ #include "resize.h" -#include "guiutils.h" + #include "eventmapper.h" +#include "guiutils.h" + +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/rgbcurves.cc b/rtgui/rgbcurves.cc index 1ffb8cc46..75af43508 100644 --- a/rtgui/rgbcurves.cc +++ b/rtgui/rgbcurves.cc @@ -18,6 +18,8 @@ */ #include "rgbcurves.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/rotate.cc b/rtgui/rotate.cc index 9f70010df..9f5d665d5 100644 --- a/rtgui/rotate.cc +++ b/rtgui/rotate.cc @@ -16,11 +16,15 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "rotate.h" #include + +#include "rotate.h" + #include "guiutils.h" #include "rtimage.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/sensorbayer.cc b/rtgui/sensorbayer.cc index 8bd36fe32..44afdd2e8 100644 --- a/rtgui/sensorbayer.cc +++ b/rtgui/sensorbayer.cc @@ -20,9 +20,6 @@ #include "guiutils.h" #include "rtimage.h" -using namespace rtengine; -using namespace rtengine::procparams; - SensorBayer::SensorBayer () : FoldableToolPanel(this, "sensorbayer", M("TP_RAW_SENSOR_BAYER_LABEL")) { diff --git a/rtgui/sensorxtrans.cc b/rtgui/sensorxtrans.cc index 3f93e050a..c0a704ebf 100644 --- a/rtgui/sensorxtrans.cc +++ b/rtgui/sensorxtrans.cc @@ -20,9 +20,6 @@ #include "guiutils.h" #include "rtimage.h" -using namespace rtengine; -using namespace rtengine::procparams; - SensorXTrans::SensorXTrans () : FoldableToolPanel(this, "sensorxtrans", M("TP_RAW_SENSOR_XTRANS_LABEL")) { diff --git a/rtgui/shadowshighlights.cc b/rtgui/shadowshighlights.cc index f4ed90138..6fdf6f2f3 100644 --- a/rtgui/shadowshighlights.cc +++ b/rtgui/shadowshighlights.cc @@ -17,8 +17,11 @@ * along with RawTherapee. If not, see . */ #include "shadowshighlights.h" + #include "eventmapper.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/sharpenedge.cc b/rtgui/sharpenedge.cc index 03675a3bf..b6528e4c9 100644 --- a/rtgui/sharpenedge.cc +++ b/rtgui/sharpenedge.cc @@ -16,10 +16,14 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "sharpenedge.h" -#include "guiutils.h" -#include #include +#include + +#include "sharpenedge.h" + +#include "guiutils.h" + +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/sharpenmicro.cc b/rtgui/sharpenmicro.cc index 971f9247a..0b4142677 100644 --- a/rtgui/sharpenmicro.cc +++ b/rtgui/sharpenmicro.cc @@ -18,9 +18,13 @@ */ #include #include + #include "sharpenmicro.h" -#include "guiutils.h" + #include "eventmapper.h" +#include "guiutils.h" + +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/softlight.cc b/rtgui/softlight.cc index 072c45e98..0054f8f6d 100644 --- a/rtgui/softlight.cc +++ b/rtgui/softlight.cc @@ -17,10 +17,14 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "softlight.h" -#include "eventmapper.h" -#include #include +#include + +#include "softlight.h" + +#include "eventmapper.h" + +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/thresholdselector.cc b/rtgui/thresholdselector.cc index 891095e6f..2d94d43de 100644 --- a/rtgui/thresholdselector.cc +++ b/rtgui/thresholdselector.cc @@ -21,9 +21,12 @@ #include #include "thresholdselector.h" + #include "multilangmgr.h" #include "mycurve.h" +#include "../rtengine/procparams.h" + ThresholdSelector::ThresholdSelector(double minValueBottom, double maxValueBottom, double defBottom, Glib::ustring labelBottom, unsigned int precisionBottom, double minValueTop, double maxValueTop, double defTop, Glib::ustring labelTop, unsigned int precisionTop, ThresholdCurveProvider* curveProvider) diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index 99f5279ed..0bcdd470a 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -32,7 +32,7 @@ #include "threadutils.h" class CacheManager; -class ParamsEdited; +struct ParamsEdited; class Thumbnail { @@ -51,7 +51,7 @@ class Thumbnail float imgRatio; // hack to avoid rounding error // double scale; // portion of the sizes of the processed thumbnail image and the full scale image - std::unique_ptr pparams; + const std::unique_ptr pparams; bool pparamsValid; bool imageLoading; diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index 9b654e387..1bd8b2cbd 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -16,13 +16,18 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "tonecurve.h" -#include "adjuster.h" -#include #include -#include "ppversion.h" + +#include + +#include "tonecurve.h" + +#include "adjuster.h" #include "edit.h" #include "eventmapper.h" +#include "ppversion.h" + +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/toolpanel.cc b/rtgui/toolpanel.cc index c9c4f823c..1fe9808cd 100644 --- a/rtgui/toolpanel.cc +++ b/rtgui/toolpanel.cc @@ -20,6 +20,8 @@ #include "toolpanelcoord.h" #include "guiutils.h" +#include "../rtengine/procparams.h" + using namespace rtengine::procparams; diff --git a/rtgui/toolpanel.h b/rtgui/toolpanel.h index fbe87f5f0..521d52949 100644 --- a/rtgui/toolpanel.h +++ b/rtgui/toolpanel.h @@ -22,7 +22,6 @@ #include #include #include "../rtengine/rtengine.h" -#include "../rtengine/procparams.h" #include "guiutils.h" #include "multilangmgr.h" #include "paramsedited.h" diff --git a/rtgui/vignetting.cc b/rtgui/vignetting.cc index 34559ef21..799a4cff7 100644 --- a/rtgui/vignetting.cc +++ b/rtgui/vignetting.cc @@ -18,6 +18,8 @@ */ #include "vignetting.h" +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/xtransprocess.cc b/rtgui/xtransprocess.cc index 9639ce29d..866df06e4 100644 --- a/rtgui/xtransprocess.cc +++ b/rtgui/xtransprocess.cc @@ -16,10 +16,13 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "eventmapper.h" #include "xtransprocess.h" -#include "options.h" + +#include "eventmapper.h" #include "guiutils.h" +#include "options.h" + +#include "../rtengine/procparams.h" using namespace rtengine; using namespace rtengine::procparams; diff --git a/rtgui/xtransrawexposure.cc b/rtgui/xtransrawexposure.cc index 19fcb0c46..b58a6e72a 100644 --- a/rtgui/xtransrawexposure.cc +++ b/rtgui/xtransrawexposure.cc @@ -16,10 +16,14 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include "xtransrawexposure.h" -#include "guiutils.h" #include +#include "xtransrawexposure.h" + +#include "guiutils.h" + +#include "../rtengine/procparams.h" + using namespace rtengine; using namespace rtengine::procparams; From 30748036888e52e938161d23d714c0be8af327d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Fri, 1 Mar 2019 20:31:22 +0100 Subject: [PATCH 09/36] Fix init order --- rtgui/thumbnail.cc | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index b842c01dd..757708002 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -37,10 +37,21 @@ using namespace rtengine::procparams; -Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf) - : fname(fname), cfs(*cf), cachemgr(cm), ref(1), enqueueNumber(0), tpp(nullptr), - pparamsValid(false), pparams(new ProcParams), imageLoading(false), lastImg(nullptr), - lastW(0), lastH(0), lastScale(0), initial_(false) +Thumbnail::Thumbnail(CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf) : + fname(fname), + cfs(*cf), + cachemgr(cm), + ref(1), + enqueueNumber(0), + tpp(nullptr), + pparams(new ProcParams), + pparamsValid(false), + imageLoading(false), + lastImg(nullptr), + lastW(0), + lastH(0), + lastScale(0), + initial_(false) { loadProcParams (); @@ -65,10 +76,20 @@ Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageDa tpp = nullptr; } -Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5) - : fname(fname), cachemgr(cm), ref(1), enqueueNumber(0), tpp(nullptr), pparamsValid(false), - pparams(new ProcParams), imageLoading(false), lastImg(nullptr), - lastW(0), lastH(0), lastScale(0.0), initial_(true) +Thumbnail::Thumbnail(CacheManager* cm, const Glib::ustring& fname, const std::string& md5) : + fname(fname), + cachemgr(cm), + ref(1), + enqueueNumber(0), + tpp(nullptr), + pparams(new ProcParams), + pparamsValid(false), + imageLoading(false), + lastImg(nullptr), + lastW(0), + lastH(0), + lastScale(0.0), + initial_(true) { From db57a02384fddf85249d8e7f60326439fa9f7c6c Mon Sep 17 00:00:00 2001 From: Desmis Date: Sat, 2 Mar 2019 08:14:35 +0100 Subject: [PATCH 10/36] Change default outputprofile to RTv4_sRGB --- rtgui/options.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rtgui/options.cc b/rtgui/options.cc index b38a9f689..1dd3040aa 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -562,7 +562,7 @@ void Options::setDefaults() rtSettings.adobe = "RTv2_Medium"; // put the name of yours profiles (here windows) rtSettings.prophoto = "RTv2_Large"; // these names appear in the menu "output profile" rtSettings.widegamut = "RTv2_Wide"; - rtSettings.srgb = "RTv2_sRGB"; + rtSettings.srgb = "RTv4_sRGB"; rtSettings.bruce = "RTv2_Bruce"; rtSettings.beta = "RTv2_Beta"; rtSettings.best = "RTv2_Best"; @@ -1483,8 +1483,8 @@ void Options::readFromFile(Glib::ustring fname) if (keyFile.has_key("Color Management", "sRGB")) { rtSettings.srgb = keyFile.get_string("Color Management", "sRGB"); - if (rtSettings.srgb == "RT_sRGB" || rtSettings.srgb == "RTv4_sRGB") { - rtSettings.srgb = "RTv2_sRGB"; + if (rtSettings.srgb == "RT_sRGB" || rtSettings.srgb == "RTv2_sRGB") { + rtSettings.srgb = "RTv4_sRGB"; } } From bcfbfae0b275e1fe61c310b996c9daa5c5a2a919 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Sat, 2 Mar 2019 15:32:10 +0100 Subject: [PATCH 11/36] Enabled raw CA correction in Unclipped.pp3 --- rtdata/profiles/Unclipped.pp3 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rtdata/profiles/Unclipped.pp3 b/rtdata/profiles/Unclipped.pp3 index c112e7d88..48cf72f86 100644 --- a/rtdata/profiles/Unclipped.pp3 +++ b/rtdata/profiles/Unclipped.pp3 @@ -21,3 +21,7 @@ LumaMode=false [Color Management] ApplyLookTable=false + +[RAW] +CA=true +CAAutoIterations=2 From b83069fd51974a1c5caab2fb50d8aceb5da1670a Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 3 Mar 2019 14:52:44 +0100 Subject: [PATCH 12/36] Allow user-defined setting for raw ca correction tiles per thread --- rtdata/languages/default | 2 ++ rtengine/CA_correct_RT.cc | 9 +++++---- rtengine/rawimagesource.cc | 8 ++++---- rtengine/rawimagesource.h | 3 ++- rtgui/options.cc | 7 ++++++- rtgui/options.h | 2 +- rtgui/preferences.cc | 16 ++++++++++++++++ rtgui/preferences.h | 1 + 8 files changed, 37 insertions(+), 11 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 3d74db023..3019f49bd 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1202,6 +1202,8 @@ PREFERENCES_PRTPROFILE;Color profile PREFERENCES_PSPATH;Adobe Photoshop installation directory PREFERENCES_REMEMBERZOOMPAN;Remember zoom % and pan offset PREFERENCES_REMEMBERZOOMPAN_TOOLTIP;Remember the zoom % and pan offset of the current image when opening a new image.\n\nThis option only works in "Single Editor Tab Mode" and when "Demosaicing method used for the preview at <100% zoom" is set to "As in PP3". +PREFERENCES_RAWCA;Raw CA correction +PREFERENCES_RAWCA_CHUNKSIZE;Tiles per thread PREFERENCES_SAVE_TP_OPEN_NOW;Save tool collapsed/expanded state now PREFERENCES_SELECTLANG;Select language PREFERENCES_SERIALIZE_TIFF_READ;TIFF Read Settings diff --git a/rtengine/CA_correct_RT.cc b/rtengine/CA_correct_RT.cc index e27f894ee..0d150c5c4 100644 --- a/rtengine/CA_correct_RT.cc +++ b/rtengine/CA_correct_RT.cc @@ -27,7 +27,7 @@ #include "rt_math.h" #include "gauss.h" #include "median.h" -//#define BENCHMARK +#define BENCHMARK #include "StopWatch.h" namespace { @@ -121,7 +121,8 @@ float* RawImageSource::CA_correct_RT( bool fitParamsIn, bool fitParamsOut, float* buffer, - bool freeBuffer + bool freeBuffer, + size_t chunkSize ) { BENCHFUN @@ -279,7 +280,7 @@ float* RawImageSource::CA_correct_RT( float blockdenomthr[2][2] = {}; #ifdef _OPENMP - #pragma omp for collapse(2) schedule(dynamic) nowait + #pragma omp for collapse(2) schedule(dynamic, chunkSize) nowait #endif for (int top = -border ; top < height; top += ts - border2) { for (int left = -border; left < width - (W & 1); left += ts - border2) { @@ -821,7 +822,7 @@ float* RawImageSource::CA_correct_RT( //green interpolated to optical sample points for R/B float* gshift = (float (*)) (data + 2 * sizeof(float) * ts * ts + sizeof(float) * ts * tsh + 4 * 64); // there is no overlap in buffer usage => share #ifdef _OPENMP - #pragma omp for schedule(dynamic) collapse(2) + #pragma omp for schedule(dynamic, chunkSize) collapse(2) #endif for (int top = -border; top < height; top += ts - border2) { for (int left = -border; left < width - (W & 1); left += ts - border2) { diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index b7f90ba3a..d567ab671 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2031,13 +2031,13 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } if(numFrames == 4) { double fitParams[64]; - float *buffer = CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, *rawDataFrames[0], fitParams, false, true, nullptr, false); + float *buffer = CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, *rawDataFrames[0], fitParams, false, true, nullptr, false, options.chunkSizeCA); for(int i = 1; i < 3; ++i) { - CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, *rawDataFrames[i], fitParams, true, false, buffer, false); + CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, *rawDataFrames[i], fitParams, true, false, buffer, false, options.chunkSizeCA); } - CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, *rawDataFrames[3], fitParams, true, false, buffer, true); + CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, *rawDataFrames[3], fitParams, true, false, buffer, true, options.chunkSizeCA); } else { - CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, rawData, nullptr, false, false, nullptr, true); + CA_correct_RT(raw.ca_autocorrect, raw.caautoiterations, raw.cared, raw.cablue, raw.ca_avoidcolourshift, rawData, nullptr, false, false, nullptr, true, options.chunkSizeCA); } } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index acf2deccb..34ac1cef3 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -249,7 +249,8 @@ protected: bool fitParamsIn, bool fitParamsOut, float* buffer, - bool freeBuffer + bool freeBuffer, + size_t chunkSize = 1 ); void ddct8x8s(int isgn, float a[8][8]); diff --git a/rtgui/options.cc b/rtgui/options.cc index 1dd3040aa..01146111d 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -448,7 +448,7 @@ void Options::setDefaults() maxInspectorBuffers = 2; // a rather conservative value for low specced systems... inspectorDelay = 0; serializeTiffRead = true; - + chunkSizeCA = 1; FileBrowserToolbarSingleRow = false; hideTPVScrollbar = false; whiteBalanceSpotSize = 8; @@ -1079,6 +1079,10 @@ void Options::readFromFile(Glib::ustring fname) serializeTiffRead = keyFile.get_boolean("Performance", "SerializeTiffRead"); } + if (keyFile.has_key("Performance", "ChunkSizeCA")) { + chunkSizeCA = keyFile.get_integer("Performance", "ChunkSizeCA"); + } + if (keyFile.has_key("Performance", "ThumbnailInspectorMode")) { rtSettings.thumbnail_inspector_mode = static_cast(keyFile.get_integer("Performance", "ThumbnailInspectorMode")); } @@ -1949,6 +1953,7 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_integer("Performance", "InspectorDelay", inspectorDelay); keyFile.set_integer("Performance", "PreviewDemosaicFromSidecar", prevdemo); keyFile.set_boolean("Performance", "SerializeTiffRead", serializeTiffRead); + keyFile.set_integer("Performance", "ChunkSizeCA", chunkSizeCA); keyFile.set_integer("Performance", "ThumbnailInspectorMode", int(rtSettings.thumbnail_inspector_mode)); keyFile.set_string("Output", "Format", saveFormat.format); diff --git a/rtgui/options.h b/rtgui/options.h index 5001306ff..f325605ab 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -314,7 +314,7 @@ public: bool filledProfile; // Used as reminder for the ProfilePanel "mode" prevdemo_t prevdemo; // Demosaicing method used for the <100% preview bool serializeTiffRead; - + size_t chunkSizeCA; bool menuGroupRank; bool menuGroupLabel; bool menuGroupFileOperations; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index c10c37b1f..94c9118c3 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -666,6 +666,20 @@ Gtk::Widget* Preferences::getPerformancePanel () fclut->add (*clutCacheSizeHB); vbPerformance->pack_start (*fclut, Gtk::PACK_SHRINK, 4); + Gtk::Frame* fca = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_RAWCA")) ); + Gtk::HBox* cachunkSizeHB = Gtk::manage ( new Gtk::HBox () ); + cachunkSizeHB->set_spacing (4); + Gtk::Label* CALl = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_RAWCA_CHUNKSIZE") + ":", Gtk::ALIGN_START)); + chunkSizeCASB = Gtk::manage ( new Gtk::SpinButton () ); + chunkSizeCASB->set_digits (0); + chunkSizeCASB->set_increments (1, 5); + chunkSizeCASB->set_max_length (2); // Will this be sufficient? :) + chunkSizeCASB->set_range (1, 16); + cachunkSizeHB->pack_start (*CALl, Gtk::PACK_SHRINK, 0); + cachunkSizeHB->pack_end (*chunkSizeCASB, Gtk::PACK_SHRINK, 0); + fca->add (*cachunkSizeHB); + vbPerformance->pack_start (*fca, Gtk::PACK_SHRINK, 4); + Gtk::Frame* finspect = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_INSPECT_LABEL")) ); Gtk::HBox* maxIBuffersHB = Gtk::manage ( new Gtk::HBox () ); maxIBuffersHB->set_spacing (4); @@ -1783,6 +1797,7 @@ void Preferences::storePreferences () moptions.rgbDenoiseThreadLimit = threadsSpinBtn->get_value_as_int(); moptions.clutCacheSize = clutCacheSizeSB->get_value_as_int(); + moptions.chunkSizeCA = chunkSizeCASB->get_value_as_int(); moptions.maxInspectorBuffers = maxInspectorBuffersSB->get_value_as_int(); moptions.rtSettings.thumbnail_inspector_mode = static_cast(thumbnailInspectorMode->get_active_row_number()); @@ -1987,6 +2002,7 @@ void Preferences::fillPreferences () threadsSpinBtn->set_value (moptions.rgbDenoiseThreadLimit); clutCacheSizeSB->set_value (moptions.clutCacheSize); + chunkSizeCASB->set_value (moptions.chunkSizeCA); maxInspectorBuffersSB->set_value (moptions.maxInspectorBuffers); thumbnailInspectorMode->set_active(int(moptions.rtSettings.thumbnail_inspector_mode)); diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 3b78c0472..2320209d9 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -161,6 +161,7 @@ class Preferences : public Gtk::Dialog, public ProfileStoreListener Gtk::SpinButton* threadsSpinBtn; Gtk::SpinButton* clutCacheSizeSB; + Gtk::SpinButton* chunkSizeCASB; Gtk::SpinButton* maxInspectorBuffersSB; Gtk::ComboBoxText *thumbnailInspectorMode; From 77475a3827b8362977f0eaa4ed2ba5db107e5e49 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 3 Mar 2019 17:29:19 +0100 Subject: [PATCH 13/36] configurable tiles per thread also for rcd, #5203 --- rtdata/languages/default | 5 +++-- rtengine/amaze_demosaic_RT.cc | 3 ++- rtengine/dual_demosaic_RT.cc | 4 ++-- rtengine/rawimagesource.cc | 2 +- rtengine/rawimagesource.h | 2 +- rtengine/rcd_demosaic.cc | 5 +++-- rtgui/options.cc | 9 +++++++-- rtgui/options.h | 1 + rtgui/preferences.cc | 26 ++++++++++++++++++++++---- rtgui/preferences.h | 1 + 10 files changed, 43 insertions(+), 15 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 3019f49bd..804ae1624 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1064,6 +1064,9 @@ PREFERENCES_CACHECLEAR_SAFETY;Only files in the cache are cleared. Processing pr PREFERENCES_CACHEMAXENTRIES;Maximum number of cache entries PREFERENCES_CACHEOPTS;Cache Options PREFERENCES_CACHETHUMBHEIGHT;Maximum thumbnail height +PREFERENCES_CHUNKSIZES;Tiles per thread +PREFERENCES_CHUNKSIZE_RAW_CA;Raw CA correction +PREFERENCES_CHUNKSIZE_RAW_RCD;RCD demosaic PREFERENCES_CLIPPINGIND;Clipping Indication PREFERENCES_CLUTSCACHE;HaldCLUT Cache PREFERENCES_CLUTSCACHE_LABEL;Maximum number of cached CLUTs @@ -1202,8 +1205,6 @@ PREFERENCES_PRTPROFILE;Color profile PREFERENCES_PSPATH;Adobe Photoshop installation directory PREFERENCES_REMEMBERZOOMPAN;Remember zoom % and pan offset PREFERENCES_REMEMBERZOOMPAN_TOOLTIP;Remember the zoom % and pan offset of the current image when opening a new image.\n\nThis option only works in "Single Editor Tab Mode" and when "Demosaicing method used for the preview at <100% zoom" is set to "As in PP3". -PREFERENCES_RAWCA;Raw CA correction -PREFERENCES_RAWCA_CHUNKSIZE;Tiles per thread PREFERENCES_SAVE_TP_OPEN_NOW;Save tool collapsed/expanded state now PREFERENCES_SELECTLANG;Select language PREFERENCES_SERIALIZE_TIFF_READ;TIFF Read Settings diff --git a/rtengine/amaze_demosaic_RT.cc b/rtengine/amaze_demosaic_RT.cc index 31419022d..3aafbd448 100644 --- a/rtengine/amaze_demosaic_RT.cc +++ b/rtengine/amaze_demosaic_RT.cc @@ -33,6 +33,7 @@ #include "sleef.c" #include "opthelper.h" #include "median.h" +#define BENCHMARK #include "StopWatch.h" namespace rtengine @@ -176,7 +177,7 @@ void RawImageSource::amaze_demosaic_RT(int winx, int winy, int winw, int winh, c // Main algorithm: Tile loop // use collapse(2) to collapse the 2 loops to one large loop, so there is better scaling #ifdef _OPENMP - #pragma omp for schedule(dynamic) collapse(2) nowait + #pragma omp for schedule(dynamic, 8) collapse(2) nowait #endif for (int top = winy - 16; top < winy + height; top += ts - 32) { diff --git a/rtengine/dual_demosaic_RT.cc b/rtengine/dual_demosaic_RT.cc index 790275d7e..e6397fe17 100644 --- a/rtengine/dual_demosaic_RT.cc +++ b/rtengine/dual_demosaic_RT.cc @@ -48,7 +48,7 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int wi } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::DCBVNG4) ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::RCDVNG4) ) { - rcd_demosaic(); + rcd_demosaic(options.chunkSizeCA); } } else { if (raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FOUR_PASS) ) { @@ -74,7 +74,7 @@ void RawImageSource::dual_demosaic_RT(bool isBayer, const RAWParams &raw, int wi } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::DCBVNG4) ) { dcb_demosaic(raw.bayersensor.dcb_iterations, raw.bayersensor.dcb_enhance); } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::RCDVNG4) ) { - rcd_demosaic(); + rcd_demosaic(options.chunkSizeCA); } } else { if (raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FOUR_PASS) ) { diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index d567ab671..d6cffda26 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2103,7 +2103,7 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::MONO) ) { nodemosaic(true); } else if (raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::RCD) ) { - rcd_demosaic (); + rcd_demosaic(options.chunkSizeRCD); } else { nodemosaic(false); } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 34ac1cef3..5fb233c2b 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -277,7 +277,7 @@ protected: void fast_demosaic();//Emil's code for fast demosaicing void dcb_demosaic(int iterations, bool dcb_enhance); void ahd_demosaic(); - void rcd_demosaic(); + void rcd_demosaic(size_t chunkSize = 1); void border_interpolate(unsigned int border, float (*image)[4], unsigned int start = 0, unsigned int end = 0); void border_interpolate2(int winw, int winh, int lborders, const array2D &rawData, array2D &red, array2D &green, array2D &blue); void dcb_initTileLimits(int &colMin, int &rowMin, int &colMax, int &rowMax, int x0, int y0, int border); diff --git a/rtengine/rcd_demosaic.cc b/rtengine/rcd_demosaic.cc index 01430a894..137c98c18 100644 --- a/rtengine/rcd_demosaic.cc +++ b/rtengine/rcd_demosaic.cc @@ -22,6 +22,7 @@ #include "rt_math.h" #include "../rtgui/multilangmgr.h" #include "opthelper.h" +#define BENCHMARK #include "StopWatch.h" using namespace std; @@ -39,7 +40,7 @@ namespace rtengine * Licensed under the GNU GPL version 3 */ // Tiled version by Ingo Weyrich (heckflosse67@gmx.de) -void RawImageSource::rcd_demosaic() +void RawImageSource::rcd_demosaic(size_t chunkSize) { BENCHFUN @@ -72,7 +73,7 @@ void RawImageSource::rcd_demosaic() float *lpf = PQ_Dir; // reuse buffer, they don't overlap in usage #ifdef _OPENMP - #pragma omp for schedule(dynamic) collapse(2) nowait + #pragma omp for schedule(dynamic, chunkSize) collapse(2) nowait #endif for(int tr = 0; tr < numTh; ++tr) { for(int tc = 0; tc < numTw; ++tc) { diff --git a/rtgui/options.cc b/rtgui/options.cc index 01146111d..8f7fbbc50 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -449,6 +449,7 @@ void Options::setDefaults() inspectorDelay = 0; serializeTiffRead = true; chunkSizeCA = 1; + chunkSizeRCD = 1; FileBrowserToolbarSingleRow = false; hideTPVScrollbar = false; whiteBalanceSpotSize = 8; @@ -1080,7 +1081,11 @@ void Options::readFromFile(Glib::ustring fname) } if (keyFile.has_key("Performance", "ChunkSizeCA")) { - chunkSizeCA = keyFile.get_integer("Performance", "ChunkSizeCA"); + chunkSizeCA = std::min(16, std::max(1, keyFile.get_integer("Performance", "ChunkSizeCA"))); + } + + if (keyFile.has_key("Performance", "ChunkSizeRCD")) { + chunkSizeRCD = std::min(16, std::max(1, keyFile.get_integer("Performance", "ChunkSizeRCD"))); } if (keyFile.has_key("Performance", "ThumbnailInspectorMode")) { @@ -1953,7 +1958,7 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_integer("Performance", "InspectorDelay", inspectorDelay); keyFile.set_integer("Performance", "PreviewDemosaicFromSidecar", prevdemo); keyFile.set_boolean("Performance", "SerializeTiffRead", serializeTiffRead); - keyFile.set_integer("Performance", "ChunkSizeCA", chunkSizeCA); + keyFile.set_integer("Performance", "ChunkSizeRCD", chunkSizeRCD); keyFile.set_integer("Performance", "ThumbnailInspectorMode", int(rtSettings.thumbnail_inspector_mode)); keyFile.set_string("Output", "Format", saveFormat.format); diff --git a/rtgui/options.h b/rtgui/options.h index f325605ab..042889337 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -315,6 +315,7 @@ public: prevdemo_t prevdemo; // Demosaicing method used for the <100% preview bool serializeTiffRead; size_t chunkSizeCA; + size_t chunkSizeRCD; bool menuGroupRank; bool menuGroupLabel; bool menuGroupFileOperations; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 94c9118c3..f9724a15c 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -666,10 +666,11 @@ Gtk::Widget* Preferences::getPerformancePanel () fclut->add (*clutCacheSizeHB); vbPerformance->pack_start (*fclut, Gtk::PACK_SHRINK, 4); - Gtk::Frame* fca = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_RAWCA")) ); + Gtk::Frame* fchunksize = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_CHUNKSIZES")) ); + Gtk::VBox* chunkSizeVB = Gtk::manage ( new Gtk::VBox () ); Gtk::HBox* cachunkSizeHB = Gtk::manage ( new Gtk::HBox () ); cachunkSizeHB->set_spacing (4); - Gtk::Label* CALl = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_RAWCA_CHUNKSIZE") + ":", Gtk::ALIGN_START)); + Gtk::Label* CALl = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_CHUNKSIZE_RAW_CA") + ":", Gtk::ALIGN_START)); chunkSizeCASB = Gtk::manage ( new Gtk::SpinButton () ); chunkSizeCASB->set_digits (0); chunkSizeCASB->set_increments (1, 5); @@ -677,8 +678,23 @@ Gtk::Widget* Preferences::getPerformancePanel () chunkSizeCASB->set_range (1, 16); cachunkSizeHB->pack_start (*CALl, Gtk::PACK_SHRINK, 0); cachunkSizeHB->pack_end (*chunkSizeCASB, Gtk::PACK_SHRINK, 0); - fca->add (*cachunkSizeHB); - vbPerformance->pack_start (*fca, Gtk::PACK_SHRINK, 4); + chunkSizeVB->add(*cachunkSizeHB); + + Gtk::HBox* rcdchunkSizeHB = Gtk::manage ( new Gtk::HBox () ); + rcdchunkSizeHB->set_spacing (4); + Gtk::Label* RCDLl = Gtk::manage ( new Gtk::Label (M ("PREFERENCES_CHUNKSIZE_RAW_RCD") + ":", Gtk::ALIGN_START)); + chunkSizeRCDSB = Gtk::manage ( new Gtk::SpinButton () ); + chunkSizeRCDSB->set_digits (0); + chunkSizeRCDSB->set_increments (1, 5); + chunkSizeRCDSB->set_max_length (2); // Will this be sufficient? :) + chunkSizeRCDSB->set_range (1, 16); + rcdchunkSizeHB->pack_start (*RCDLl, Gtk::PACK_SHRINK, 0); + rcdchunkSizeHB->pack_end (*chunkSizeRCDSB, Gtk::PACK_SHRINK, 0); + chunkSizeVB->add(*rcdchunkSizeHB); + + fchunksize->add (*chunkSizeVB); + + vbPerformance->pack_start (*fchunksize, Gtk::PACK_SHRINK, 4); Gtk::Frame* finspect = Gtk::manage ( new Gtk::Frame (M ("PREFERENCES_INSPECT_LABEL")) ); Gtk::HBox* maxIBuffersHB = Gtk::manage ( new Gtk::HBox () ); @@ -1798,6 +1814,7 @@ void Preferences::storePreferences () moptions.rgbDenoiseThreadLimit = threadsSpinBtn->get_value_as_int(); moptions.clutCacheSize = clutCacheSizeSB->get_value_as_int(); moptions.chunkSizeCA = chunkSizeCASB->get_value_as_int(); + moptions.chunkSizeRCD= chunkSizeRCDSB->get_value_as_int(); moptions.maxInspectorBuffers = maxInspectorBuffersSB->get_value_as_int(); moptions.rtSettings.thumbnail_inspector_mode = static_cast(thumbnailInspectorMode->get_active_row_number()); @@ -2003,6 +2020,7 @@ void Preferences::fillPreferences () threadsSpinBtn->set_value (moptions.rgbDenoiseThreadLimit); clutCacheSizeSB->set_value (moptions.clutCacheSize); chunkSizeCASB->set_value (moptions.chunkSizeCA); + chunkSizeRCDSB->set_value (moptions.chunkSizeRCD); maxInspectorBuffersSB->set_value (moptions.maxInspectorBuffers); thumbnailInspectorMode->set_active(int(moptions.rtSettings.thumbnail_inspector_mode)); diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 2320209d9..60ed04a51 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -162,6 +162,7 @@ class Preferences : public Gtk::Dialog, public ProfileStoreListener Gtk::SpinButton* threadsSpinBtn; Gtk::SpinButton* clutCacheSizeSB; Gtk::SpinButton* chunkSizeCASB; + Gtk::SpinButton* chunkSizeRCDSB; Gtk::SpinButton* maxInspectorBuffersSB; Gtk::ComboBoxText *thumbnailInspectorMode; From c8d47f3d5ad64af15423ab12a3c0c7c2fcaa2a01 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Mon, 4 Mar 2019 22:09:36 +0100 Subject: [PATCH 14/36] Added FUJIFILM GFX 50R dual-illuminant DCP --- rtdata/dcpprofiles/FUJIFILM GFX 50R.dcp | Bin 0 -> 1102958 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 rtdata/dcpprofiles/FUJIFILM GFX 50R.dcp diff --git a/rtdata/dcpprofiles/FUJIFILM GFX 50R.dcp b/rtdata/dcpprofiles/FUJIFILM GFX 50R.dcp new file mode 100644 index 0000000000000000000000000000000000000000..a17d5e02d672b666a94f17cce40b9c192b282a41 GIT binary patch literal 1102958 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

PQR#&BF&VCuo2VGEUJ5ALP{11nxnk&SE#s2b<1N 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

  • z(jTR@^h5ssQB5r^SE*5i4vNki$aS<*PBzc14`=RQGO633!{EId>|C@;s+_OIg1;KL zC2W=U^wW}eL{IP&yQKyj=!1P!i|fbtN?&%Vv7OxDLcjge#cL{b*`&kAxV_TQ$auJR z;2ur&&C;2wvB=A(&xqL)sXA*{XU^Xn)Ju>qyo$sR6V^X@QziGy5jdBVgglqF(twH) zsOC>Ui)Zij%btXzMZ*-#eCj40vyMO{>-GTu3bLJB1ZI7wUQ?Y=d7ml*W2#f9BIuyJ z_;w^V6A!YwW|tFj zc&7%vXJ3`tkppt>4?Vf;Zc9gI&^wEKs_{SWNtbQuWnG{}d$R}9Vqa>|_M>;n>0-&0 zT!~GR4&n9AN;y0;))T3}bMNS2TUm>%?e0kzo@z0f{6G)8dy*kngKC$wSak7@xo)g&uRb z`>)NDdpc7`bXp2}eJqnZ--t(}7p$Eeni@LLbMWO|&N8YsH0+%)>w@NdCT)2b@zc)Z8cI-#^?t;oQ2l>epI(QQlr#3^z~9>Y#Fs6 zs8`yEGn%vRTFJ~ohpHE-i7;-NR7(AcvOj7JNz9U_&|}1-j|NLZ2}dypyNCVfA!+bT6Y+^)}|Mw zOHpwsIIDx-xWiH%@{Q+Hw{~K$RnnZJk+@3C+{`^z+MdZgu#Wp;zip+XC&TefNgu=T zkNU_d;W%2Hgcd8PSARX6?}cYO&q<1Z6oH}K;jO*fNLHVSglhxF_Lxd8_!tF~wwwh_ zz9w7Mh(k5*>n)wu%;3_H_Z9a9TQnPL7~D;R&f&?3{iZP7;&~YDk%(=-{wg&GRMcfH zA7|InyNX8_ym6(g8g0gJ&#TtZ2Ywc6JTmdpzdAMxj=g*5`oPA7M%2|)&QF@y(PwFBs_!x`0Db#7{(_fyG z5`$_F=~Z{kL2mjt5|`uXWtKlyb}R`8+ERO#SnJt8Ve~5H`!$Y`=ZA#hID4oaE0bi4 zE9B62Wo_oPOpY2C2FDBB*VbgqL5ISzO;DThYmppUITHP;-Q<*PWY`xUg&HyB?R@TF z`1v#zUQsD%cX+VDc7hu2N_r?a_B3R0W;Js`GU~pVVCY4D?v2Dm%&xys(SDZ-r+DuF zKOgB$@GHfIz23x-)rhz~+2HI%uSvBUciRjyR4NRj4wD*l3l)Y&E^1VIOTJA~AH%0_ z8r-%b?{`se!)ApB5pL9qt<~G$vs#TiEB>oPtPRPYYSy_L9BbXzppNFV(ppPgQeiOZ ztVTTbsMk)lGfcf559`ZX?5sY}@cnQcGI)<9^l&f~Zi+!a*4U4$Iv5U~jzYH{^e&0B zH#7{7q~>7)?pJ|fv~l=9ea`qM{SBwugd*${W4pVTA*gEzLNk+KHKvQfG$9xoVzWk1 z%?&;d!3ZKJr;|lP!)LD$m{_D>hHou{#gH)MdZeKLi8_Yuts=0~kKC|!W(K2Ek+5^* zzSt2m7naB3E6=mf+OdYc!D{a3QoA@L)F5}FC!r^I+Xs6aOxJ4AGMai3FWkk?jVes? zFCXW%nco!MmU?5-IOe`r*@mfIBC(D0mrzwg{_c9S@m$s*=_l>hq~{c2ZeQDyW?LjwoKs*rmGRj(Ls?}@?tpIX$f zEE%>G$KWsV0mYa-hMr;3)XV>`mRN6?v?U4}?qamtz1U#RoN3%O0o$!o4V(4h7&MQ* zOl8bh7MK}4O2d%DIry-I4u*&e z5wI&w#`m}V4eHM^Sa~WLLwZa#Y~y)r%bq2&r^>M3O-t?xF{q3n!`_P;Xhw7PQNC8Q|Nht;ngs-)7iT)BANDqkJ{kze)5+L#q?2LJqF`+Jz?oWDJHsaOnJtLJ z3~6j(_;D&6Axn}maeGfgYg_VOz|ZBxAcLA5x>2|2KYPN(@H0z`yMy@kl;MW)U9@mv z9=lXh4XR8PVjq={b7{94$~L~4arn7&EEI`gHnbNetX zI7Tk?G?CPpVIa0sYG)Y8I%ov>6@8mH8dfjU zV$^7Q3kDeDkXD7XlJap5cwb*xX`(j@W7Mek8)nEoIb*V1LU<&1E^n; z2>DxcIb}c~Od_ajap`BO_IB)+~}H8mVv zsi9F}@5n)8X0n#6xU9et_Kcjvv(iN13C zqvhv+qOgkkJb@Pu$Q3-}(Vu;S-mV#t(>VxN=c(auS(f*@QXn|f?>vx%k;m3OB?XFIomFRHy zkQ#p$Et5KBCjuAg5q|4{ls+#Jlb@-vt?vbCttx>#+~leLdM3>uP9KKe8g#q!The#c zq8IzY@QucD&R6EAMH=*UtS>*OM%E|(-l{e&WcQCMSnyfsT+~*s<`#z?$y#g)=lt3- z2ID_yam=%a{EFD)xEVU6>aFEp!NgBk;|;mlSKj6o2Ax|1wm!C%U)zKtl3bM4L+s=V ze?w4VmKRP6!^%3;TD&lZ9^VlVjJe5NZ~4N~NG#xedZ1d8 zT(K8*y|*wI+3%O{CdA{MEp_Bt|B}m|@{F8Mz>WMK2HT!|9j^rJzR}fi?12{3O?5bO z=bpIaslw*E<>UNeV_aU`i7?Kc=vVeLQ*T`}6kS)Tk=oQqdht98dx_WGqQ-?yAMUee zvzCrpCrvw;jNLr*FK^{Y&wS|JdV?Byov%rm%wY$=(?_K4JL&kT1eCSW;N|N|axIMx zA)_@g(bkf?e<98kr@{Po&EyK!tgnv~5Bb$j4n3?!qgq;eZ&=Ff%;S+COblh8jlA?^ z48D<yetPqrLqnE+;nR0M(C={HPw7VW8zuFg$;xCCfu_s>k=d-i7AQ2OW zr^-vtMPUc$&OP_;lBf0L??cQsdc<>CaY2JsQ|Jd>(8}=5DuMf7It(jrZ1B0N1(>6U zB;|`ZClv-aDv#IYc3P%?G?tzvOVrqTZ?FEbWf+viNRQw6t#_{)L*9fMLz6~J-B~Mn zk=JyXAH)IksE@kFM!vT>1{L3E@mx1huA_*8m#YpA=SRz7pq4xLC~N<6lIK^WzsZOM>^nV6 zo>3Hr;sf+>uN5w@dPS`a@+D5rRLenDd=~m}M{Hh#Jh4_3ikSz_-A$H1G-3_Fx&Iow zbU9&d45kH=|2AraT!VebU*clR^o8;hr4}#tXz`&^B|~pw=Ys>tE4cJVu6a?5-aXZ5 z(JDh!o~}YxLHYAssX=8ad42>oE@TX+UeG@s5r(RabITvE^t)>lkJ`x|yq$$~K85?2 zvKsH-jF1+ymYjW^^-akvsS(d}9p0N!pQt-JI0FkwP z5(BC_>4dbCHTb?L##wPos^>%v@S_^^-|<1ps=%24ZygSCyd3Fn@bqvZwPBcSNVnX;=&et4dJkPS7)U1Q}3hoX6}a>ptTCCyFwD|3uZAtZ+0rtw_P8GpUfMU)9>g_-D9vNi#|6KD@j&aNvLy{v2|-G zEiOvNR_0{8Y8H|acObm~GUs*_(iPT{qfL2Vu9_}oj^d2#zk6^EJ>UQ8(49C^-oZsu z+re5aUP!zybelAT|8*+TpzfVKX|OH7=B%wa*;J$hr1@tNyS z>|?W-B?Xp|1IQlUa4%V^vYR|&g%(~d)=6si`XT9Bd`dVX^)+J5Su=gBc~#oqL4|hR zS>yHpDIMD!i`pCb`R%DIFFhNLw{;Tm&Az>y|1Js*qNvw*udkfVx@G#61myl6A&=l( zv{7^7cn7D;nSEnWXwR8)#x%L-B65c~)2}$#LH6bfeM*2ACK3^)mHBn@rBx%4?6|NHJoUrSO-acLfdtxk4 z_gRRc>`n4Kb@an|AYO3Jrehv)>s2B~b4E1gff|25Knk#9?L?24|BoZ>irO#vERMoh z)^byf+Dqn#!?A`rx$24>eVbUGnL;&v0q85#F&Xa6p>yB7&#Co`dzQomM|TcX=rZU9 zO{}V{-Zq7Xb?8qO^YELcip}kb>oB%ePuEpcXACCX(jax@<=pIE-21Q2&wl#Vyues3 zmUEus*In^AnA!A z9(CGNpW*R(sU@f#x19CWtqYQUSH`?fA{u&qm!3C^CH_Xuf!cNDX5_oQJ(Y+vrDn42 zt~mI;r}pxXx^m-Z@!0n^5#Q#Vlk(LnlpSV|Q?p1PHJ&>?!|C(YQ!7lE8&VGPxv1EI zI~h9iXmoI8FLaz(diWQ5rt^M?T}}LaiUy`x>m|7-XC~Ln#~BMRO1lq4p)GeSyeip9 z_Kb5~)^D5F9OTY2{m3qJ_FYmjFQLkRduhDmDz#K*8IobozQwv@va;piWONDUuHup{ z%3<$#F4k-C?c;vsPu}xOn0udNk8&gLLHjD~K}yyuGx&V1Vtz>Iv{c!hdw6*%oXfuq zQaYGu;eKC>2lXB*?$^}dg3w__rMh`NoYnZUUPqpXlYTev{pvM{Imdt1zd27VT9<&C za~-5<>R4QCOL@+R-QyEmlL(Xm+9ojcL4Z>1eq;_%Lu z{M#3&B~u#}ws0o0xssLi?2ih&x+RehVJEEFw{1R`i0T$?@SfO1je&`{{ct{viF*~# zOQ0{yMd(?xUtgrd-W~_Bbr$a()_j2l@1=zeRp|JJQfyi{ zV)hfyH{Y+HOC4z?Ib;2bXDY7B#A8?wPiVA4*?~2NhP6Ur_H*SD&J#S-H5j_Orl`Rl z_dfBxr{9~2w>7z!|DAa0x)wtErA6bOS{%M&F21v_iwop_hoOU*f0lnQGqx8xiYu3i zOOv3h#NXDi=$7i(_Of0D>6h(jM+-s{xzYRR0}jl7_+dlf}WyBKsOj>{W*#aob67cc4(g! z!aG3)f{$g480G6F3mzV}E_O;UWF)9x)ih zSZKT)m0_KUbqV4Z<4i>Bz0@JrY3MyXL@fD3esrD&qf7(E74~FRI9I)PGf7;W!@N6y z@r+m?b_~_PocUp^VU3v2d6yCUyCrFx#lb-;JYasvcHJo!?u>_FJF(L(+l6WGI2#2$ zPz+;F_s2rK=Icx)M&bC~U;GJ5#4qOI8MWq#56q*hnrcyf=|(Y^by_KL@Tt4@inmte z9qiMhtmwFSGfV}~x|}`jx+pCB#bIf@4$Y6=5(d@`V?OAxcGi7yv2qOd5EpWfz9$ZN zMl~ZqGe}#mhul z+i>j5O2*WUsUn|#9JR>hcn~;WjC&k~X)fID(!CXBM`KYnm^#}RrlVEgcw~)AfpjVd z^LMK7^bX@q%C3~XC}|O6FZ$LiAc`9ug5bFcfTr@9E`_@ zds_TiS0aWTibE-%z4aIW2$Q8TsLlG}S)MVPsiR>+T*h~JEtEbcUds8@`K@)3TN;j8 z4v9EFrXG&v5&tQocWr2G%xV^jLE%ZLaiIpT{0+vcqWr^GSBUYin_DHqZRbF?JPmG?+@vq@ei&d>NsFX&7^0?`nq6 znm9y{F3PYwM4 zP8N5QxogGOu+Lg90@>rcv6eV}J6HJG^S+y)#pq$hB7U?Ad3)GvwEQAIy&x9UP=`~G zs*@WS16wUM*$y_w>uTiw{ncUhr8d~&6M+Qw1qF>QG3<007BwQzgL?qk$3xI}7x}Bd zsk^BU!fWndtIZUc(Jc^tesTxxHTMfA2OwlKc>*^EV9k>`0m8wTRdHR=g( z8iQPN;RXz+-^6AYeBBcUH91HX#?8atu2JZ-jk=)c&tuO+&Uq84-<#3Et`+N<*4^eJ z!`a^MgNqtJkMQ&Io?H6ldKx}Tv2Z&R zSuQ`{jvXmiERDnk)^gg*>!k<8zAm!HcypqN9+6SlO+5L9-zjB%-aoY$^4v!HiyQZe zU47DENXH%GWT+0025HfvU6D}QYp{5o7DYF{2hC{c$NZ0JgP>kNFJ4=mWD6`rrOb<;gf$XX5>?xmbB~FDT-DqRr1xu>Gny+Ud)hM^brHX|NYwEM=HZ!2oh6`QuPd)Fuy*0<R@-?QjLr6=mi;A-%i2a`jiFtD2wII zChr%Qi1Ys>o)%Z*f%x!Ch0Cnr;_n%u)9xsGBJkgoHAc*o5IiVh4PDd`Uo&UpDKXpS zxzxy9?Sp#1*)Kbcz#6p|o~=kk`%_LB?Bb5%G4x^YAAsDGuE?xPj~?Eo3xBxaW^OW0 zZk~(HTbwZ`g4*3j7Q!*YnSPMmWjnPRu@7BPKcAYV_S+dA_JYzK{>G?s1lHMAn%o7}4wXdT349kgs^M0cSd|&2jh4Y&>C|KhVz_);GP7 zZJLOm?M5Ip(E}rL*k2U7!KOL+qJH$m!Hnq zqvm^0+z6$@1zo83HGAS-l(u!lW<7NwMo924^FU{6N>{6M9^0&EqL6&)aaW45@nZn$ ztxCn(rk61BK^Uqq&bPWB!eQ>Ts(z7+o4pLGow3;4i}_^CGW@h5zV5(#^Vkk_d#|DI zGW9$|qcDIqwmGq;8evxWl}k*buNH&uf3yA1Z(?0(dA!aj*h>zI4#hO$#ygB;scvd8 zdbZRcEw!!mBZ0jkb8^O$S&B~+IZt7|?qX9@1n~KMK1qx4h5;gIwifEVFKcd2Qz41AFAUOS*Hn*c-v*-+I>?#yZ~< z{f?5~{>>e6zujPAtFW zh8M=%@mZOJJ|8{)?QA}7dKQiDdSedvR*uQVXgbOtzntms*5Da;d+5JL4dh>;cQIve zB;={7#Eo;&8QgbxHW&8Hv$JjEQHjsU-&gbp;62zG+@-y5hd;y#w*5-NLVZ7WKJmb#E3rIpOX3n1w)t&y>Me6^K+Ura{GB; z6}jatiT!Lp=#JFN^c8xW4*MJK*t9DdyOLMq;~sbHn2k5_3D_ufN-Y zc;s9DtSlR4@4Y%4oxvW{zKW>Bct=URXG^DuNv~ORcGclTw-sW*Al7M{b-20njF=k8 zIW_x^njgzV)QdUj&p3OHZH2=@KG@WXT$hIZ;S=bE-i)&&{ZDrAZ2zEU=DV;E>UVl# z(~l%1w;)H~#uN9~B;(e_K75Lbfh+FWrs+L?5_fBhx15leN)?CW1E>c}9K*@jP5M$f91S?9URC{w{zYvaJ~KBhc(=rM@(OAd zvj<7vm8DdS(84ueORc&N;v2cjjk^;QuC5X}U7{h;)AMOzwzv=;ir|*a&tsm8RQmw( zUK7ylSpz(~?1Ng2a~5}D1Fn1F5^Ic!4~FAlnkTL>&OLH`@Z`EDX0jI(e19jVdf~|; z-h(3+VQ&jB9OZjYdbbJ10o07TM~$h#gQ$7M7dd`&5p7?9!e4$^`;uCtORk`UcMyt@ ziUEsmWAK#-*!rfzJ@5(&YLRcoIA?|(z(w|_;~3{9<2ASr;>6U%8^5OwMiYB^&GY== zVUE~*R|_5EeCuN!afX=Lstnd%6QY%scCjw=qMIb%)WA7EE*AjNh=d@yo)hrboRyW zmh=ia)EYl}d1E)@+@_C`JD;BT#W=Swn1=m3JW*Df1oVlbKY%B^SSK&@O~>joPk0Qc z&h4z#$Vj0E8nsaD9kOty@=TP5@g6M6!Hg7t)Zng!|JhTB?Ga4xyHspCa1mYESH=WW ze|YLC?B%}uE2mUku-%D_R22&Oxs=uqr$#65GTyEAeVbw{@j9oWDY(31tFV5-`igNr z?C?i9mGcTmV(VMYEtSIyHMs9j40^z+e{o*_KXJ}o94Jq-W4-Z#K3IS5ONM&EuxhVC zt2b)tSaukaW^2&Eqn^~9{hXfIRiu$h?>dtlWM9rnAHKJ(UQ>%VXS6u`W4*Grj$CQ( z`-DZd5&b?yL2!0yu{&OL>_+_riv+a)d_W|c1z_Yl*5b2RW4H9hmNxWqileuYi}yeM z|9II7nW-Jy*pYtB%F6Y)s_myUP4Z85z zRJj!^_7PvV2+_iO^oD9mtnmo-Ac#guy9* zci)f>(vw0h#uDc&y>?JPjJ3ygKk``GNO|@6J49S055JnV(t3yru1e-^<8R7{+$g-D zhM~9nIMJ{{DC%`hK*;h{;tO||K5r%uztbIYalH?2btMOVs4<*Oy^wR7{tLR+kYYXX zC72kBuLAcSJrL7^dba(iP=k^?eTB(rT9+J8#y^)ko|)TH@c96>1*pxKWU&<0m-!-o z^;~SazY#72{4vQa6*=>>kX(KAM;*fA3A)+N#!15z#(fmAO91sNP0|8 zcO-d+7ia&A^P39ghbM6NqK6#LmKOU&R&0MnM8f$2mSViI}6-vlEkJIc^&Oa8#St92ki#v<3 zdZ9RFP5x(vM6vPA9CX>o-T%`ksFUW6U!2noZU05AZ10Il4-=8OtUmoh-C>zY4Y8SB z@GH_C*8P)FDarw>dwJmP6Mj9LT9sEkur)n}yMmF#a=fs+EB!&Lakr|kFTNkACRpfV z%&6^;uFMri?^ff2Q82L&>b)yBpvJjKd@f4GjRPxiyiq*X9c1mn*^G5lH753?m&cs} zDB>LNu=9VKS8qgM1ugfY*vk`>oWkdN4`&|1TMjBS8RzFbGk&&p6z`Z@UdJ)FX4n1~ zXY0S^>*u0*p>h`W8!vq#-lTmk4Ws9*YiA8QeV;F#uMm#$VH%9TK0val$DL-rUPe}_ zen2L9FA-X(Rmu8ErsTx&Zs`5-Q?B=V)^(2L+ZzQaJ5`BhouY%Txv?-~{*NA*fLSX% zME#0$Fy(9lve)kt6YhHjAUfD zwnDbS9V2USui?^Q-VGjDd6ZuVa|f}e7h26=uN_DKfkwWV^kpt=EAst2_@i-DDvE5< z@ODlxzR;UvdU7T{hDRZi-U{8Ag9f~a$EY{-HRv)6F=1-F_F-?h$`UJCGrvh=Zr^cT zENad7I*(rJy6K|p11(DGC!`30l;0Y5K2EY56~WO4qBQ za)-DuSbpK$%Jz*^Y!rgpmKxmjS|lZ`566-y)`&-jNYB|rf2~TKD66XU{GkpTROD2A zUaQy5)Z!d-*2G5nc@NChXgXa7llBdiBi3`SL9Wi$Q8$%k)u|6TBLP;+glL{N8^zRO znv}Irj2!EQ!?D!F%RVM*|8~d6R_prK!jiWo;< z>P6JB#HsJ@82By)=@A1k^rR=YE}M(~z7wFX;EO%IQc`>Ug(cjxsU89! z`U>5!4Z}HAG>(o-!)5hMT&zm|X74oU9ERg#WewV7(Z4LM3G~xA&*XDqzC;o&c^75w zPr>@Oql6Rh!ROSn9)Et1@=2}+KaNm?PBB>Vh&k1a_`|xYOLG6~Q>y(>oZDxI$}#=J zvE?iI`VZeonjIndY{lonYO%D}IRbs-*#l+|k?wGI(6=_ZE0VD^l4nzsLJU7^tNz7l zEprZe=J7`Qa~d^#eRZhdnynaFkv>GkG_FnEq3r!K1Ro-JhPRuFxAZWYO00f$g<#S0 zj3;!fso`(7Qe@6|=b2~TtC1@X40A&z_O|sc?g~%1!E1jqt~4wYsoUI88bEEdM)k1H z#~q_B=n3+yHDGxWC9T30zm8_oa9sIDE^huC zDbFkv6MB+UF=vs~{y_wcwB&QnA0WB(N#MQ`xw!2sN=Qh+t$A8}j$EUEVx)tC*imtt z%K91PAO!H-M>qy5b{>gFj|!Ye4^LDk$An-SF^#h1Z_3XZ{?rrV{BE;S;HL-d*lW9o z1&dp^-C*gSgooo6iN~8<@yIM0B@6b5OMhJO<$f~M-_D3H8hTN2*Kh8GXTmes4PB>F z%Pyl#%+z?`Y4udRtZ9O(mOi+!I~C{7G{$*bdKN3wFg?8`W+jE-@wPNrsM=uv>KO9W z(&$xY1_S5$=Z>dg@yr@{^;LrrUDL4f!ENEwhdd2SdVhPb6589m-~LeVuKO@i=L^3- zC>gp2H39Iy5%h_o7Wd5(soJzq zl=LFku+{=;QHw}yO5jdqb!(|LpL@|%i|-$v>Kkt0{?-!qfPq?lL*hohoaG?Okhgpn z=L0GoX3UwbnAj>Blj|j5bL&aU=O==(Zes!-&(Bdttns4#ejs_j6?vxD=Ksun*PeS? z$(&7EZcuct90lVR3D_BErL^ETS#eTWuAm$GM+lEkft>=7KPVP!f~w0uQg4DXAS zoMxioUe?T?SUaW5%Aw7PdmQ2&xw82`|G}86<>Tx>*GFzqF$9*}W1TqXmgF54j1bn( zxtS{I^D*vxMQdOeRYm$t{_|u0th49U`nJ>qHmyAP(PtaDn2h zgBzwTOT|Uk?}~M-JzR&Tp{#NzW#88`@%cp>Y(Iu5+nNQTvsXH%UEHgjGCB(82hx#y z>yz>!G31f!(~|^N7+XgHAsWgupn{TON+hK0y^A3NbDU$p2>G= z?v3jxO6qIq1&|1@+8>lp`2X*|$$DT|*MD(tJHLFKH_d4$pZFMpoy4D?n4OZ+l7n&C zT!R)P-K5%=!_hl}oX$>X^^(m4Ugc59Jr)=;r{J-L&_LOXA$tn^}C z6t{!C%2zFwn-tO5XP1DiuGN&*l|tZfI{_J?iHcD#{4h0`o`#)Q=ZzZWfr<^1aB@@? zebNV4tSuzoXlA3|cE$xA=F_KXaJatzJ7=8X%+!0$O8wPQE*RToF6wQ})o*L=if*jm ztbL31HW%Hfi z3$733KKSGQ;`%@}cJ<}+c)5X4_2!KFi55wYBmTvC5;5KX&nxIXd6~kZQ3US2P-DG^ znet0aD8>@scs(Ii=`c1DonkdO7hxn?4<^^Q2cL^!t;Jws+r#p;^e^cy0xoTsGlJa-H=7hSI?HSb5VE9(P#8Wz~;FI&5!XK)I3cyH6ExVz$ml5>;JpY<8UqCXj@ zqP3%$w35$-;#?}VtNKdsrh1{XE)6}LMoR5^&%|^3Io3KqT9Ud4VET@9Sccn4_3MVi z>Q_3pc~_U*b7P>dl7Y{m&Gh{r#pA@Pbksb4MOmjE_ty&2Fu9#hln|RAxjYrCK4*&4 z6Vy1*`D2Y~vCh(TF&|E&H|U#hQO{UT~y5kFjye0>xbO2z+@=p3Ic4 z$^>e_E^I-~%%Q84Eqo%0RcP?6LnHB0$$pM^@ab!Pgrx^-#tT~1EFLQQUhR@0$ig;9cpT-=uTs$1deM!z=`uMLD zGdIPN2bPQz?Y+hJ>{u*dUDsuRlc;RR9T3iy7Svh#FV3xu%Ex(vS-N6rd-Al&he=FO zDlbw4HiPq&c{_G1Ej%Kr;Y$4Zf`vHEeLi2#3rc#85$WX1H{~<(Dalhz;eFV_M~Csp zeMF^E+;RC%-S12%F_3x`Z_~L?r*aUjiL3u1o^L#@zNpDvv$=X|9S?|8W;OK2M;G#i z%p4VGs(4@$cOGl~`IUD+#tqu%^g>;@RDbV>@dBa_7Et8mc!>l3LaFqNjZt9;{m-&8g~(WbbsOrf-ry7x<$Ky&!uY*&ylI z^XB%-z{(NPQj?((xYCb)g|Bn<&ke+KAJb2E!FS~+?j=pFnvPClq1b#V2B8kAFoY}? zBa@jA{m4tcIa@S&5RC+K{-?H!6kQjq(4DpJkf6)|;(TmUd7jL^B}s~}9V0NF`8ja- zXl08v)HH5Q9^nmxvUE};I8Yfv}gs+Pe3s&&=IYyk>*-O-CUmrf6{q>A~;um$Q$C00@Y>=)Z9X&3zqt!M^|-zo`4Qb^P72&6VD!8m-hO#1k7@rz5uND(Pee&TB5DQ!8n^a#~hqN!yDa({kM<}HiFIFoezE=d-D|3u*PtGURxm@n?H zV{T{PUAM7T{N;UWJ(+usL5sxAWAV6mfP1MszWs~y!~fwUB|57WW|k3H`jRt6BR6Hx z7S5R3Y4F7AnsNeP_h&L^uXjg@7MyXnA}8{~9*wx%C;>@LbXXM3*R|Eco_Kx(>m_3N zITac@B%pu50%6=X8Uxv1r+rBj-|a&&JSh=nQ{BYSiF44rJ@x#H>IlUHZyctUN1qx; zl|OPkpdyCv*wIGW=d&AfsmTx%Y@B<$*cFEcQJ+d0uYY*K6|IQBtse1M|NV?BEZDn! zv*;}C(Ym40$ut<>n;{iscwpjOdTw4#l}s*rVTWx7^XFKr4&a`=A+TT!Q z@xK0&zEp(2iNHE<;u|fG2<1WZDo%$ZYav8CV!7`Wu?KcsGLr|(03cfH)B^QIR{DHI8Z0v#0B(RoX|4GjoV}KT3B#S6uXVi&Y(lR<6Jwo=z9H*$wEVAa-Nn)KNN_Kh=fX4fWZd}H?J zJi~MSv!w2hGvOvOFf1obdS~N@{`B}By>we%*k*rdr>A0KtWxwkJ)3nXasCCHMBAJ| ze62@q&%SSkaY+~|o+JMxqdwvjW3ip}ZqNMB|Kj|uZuxsKzO92|jo_{#=iPNmlay;u zh9aA|sB`zqVkqNWxRm-D4^$%RgbtThYw_;NW>Li2t*tw~2$$rEiRA3>A_jSF>KWl- z9S^Jh3HaUQf-qEz#A9#nHeN3jrF(+#xp5Lgy>mnlBR{l1K|bfM6(TdhgZlCGN7#}s zde?NrF>)l<<*P(3Zx?v9or_xIJcJO===ysudh`>*f|}UpFQ;Nfn+jseH7D5YBSx_} zNLdi)gs`}Dv}l=-r?~5c>+Le2|8-ZNeQyTjtr_S%(pjn+=|cWm1}s7kNIQ+(QJMLq zec^G*a;_&9@H6^dHczVY#2Z=l*rzAg*SDEI6Yt{YqRZPEVy>qjGzrPbk#CE@_yF`Y zqF+gvIV?wop|c~s)lx_iq&zr za*f`aVGl*s9uXLpK|aQmhr)ehAnFZB!lP<8#FDKuQS$>ia(#0}+pBJ9wlNtOV)u(1 z>_G;FrodzD4v`-+1JlRM#p&!-Vmb9ci^$h{UoAz9UOEj|KBQu2<>^Aao(lJ4Y4j0j zB95!3q6Pbl;?pyg`8Nx4h&0q_27Zo7 zM~U%SNn-wK5Ris}qcSBUVzW&xI5+(2t=N`KZi$|C^71`m`sJDU*fkjkU$;Za{W