diff --git a/rtdata/languages/default b/rtdata/languages/default index 90c27adf0..0dfc856bb 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2154,6 +2154,7 @@ TP_LOCALLAB_SCOPEMASK;Scope Mask DeltaE Image TP_LOCALLAB_SCOPEMASK_TOOLTIP;Enabled if Mask DeltaE Image is enabled.\nLow values avoid retouching selected area TP_LOCALLAB_MASFRAME;Mask and Merge TP_LOCALLAB_MERGETYPE;Merge image and mask +TP_LOCALLAB_MERGETYPE_TOOLTIP;None, use all mask in LCH mode.\nShort curves 'L' mask, use a short circuit for mask 2, 3, 4, 6, 7.\nOriginal mask 7, blend current image with original TP_LOCALLAB_MERGENONE;None TP_LOCALLAB_MERGEONE;Short Curves 'L' Mask TP_LOCALLAB_MERGETWO;Original (Mask 7) @@ -2161,8 +2162,15 @@ TP_LOCALLAB_MERGE1COLFRA;Merge with Original TP_LOCALLAB_OPACOL;Opacity TP_LOCALLAB_MERGECOLFRA;Mask LCH TP_LOCALLAB_MERONE;Normal -TP_LOCALLAB_MERTWO;Difference +TP_LOCALLAB_MERTWO;Substract TP_LOCALLAB_MERTHR;Multiply +TP_LOCALLAB_MERFOU;Addition +TP_LOCALLAB_MERFIV;Divide +TP_LOCALLAB_MERSIX;Soft Light +TP_LOCALLAB_MERSEV;Overlay +TP_LOCALLAB_MERHEI;Screen +TP_LOCALLAB_MERNIN;Darken only +TP_LOCALLAB_MERTEN;Lighten only TP_LOCALLAB_MASFRAME_TOOLTIP;For all masks.\nTake into account deltaE image to avoid retouching the selection area when sliders gamma mask, slope mask, chroma mask and contrast curves and levels contrasts curves are used.\nDisabled in Inverse TP_LOCALLAB_WAMASKCOL;Mask Wavelet level TP_LOCALLAB_CSTHRESHOLDBLUR;Mask Wavelet level diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index a4af0bc90..f30dcb50e 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -601,6 +601,20 @@ static void calcLocalParams(int sp, int oW, int oH, const LocallabParams& locall lp.mergecolMethod = 1; } else if (locallab.spots.at(sp).mergecolMethod == "thr") { lp.mergecolMethod = 2; + } else if (locallab.spots.at(sp).mergecolMethod == "fou") { + lp.mergecolMethod = 3; + } else if (locallab.spots.at(sp).mergecolMethod == "fiv") { + lp.mergecolMethod = 4; + } else if (locallab.spots.at(sp).mergecolMethod == "six") { + lp.mergecolMethod = 5; + } else if (locallab.spots.at(sp).mergecolMethod == "sev") { + lp.mergecolMethod = 6; + } else if (locallab.spots.at(sp).mergecolMethod == "hei") { + lp.mergecolMethod = 7; + } else if (locallab.spots.at(sp).mergecolMethod == "nin") { + lp.mergecolMethod = 8; + } else if (locallab.spots.at(sp).mergecolMethod == "ten") { + lp.mergecolMethod = 9; } lp.opacol = 0.01f * locallab.spots.at(sp).opacol; @@ -5212,8 +5226,28 @@ const int fftw_size[] = {18144, 18000, 17920, 17836, 17820, 17640, 17600, 17550, int N_fftwsize = sizeof(fftw_size) / sizeof(fftw_size[0]); +static void softlig (float &a, float &b) +{ + if(b <= 0.5f) { + a = (2.f * a * b) + a * a * (1.f - 2.f * b); + } else { + a = 2.f * a *(1.f - b) + sqrt(a) * (2.f * b - 1.f); + } +} +static void overlay (float &a, float &b) +{ + if(b <= 0.5f) { + a = (2.f * a * b); + } else { + a = 1.f - 2.f * (1.f - a) * (1.f - b); + } +} +static void screen (float &a, float &b) +{ + a = 1.f - (1.f - a) * (1.f - b); +} @@ -11717,7 +11751,7 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o if(lp.mergemet == 2) {//merge result with original std::unique_ptr bufcolreserv; bufcolreserv.reset(new LabImage(bfw, bfh)); - +//printf("method=%i \n", lp.mergecolMethod); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) #endif @@ -11730,7 +11764,7 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o } } - if(lp.mergecolMethod == 0) { + if(lp.mergecolMethod == 0) {//normal #ifdef _OPENMP @@ -11758,7 +11792,7 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o lab2rgb(*bufcolreserv, *tmpImagereserv, params->icm.workingProfile); tmpImagereserv->normalizeFloatTo1(); //various combinaison substrct, multiply, difference, etc. todo - if(lp.mergecolMethod == 1) { + if(lp.mergecolMethod == 1) {//substract #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) #endif @@ -11771,7 +11805,7 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o } } - if(lp.mergecolMethod == 2) { + else if(lp.mergecolMethod == 2) {//multiply #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) #endif @@ -11783,6 +11817,122 @@ void ImProcFunctions::Lab_Local(int call, int sp, float** shbuffer, LabImage * o } } } + + else if(lp.mergecolMethod == 3) {//addition +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = lp.opacol * LIM01(tmpImageorig->r(y, x) + tmpImagereserv->r(y, x)) + (1.f - lp.opacol) * tmpImageorig->r(y, x); + tmpImageorig->g(y, x) = lp.opacol * LIM01(tmpImageorig->g(y, x) + tmpImagereserv->g(y, x)) + (1.f - lp.opacol) * tmpImageorig->g(y, x); + tmpImageorig->b(y, x) = lp.opacol * LIM01(tmpImageorig->b(y, x) + tmpImagereserv->b(y, x)) + (1.f - lp.opacol) * tmpImageorig->b(y, x); + } + } + } + + else if(lp.mergecolMethod == 4) {//divide +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = lp.opacol * LIM01(tmpImageorig->r(y, x) / (tmpImagereserv->r(y, x) + 0.00001f)) + (1.f - lp.opacol) * tmpImageorig->r(y, x); + tmpImageorig->g(y, x) = lp.opacol * LIM01(tmpImageorig->g(y, x) / (tmpImagereserv->g(y, x) + 0.00001f)) + (1.f - lp.opacol) * tmpImageorig->g(y, x); + tmpImageorig->b(y, x) = lp.opacol * LIM01(tmpImageorig->b(y, x) / (tmpImagereserv->b(y, x) + 0.00001f)) + (1.f - lp.opacol) * tmpImageorig->b(y, x); + } + } + } + else if(lp.mergecolMethod == 5) {//soft light softlig (float &a, float &b) +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + float a = tmpImageorig->r(y, x); + float b = tmpImagereserv->r(y, x); + softlig(a, b); + tmpImageorig->r(y, x) = lp.opacol * LIM01(a) + (1.f - lp.opacol) * tmpImageorig->r(y, x); + a = tmpImageorig->g(y, x); + b = tmpImagereserv->g(y, x); + softlig(a, b); + tmpImageorig->g(y, x) = lp.opacol * LIM01(a) + (1.f - lp.opacol) * tmpImageorig->g(y, x); + a = tmpImageorig->b(y, x); + b = tmpImagereserv->b(y, x); + softlig(a, b); + tmpImageorig->b(y, x) = lp.opacol * LIM01(a) + (1.f - lp.opacol) * tmpImageorig->b(y, x); + } + } + } + + else if(lp.mergecolMethod == 6) {//overlay overlay (float &a, float &b) +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + float a = tmpImageorig->r(y, x); + float b = tmpImagereserv->r(y, x); + overlay(a, b); + tmpImageorig->r(y, x) = lp.opacol * LIM01(a) + (1.f - lp.opacol) * tmpImageorig->r(y, x); + a = tmpImageorig->g(y, x); + b = tmpImagereserv->g(y, x); + overlay(a, b); + tmpImageorig->g(y, x) = lp.opacol * LIM01(a) + (1.f - lp.opacol) * tmpImageorig->g(y, x); + a = tmpImageorig->b(y, x); + b = tmpImagereserv->b(y, x); + overlay(a, b); + tmpImageorig->b(y, x) = lp.opacol * LIM01(a) + (1.f - lp.opacol) * tmpImageorig->b(y, x); + } + } + } + + else if(lp.mergecolMethod == 7) {//screen screen (float &a, float &b) +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + float a = tmpImageorig->r(y, x); + float b = tmpImagereserv->r(y, x); + screen(a, b); + tmpImageorig->r(y, x) = lp.opacol * LIM01(a) + (1.f - lp.opacol) * tmpImageorig->r(y, x); + a = tmpImageorig->g(y, x); + b = tmpImagereserv->g(y, x); + screen(a, b); + tmpImageorig->g(y, x) = lp.opacol * LIM01(a) + (1.f - lp.opacol) * tmpImageorig->g(y, x); + a = tmpImageorig->b(y, x); + b = tmpImagereserv->b(y, x); + screen(a, b); + tmpImageorig->b(y, x) = lp.opacol * LIM01(a) + (1.f - lp.opacol) * tmpImageorig->b(y, x); + } + } + } + else if(lp.mergecolMethod == 8) {//darken only +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = lp.opacol * std::min(tmpImageorig->r(y, x), tmpImagereserv->r(y, x)) + (1.f - lp.opacol) * tmpImageorig->r(y, x); + tmpImageorig->g(y, x) = lp.opacol * std::min(tmpImageorig->g(y, x), tmpImagereserv->g(y, x)) + (1.f - lp.opacol) * tmpImageorig->g(y, x); + tmpImageorig->b(y, x) = lp.opacol * std::min(tmpImageorig->b(y, x), tmpImagereserv->b(y, x)) + (1.f - lp.opacol) * tmpImageorig->b(y, x); + } + } + } + else if(lp.mergecolMethod == 9) {//lighten only +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + for (int y = 0; y < bfh ; y++) { + for (int x = 0; x < bfw; x++) { + tmpImageorig->r(y, x) = lp.opacol * std::max(tmpImageorig->r(y, x), tmpImagereserv->r(y, x)) + (1.f - lp.opacol) * tmpImageorig->r(y, x); + tmpImageorig->g(y, x) = lp.opacol * std::max(tmpImageorig->g(y, x), tmpImagereserv->g(y, x)) + (1.f - lp.opacol) * tmpImageorig->g(y, x); + tmpImageorig->b(y, x) = lp.opacol * std::max(tmpImageorig->b(y, x), tmpImagereserv->b(y, x)) + (1.f - lp.opacol) * tmpImageorig->b(y, x); + } + } + } + tmpImageorig->normalizeFloatTo65535(); rgb2lab(*tmpImageorig, *bufcolfin, params->icm.workingProfile); diff --git a/rtgui/controlspotpanel.cc b/rtgui/controlspotpanel.cc index 69ec4e524..5cc7d7e7b 100644 --- a/rtgui/controlspotpanel.cc +++ b/rtgui/controlspotpanel.cc @@ -294,8 +294,6 @@ ControlSpotPanel::ControlSpotPanel(): sigc::mem_fun( *this, &ControlSpotPanel::mergeMethodChanged)); ctboxmergemethod->pack_start(*mergeMethod_); -// pack_start(*ctboxmergemethod); - avoidConn_ = avoid_->signal_toggled().connect( sigc::mem_fun(*this, &ControlSpotPanel::avoidChanged)); @@ -321,8 +319,14 @@ ControlSpotPanel::ControlSpotPanel(): maskBox->pack_start(*deltae_); maskBox->pack_start(*scopemask_); // maskBox->pack_start(*shortc_); + Gtk::HSeparator *separator = Gtk::manage(new Gtk::HSeparator()); + maskBox->pack_start(*separator, Gtk::PACK_SHRINK, 2); + maskBox->pack_start(*ctboxmergemethod); + Gtk::HSeparator *separator1 = Gtk::manage(new Gtk::HSeparator()); + maskBox->pack_start(*separator1, Gtk::PACK_SHRINK, 2); + maskBox->pack_start(*lumask_); // maskBox->pack_start(*savrest_); maskFrame->add(*maskBox); diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc index ab279172f..d54fbfcd5 100644 --- a/rtgui/locallab.cc +++ b/rtgui/locallab.cc @@ -633,6 +633,13 @@ Locallab::Locallab(): mergecolMethod->append(M("TP_LOCALLAB_MERONE")); mergecolMethod->append(M("TP_LOCALLAB_MERTWO")); mergecolMethod->append(M("TP_LOCALLAB_MERTHR")); + mergecolMethod->append(M("TP_LOCALLAB_MERFOU")); + mergecolMethod->append(M("TP_LOCALLAB_MERFIV")); + mergecolMethod->append(M("TP_LOCALLAB_MERSIX")); + mergecolMethod->append(M("TP_LOCALLAB_MERSEV")); + mergecolMethod->append(M("TP_LOCALLAB_MERHEI")); + mergecolMethod->append(M("TP_LOCALLAB_MERNIN")); + mergecolMethod->append(M("TP_LOCALLAB_MERTEN")); mergecolMethod->set_active(0); mergecolMethodConn = mergecolMethod->signal_changed().connect(sigc::mem_fun(*this, &Locallab::mergecolMethodChanged)); @@ -3489,6 +3496,20 @@ void Locallab::write(ProcParams* pp, ParamsEdited* pedited) pp->locallab.spots.at(pp->locallab.selspot).mergecolMethod = "two"; } else if (mergecolMethod->get_active_row_number() == 2) { pp->locallab.spots.at(pp->locallab.selspot).mergecolMethod = "thr"; + } else if (mergecolMethod->get_active_row_number() == 3) { + pp->locallab.spots.at(pp->locallab.selspot).mergecolMethod = "fou"; + } else if (mergecolMethod->get_active_row_number() == 4) { + pp->locallab.spots.at(pp->locallab.selspot).mergecolMethod = "fiv"; + } else if (mergecolMethod->get_active_row_number() == 5) { + pp->locallab.spots.at(pp->locallab.selspot).mergecolMethod = "six"; + } else if (mergecolMethod->get_active_row_number() == 6) { + pp->locallab.spots.at(pp->locallab.selspot).mergecolMethod = "sev"; + } else if (mergecolMethod->get_active_row_number() == 7) { + pp->locallab.spots.at(pp->locallab.selspot).mergecolMethod = "hei"; + } else if (mergecolMethod->get_active_row_number() == 8) { + pp->locallab.spots.at(pp->locallab.selspot).mergecolMethod = "nin"; + } else if (mergecolMethod->get_active_row_number() == 9) { + pp->locallab.spots.at(pp->locallab.selspot).mergecolMethod = "ten"; } pp->locallab.spots.at(pp->locallab.selspot).llcurve = llshape->getCurve(); @@ -8545,7 +8566,21 @@ void Locallab::updateLocallabGUI(const rtengine::procparams::ProcParams* pp, con mergecolMethod->set_active(1); } else if (pp->locallab.spots.at(index).mergecolMethod == "thr") { mergecolMethod->set_active(2); - } + } else if (pp->locallab.spots.at(index).mergecolMethod == "fou") { + mergecolMethod->set_active(3); + } else if (pp->locallab.spots.at(index).mergecolMethod == "fiv") { + mergecolMethod->set_active(4); + } else if (pp->locallab.spots.at(index).mergecolMethod == "six") { + mergecolMethod->set_active(5); + } else if (pp->locallab.spots.at(index).mergecolMethod == "sev") { + mergecolMethod->set_active(6); + } else if (pp->locallab.spots.at(index).mergecolMethod == "hei") { + mergecolMethod->set_active(7); + } else if (pp->locallab.spots.at(index).mergecolMethod == "nin") { + mergecolMethod->set_active(8); + } else if (pp->locallab.spots.at(index).mergecolMethod == "ten") { + mergecolMethod->set_active(9); + } if (pp->locallab.spots.at(index).scalereti == 1) {