diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index d858d5a7a..41fcacd53 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -15,7 +15,7 @@ on: workflow_dispatch: env: - publish_pre_dev_labels: '[]' + publish_pre_dev_labels: '["Beep6581:avoidneg"]' jobs: build: diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 004aba59d..5a2d240dc 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -15,7 +15,7 @@ on: workflow_dispatch: env: - publish_pre_dev_labels: '[]' + publish_pre_dev_labels: '["Beep6581:avoidneg"]' jobs: diff --git a/rtdata/languages/default b/rtdata/languages/default index b20bd36da..93d2eef94 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1488,6 +1488,7 @@ HISTORY_MSG_ICM_WORKING_PRIM_METHOD;Primaries method HISTORY_MSG_ICM_WORKING_SLOPE;TRC - Slope HISTORY_MSG_ICM_WORKING_TRC_METHOD;TRC method HISTORY_MSG_ILLUM;CAL - SC - Illuminant +HISTORY_MSG_LOCAL_AVOIDNEGATIVE;Local - SC - Pre-filter zero and negative values HISTORY_MSG_LOCAL_CIE_CONTSIG;Local CIECAM - Sigmoid contrast HISTORY_MSG_LOCAL_CIE_SKEWSIG;Local CIECAM - Sigmoid skew HISTORY_MSG_LOCAL_CIE_SMOOTHTH;Local CIECAM - Attenuation threshold @@ -2997,6 +2998,7 @@ TP_LOCALLAB_AVOID;Avoid color shift TP_LOCALLAB_AVOIDCOLORSHIFT_TOOLTIP;Fit colors into gamut of the working color space and apply Munsell correction (Uniform Perceptual Lab). Default: Munsell only.\n\nMunsell only: Fixes Lab mode hue drifts due to non-linearity when chromaticity is changed (Uniform Perceptual Lab).\nLab: Applies a gamut control in relative colorimetric. Munsell is then applied.\nXYZ Absolute: Applies gamut control in absolute colorimetric. Munsell is then applied.\nXYZ Relative: Applies gamut control in relative colorimetric. Munsell is then applied. The result is not the same as Lab. TP_LOCALLAB_AVOIDMUN;Munsell correction only TP_LOCALLAB_AVOIDMUN_TOOLTIP;Munsell correction always disabled when Jz or CAM16 is used. +TP_LOCALLAB_AVOIDNEG;Pre-filter zero and negative values TP_LOCALLAB_AVOIDRAD;Soft radius TP_LOCALLAB_BALAN;ab-L balance (ΔE) TP_LOCALLAB_BALANEXP;Laplacian balance diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 9d2f0e997..2e32acb00 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -843,6 +843,7 @@ struct local_params { float residhithr; float residgam; float residslop; + bool avoidneg; bool blwh; bool fftma; float blurma; @@ -1892,6 +1893,7 @@ static void calcLocalParams(int sp, int oW, int oH, const LocallabParams& locall lp.residhithr = locallab.spots.at(sp).residhithr; lp.residgam = locallab.spots.at(sp).residgam; lp.residslop = locallab.spots.at(sp).residslop; + lp.avoidneg = locallab.spots.at(sp).avoidneg; lp.blwh = locallab.spots.at(sp).blwh; lp.senscolor = (int) locallab.spots.at(sp).colorscope; //replace scope color vibrance shadows @@ -14276,13 +14278,46 @@ void ImProcFunctions::Lab_Local( return; } - //BENCHFUN + constexpr int del = 3; // to avoid crash with [loy - begy] and [lox - begx] and bfh bfw // with gtk2 [loy - begy-1] [lox - begx -1 ] and del = 1 struct local_params lp; calcLocalParams(sp, oW, oH, params->locallab, lp, prevDeltaE, llColorMask, llColorMaskinv, llExpMask, llExpMaskinv, llSHMask, llSHMaskinv, llvibMask, lllcMask, llsharMask, llcbMask, llretiMask, llsoftMask, lltmMask, llblMask, lllogMask, ll_Mask, llcieMask, locwavCurveden, locwavdenutili); //avoidcolshi(lp, sp, transformed, reserved, cy, cx, sk); + //BENCHFUN + + + + + //Pre-filter zero and negative values RGB then Lab when using before SE CBDL or Dehaze, or processor type... + + int bw0 = transformed->W; + int bh0 = transformed->H; + + float epsi0 = 0.000001f; + bool nocrash = false; + bool cbdl = false; + if(params->dirpyrequalizer.cbdlMethod == "bef") {//If user choose "after black and white" this function which removes negative values is not used, hence CBDL is best performed, after Selective Editing in Lab mode + cbdl = true; + } + nocrash = (params->dirpyrequalizer.enabled && cbdl) || params->dehaze.enabled || lp.avoidneg;//lp.avoidneg in setting + + + if(nocrash) {//allows memory and conversion labrgb only in these cases and prevent negative RGB values + const std::unique_ptr prov0(new Imagefloat(bw0, bh0)); + lab2rgb(*transformed, *prov0, params->icm.workingProfile); +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 0; i < bh0; ++i) + for (int j = 0; j < bw0; ++j) { + prov0->r(i, j) = (rtengine::max(prov0->r(i, j), epsi0)); + prov0->g(i, j) = (rtengine::max(prov0->g(i, j), epsi0)); + prov0->b(i, j) = (rtengine::max(prov0->b(i, j), epsi0)); + } + rgb2lab(*prov0, *transformed, params->icm.workingProfile); + } const float radius = lp.rad / (sk * 1.4); //0 to 70 ==> see skip int levred; @@ -21083,7 +21118,6 @@ void ImProcFunctions::Lab_Local( float epsi = 0.000001f; - if((lp.laplacexp > 1.f && lp.exposena) || (lp.strng > 2.f && lp.sfena) || (lp.exposena && lp.expcomp != 0.f && params->dirpyrequalizer.enabled)){//strong Laplacian notlaplacian = true; } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 9746c3aab..2eb4c30df 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -3317,6 +3317,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : transitgrad(0.0), hishow(options.complexity != 2), activ(true), + avoidneg(true), blwh(false), recurs(false), laplac(true), @@ -5219,6 +5220,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && transitgrad == other.transitgrad && hishow == other.hishow && activ == other.activ + && avoidneg == other.avoidneg && blwh == other.blwh && recurs == other.recurs && laplac == other.laplac @@ -7226,6 +7228,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || spot_edited->transitgrad, "Locallab", "Transitgrad_" + index_str, spot.transitgrad, keyFile); saveToKeyfile(!pedited || spot_edited->hishow, "Locallab", "Hishow_" + index_str, spot.hishow, keyFile); saveToKeyfile(!pedited || spot_edited->activ, "Locallab", "Activ_" + index_str, spot.activ, keyFile); + saveToKeyfile(!pedited || spot_edited->avoidneg, "Locallab", "Avoidneg_" + index_str, spot.avoidneg, keyFile); saveToKeyfile(!pedited || spot_edited->blwh, "Locallab", "Blwh_" + index_str, spot.blwh, keyFile); saveToKeyfile(!pedited || spot_edited->recurs, "Locallab", "Recurs_" + index_str, spot.recurs, keyFile); saveToKeyfile(!pedited || spot_edited->laplac, "Locallab", "Laplac_" + index_str, spot.laplac, keyFile); @@ -9560,6 +9563,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "Transitgrad_" + index_str, spot.transitgrad, spotEdited.transitgrad); assignFromKeyfile(keyFile, "Locallab", "Hishow_" + index_str, spot.hishow, spotEdited.hishow); assignFromKeyfile(keyFile, "Locallab", "Activ_" + index_str, spot.activ, spotEdited.activ); + assignFromKeyfile(keyFile, "Locallab", "Avoidneg_" + index_str, spot.avoidneg, spotEdited.avoidneg); assignFromKeyfile(keyFile, "Locallab", "Blwh_" + index_str, spot.blwh, spotEdited.blwh); assignFromKeyfile(keyFile, "Locallab", "Recurs_" + index_str, spot.recurs, spotEdited.recurs); assignFromKeyfile(keyFile, "Locallab", "Laplac_" + index_str, spot.laplac, spotEdited.laplac); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 6719b5004..f76afffd9 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1118,6 +1118,7 @@ struct LocallabParams { double transitgrad; bool hishow; bool activ; + bool avoidneg; bool blwh; bool recurs; bool laplac; diff --git a/rtgui/controlspotpanel.cc b/rtgui/controlspotpanel.cc index c4292688a..6bc328c22 100644 --- a/rtgui/controlspotpanel.cc +++ b/rtgui/controlspotpanel.cc @@ -86,6 +86,7 @@ ControlSpotPanel::ControlSpotPanel(): hishow_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_PREVSHOW")))), activ_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ACTIVSPOT")))), + avoidneg_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_AVOIDNEG")))), blwh_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_BLWH")))), recurs_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_RECURS")))), laplac_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_LAPLACC")))), @@ -118,6 +119,7 @@ ControlSpotPanel::ControlSpotPanel(): { auto m = ProcEventMapper::getInstance(); EvLocallabavoidgamutMethod = m->newEvent(AUTOEXP, "HISTORY_MSG_LOCAL_GAMUTMUNSEL"); + EvLocallabavoidnegative = m->newEvent(AUTOEXP, "HISTORY_MSG_LOCAL_AVOIDNEGATIVE"); const bool showtooltip = options.showtooltip; // pack_start(*hishow_); @@ -430,6 +432,8 @@ ControlSpotPanel::ControlSpotPanel(): avFrame->add(*avbox); specCaseBox->pack_start(*avFrame); + avoidnegConn_ = avoidneg_->signal_toggled().connect( + sigc::mem_fun(*this, &ControlSpotPanel::avoidnegChanged)); blwhConn_ = blwh_->signal_toggled().connect( sigc::mem_fun(*this, &ControlSpotPanel::blwhChanged)); @@ -439,6 +443,7 @@ ControlSpotPanel::ControlSpotPanel(): } specCaseBox->pack_start(*blwh_); + specCaseBox->pack_start(*avoidneg_); recursConn_ = recurs_->signal_toggled().connect( sigc::mem_fun(*this, &ControlSpotPanel::recursChanged)); @@ -871,6 +876,7 @@ void ControlSpotPanel::load_ControlSpot_param() avoidrad_->setValue((double)row[spots_.avoidrad]); hishow_->set_active(row[spots_.hishow]); activ_->set_active(row[spots_.activ]); + avoidneg_->set_active(row[spots_.avoidneg]); blwh_->set_active(row[spots_.blwh]); recurs_->set_active(row[spots_.recurs]); // laplac_->set_active(row[spots_.laplac]); @@ -1768,6 +1774,31 @@ void ControlSpotPanel::activChanged() } } +void ControlSpotPanel::avoidnegChanged() +{ + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + row[spots_.avoidneg] = avoidneg_->get_active(); + + // Raise event + if (listener) { + if (avoidneg_->get_active()) { + listener->panelChanged(EvLocallabavoidnegative, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(EvLocallabavoidnegative, M("GENERAL_DISABLED")); + } + } +} + + void ControlSpotPanel::blwhChanged() { @@ -1963,6 +1994,7 @@ void ControlSpotPanel::disableParamlistener(bool cond) avoidrad_->block(cond); hishowconn_.block(cond); activConn_.block(cond); + avoidnegConn_.block(cond); blwhConn_.block(cond); recursConn_.block(cond); laplacConn_.block(cond); @@ -2010,6 +2042,7 @@ void ControlSpotPanel::setParamEditable(bool cond) avoidrad_->set_sensitive(cond); hishow_->set_sensitive(cond); activ_->set_sensitive(cond); + avoidneg_->set_sensitive(cond); blwh_->set_sensitive(cond); recurs_->set_sensitive(cond); laplac_->set_sensitive(cond); @@ -2698,6 +2731,7 @@ std::unique_ptr ControlSpotPanel::getSpot(const int i r->lumask = row[spots_.lumask]; r->hishow = row[spots_.hishow]; r->activ = row[spots_.activ]; + r->avoidneg = row[spots_.avoidneg]; r->blwh = row[spots_.blwh]; r->recurs = row[spots_.recurs]; r->laplac = row[spots_.laplac]; @@ -2830,6 +2864,7 @@ void ControlSpotPanel::addControlSpot(const SpotRow &newSpot) row[spots_.avoidrad] = newSpot.avoidrad; row[spots_.hishow] = newSpot.hishow; row[spots_.activ] = newSpot.activ; + row[spots_.avoidneg] = newSpot.avoidneg; row[spots_.blwh] = newSpot.blwh; row[spots_.recurs] = newSpot.recurs; row[spots_.laplac] = newSpot.laplac; @@ -2999,6 +3034,7 @@ ControlSpotPanel::ControlSpots::ControlSpots() add(avoidrad); add(hishow); add(activ); + add(avoidneg); add(blwh); add(recurs); add(laplac); diff --git a/rtgui/controlspotpanel.h b/rtgui/controlspotpanel.h index cf80a1888..7ebc2648b 100644 --- a/rtgui/controlspotpanel.h +++ b/rtgui/controlspotpanel.h @@ -82,6 +82,7 @@ public: double avoidrad; bool hishow; bool activ; + bool avoidneg; bool blwh; bool recurs; bool laplac; @@ -261,6 +262,7 @@ private: void hishowChanged(); void activChanged(); + void avoidnegChanged(); void blwhChanged(); void recursChanged(); void laplacChanged(); @@ -323,6 +325,7 @@ private: Gtk::TreeModelColumn avoidrad; Gtk::TreeModelColumn hishow; Gtk::TreeModelColumn activ; + Gtk::TreeModelColumn avoidneg; Gtk::TreeModelColumn blwh; Gtk::TreeModelColumn recurs; Gtk::TreeModelColumn laplac; @@ -354,6 +357,7 @@ private: ControlSpots spots_; rtengine::ProcEvent EvLocallabavoidgamutMethod; + rtengine::ProcEvent EvLocallabavoidnegative; // Child widgets Gtk::ScrolledWindow* const scrolledwindow_; @@ -420,6 +424,8 @@ private: sigc::connection hishowconn_; Gtk::CheckButton* const activ_; sigc::connection activConn_; + Gtk::CheckButton* const avoidneg_; + sigc::connection avoidnegConn_; Gtk::CheckButton* const blwh_; sigc::connection blwhConn_; Gtk::CheckButton* const recurs_; diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc index 776b971ae..2fe7dfb53 100644 --- a/rtgui/locallab.cc +++ b/rtgui/locallab.cc @@ -344,6 +344,7 @@ void Locallab::read(const rtengine::procparams::ProcParams* pp, const ParamsEdit r.avoidrad = pp->locallab.spots.at(i).avoidrad; r.hishow = pp->locallab.spots.at(i).hishow; r.activ = pp->locallab.spots.at(i).activ; + r.avoidneg = pp->locallab.spots.at(i).avoidneg; r.blwh = pp->locallab.spots.at(i).blwh; r.recurs = pp->locallab.spots.at(i).recurs; r.laplac = true; //pp->locallab.spots.at(i).laplac; @@ -539,6 +540,7 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited r.avoidrad = newSpot->avoidrad; r.hishow = newSpot->hishow; r.activ = newSpot->activ; + r.avoidneg = newSpot->avoidneg; r.blwh = newSpot->blwh; r.recurs = newSpot->recurs; r.laplac = newSpot->laplac; @@ -879,6 +881,7 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited r.avoidrad = newSpot->avoidrad; r.hishow = newSpot->hishow; r.activ = newSpot->activ; + r.avoidneg = newSpot->avoidneg; r.blwh = newSpot->blwh; r.recurs = newSpot->recurs; r.laplac = newSpot->laplac; @@ -1051,6 +1054,7 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited pp->locallab.spots.at(pp->locallab.selspot).avoidrad = r->avoidrad; pp->locallab.spots.at(pp->locallab.selspot).hishow = r->hishow; pp->locallab.spots.at(pp->locallab.selspot).activ = r->activ; + pp->locallab.spots.at(pp->locallab.selspot).avoidneg = r->avoidneg; pp->locallab.spots.at(pp->locallab.selspot).blwh = r->blwh; pp->locallab.spots.at(pp->locallab.selspot).recurs = r->recurs; pp->locallab.spots.at(pp->locallab.selspot).laplac = r->laplac; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index cfc58c310..9b9345846 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -1317,6 +1317,7 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).transitgrad = locallab.spots.at(j).transitgrad && pSpot.transitgrad == otherSpot.transitgrad; locallab.spots.at(j).hishow = locallab.spots.at(j).hishow && pSpot.hishow == otherSpot.hishow; locallab.spots.at(j).activ = locallab.spots.at(j).activ && pSpot.activ == otherSpot.activ; + locallab.spots.at(j).avoidneg = locallab.spots.at(j).avoidneg && pSpot.avoidneg == otherSpot.avoidneg; locallab.spots.at(j).blwh = locallab.spots.at(j).blwh && pSpot.blwh == otherSpot.blwh; locallab.spots.at(j).recurs = locallab.spots.at(j).recurs && pSpot.recurs == otherSpot.recurs; locallab.spots.at(j).laplac = locallab.spots.at(j).laplac && pSpot.laplac == otherSpot.laplac; @@ -3966,6 +3967,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).activ = mods.locallab.spots.at(i).activ; } + if (locallab.spots.at(i).avoidneg) { + toEdit.locallab.spots.at(i).avoidneg = mods.locallab.spots.at(i).avoidneg; + } + if (locallab.spots.at(i).blwh) { toEdit.locallab.spots.at(i).blwh = mods.locallab.spots.at(i).blwh; } @@ -8338,6 +8343,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : transitgrad(v), hishow(v), activ(v), + avoidneg(v), blwh(v), recurs(v), laplac(v), @@ -9123,6 +9129,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) transitgrad = v; hishow = v; activ = v; + avoidneg = v; blwh = v; recurs = v; laplac = v; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 987c0196c..142e3f05a 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -458,6 +458,7 @@ public: bool transitgrad; bool hishow; bool activ; + bool avoidneg; bool blwh; bool recurs; bool laplac;