diff --git a/rtdata/languages/default b/rtdata/languages/default index 15f0f8b57..307a742f9 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -235,6 +235,11 @@ HISTORY_MSG_97;'b' curve HISTORY_MSG_98;Demozaicing HISTORY_MSG_99;Preprocessing HISTORY_MSG_9;Highlight Compression +HISTORY_MSG_100;RGB saturation +HISTORY_MSG_101;HSV EQ -- Hue +HISTORY_MSG_102;HSV EQ -- Saturation +HISTORY_MSG_103;HSV EQ -- Value +HISTORY_MSG_104;HSV Equalizer HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOTAS;As... HISTORY_NEWSSDIALOGLABEL;Label of the snapshot: @@ -629,6 +634,20 @@ TP_HLREC_COLOR;Color Propagation TP_HLREC_LABEL;Highlight Reconstruction TP_HLREC_LUMINANCE;Luminance Recovery TP_HLREC_METHOD;Method: +TP_HSVEQUALIZER1;Red +TP_HSVEQUALIZER2;Orange +TP_HSVEQUALIZER3;Yellow +TP_HSVEQUALIZER4;Green +TP_HSVEQUALIZER5;Aqua +TP_HSVEQUALIZER6;Blue +TP_HSVEQUALIZER7;Purple +TP_HSVEQUALIZER8;Magenta +TP_HSVEQUALIZER_CHANNEL;HSV Channel +TP_HSVEQUALIZER_HUE;Hue +TP_HSVEQUALIZER_LABEL;HSV Equalizer +TP_HSVEQUALIZER_NEUTRAL;Neutral +TP_HSVEQUALIZER_SAT;Saturation +TP_HSVEQUALIZER_VAL;Value TP_ICM_FILEDLGFILTERANY;Any files TP_ICM_FILEDLGFILTERICM;ICC Profile Files TP_ICM_GAMMABEFOREINPUT;Profile applies Gamma diff --git a/rtdata/profiles/crisp.pp3 b/rtdata/profiles/crisp.pp3 index 888d0f708..04fdbf642 100644 --- a/rtdata/profiles/crisp.pp3 +++ b/rtdata/profiles/crisp.pp3 @@ -1,6 +1,6 @@ [Version] -Version=20101019 +Version=20101111 [Exposure] Auto=true diff --git a/rtdata/profiles/default.pp3 b/rtdata/profiles/default.pp3 index 02d1cb9a6..ae5bcc611 100644 --- a/rtdata/profiles/default.pp3 +++ b/rtdata/profiles/default.pp3 @@ -1,6 +1,6 @@ [Version] -Version=20101019 +Version=20101111 [Exposure] Auto=true diff --git a/rtdata/profiles/neutral.pp3 b/rtdata/profiles/neutral.pp3 index 4705aa2d4..e2fa6c34a 100644 --- a/rtdata/profiles/neutral.pp3 +++ b/rtdata/profiles/neutral.pp3 @@ -1,6 +1,6 @@ [Version] -Version=20101019 +Version=20101111 [Exposure] Auto=false diff --git a/rtengine/curves.cc b/rtengine/curves.cc index c4234a14c..5d24e90a0 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -704,7 +704,7 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou //val = basecurve (val*def_mul, a, black, def_mul, hlcompr/100.0, 1.5*shcompr/100.0); //val = basecurvenew->getVal (val); - hlCurve[i] = (int) (65535.0 * CLIPD(val)); + hlCurve[i] = (65535.0 * CLIPD(val)); //%%%%%%%%%%%%%%%%%%%%%%%%%% // change to [0,1] range @@ -712,7 +712,7 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou val = basecurve (val, 1, black, def_mul, 1, 1.5*shcompr/100.0); - shCurve[i] = (int) (65535.0 * CLIPD(val)); + shCurve[i] = (65535.0 * CLIPD(val)); } //%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -720,6 +720,8 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou // change to [0,1] range double val = (double)i / 65535.0; + float val0 = val; + float cum = (int)shCurve[(int)(hlCurve[i])]; // gamma correction if (gamma_>0) @@ -732,7 +734,8 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou // apply custom/parametric/NURBS curve, if any if (tcurve) { if (outBeforeCCurveHistogram) { - double hval = brightcurve->getVal ((int)shCurve[(int)hlCurve[(int)val]]); + cum *= (float)val/val0; + float hval = brightcurve->getVal (cum); //if (needigamma) // hval = igamma2 (hval); int hi = (int)(255.0*CLIPD(hval)); diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 650e4b100..e2fd17fa6 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -281,7 +281,17 @@ void ImProcFunctions::rgbProc (Image16* working, LabImage* lab, float* hltonecur int tW = working->width; int tH = working->height; int r, g, b; - #pragma omp parallel for private(r, g, b,factor,mapval) if (multiThread) + float h, s, v; + float satparam,valparam; + int hue, hueband, hueres, nbrband; + double pi = M_PI; + + float* cossq = new float [8093]; + for (int i=0; i<8093; i++) + cossq[i] = SQR(cos(pi*(float)i/16384)); + + +#pragma omp parallel for private(r, g, b,factor,mapval,h,s,v,hue,hueband,hueres,nbrband,satparam,valparam) if (multiThread) for (int i=0; i0 ? (float)tonecurve[Y]/Y : 1); + //r *= tonefactor; + //g *= tonefactor; + //b *= tonefactor; r = tonecurve[CLIP(r)]; g = tonecurve[CLIP(g)]; b = tonecurve[CLIP(b)]; - if (abs(sat)>0.5) { - float h, s, v; + if (abs(sat)>0.5 || params->hsvequalizer.enabled) { rgb2hsv(r,g,b,h,s,v); - if (sat>0) { + if (sat > 0.5) { s = (1-(float)sat/100)*s+(float)sat/100*(1-SQR(SQR(1-s))); } else { - s *= 1+(float)sat/100; + if (sat < -0.5) + s *= 1+(float)sat/100; + } + //HSV equalizer + if (params->hsvequalizer.enabled) { + hue = (int)(65535*h); + hueres = hue & 8091;//location of hue within a band + hueband = (hue-hueres) >> 13;//divides hue range into 8 bands + nbrband = (hueband+1)&7; + + //shift hue + h = fmod(h + 0.0025*(params->hsvequalizer.hue[hueband] * cossq[hueres] + params->hsvequalizer.hue[nbrband] * (1-cossq[hueres])),1); + if (h<0) h +=1; + hue = (int)(65535*h); + hueres = hue & 8091;//location of hue within a band + hueband = (hue-hueres) >> 13;//divides hue range into 8 bands + nbrband = (hueband+1)&7; + + //change saturation + satparam = 0.01*(params->hsvequalizer.sat[hueband] * cossq[hueres] + params->hsvequalizer.sat[nbrband] * (1-cossq[hueres])); + if (satparam > 0.00001) { + s = (1-satparam)*s+satparam*(1-SQR(1-s)); + } else { + if (satparam < -0.00001) + s *= 1+satparam; + } + + //change value + valparam = 0.005*(params->hsvequalizer.val[hueband] * cossq[hueres] + params->hsvequalizer.val[nbrband] * (1-cossq[hueres])); + valparam *= (1-SQR(SQR(1-s))); + if (valparam > 0.00001) { + v = (1-valparam)*v+valparam*(1-SQR(1-v)); + } else { + if (valparam < -0.00001) + v *= (1+valparam); + } } hsv2rgb(h,s,v,r,g,b); } @@ -375,6 +424,9 @@ void ImProcFunctions::rgbProc (Image16* working, LabImage* lab, float* hltonecur lab->b[i][j] = CLIPC(((cacheb[y] - cacheb[z]) * chroma_scale) >> 15); } } + + delete [] cossq; + } void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, int* curve, int row_from, int row_to) { @@ -385,22 +437,23 @@ void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, int* curve for (int j=0; jL[i][j] = curve[lold->L[i][j]]; } - - void ImProcFunctions::chrominanceCurve (LabImage* lold, LabImage* lnew, int channel, int* curve, int row_from, int row_to) { - int W = lold->W; - //int H = lold->H; - if (channel==0) { + +void ImProcFunctions::chrominanceCurve (LabImage* lold, LabImage* lnew, int channel, int* curve, int row_from, int row_to) { + + int W = lold->W; + //int H = lold->H; + if (channel==0) { + for (int i=row_from; ia[i][j] = curve[lold->a[i][j]+32768]-32768; + } + if (channel==1) { for (int i=row_from; ia[i][j] = curve[lold->a[i][j]+32768]-32768; - } - if (channel==1) { - for (int i=row_from; ib[i][j] = curve[lold->b[i][j]+32768]-32768; - } + lnew->b[i][j] = curve[lold->b[i][j]+32768]-32768; } +} #include "cubic.cc" diff --git a/rtengine/procevents.h b/rtengine/procevents.h index f4bfc7420..6d0313227 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -122,7 +122,11 @@ enum ProcEvent { EvDemosaic=97, EvPreProcess=98, EvSaturation=99, - NUMOFEVENTS=100 + EvHSVEqualizerH=100, + EvHSVEqualizerS=101, + EvHSVEqualizerV=102, + EvHSVEqEnabled=103, + NUMOFEVENTS=104 }; } #endif diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 44faaf8d4..9f6d27e3e 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -187,6 +187,13 @@ void ProcParams::setDefaults () { dirpyrequalizer.mult[i] = 1.0; } dirpyrequalizer.mult[4] = 0.0; + hsvequalizer.enabled = false; + for(int i = 0; i < 8; i ++) + { + hsvequalizer.sat[i] = 0; + hsvequalizer.val[i] = 0; + hsvequalizer.hue[i] = 0; + } raw.df_autoselect = false; raw.ca_autocorrect = false; raw.hotdeadpix_filt = false; @@ -380,6 +387,28 @@ int ProcParams::save (Glib::ustring fname) const { ss << "Mult" << i; keyFile.set_double("Directional Pyramid Equalizer", ss.str(), dirpyrequalizer.mult[i]); } + + // save hsv equalizer parameters + keyFile.set_boolean ("HSV Equalizer", "Enabled", hsvequalizer.enabled); + keyFile.set_string ("HSV Equalizer", "Channel", hsvequalizer.hsvchannel); + for(int i = 0; i < 8; i++) + { + std::stringstream ss; + ss << "Sat" << i; + keyFile.set_double("HSV Equalizer", ss.str(), hsvequalizer.sat[i]); + } + for(int i = 0; i < 8; i++) + { + std::stringstream ss; + ss << "Val" << i; + keyFile.set_double("HSV Equalizer", ss.str(), hsvequalizer.val[i]); + } + for(int i = 0; i < 8; i++) + { + std::stringstream ss; + ss << "Hue" << i; + keyFile.set_double("HSV Equalizer", ss.str(), hsvequalizer.hue[i]); + } // save RAW parameters keyFile.set_string ("RAW", "DarkFrame", raw.dark_frame ); @@ -663,6 +692,29 @@ if (keyFile.has_group ("Directional Pyramid Equalizer")) { if(keyFile.has_key ("Directional Pyramid Equalizer", ss.str())) dirpyrequalizer.mult[i] = keyFile.get_double ("Directional Pyramid Equalizer", ss.str()); } } + + // load wavelet equalizer parameters +if (keyFile.has_group ("HSV Equalizer")) { + if (keyFile.has_key ("HSV Equalizer", "Enabled")) hsvequalizer.enabled = keyFile.get_boolean ("HSV Equalizer", "Enabled"); + for(int i = 0; i < 8; i ++) + { + std::stringstream ss; + ss << "Sat" << i; + if(keyFile.has_key ("HSV Equalizer", ss.str())) hsvequalizer.sat[i] = keyFile.get_double ("HSV Equalizer", ss.str()); + } + for(int i = 0; i < 8; i ++) + { + std::stringstream ss; + ss << "Val" << i; + if(keyFile.has_key ("HSV Equalizer", ss.str())) hsvequalizer.val[i] = keyFile.get_double ("HSV Equalizer", ss.str()); + } + for(int i = 0; i < 8; i ++) + { + std::stringstream ss; + ss << "Hue" << i; + if(keyFile.has_key ("HSV Equalizer", ss.str())) hsvequalizer.hue[i] = keyFile.get_double ("HSV Equalizer", ss.str()); + } +} // load raw settings if (keyFile.has_group ("RAW")) { @@ -733,6 +785,17 @@ bool operator==(const DirPyrEqualizerParams & a, const DirPyrEqualizerParams & b return true; } +bool operator==(const HSVEqualizerParams & a, const HSVEqualizerParams & b) { + if(a.enabled != b.enabled) + return false; + + for(int i = 0; i < 8; i++) { + if(a.sat[i] != b.sat[i] && a.val[i] != b.val[i] && a.hue[i] != b.hue[i]) + return false; + } + return true; +} + bool operator==(const ExifPair& a, const ExifPair& b) { return a.field == b.field && a.value == b.value; @@ -856,6 +919,7 @@ bool ProcParams::operator== (const ProcParams& other) { && icm.output == other.icm.output && equalizer == other.equalizer && dirpyrequalizer == other.dirpyrequalizer + && hsvequalizer == other.hsvequalizer && exif==other.exif && iptc==other.iptc; } diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 095eae1d0..70222141a 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -343,14 +343,27 @@ class EqualizerParams { }; /** - * Directional pyramid equalizer params - */ - class DirPyrEqualizerParams { - - public: - bool enabled; - double mult[8]; - }; +* Directional pyramid equalizer params +*/ +class DirPyrEqualizerParams { + + public: + bool enabled; + double mult[8]; +}; + +/** + * Wavelet equalizer params + */ +class HSVEqualizerParams { + + public: + bool enabled; + Glib::ustring hsvchannel; + int sat[8]; + int val[8]; + int hue[8]; +}; /** * Parameters for RAW demosaicing @@ -407,7 +420,8 @@ class ProcParams { ColorManagementParams icm; ///< profiles/color spaces used during the image processing EqualizerParams equalizer; ///< wavelet equalizer parameters RAWParams raw; ///< RAW parameters before demosaicing - DirPyrEqualizerParams dirpyrequalizer;///< directional pyramid equalizer parameters + DirPyrEqualizerParams dirpyrequalizer; ///< directional pyramid equalizer parameters + HSVEqualizerParams hsvequalizer; ///< hsv equalizer parameters std::vector exif; ///< List of modifications appplied on the exif tags of the input image std::vector iptc; ///< The IPTC tags and values to be saved to the output image int version; ///< Version of the file from which the parameters have been read diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index adae259c8..0069836f6 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -120,5 +120,9 @@ LUMINANCECURVE, // EvLbCurve, DEMOSAIC, // EvDemosaic DARKFRAME, //EvPreProcess RGBCURVE, // EvSaturation, +RGBCURVE, // EvHSVEqualizerH, +RGBCURVE, // EvHSVEqualizerS, +RGBCURVE, // EvHSVEqualizerV, +RGBCURVE, // EvHSVEqEnabled, }; diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 06f751323..1a11190d1 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -26,7 +26,7 @@ set (BASESOURCEFILES batchqueue.cc lwbutton.cc lwbuttonset.cc batchqueuebuttonset.cc browserfilter.cc exiffiltersettings.cc profilestore.cc partialpastedlg.cc rawprocess.cc preprocess.cc - equalizer.cc dirpyrequalizer.cc + equalizer.cc dirpyrequalizer.cc hsvequalizer.cc popupcommon.cc popupbutton.cc popuptogglebutton.cc) if (WIN32) diff --git a/rtgui/hsvequalizer.cc b/rtgui/hsvequalizer.cc new file mode 100644 index 000000000..6ccb3b673 --- /dev/null +++ b/rtgui/hsvequalizer.cc @@ -0,0 +1,358 @@ +/* + * This file is part of RawTherapee. + * + * 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 . + * + * 2010 Ilya Popov + */ + +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +HSVEqualizer::HSVEqualizer () : ToolPanel () { + + enabled = Gtk::manage (new Gtk::CheckButton (M("GENERAL_ENABLED"))); + enabled->set_active (true); + pack_start(*enabled); + enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &HSVEqualizer::enabledToggled) ); + + Gtk::HSeparator *hsvsepa = Gtk::manage (new Gtk::HSeparator()); + pack_start(*hsvsepa, Gtk::PACK_SHRINK, 2); + hsvsepa->show (); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ()); + hb->set_border_width (4); + hb->show (); + Gtk::Label* hsvselect = Gtk::manage (new Gtk::Label (M("TP_HSVEQUALIZER_CHANNEL")+":")); + hsvselect->show (); + hsvchannel = Gtk::manage (new Gtk::ComboBoxText ()); + hsvchannel->append_text (M("TP_HSVEQUALIZER_SAT")); + hsvchannel->append_text (M("TP_HSVEQUALIZER_VAL")); + hsvchannel->append_text (M("TP_HSVEQUALIZER_HUE")); + hsvchannel->show (); + hb->pack_start(*hsvselect, Gtk::PACK_SHRINK, 4); + hb->pack_start(*hsvchannel); + + Gtk::Button * neutralButton = Gtk::manage (new Gtk::Button(M("TP_HSVEQUALIZER_NEUTRAL"))); + hb->pack_start(*neutralButton, Gtk::PACK_SHRINK, 2); + neutralPressedConn = neutralButton->signal_pressed().connect( sigc::mem_fun(*this, &HSVEqualizer::neutralPressed)); + + + pack_start (*hb); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + /* + Gtk::HBox * buttonBox17 = Gtk::manage (new Gtk::HBox()); + pack_start(*buttonBox17, Gtk::PACK_SHRINK, 2); + + Gtk::Button * neutralButton = Gtk::manage (new Gtk::Button(M("TP_HSVEQUALIZER_NEUTRAL"))); + buttonBox17->pack_start(*neutralButton, Gtk::PACK_SHRINK, 2); + neutralPressedConn = neutralButton->signal_pressed().connect( sigc::mem_fun(*this, &HSVEqualizer::neutralPressed)); + + buttonBox17->show(); + */ + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Gtk::HSeparator *hsvsepb = Gtk::manage (new Gtk::HSeparator()); + pack_start(*hsvsepb, Gtk::PACK_SHRINK, 2); + hsvsepb->show (); + + satbox = new Gtk::VBox (); + sat[0] = new Adjuster (M("TP_HSVEQUALIZER1"), -100, 100, 0.1, 0); + sat[1] = new Adjuster (M("TP_HSVEQUALIZER2"), -100, 100, 0.1, 0); + sat[2] = new Adjuster (M("TP_HSVEQUALIZER3"), -100, 100, 0.1, 0); + sat[3] = new Adjuster (M("TP_HSVEQUALIZER4"), -100, 100, 0.1, 0); + sat[4] = new Adjuster (M("TP_HSVEQUALIZER5"), -100, 100, 0.1, 0); + sat[5] = new Adjuster (M("TP_HSVEQUALIZER6"), -100, 100, 0.1, 0); + sat[6] = new Adjuster (M("TP_HSVEQUALIZER7"), -100, 100, 0.1, 0); + sat[7] = new Adjuster (M("TP_HSVEQUALIZER8"), -100, 100, 0.1, 0); + for(int i = 0; i < 8; i++) + { + sat[i]->setAdjusterListener(this); + satbox->pack_start(*sat[i]); + } + + //show_all_children (); + satbox->show (); + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + valbox = new Gtk::VBox (); + val[0] = new Adjuster (M("TP_HSVEQUALIZER1"), -100, 100, 0.1, 0); + val[1] = new Adjuster (M("TP_HSVEQUALIZER2"), -100, 100, 0.1, 0); + val[2] = new Adjuster (M("TP_HSVEQUALIZER3"), -100, 100, 0.1, 0); + val[3] = new Adjuster (M("TP_HSVEQUALIZER4"), -100, 100, 0.1, 0); + val[4] = new Adjuster (M("TP_HSVEQUALIZER5"), -100, 100, 0.1, 0); + val[5] = new Adjuster (M("TP_HSVEQUALIZER6"), -100, 100, 0.1, 0); + val[6] = new Adjuster (M("TP_HSVEQUALIZER7"), -100, 100, 0.1, 0); + val[7] = new Adjuster (M("TP_HSVEQUALIZER8"), -100, 100, 0.1, 0); + for(int i = 0; i < 8; i++) + { + val[i]->setAdjusterListener(this); + valbox->pack_start(*val[i]); + } + + //show_all_children (); + valbox->show (); + //%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + huebox = new Gtk::VBox (); + + + hue[0] = new Adjuster (M("TP_HSVEQUALIZER1"), -100, 100, 0.1, 0); + hue[1] = new Adjuster (M("TP_HSVEQUALIZER2"), -100, 100, 0.1, 0); + hue[2] = new Adjuster (M("TP_HSVEQUALIZER3"), -100, 100, 0.1, 0); + hue[3] = new Adjuster (M("TP_HSVEQUALIZER4"), -100, 100, 0.1, 0); + hue[4] = new Adjuster (M("TP_HSVEQUALIZER5"), -100, 100, 0.1, 0); + hue[5] = new Adjuster (M("TP_HSVEQUALIZER6"), -100, 100, 0.1, 0); + hue[6] = new Adjuster (M("TP_HSVEQUALIZER7"), -100, 100, 0.1, 0); + hue[7] = new Adjuster (M("TP_HSVEQUALIZER8"), -100, 100, 0.1, 0); + for(int i = 0; i < 8; i++) + { + hue[i]->setAdjusterListener(this); + huebox->pack_start(*hue[i]); + } + + //huebox->show_all_children (); + huebox->show (); + //%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + huebox->reference (); + valbox->reference (); + satbox->reference (); + + //enaConn = enabled->signal_toggled().connect( sigc::mem_fun(*this, &HSVEqualizer::enabled_toggled) ); + hsvchannel->signal_changed().connect( sigc::mem_fun(*this, &HSVEqualizer::hsvchannelChanged) ); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +HSVEqualizer::~HSVEqualizer () { + + delete hue; + delete val; + delete sat; +} + + +void HSVEqualizer::read (const ProcParams* pp, const ParamsEdited* pedited) { + + disableListener (); + + if (pedited) { + for (int i=0; i<8; i++) { + sat[i]->setEditedState (pedited->hsvequalizer.sat[i] ? Edited : UnEdited); + val[i]->setEditedState (pedited->hsvequalizer.val[i] ? Edited : UnEdited); + hue[i]->setEditedState (pedited->hsvequalizer.hue[i] ? Edited : UnEdited); + } + enabled->set_inconsistent (!pedited->hsvequalizer.enabled); + } + + enaConn.block (true); + enabled->set_active (pp->hsvequalizer.enabled); + enaConn.block (false); + lastEnabled = pp->hsvequalizer.enabled; + + for (int i=0; i<8; i++) { + sat[i]->setValue (pp->hsvequalizer.sat[i]); + val[i]->setValue (pp->hsvequalizer.val[i]); + hue[i]->setValue (pp->hsvequalizer.hue[i]); + } + + if (pedited && !pedited->hsvequalizer.hsvchannel) + hsvchannel->set_active (3); + else if (pp->hsvequalizer.hsvchannel=="sat") + hsvchannel->set_active (0); + else if (pp->hsvequalizer.hsvchannel=="val") + hsvchannel->set_active (1); + else if (pp->hsvequalizer.hsvchannel=="hue") + hsvchannel->set_active (2); + + enableListener (); +} + +void HSVEqualizer::write (ProcParams* pp, ParamsEdited* pedited) { + + pp->hsvequalizer.enabled = enabled->get_active (); + for (int i=0; i<8; i++) { + pp->hsvequalizer.sat[i] = sat[i]->getValue(); + pp->hsvequalizer.val[i] = val[i]->getValue(); + pp->hsvequalizer.hue[i] = hue[i]->getValue(); + } + + if (hsvchannel->get_active_row_number()==0) + pp->hsvequalizer.hsvchannel = "sat"; + else if (hsvchannel->get_active_row_number()==1) + pp->hsvequalizer.hsvchannel = "val"; + else if (hsvchannel->get_active_row_number()==2) + pp->hsvequalizer.hsvchannel = "hue"; + + if (pedited) { + pedited->hsvequalizer.enabled = !enabled->get_inconsistent();//from dirpyreq + for (int i=0; i<8; i++) { + pedited->hsvequalizer.sat[i] = sat[i]->getEditedState (); + pedited->hsvequalizer.val[i] = val[i]->getEditedState (); + pedited->hsvequalizer.hue[i] = hue[i]->getEditedState (); + } + } +} + +void HSVEqualizer::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) { + + for (int i = 0; i < 8; i++) { + sat[i]->setDefault(defParams->hsvequalizer.sat[i]); + val[i]->setDefault(defParams->hsvequalizer.val[i]); + hue[i]->setDefault(defParams->hsvequalizer.hue[i]); + } + + if (pedited) { + for (int i = 0; i < 8; i++) { + sat[i]->setDefaultEditedState(pedited->hsvequalizer.sat[i] ? Edited : UnEdited); + val[i]->setDefaultEditedState(pedited->hsvequalizer.val[i] ? Edited : UnEdited); + hue[i]->setDefaultEditedState(pedited->hsvequalizer.hue[i] ? Edited : UnEdited); + } + } + else { + for (int i = 0; i < 8; i++) { + sat[i]->setDefaultEditedState(Irrelevant); + val[i]->setDefaultEditedState(Irrelevant); + hue[i]->setDefaultEditedState(Irrelevant); + } + } +} + +void HSVEqualizer::adjusterChanged (Adjuster* a, double newval) { + + if (listener && enabled->get_active()) { + std::stringstream ss; + ss << "("; + int i; + if (hsvchannel->get_active_row_number()==0) { + for (i = 0; i < 8; i++) { + if (i > 0) { + ss << ", "; + } + ss << static_cast(sat[i]->getValue()); + } + listener->panelChanged (EvHSVEqualizerS, ss.str()); + } + else if (hsvchannel->get_active_row_number()==1) { + for (i = 0; i < 8; i++) { + if (i > 0) { + ss << ", "; + } + ss << static_cast(val[i]->getValue()); + } + listener->panelChanged (EvHSVEqualizerV, ss.str()); + } + else if (hsvchannel->get_active_row_number()==2) { + for (i = 0; i < 8; i++) { + if (i > 0) { + ss << ", "; + } + ss << static_cast(hue[i]->getValue()); + } + listener->panelChanged (EvHSVEqualizerH, ss.str()); + } + + ss << ")"; + //listener->panelChanged (EvHSVEqualizer, ss.str()); + } +} + +void HSVEqualizer::enabledToggled () { + + if (batchMode) { + if (enabled->get_inconsistent()) { + enabled->set_inconsistent (false); + enaConn.block (true); + enabled->set_active (false); + enaConn.block (false); + } + else if (lastEnabled) + enabled->set_inconsistent (true); + + lastEnabled = enabled->get_active (); + } + + if (listener) { + if (enabled->get_active ()) + listener->panelChanged (EvHSVEqEnabled, M("GENERAL_ENABLED")); + else + listener->panelChanged (EvHSVEqEnabled, M("GENERAL_DISABLED")); + } +} + + +void HSVEqualizer::hsvchannelChanged () { + + removeIfThere (this, satbox, false); + removeIfThere (this, valbox, false); + removeIfThere (this, huebox, false); + + if (hsvchannel->get_active_row_number()==0) + pack_start (*satbox); + else if (hsvchannel->get_active_row_number()==1) + pack_start (*valbox); + else if (hsvchannel->get_active_row_number()==2) + pack_start (*huebox); + + if (listener && enabled->get_active ()) { + if (hsvchannel->get_active_row_number()==0) + listener->panelChanged (EvHSVEqualizerS, hsvchannel->get_active_text ()); + else if (hsvchannel->get_active_row_number()==1) + listener->panelChanged (EvHSVEqualizerV, hsvchannel->get_active_text ()); + else if (hsvchannel->get_active_row_number()==2) + listener->panelChanged (EvHSVEqualizerH, hsvchannel->get_active_text ()); + } +} + +void HSVEqualizer::setBatchMode (bool batchMode) { + + ToolPanel::setBatchMode (batchMode); + + for (int i = 0; i < 8; i++) { + sat[i]->showEditedCB(); + val[i]->showEditedCB(); + hue[i]->showEditedCB(); + } + + hsvchannel->append_text (M("GENERAL_UNCHANGED")); +} + +void HSVEqualizer::neutralPressed () { + if (hsvchannel->get_active_row_number()==0) + for (int i = 0; i < 8; i++) { + sat[i]->setValue(0); + adjusterChanged(sat[i], 0); + } + else if (hsvchannel->get_active_row_number()==1) + for (int i = 0; i < 8; i++) { + val[i]->setValue(0); + adjusterChanged(val[i], 0); + } + else if (hsvchannel->get_active_row_number()==2) + for (int i = 0; i < 8; i++) { + hue[i]->setValue(0); + adjusterChanged(hue[i], 0); + } + + +} \ No newline at end of file diff --git a/rtgui/hsvequalizer.h b/rtgui/hsvequalizer.h new file mode 100644 index 000000000..468c710c6 --- /dev/null +++ b/rtgui/hsvequalizer.h @@ -0,0 +1,68 @@ +/* + * This file is part of RawTherapee. + * + * 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 . + * + * 2010 Ilya Popov + */ + +#ifndef HSVEQUALIZER_H_INCLUDED +#define HSVEQUALIZER_H_INCLUDED + +#include +#include +#include +#include + + +class HSVEqualizer : public Gtk::VBox, public AdjusterListener, public ToolPanel +{ + +protected: + + Gtk::CheckButton * enabled; + Gtk::ComboBoxText* hsvchannel; + + Gtk::VBox* satbox; + Gtk::VBox* valbox; + Gtk::VBox* huebox; + + Adjuster* sat[8]; + Adjuster* val[8]; + Adjuster* hue[8]; + + sigc::connection enaConn; + sigc::connection neutralPressedConn; + + bool lastEnabled; + +public: + + HSVEqualizer (); + virtual ~HSVEqualizer (); + + void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited=NULL); + void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited=NULL); + void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited=NULL); + void setBatchMode (bool batchMode); + + void adjusterChanged (Adjuster* a, double newval); + void enabledToggled (); + void hsvchannelChanged (); + + void neutralPressed (); + +}; + +#endif diff --git a/rtgui/navigator.cc b/rtgui/navigator.cc index cda896052..8de4a3e5a 100644 --- a/rtgui/navigator.cc +++ b/rtgui/navigator.cc @@ -100,7 +100,7 @@ void Navigator::rgb2hsv (int r, int g, int b, int &h, int &s, int &v) { volatile double var_G = g / 255.0; volatile double var_B = b / 255.0; - volatile double var_Min = MIN(MIN(var_R,var_G),var_B); + /*volatile double var_Min = MIN(MIN(var_R,var_G),var_B); volatile double var_Max = MAX(MAX(var_R,var_G),var_B); double del_Max = var_Max - var_Min; double V = (var_Max + var_Min) / 2; @@ -120,6 +120,27 @@ void Navigator::rgb2hsv (int r, int g, int b, int &h, int &s, int &v) { else if ( var_G == var_Max ) H = (1.0 / 3.0) + del_R - del_B; else if ( var_B == var_Max ) H = (2.0 / 3.0) + del_G - del_R; + if ( H < 0 ) H += 1; + if ( H > 1 ) H -= 1; + }*/ + + double var_Min = MIN(MIN(var_R,var_G),var_B); + double var_Max = MAX(MAX(var_R,var_G),var_B); + double del_Max = var_Max - var_Min; + double V = var_Max; + double H, S; + if (fabs(del_Max)<0.001) { + H = 0; + S = 0; + } + else { + S = del_Max/var_Max; + + if ( var_R == var_Max ) H = (var_G - var_B)/del_Max; + else if ( var_G == var_Max ) H = 2.0 + (var_B - var_R)/del_Max; + else if ( var_B == var_Max ) H = 4.0 + (var_R - var_G)/del_Max; + H /= 6.0; + if ( H < 0 ) H += 1; if ( H > 1 ) H -= 1; } diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 763cae160..43f2aadae 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -138,12 +138,18 @@ void ParamsEdited::set (bool v) { raw.dcbEnhance = v; equalizer.enabled = v; dirpyrequalizer.enabled = v; - - for(int i = 0; i < 5; i++) - { + hsvequalizer.enabled = v; + for(int i = 0; i < 8; i++) { equalizer.c[i] = v; - dirpyrequalizer.mult[i] = v; } + for(int i = 0; i < 5; i++) { + dirpyrequalizer.mult[i] = v; + } + for(int i = 0; i < 8; i++) { + hsvequalizer.sat[i] = v; + hsvequalizer.val[i] = v; + hsvequalizer.hue[i] = v; + } exif.clear (); iptc.clear (); } @@ -286,6 +292,12 @@ void ParamsEdited::initFrom (const std::vector for(int i = 0; i < 8; i++) { dirpyrequalizer.mult[i] = dirpyrequalizer.mult[i] && p.dirpyrequalizer.mult[i] == other.dirpyrequalizer.mult[i]; } + hsvequalizer.enabled = hsvequalizer.enabled && p.hsvequalizer.enabled == other.hsvequalizer.enabled; + for(int i = 0; i < 8; i++) { + hsvequalizer.sat[i] = hsvequalizer.sat[i] && p.hsvequalizer.sat[i] == other.hsvequalizer.sat[i]; + hsvequalizer.val[i] = hsvequalizer.val[i] && p.hsvequalizer.val[i] == other.hsvequalizer.val[i]; + hsvequalizer.hue[i] = hsvequalizer.hue[i] && p.hsvequalizer.hue[i] == other.hsvequalizer.hue[i]; + } // exif = exif && p.exif==other.exif // iptc = other.iptc; } @@ -415,9 +427,15 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if(equalizer.c[i]) toEdit.equalizer.c[i] = mods.equalizer.c[i]; } if (dirpyrequalizer.enabled) toEdit.dirpyrequalizer.enabled = mods.dirpyrequalizer.enabled; - for(int i = 0; i < 8; i++) { + for(int i = 0; i < 5; i++) { if(dirpyrequalizer.mult[i]) toEdit.dirpyrequalizer.mult[i] = mods.dirpyrequalizer.mult[i]; } + if (hsvequalizer.enabled) toEdit.hsvequalizer.enabled = mods.hsvequalizer.enabled; + for(int i = 0; i < 8; i++) { + if(hsvequalizer.sat[i]) toEdit.hsvequalizer.sat[i] = mods.hsvequalizer.sat[i]; + if(hsvequalizer.val[i]) toEdit.hsvequalizer.val[i] = mods.hsvequalizer.val[i]; + if(hsvequalizer.hue[i]) toEdit.hsvequalizer.hue[i] = mods.hsvequalizer.hue[i]; + } // if (exif) toEdit.exif==mo.exif = mods.exif==other.exif; // if (iptc;) toEdit.iptc==other.iptc; = mods.iptc==other.iptc;; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index a70f26886..6fabc3e46 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -253,6 +253,16 @@ public: bool mult[8]; }; +class HSVEqualizerParamsEdited { + +public: + bool enabled; + bool sat[6]; + bool val[6]; + bool hue[6]; + int hsvchannel; +}; + class RAWParamsEdited { public: @@ -313,6 +323,7 @@ class ParamsEdited { EqualizerParamsEdited equalizer; RAWParamsEdited raw; DirPyrEqualizerParamsEdited dirpyrequalizer; + HSVEqualizerParamsEdited hsvequalizer; std::vector exif; std::vector iptc; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index b903365af..88dd47e32 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -51,6 +51,7 @@ PartialPasteDlg::PartialPasteDlg () { colorboost = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_COLORBOOST"))); colorden = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_COLORDENOISE"))); dirpyrden = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DIRPYRDENOISE"))); + hsveq = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_HSVEQUALIZER"))); // options in lens: distortion = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DISTORTION"))); @@ -97,6 +98,7 @@ PartialPasteDlg::PartialPasteDlg () { vboxes[2]->pack_start (*colormixer, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*colorshift, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*colorboost, Gtk::PACK_SHRINK, 2); + vboxes[2]->pack_start (*hsveq, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*colorden, Gtk::PACK_SHRINK, 2); vboxes[2]->pack_start (*dirpyrden, Gtk::PACK_SHRINK, 2); @@ -160,7 +162,8 @@ PartialPasteDlg::PartialPasteDlg () { colormixerConn = colormixer->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true)); colorshiftConn = colorshift->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true)); colorboostConn = colorboost->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true)); - colordenConn = colorden->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true)); + hsveqConn = hsveq->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true)); + colordenConn = colorden->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true)); dirpyrdenConn = dirpyrden->signal_toggled().connect (sigc::bind (sigc::mem_fun(*color, &Gtk::CheckButton::set_inconsistent), true)); distortionConn = distortion->signal_toggled().connect (sigc::bind (sigc::mem_fun(*lens, &Gtk::CheckButton::set_inconsistent), true)); @@ -242,6 +245,7 @@ void PartialPasteDlg::colorToggled () { colormixer->set_active (color->get_active ()); colorshift->set_active (color->get_active ()); colorboost->set_active (color->get_active ()); + hsveq->set_active (color->get_active ()); colorden->set_active (color->get_active ()); dirpyrden->set_active (color->get_active ()); @@ -324,6 +328,7 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dst, const r if (colormixer->get_active ()) dst->chmixer = src->chmixer; if (colorshift->get_active ()) dst->colorShift = src->colorShift; if (colorboost->get_active ()) dst->colorBoost = src->colorBoost; + if (hsveq->get_active ()) dst->hsvequalizer = src->hsvequalizer; if (colorden->get_active ()) dst->colorDenoise = src->colorDenoise; if (dirpyrden->get_active ()) dst->dirpyrDenoise = src->dirpyrDenoise; diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index 2ea23772a..127b83833 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -51,6 +51,7 @@ class PartialPasteDlg : public Gtk::Dialog { Gtk::CheckButton* colormixer; Gtk::CheckButton* colorshift; Gtk::CheckButton* colorboost; + Gtk::CheckButton* hsveq; Gtk::CheckButton* colorden; Gtk::CheckButton* dirpyrden; @@ -73,7 +74,7 @@ class PartialPasteDlg : public Gtk::Dialog { sigc::connection basicConn, luminanceConn, colorConn, lensConn, compositionConn, metaicmConn; sigc::connection wbConn, exposureConn, hlrecConn; - sigc::connection sharpenConn, impdenConn, lumadenConn, labcurveConn, shConn, dirpyreqConn, waveqConn; + sigc::connection sharpenConn, impdenConn, lumadenConn, labcurveConn, shConn, dirpyreqConn, waveqConn, hsveqConn; sigc::connection colormixerConn, colorshiftConn, colorboostConn, colordenConn, dirpyrdenConn; sigc::connection distortionConn, cacorrConn, vignettingConn; sigc::connection coarserotConn, finerotConn, cropConn, resizeConn; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 9a8a200af..4b95b93ca 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -58,6 +58,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { iptcpanel = Gtk::manage (new IPTCPanel ()); equalizer = Gtk::manage (new Equalizer ()); dirpyrequalizer = Gtk::manage (new DirPyrEqualizer ()); + hsvequalizer = Gtk::manage (new HSVEqualizer ()); rawprocess = Gtk::manage (new RawProcess ()); preprocess = Gtk::manage (new PreProcess ()); @@ -69,7 +70,8 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) { addPanel (detailsPanel, sharpening, M("TP_SHARPENING_LABEL")); toolPanels.push_back (sharpening); addPanel (colorPanel, colorboost, M("TP_COLORBOOST_LABEL")); toolPanels.push_back (colorboost); addPanel (colorPanel, colorshift, M("TP_COLORSHIFT_LABEL")); toolPanels.push_back (colorshift); - addPanel (exposurePanel, lcurve, M("TP_LABCURVE_LABEL")); toolPanels.push_back (lcurve); + addPanel (colorPanel, hsvequalizer, M("TP_HSVEQUALIZER_LABEL")); toolPanels.push_back (hsvequalizer); + addPanel (exposurePanel, lcurve, M("TP_LABCURVE_LABEL")); toolPanels.push_back (lcurve); addPanel (detailsPanel, impulsedenoise, M("TP_IMPULSEDENOISE_LABEL")); toolPanels.push_back (impulsedenoise); addPanel (detailsPanel, lumadenoise, M("TP_LUMADENOISE_LABEL")); toolPanels.push_back (lumadenoise); addPanel (detailsPanel, colordenoise, M("TP_COLORDENOISE_LABEL")); toolPanels.push_back (colordenoise); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index e17c1940d..669066afb 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -95,6 +96,7 @@ class ToolPanelCoordinator : public ToolPanelListener, LCurve* lcurve; Equalizer * equalizer; DirPyrEqualizer * dirpyrequalizer; + HSVEqualizer * hsvequalizer; RawProcess* rawprocess; PreProcess* preprocess;