diff --git a/rtdata/languages/default b/rtdata/languages/default index 739fb6d71..cd7f1634e 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -725,6 +725,11 @@ HISTORY_MSG_490;HDR TM - Amount HISTORY_MSG_491;White Balance HISTORY_MSG_492;RGB Curves HISTORY_MSG_493;L*a*b* Adjustments +HISTORY_MSG_LOCALCONTRAST_ENABLED;Local Contrast +HISTORY_MSG_LOCALCONTRAST_RADIUS;Local Contrast - Radius +HISTORY_MSG_LOCALCONTRAST_AMOUNT;Local Contrast - Amount +HISTORY_MSG_LOCALCONTRAST_DARKNESS;Local Contrast - Darkness +HISTORY_MSG_LOCALCONTRAST_LIGHTNESS;Local Contrast - Lightness HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -902,6 +907,7 @@ PARTIALPASTE_IPTCINFO;IPTC PARTIALPASTE_LABCURVE;L*a*b* adjustments PARTIALPASTE_LENSGROUP;Lens Related Settings PARTIALPASTE_LENSPROFILE;Profiled lens correction +PARTIALPASTE_LOCALCONTRAST;Local contrast PARTIALPASTE_METAGROUP;Metadata PARTIALPASTE_PCVIGNETTE;Vignette filter PARTIALPASTE_PERSPECTIVE;Perspective @@ -1679,6 +1685,11 @@ TP_LENSPROFILE_LABEL;Profiled Lens Correction TP_LENSPROFILE_USECA;Chromatic aberration correction TP_LENSPROFILE_USEDIST;Distortion correction TP_LENSPROFILE_USEVIGN;Vignetting correction +TP_LOCALCONTRAST_LABEL;Local Contrast +TP_LOCALCONTRAST_RADIUS;Radius +TP_LOCALCONTRAST_AMOUNT;Amount +TP_LOCALCONTRAST_DARKNESS;Darkness level +TP_LOCALCONTRAST_LIGHTNESS;Lightness level TP_NEUTRAL;Reset TP_NEUTRAL_TIP;Resets exposure sliders to neutral values.\nApplies to the same controls that Auto Levels applies to, regardless of whether you used Auto Levels or not. TP_PCVIGNETTE_FEATHER;Feather diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 70416af62..3e5eb15e4 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -115,6 +115,7 @@ set(RTENGINESOURCEFILES utils.cc rtlensfun.cc tmo_fattal02.cc + iplocalcontrast.cc ) if(LENSFUN_HAS_LOAD_DIRECTORY) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 9c80eed9e..6403612d6 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1378,7 +1378,8 @@ ProcParams* ImProcCoordinator::beginUpdateParams () void ImProcCoordinator::endUpdateParams (ProcEvent change) { - endUpdateParams ( refreshmap[ (int)change] ); + int action = RefreshMapper::getInstance()->getAction(change); + endUpdateParams(action); } void ImProcCoordinator::endUpdateParams (int changeFlags) diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 5223a7f85..2c92e1321 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -3427,6 +3427,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer int tW; int tH; + // zero out the buffers + memset(buffer, 0, 3 * sizeof (float) * TS * TS + 20 * 64 + 63); + // Allocating buffer for the PipetteBuffer float *editIFloatTmpR = nullptr, *editIFloatTmpG = nullptr, *editIFloatTmpB = nullptr, *editWhateverTmp = nullptr; @@ -4965,6 +4968,11 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer if (vCurveEnabled) { delete vCurve; } + + if (params->localContrast.enabled) { + // Alberto's local contrast + localContrast(lab); + } } /** diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 08c3fa4cc..b7e7a7545 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -345,6 +345,8 @@ public: void BadpixelsLab (LabImage * src, LabImage * dst, double radius, int thresh, int mode, float skinprot, float chrom); void ToneMapFattal02(Imagefloat *rgb); + //void localContrast(float *r, float *g, float *b, int width, int height); + void localContrast(LabImage *lab); Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm); Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, GammaValues *ga = nullptr); diff --git a/rtengine/iplocalcontrast.cc b/rtengine/iplocalcontrast.cc new file mode 100644 index 000000000..24739fb6b --- /dev/null +++ b/rtengine/iplocalcontrast.cc @@ -0,0 +1,70 @@ +/* -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Ported from G'MIC by Alberto Griggio + * + * The original implementation in G'MIC was authored by Arto Huotari, and was + * released under the CeCILL free software license (see + * http://www.cecill.info/licences/Licence_CeCILL_V2-en.html) + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#ifdef _OPENMP +#include +#endif + +#include "improcfun.h" +#include "gauss.h" +#include "array2D.h" + +namespace rtengine { + +void ImProcFunctions::localContrast(LabImage *lab) +{ + if (!params->localContrast.enabled) { + return; + } + + const int width = lab->W; + const int height = lab->H; + const float a = params->localContrast.amount; + const float dark = params->localContrast.darkness; + const float light = params->localContrast.lightness; + array2D buf(width, height); + const float sigma = params->localContrast.radius / scale; + +#ifdef _OPENMP + #pragma omp parallel if(multiThread) +#endif + gaussianBlur(lab->L, buf, width, height, sigma); + +#ifdef _OPENMP + #pragma omp parallel for if(multiThread) +#endif + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + float bufval = (lab->L[y][x] - buf[y][x]) * a; + + if (dark != 1 || light != 1) { + bufval *= (bufval > 0.f) ? light : dark; + } + + lab->L[y][x] += bufval; + } + } +} + +} // namespace rtengine diff --git a/rtengine/procevents.h b/rtengine/procevents.h index b4bb6be73..f5751c7d0 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -26,7 +26,7 @@ namespace rtengine // Aligned so the first entry starts on line 30 -enum ProcEvent { +enum ProcEventCode { EvPhotoLoaded = 0, EvProfileLoaded = 1, EvProfileChanged = 2, @@ -525,6 +525,27 @@ enum ProcEvent { NUMOFEVENTS }; + + +class ProcEvent { +public: + ProcEvent(): code_(0) {} + ProcEvent(ProcEventCode code): code_(code) {} + explicit ProcEvent(int code): code_(code) {} + operator int() { return code_; } + +private: + int code_; +}; + + +inline bool operator==(ProcEvent a, ProcEvent b) { return int(a) == int(b); } +inline bool operator==(ProcEvent a, ProcEventCode b) { return int(a) == int(b); } +inline bool operator==(ProcEventCode a, ProcEvent b) { return int(a) == int(b); } +inline bool operator!=(ProcEvent a, ProcEvent b) { return int(a) != int(b); } +inline bool operator!=(ProcEvent a, ProcEventCode b) { return int(a) != int(b); } +inline bool operator!=(ProcEventCode a, ProcEvent b) { return int(a) != int(b); } + } #endif diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 64a3fc67f..4c8aa349e 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -590,6 +590,34 @@ bool RGBCurvesParams::operator !=(const RGBCurvesParams& other) const return !(*this == other); } + +LocalContrastParams::LocalContrastParams(): + enabled(false), + radius(80), + amount(0.2), + darkness(1.0), + lightness(1.0) +{ +} + + +bool LocalContrastParams::operator==(const LocalContrastParams &other) const +{ + return + enabled == other.enabled + && radius == other.radius + && amount == other.amount + && darkness == other.darkness + && lightness == other.lightness; +} + + +bool LocalContrastParams::operator!=(const LocalContrastParams &other) const +{ + return !(*this == other); +} + + ColorToningParams::ColorToningParams() : enabled(false), autosat(true), @@ -2591,6 +2619,8 @@ void ProcParams::setDefaults () rgbCurves = RGBCurvesParams(); + localContrast = LocalContrastParams(); + colorToning = ColorToningParams(); sharpenEdge = SharpenEdgeParams(); @@ -2758,6 +2788,14 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->retinex.transmissionCurve, "Retinex", "TransmissionCurve", retinex.transmissionCurve, keyFile); saveToKeyfile(!pedited || pedited->retinex.gaintransmissionCurve, "Retinex", "GainTransmissionCurve", retinex.gaintransmissionCurve, keyFile); +// Local contrast + saveToKeyfile(!pedited || pedited->localContrast.enabled, "Local Contrast", "Enabled", localContrast.enabled, keyFile); + saveToKeyfile(!pedited || pedited->localContrast.radius, "Local Contrast", "Radius", localContrast.radius, keyFile); + saveToKeyfile(!pedited || pedited->localContrast.amount, "Local Contrast", "Amount", localContrast.amount, keyFile); + saveToKeyfile(!pedited || pedited->localContrast.darkness, "Local Contrast", "Darkness", localContrast.darkness, keyFile); + saveToKeyfile(!pedited || pedited->localContrast.lightness, "Local Contrast", "Lightness", localContrast.lightness, keyFile); + + // Channel mixer saveToKeyfile(!pedited || pedited->chmixer.enabled, "Channel Mixer", "Enabled", chmixer.enabled, keyFile); if (!pedited || pedited->chmixer.red[0] || pedited->chmixer.red[1] || pedited->chmixer.red[2]) { @@ -3594,6 +3632,14 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Retinex", "GainTransmissionCurve", pedited, retinex.gaintransmissionCurve, pedited->retinex.gaintransmissionCurve); } + if (keyFile.has_group("Local Contrast")) { + assignFromKeyfile(keyFile, "Local Contrast", "Enabled", pedited, localContrast.enabled, pedited->localContrast.enabled); + assignFromKeyfile(keyFile, "Local Contrast", "Radius", pedited, localContrast.radius, pedited->localContrast.radius); + assignFromKeyfile(keyFile, "Local Contrast", "Amount", pedited, localContrast.amount, pedited->localContrast.amount); + assignFromKeyfile(keyFile, "Local Contrast", "Darkness", pedited, localContrast.darkness, pedited->localContrast.darkness); + assignFromKeyfile(keyFile, "Local Contrast", "Lightness", pedited, localContrast.lightness, pedited->localContrast.lightness); + } + if (keyFile.has_group ("Luminance Curve")) { if (ppVersion >= 329) { assignFromKeyfile(keyFile, "Luminance Curve", "Enabled", pedited, labCurve.enabled, pedited->labCurve.enabled); @@ -4721,6 +4767,7 @@ bool ProcParams::operator ==(const ProcParams& other) const return toneCurve == other.toneCurve && retinex == other.retinex + && localContrast == other.localContrast && labCurve == other.labCurve && sharpenEdge == other.sharpenEdge && sharpenMicro == other.sharpenMicro diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 6c95b3a7f..a2514ef1b 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -364,6 +364,24 @@ struct LCurveParams bool operator !=(const LCurveParams& other) const; }; + +/** + * Parameters for local contrast + */ +struct LocalContrastParams { + bool enabled; + int radius; + double amount; + double darkness; + double lightness; + + LocalContrastParams(); + + bool operator==(const LocalContrastParams &other) const; + bool operator!=(const LocalContrastParams &other) const; +}; + + /** * Parameters of the RGB curves */ @@ -1341,6 +1359,7 @@ public: ToneCurveParams toneCurve; ///< Tone curve parameters LCurveParams labCurve; ///< CIELAB luminance curve parameters RetinexParams retinex; ///< Retinex parameters + LocalContrastParams localContrast; ////< Local contrast parameters RGBCurvesParams rgbCurves; ///< RGB curves parameters ColorToningParams colorToning; ///< Color Toning parameters SharpeningParams sharpening; ///< Sharpening parameters diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 06879fb26..e76338fc0 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -523,3 +523,45 @@ int refreshmap[rtengine::NUMOFEVENTS] = { DEMOSAIC // EvPixelShiftOneGreen }; + +namespace rtengine { + +RefreshMapper::RefreshMapper(): + next_event_(rtengine::NUMOFEVENTS) +{ + for (int event = 0; event < rtengine::NUMOFEVENTS; ++event) { + actions_[event] = refreshmap[event]; + } +} + + +ProcEvent RefreshMapper::newEvent() +{ + return ProcEvent(++next_event_); +} + + +void RefreshMapper::mapEvent(ProcEvent event, int action) +{ + actions_[event] = action; +} + + +int RefreshMapper::getAction(ProcEvent event) const +{ + auto it = actions_.find(event); + if (it == actions_.end()) { + return 0; + } else { + return it->second; + } +} + + +RefreshMapper *RefreshMapper::getInstance() +{ + static RefreshMapper instance; + return &instance; +} + +} // namespace rtengine diff --git a/rtengine/refreshmap.h b/rtengine/refreshmap.h index cea6b3c8e..09059470b 100644 --- a/rtengine/refreshmap.h +++ b/rtengine/refreshmap.h @@ -19,6 +19,9 @@ #ifndef __REFRESHMAP__ #define __REFRESHMAP__ +#include +#include "procevents.h" + // Use M_VOID if you wish to update the proc params without updating the preview at all ! #define M_VOID (1<<17) // Use M_MINUPDATE if you wish to update the preview without modifying the image (think about it like a "refreshPreview") @@ -74,4 +77,23 @@ #define OUTPUTPROFILE M_MONITOR extern int refreshmap[]; + +namespace rtengine { + +class RefreshMapper { +public: + static RefreshMapper *getInstance(); + ProcEvent newEvent(); + void mapEvent(ProcEvent event, int action); + int getAction(ProcEvent event) const; + +private: + RefreshMapper(); + + int next_event_; + std::unordered_map actions_; +}; + +} // namespace rtengine + #endif diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 5c1343cc3..f7bdc36cb 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -413,6 +413,7 @@ public: * The image update starts immediately in the background. If it is ready, the result is passed to a PreviewImageListener * and to a DetailedCropListener (if enabled). */ virtual void endUpdateParams (ProcEvent change) = 0; + void endUpdateParams(ProcEventCode change) { endUpdateParams(ProcEvent(change)); } virtual void endUpdateParams (int changeFlags) = 0; // Starts a minimal update virtual void startProcessing (int changeCode) = 0; diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 36c7a4034..222ee2550 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -148,6 +148,8 @@ set(NONCLISOURCEFILES xtransrawexposure.cc zoompanel.cc fattaltonemap.cc + localcontrast.cc + eventmapper.cc ) include_directories(BEFORE "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/rtgui/addsetids.h b/rtgui/addsetids.h index 07cf47d18..509b00610 100644 --- a/rtgui/addsetids.h +++ b/rtgui/addsetids.h @@ -129,6 +129,10 @@ enum { ADDSET_EPD_REWEIGHTINGITERATES, ADDSET_FATTAL_ALPHA, ADDSET_FATTAL_BETA, + ADDSET_LOCALCONTRAST_RADIUS, + ADDSET_LOCALCONTRAST_AMOUNT, + ADDSET_LOCALCONTRAST_DARKNESS, + ADDSET_LOCALCONTRAST_LIGHTNESS, ADDSET_PARAM_NUM // THIS IS USED AS A DELIMITER!! }; diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index a854db612..c2422a566 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -193,6 +193,7 @@ void BatchToolPanelCoordinator::initSession () prsharpening->setAdjusterBehavior (options.baBehav[ADDSET_SHARP_RADIUS], options.baBehav[ADDSET_SHARP_AMOUNT], options.baBehav[ADDSET_SHARP_DAMPING], options.baBehav[ADDSET_SHARP_ITER], options.baBehav[ADDSET_SHARP_EDGETOL], options.baBehav[ADDSET_SHARP_HALOCTRL]); epd->setAdjusterBehavior (options.baBehav[ADDSET_EPD_STRENGTH], options.baBehav[ADDSET_EPD_GAMMA], options.baBehav[ADDSET_EPD_EDGESTOPPING], options.baBehav[ADDSET_EPD_SCALE], options.baBehav[ADDSET_EPD_REWEIGHTINGITERATES]); fattal->setAdjusterBehavior (options.baBehav[ADDSET_FATTAL_ALPHA], options.baBehav[ADDSET_FATTAL_BETA]); + localContrast->setAdjusterBehavior(options.baBehav[ADDSET_LOCALCONTRAST_RADIUS], options.baBehav[ADDSET_LOCALCONTRAST_AMOUNT], options.baBehav[ADDSET_LOCALCONTRAST_DARKNESS], options.baBehav[ADDSET_LOCALCONTRAST_LIGHTNESS]); sharpenEdge->setAdjusterBehavior (options.baBehav[ADDSET_SHARPENEDGE_AMOUNT], options.baBehav[ADDSET_SHARPENEDGE_PASS]); sharpenMicro->setAdjusterBehavior (options.baBehav[ADDSET_SHARPENMICRO_AMOUNT], options.baBehav[ADDSET_SHARPENMICRO_UNIFORMITY]); @@ -351,6 +352,9 @@ void BatchToolPanelCoordinator::initSession () if (options.baBehav[ADDSET_RAWFFCLIPCONTROL]) { pparams.raw.ff_clipControl = 0; } if (options.baBehav[ADDSET_PREPROCESS_GREENEQUIL]) { pparams.raw.bayersensor.greenthresh = 0; } if (options.baBehav[ADDSET_PREPROCESS_LINEDENOISE]) { pparams.raw.bayersensor.linenoise = 0; } + if (options.baBehav[ADDSET_LOCALCONTRAST_AMOUNT]) { pparams.localContrast.amount = 0; } + if (options.baBehav[ADDSET_LOCALCONTRAST_DARKNESS]) { pparams.localContrast.darkness = 0; } + if (options.baBehav[ADDSET_LOCALCONTRAST_LIGHTNESS]) { pparams.localContrast.lightness = 0; } // *INDENT-ON* } diff --git a/rtgui/eventmapper.cc b/rtgui/eventmapper.cc new file mode 100644 index 000000000..de5258413 --- /dev/null +++ b/rtgui/eventmapper.cc @@ -0,0 +1,63 @@ +/* -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2017 Alberto Griggio + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#include "eventmapper.h" + + +ProcEventMapper::ProcEventMapper() +{ + for (int event = 0; event < rtengine::NUMOFEVENTS; ++event) { + history_msgs_[event] = "HISTORY_MSG_" + std::to_string(event + 1); + } +} + + +ProcEventMapper *ProcEventMapper::getInstance() +{ + static ProcEventMapper instance; + return &instance; +} + + +rtengine::ProcEvent ProcEventMapper::newEvent(int action, const std::string &history_msg) +{ + rtengine::ProcEvent event = rtengine::RefreshMapper::getInstance()->newEvent(); + rtengine::RefreshMapper::getInstance()->mapEvent(event, action); + + if (history_msg.empty()) { + history_msgs_[event] = "HISTORY_MSG_" + std::to_string(event + 1); + } else { + history_msgs_[event] = history_msg; + } + + return event; +} + + +const std::string &ProcEventMapper::getHistoryMsg(rtengine::ProcEvent event) const +{ + static std::string empty; + auto it = history_msgs_.find(event); + if (it == history_msgs_.end()) { + return empty; + } else { + return it->second; + } +} diff --git a/rtgui/eventmapper.h b/rtgui/eventmapper.h new file mode 100644 index 000000000..87ccc1d9b --- /dev/null +++ b/rtgui/eventmapper.h @@ -0,0 +1,37 @@ +/* -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2017 Alberto Griggio + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#pragma once + +#include +#include +#include "../rtengine/refreshmap.h" + + +class ProcEventMapper { +public: + static ProcEventMapper *getInstance(); + rtengine::ProcEvent newEvent(int action, const std::string &history_msg=""); + const std::string &getHistoryMsg(rtengine::ProcEvent event) const; + +private: + ProcEventMapper(); + + std::unordered_map history_msgs_; +}; diff --git a/rtgui/history.cc b/rtgui/history.cc index d62fcdb30..6b07ee7b2 100644 --- a/rtgui/history.cc +++ b/rtgui/history.cc @@ -20,6 +20,7 @@ #include "multilangmgr.h" #include "rtimage.h" #include "guiutils.h" +#include "eventmapper.h" using namespace rtengine; using namespace rtengine::procparams; @@ -231,7 +232,7 @@ void History::procParamsChanged (ProcParams* params, ProcEvent ev, Glib::ustring } // construct formatted list content - Glib::ustring text = M("HISTORY_MSG_" + std::to_string(ev + 1)); + Glib::ustring text = M(ProcEventMapper::getInstance()->getHistoryMsg(ev)); Glib::RefPtr selection = hTreeView->get_selection(); Gtk::TreeModel::iterator iter = selection->get_selected(); diff --git a/rtgui/localcontrast.cc b/rtgui/localcontrast.cc new file mode 100644 index 000000000..727479c34 --- /dev/null +++ b/rtgui/localcontrast.cc @@ -0,0 +1,167 @@ +/** -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2017 Alberto Griggio + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "localcontrast.h" +#include "eventmapper.h" +#include +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +LocalContrast::LocalContrast(): FoldableToolPanel(this, "localcontrast", M("TP_LOCALCONTRAST_LABEL"), false, true) +{ + auto m = ProcEventMapper::getInstance(); + EvLocalContrastEnabled = m->newEvent(RGBCURVE, "HISTORY_MSG_LOCALCONTRAST_ENABLED"); + EvLocalContrastRadius = m->newEvent(RGBCURVE, "HISTORY_MSG_LOCALCONTRAST_RADIUS"); + EvLocalContrastAmount = m->newEvent(RGBCURVE, "HISTORY_MSG_LOCALCONTRAST_AMOUNT"); + EvLocalContrastDarkness = m->newEvent(RGBCURVE, "HISTORY_MSG_LOCALCONTRAST_DARKNESS"); + EvLocalContrastLightness = m->newEvent(RGBCURVE, "HISTORY_MSG_LOCALCONTRAST_LIGHTNESS"); + + radius = Gtk::manage(new Adjuster(M("TP_LOCALCONTRAST_RADIUS"), 20., 200., 1., 80.)); + amount = Gtk::manage(new Adjuster(M("TP_LOCALCONTRAST_AMOUNT"), 0., 1., 0.01, 0.2)); + darkness = Gtk::manage(new Adjuster(M("TP_LOCALCONTRAST_DARKNESS"), 0., 3., 0.01, 1.)); + lightness = Gtk::manage(new Adjuster(M("TP_LOCALCONTRAST_LIGHTNESS"), 0., 3., 0.01, 1.)); + + radius->setAdjusterListener(this); + amount->setAdjusterListener(this); + darkness->setAdjusterListener(this); + lightness->setAdjusterListener(this); + + radius->show(); + amount->show(); + darkness->show(); + lightness->show(); + + pack_start(*radius); + pack_start(*amount); + pack_start(*darkness); + pack_start(*lightness); +} + + +void LocalContrast::read(const ProcParams *pp, const ParamsEdited *pedited) +{ + disableListener(); + + if (pedited) { + radius->setEditedState(pedited->localContrast.radius ? Edited : UnEdited); + amount->setEditedState(pedited->localContrast.amount ? Edited : UnEdited); + darkness->setEditedState(pedited->localContrast.darkness ? Edited : UnEdited); + lightness->setEditedState(pedited->localContrast.lightness ? Edited : UnEdited); + set_inconsistent(multiImage && !pedited->localContrast.enabled); + } + + setEnabled(pp->localContrast.enabled); + radius->setValue(pp->localContrast.radius); + amount->setValue(pp->localContrast.amount); + darkness->setValue(pp->localContrast.darkness); + lightness->setValue(pp->localContrast.lightness); + + enableListener(); +} + + +void LocalContrast::write(ProcParams *pp, ParamsEdited *pedited) +{ + pp->localContrast.radius = radius->getValue(); + pp->localContrast.amount = amount->getValue(); + pp->localContrast.darkness = darkness->getValue(); + pp->localContrast.lightness = lightness->getValue(); + pp->localContrast.enabled = getEnabled(); + + if (pedited) { + pedited->localContrast.radius = radius->getEditedState(); + pedited->localContrast.amount = amount->getEditedState(); + pedited->localContrast.darkness = darkness->getEditedState(); + pedited->localContrast.lightness = lightness->getEditedState(); + pedited->localContrast.enabled = !get_inconsistent(); + } +} + +void LocalContrast::setDefaults(const ProcParams *defParams, const ParamsEdited *pedited) +{ + radius->setDefault(defParams->localContrast.radius); + amount->setDefault(defParams->localContrast.amount); + darkness->setDefault(defParams->localContrast.darkness); + lightness->setDefault(defParams->localContrast.lightness); + + if (pedited) { + radius->setDefaultEditedState(pedited->localContrast.radius ? Edited : UnEdited); + amount->setDefaultEditedState(pedited->localContrast.amount ? Edited : UnEdited); + darkness->setDefaultEditedState(pedited->localContrast.darkness ? Edited : UnEdited); + lightness->setDefaultEditedState(pedited->localContrast.lightness ? Edited : UnEdited); + } else { + radius->setDefaultEditedState(Irrelevant); + amount->setDefaultEditedState(Irrelevant); + darkness->setDefaultEditedState(Irrelevant); + lightness->setDefaultEditedState(Irrelevant); + } +} + + +void LocalContrast::adjusterChanged(Adjuster* a, double newval) +{ + if (listener && getEnabled()) { + if (a == radius) { + listener->panelChanged(EvLocalContrastRadius, a->getTextValue()); + } else if (a == amount) { + listener->panelChanged(EvLocalContrastAmount, a->getTextValue()); + } else if (a == darkness) { + listener->panelChanged(EvLocalContrastDarkness, a->getTextValue()); + } else if (a == lightness) { + listener->panelChanged(EvLocalContrastLightness, a->getTextValue()); + } + } +} + + +void LocalContrast::enabledChanged () +{ + if (listener) { + if (get_inconsistent()) { + listener->panelChanged(EvLocalContrastEnabled, M("GENERAL_UNCHANGED")); + } else if (getEnabled()) { + listener->panelChanged(EvLocalContrastEnabled, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(EvLocalContrastEnabled, M("GENERAL_DISABLED")); + } + } +} + + +void LocalContrast::setBatchMode(bool batchMode) +{ + ToolPanel::setBatchMode(batchMode); + + radius->showEditedCB(); + amount->showEditedCB(); + darkness->showEditedCB(); + lightness->showEditedCB(); +} + + +void LocalContrast::setAdjusterBehavior(bool radiusAdd, bool amountAdd, bool darknessAdd, bool lightnessAdd) +{ + radius->setAddMode(radiusAdd); + amount->setAddMode(amountAdd); + darkness->setAddMode(darknessAdd); + lightness->setAddMode(lightnessAdd); +} + diff --git a/rtgui/localcontrast.h b/rtgui/localcontrast.h new file mode 100644 index 000000000..4f6f872af --- /dev/null +++ b/rtgui/localcontrast.h @@ -0,0 +1,53 @@ +/** -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2017 Alberto Griggio + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#pragma once + +#include +#include "adjuster.h" +#include "toolpanel.h" + +class LocalContrast: public ToolParamBlock, public AdjusterListener, public FoldableToolPanel +{ +private: + Adjuster *radius; + Adjuster *amount; + Adjuster *darkness; + Adjuster *lightness; + + rtengine::ProcEvent EvLocalContrastEnabled; + rtengine::ProcEvent EvLocalContrastRadius; + rtengine::ProcEvent EvLocalContrastAmount; + rtengine::ProcEvent EvLocalContrastDarkness; + rtengine::ProcEvent EvLocalContrastLightness; + +public: + + LocalContrast(); + + void read(const rtengine::procparams::ProcParams *pp, const ParamsEdited *pedited=nullptr); + void write(rtengine::procparams::ProcParams *pp, ParamsEdited *pedited=nullptr); + void setDefaults(const rtengine::procparams::ProcParams *defParams, const ParamsEdited *pedited=nullptr); + void setBatchMode(bool batchMode); + + void adjusterChanged(Adjuster *a, double newval); + void enabledChanged(); + void setAdjusterBehavior(bool radiusAdd, bool amountAdd, bool darknessAdd, bool lightnessAdd); +}; + diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index ea29079a0..954a42954 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -98,6 +98,11 @@ void ParamsEdited::set (bool v) labCurve.avoidcolorshift = v; labCurve.rstprotection = v; labCurve.lcredsk = v; + localContrast.enabled = v; + localContrast.radius = v; + localContrast.amount = v; + localContrast.darkness = v; + localContrast.lightness = v; rgbCurves.enabled = v; rgbCurves.lumamode = v; rgbCurves.rcurve = v; @@ -644,6 +649,13 @@ void ParamsEdited::initFrom (const std::vector labCurve.avoidcolorshift = labCurve.avoidcolorshift && p.labCurve.avoidcolorshift == other.labCurve.avoidcolorshift; labCurve.rstprotection = labCurve.rstprotection && p.labCurve.rstprotection == other.labCurve.rstprotection; labCurve.lcredsk = labCurve.lcredsk && p.labCurve.lcredsk == other.labCurve.lcredsk; + + localContrast.enabled = localContrast.enabled && p.localContrast.enabled == other.localContrast.enabled; + localContrast.radius = localContrast.radius && p.localContrast.radius == other.localContrast.radius; + localContrast.amount = localContrast.amount && p.localContrast.amount == other.localContrast.amount; + localContrast.darkness = localContrast.darkness && p.localContrast.darkness == other.localContrast.darkness; + localContrast.lightness = localContrast.lightness && p.localContrast.lightness == other.localContrast.lightness; + rgbCurves.enabled = rgbCurves.enabled && p.rgbCurves.enabled == other.rgbCurves.enabled; rgbCurves.lumamode = rgbCurves.lumamode && p.rgbCurves.lumamode == other.rgbCurves.lumamode; rgbCurves.rcurve = rgbCurves.rcurve && p.rgbCurves.rcurve == other.rgbCurves.rcurve; @@ -1372,6 +1384,22 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten toEdit.labCurve.lcredsk = mods.labCurve.lcredsk; } + if (localContrast.enabled) { + toEdit.localContrast.enabled = mods.localContrast.enabled; + } + if (localContrast.radius) { + toEdit.localContrast.radius = mods.localContrast.radius; + } + if (localContrast.amount) { + toEdit.localContrast.amount = mods.localContrast.amount; + } + if (localContrast.darkness) { + toEdit.localContrast.darkness = mods.localContrast.darkness; + } + if (localContrast.lightness) { + toEdit.localContrast.lightness = mods.localContrast.lightness; + } + if (rgbCurves.enabled) { toEdit.rgbCurves.enabled = mods.rgbCurves.enabled; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 2727f01ec..2dcbedaf8 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -118,6 +118,17 @@ public: bool clcurve; }; + +class LocalContrastParamsEdited { +public: + bool enabled; + bool radius; + bool amount; + bool darkness; + bool lightness; +}; + + class RGBCurvesParamsEdited { @@ -794,6 +805,7 @@ public: GeneralParamsEdited general; ToneCurveParamsEdited toneCurve; LCurveParamsEdited labCurve; + LocalContrastParamsEdited localContrast; RGBCurvesParamsEdited rgbCurves; ColorToningEdited colorToning; RetinexParamsEdited retinex; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index 4b5c7a857..898b6dad5 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -49,6 +49,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren // options in basic: wb = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_WHITEBALANCE"))); exposure = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EXPOSURE"))); + localcontrast = Gtk::manage(new Gtk::CheckButton(M("PARTIALPASTE_LOCALCONTRAST"))); sh = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_SHADOWSHIGHLIGHTS"))); epd = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_EPD"))); fattal = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_TM_FATTAL"))); @@ -142,6 +143,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren vboxes[0]->pack_start (*hseps[0], Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*wb, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*exposure, Gtk::PACK_SHRINK, 2); + vboxes[0]->pack_start (*localcontrast, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*sh, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*epd, Gtk::PACK_SHRINK, 2); vboxes[0]->pack_start (*fattal, Gtk::PACK_SHRINK, 2); @@ -298,6 +300,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren wbConn = wb->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); exposureConn = exposure->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); + localcontrastConn = localcontrast->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); shConn = sh->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); epdConn = epd->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); fattalConn = fattal->signal_toggled().connect (sigc::bind (sigc::mem_fun(*basic, &Gtk::CheckButton::set_inconsistent), true)); @@ -472,6 +475,7 @@ void PartialPasteDlg::basicToggled () ConnectionBlocker wbBlocker(wbConn); ConnectionBlocker exposureBlocker(exposureConn); + ConnectionBlocker localcontrastBlocker(localcontrastConn); ConnectionBlocker shBlocker(shConn); ConnectionBlocker epdBlocker(epdConn); ConnectionBlocker fattalBlocker(fattalConn); @@ -485,6 +489,7 @@ void PartialPasteDlg::basicToggled () wb->set_active (basic->get_active ()); exposure->set_active (basic->get_active ()); + localcontrast->set_active(basic->get_active()); sh->set_active (basic->get_active ()); epd->set_active (basic->get_active ()); fattal->set_active (basic->get_active ()); @@ -629,6 +634,10 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param filterPE.toneCurve = falsePE.toneCurve; } + if (!localcontrast->get_active()) { + filterPE.localContrast = falsePE.localContrast; + } + if (!sh->get_active ()) { filterPE.sh = falsePE.sh; } diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index baef6b9aa..d1ae056c3 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -44,6 +44,7 @@ public: // options in basic: Gtk::CheckButton* wb; Gtk::CheckButton* exposure; + Gtk::CheckButton* localcontrast; Gtk::CheckButton* sh; Gtk::CheckButton* epd; Gtk::CheckButton* fattal; @@ -124,7 +125,7 @@ public: sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaConn, rawConn, wavConn; - sigc::connection wbConn, exposureConn, shConn, pcvignetteConn, gradientConn, labcurveConn, colorappearanceConn; + sigc::connection wbConn, exposureConn, localcontrastConn, shConn, pcvignetteConn, gradientConn, labcurveConn, colorappearanceConn; sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, defringeConn, epdConn, fattalConn, dirpyreqConn, waveletConn, retinexConn; sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn, chmixerbwConn, colortoningConn, filmSimulationConn; sigc::connection distortionConn, cacorrConn, vignettingConn, lcpConn; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index e66edce29..e0a5747d9 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -187,6 +187,14 @@ Gtk::Widget* Preferences::getBatchProcPanel () appendBehavList (mi, M ("TP_EXPOSURE_CONTRAST"), ADDSET_TC_CONTRAST, false); appendBehavList (mi, M ("TP_EXPOSURE_SATURATION"), ADDSET_TC_SATURATION, false); + mi = behModel->append(); + mi->set_value(behavColumns.label, M("TP_LOCALCONTRAST_LABEL")); + appendBehavList(mi, M("TP_LOCALCONTRAST_RADIUS"), ADDSET_LOCALCONTRAST_RADIUS, false); + appendBehavList(mi, M("TP_LOCALCONTRAST_AMOUNT"), ADDSET_LOCALCONTRAST_AMOUNT, false); + appendBehavList(mi, M("TP_LOCALCONTRAST_DARKNESS"), ADDSET_LOCALCONTRAST_DARKNESS, false); + appendBehavList(mi, M("TP_LOCALCONTRAST_LIGHTNESS"), ADDSET_LOCALCONTRAST_LIGHTNESS, false); + + mi = behModel->append (); mi->set_value (behavColumns.label, M ("TP_EPD_LABEL")); appendBehavList (mi, M ("TP_EPD_STRENGTH"), ADDSET_EPD_STRENGTH, false); diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 9153c6fb4..318ebf55b 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -41,6 +41,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), hasChan coarse = Gtk::manage (new CoarsePanel ()); toneCurve = Gtk::manage (new ToneCurve ()); shadowshighlights = Gtk::manage (new ShadowsHighlights ()); + localContrast = Gtk::manage(new LocalContrast()); impulsedenoise = Gtk::manage (new ImpulseDenoise ()); defringe = Gtk::manage (new Defringe ()); dirpyrdenoise = Gtk::manage (new DirPyrDenoise ()); @@ -106,6 +107,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), hasChan addPanel (colorPanel, vibrance); addPanel (colorPanel, chmixer); addPanel (colorPanel, blackwhite); + addPanel (exposurePanel, localContrast); addPanel (exposurePanel, shadowshighlights); addPanel (detailsPanel, sharpening); addPanel (detailsPanel, sharpenEdge); @@ -313,7 +315,7 @@ void ToolPanelCoordinator::panelChanged (rtengine::ProcEvent event, const Glib:: return; } - int changeFlags = refreshmap[ (int)event]; + int changeFlags = rtengine::RefreshMapper::getInstance()->getAction(event); ProcParams* params = ipc->beginUpdateParams (); @@ -325,7 +327,7 @@ void ToolPanelCoordinator::panelChanged (rtengine::ProcEvent event, const Glib:: if (event == rtengine::EvCTHFlip || event == rtengine::EvCTVFlip) { if (fabs (params->rotate.degree) > 0.001) { params->rotate.degree *= -1; - changeFlags |= refreshmap[ (int)rtengine::EvROTDegree]; + changeFlags |= rtengine::RefreshMapper::getInstance()->getAction(rtengine::EvROTDegree); rotate->read (params); } } @@ -444,7 +446,7 @@ void ToolPanelCoordinator::profileChange (const PartialProfile *nparams, rtengi // start the IPC processing if (filterRawRefresh) { - ipc->endUpdateParams ( refreshmap[ (int)event] & ALLNORAW ); + ipc->endUpdateParams ( rtengine::RefreshMapper::getInstance()->getAction(event) & ALLNORAW ); } else { ipc->endUpdateParams (event); } diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 3da061b99..7c4b94ed9 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -79,6 +79,7 @@ #include "filmsimulation.h" #include "prsharpening.h" #include "fattaltonemap.h" +#include "localcontrast.h" #include "guiutils.h" class ImageEditorCoordinator; @@ -120,6 +121,7 @@ protected: Crop* crop; ToneCurve* toneCurve; ShadowsHighlights* shadowshighlights; + LocalContrast *localContrast; Defringe* defringe; ImpulseDenoise* impulsedenoise; DirPyrDenoise* dirpyrdenoise;