From d76f3c38c57144fcde61734e39b6bc157ef207a4 Mon Sep 17 00:00:00 2001 From: Oliver Duis Date: Wed, 31 Aug 2011 19:49:00 +0200 Subject: [PATCH] Blend CMS with matrix feature see issue 951 --- rtdata/languages/Deutsch | 1 + rtdata/languages/default | 1 + rtengine/imagefloat.cc | 7 +++++++ rtengine/imagefloat.h | 1 + rtengine/procparams.cc | 4 ++++ rtengine/procparams.h | 1 + rtengine/rawimagesource.cc | 36 ++++++++++++++++++++++++++++++++---- rtgui/icmpanel.cc | 34 +++++++++++++++++++++------------- rtgui/icmpanel.h | 3 ++- rtgui/paramsedited.cc | 3 +++ rtgui/paramsedited.h | 1 + 11 files changed, 74 insertions(+), 18 deletions(-) diff --git a/rtdata/languages/Deutsch b/rtdata/languages/Deutsch index 175da7501..42fff5a32 100644 --- a/rtdata/languages/Deutsch +++ b/rtdata/languages/Deutsch @@ -870,6 +870,7 @@ TP_HSVEQUALIZER_LABEL;HSV-Equalizer TP_HSVEQUALIZER_NEUTRAL;Neutral TP_HSVEQUALIZER_SAT;S TP_HSVEQUALIZER_VAL;V +TP_ICM_BLENDCMSMATRIX;Lichter aus Matrix einmischen TP_ICM_FILEDLGFILTERANY;Alle Dateien TP_ICM_FILEDLGFILTERICM;ICC-Profildateien TP_ICM_GAMMABEFOREINPUT;Profil enthält Gamma-Anpassung diff --git a/rtdata/languages/default b/rtdata/languages/default index 0f78a9076..1e0521dbc 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -860,6 +860,7 @@ TP_HSVEQUALIZER_LABEL;HSV Equalizer TP_HSVEQUALIZER_NEUTRAL;Neutral TP_HSVEQUALIZER_SAT;S TP_HSVEQUALIZER_VAL;V +TP_ICM_BLENDCMSMATRIX;Blend highlights with matrix TP_ICM_FILEDLGFILTERANY;Any files TP_ICM_FILEDLGFILTERICM;ICC Profile Files TP_ICM_GAMMABEFOREINPUT;Profile applies Gamma diff --git a/rtengine/imagefloat.cc b/rtengine/imagefloat.cc index 5fb02d6f4..9b7264286 100644 --- a/rtengine/imagefloat.cc +++ b/rtengine/imagefloat.cc @@ -36,6 +36,13 @@ Imagefloat::Imagefloat (int w, int h) allocate (w, h); } +// Copy other image +Imagefloat::Imagefloat (Imagefloat& other) { + unaligned=NULL; data=NULL; + allocate (other.width, other.height); + memcpy(data, other.data, width*height*3); +} + Imagefloat::~Imagefloat () { if (data!=NULL) { diff --git a/rtengine/imagefloat.h b/rtengine/imagefloat.h index 011378ed0..26a54dbbf 100644 --- a/rtengine/imagefloat.h +++ b/rtengine/imagefloat.h @@ -53,6 +53,7 @@ class Imagefloat : public ImageIO, public IImagefloat { Imagefloat (); Imagefloat (int width, int height); + Imagefloat (Imagefloat& other); ~Imagefloat (); Imagefloat* copy (); diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index c3fb2abb2..227f3b2f4 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -217,6 +217,7 @@ void ProcParams::setDefaults () { icm.input = ""; icm.gammaOnInput = false; + icm.blendCMSMatrix = false; icm.working = "sRGB"; icm.output = "sRGB"; icm.gamma = "default"; @@ -461,6 +462,7 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2) const { // save color management settings keyFile.set_string ("Color Management", "InputProfile", icm.input); keyFile.set_boolean ("Color Management", "ApplyGammaBeforeInputProfile", icm.gammaOnInput); + keyFile.set_boolean ("Color Management", "BlendCMSMatrix", icm.blendCMSMatrix); keyFile.set_string ("Color Management", "WorkingProfile", icm.working); keyFile.set_string ("Color Management", "OutputProfile", icm.output); keyFile.set_string ("Color Management", "Gammafree", icm.gamma); @@ -812,6 +814,7 @@ if (keyFile.has_group ("Resize")) { if (keyFile.has_group ("Color Management")) { if (keyFile.has_key ("Color Management", "InputProfile")) icm.input = keyFile.get_string ("Color Management", "InputProfile"); if (keyFile.has_key ("Color Management", "ApplyGammaBeforeInputProfile")) icm.gammaOnInput = keyFile.get_boolean ("Color Management", "ApplyGammaBeforeInputProfile"); + if (keyFile.has_key ("Color Management", "BlendCMSMatrix")) icm.blendCMSMatrix = keyFile.get_boolean ("Color Management", "BlendCMSMatrix"); if (keyFile.has_key ("Color Management", "WorkingProfile")) icm.working = keyFile.get_string ("Color Management", "WorkingProfile"); if (keyFile.has_key ("Color Management", "OutputProfile")) icm.output = keyFile.get_string ("Color Management", "OutputProfile"); if (keyFile.has_key ("Color Management", "Gammafree")) icm.gamma = keyFile.get_string ("Color Management", "Gammafree"); @@ -1061,6 +1064,7 @@ bool ProcParams::operator== (const ProcParams& other) { && raw.linenoise == other.raw.linenoise && icm.input == other.icm.input && icm.gammaOnInput == other.icm.gammaOnInput + && icm.blendCMSMatrix == other.icm.blendCMSMatrix && icm.working == other.icm.working && icm.output == other.icm.output && icm.gamma == other.icm.gamma diff --git a/rtengine/procparams.h b/rtengine/procparams.h index f9bd9e0ef..8a2d53f0e 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -339,6 +339,7 @@ class ColorManagementParams { public: Glib::ustring input; bool gammaOnInput; + bool blendCMSMatrix; Glib::ustring working; Glib::ustring output; static const Glib::ustring NoICMString; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index c330fb551..084a5ac8e 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1572,9 +1572,7 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams cmsHPROFILE in; if (!findInputProfile(cmp.input, embedded, camName, in)) return; - if (in==NULL) { - // use default camprofile, supplied by dcraw - // in this case we avoid using the slllllooooooowwww lcms + // Calculate matrix for direct conversion raw>working space TMatrix work = iccStore->workingSpaceInverseMatrix (cmp.working); float mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; for (int i=0; i<3; i++) @@ -1582,6 +1580,11 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams for (int k=0; k<3; k++) mat[i][j] += work[i][k] * camMatrix[k][j]; // rgb_xyz * xyz_cam + + if (in==NULL) { + // use default camprofile, supplied by dcraw + // in this case we avoid using the slllllooooooowwww lcms + #pragma omp parallel for for (int i=0; iheight; i++) for (int j=0; jwidth; j++) { @@ -1596,6 +1599,9 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams } } else { + Imagefloat* imgPreLCMS=NULL; + if (cmp.blendCMSMatrix) imgPreLCMS=new Imagefloat(*im); + // use supplied input profile // color space transform is expecting data in the range (0,1) for ( int h = 0; h < im->height; ++h ) @@ -1640,14 +1646,36 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams cmsDeleteTransform(hTransform); - // restore normalization to the range (0,65535) + // restore normalization to the range (0,65535) and blend matrix colors if LCMS is clipping #pragma omp parallel for for ( int h = 0; h < im->height; ++h ) for ( int w = 0; w < im->width; ++w ) { im->r[h][w] *= 65535.0 ; im->g[h][w] *= 65535.0 ; im->b[h][w] *= 65535.0 ; + + if (cmp.blendCMSMatrix) { + // Red + if (im->r[h][w]>65534.9) { + float f = mat[0][0]*imgPreLCMS->r[h][w] + mat[0][1]*imgPreLCMS->g[h][w] + mat[0][2]*imgPreLCMS->b[h][w]; + if (f>im->r[h][w]) im->r[h][w]=f; } + + // Green + if (im->g[h][w]>65534.9) { + float f = mat[1][0]*imgPreLCMS->r[h][w] + mat[1][1]*imgPreLCMS->g[h][w] + mat[1][2]*imgPreLCMS->b[h][w]; + if (f>im->g[h][w]) im->g[h][w]=f; + } + + // Blue + if (im->b[h][w]>65534.9) { + float f = mat[2][0]*imgPreLCMS->r[h][w] + mat[2][1]*imgPreLCMS->g[h][w] + mat[2][2]*imgPreLCMS->b[h][w]; + if (f>im->b[h][w]) im->b[h][w]=f; + } + } + } + + if (imgPreLCMS!=NULL) delete imgPreLCMS; } //t3.set (); diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index 7a8b67955..81af08cdf 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -69,6 +69,10 @@ ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL), igamma->set_sensitive (false); pack_start (*igamma, Gtk::PACK_SHRINK, 4); + ckbBlendCMSMatrix = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_BLENDCMSMATRIX"))); + ckbBlendCMSMatrix->set_sensitive (false); + pack_start (*ckbBlendCMSMatrix, Gtk::PACK_SHRINK, 4); + saveRef = Gtk::manage (new Gtk::Button (M("TP_ICM_SAVEREFERENCE"))); saveRef->set_image (*Gtk::manage (new Gtk::Image (Gtk::StockID("gtk-save"), Gtk::ICON_SIZE_BUTTON))); pack_start (*saveRef, Gtk::PACK_SHRINK, 4); @@ -174,7 +178,8 @@ ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL), icameraICC->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) ); iembedded->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) ); ifromfile->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) ); - igamma->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::profAppGammaChanged) ); + igamma->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::iccTogglesChanged) ); + ckbBlendCMSMatrix->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::iccTogglesChanged) ); ipc = ipDialog->signal_selection_changed().connect( sigc::mem_fun(*this, &ICMPanel::ipSelectionChanged) ); saveRef->signal_pressed().connect( sigc::mem_fun(*this, &ICMPanel::saveReferencePressed) ); @@ -188,25 +193,25 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { ipc.block (true); if (pp->icm.input == "(none)" && icamera->get_state()!=Gtk::STATE_INSENSITIVE) { inone->set_active (true); - igamma->set_sensitive (false); + igamma->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive (false); } else if (pp->icm.input == "(embedded)" || ((pp->icm.input == "(camera)" || pp->icm.input=="") && icamera->get_state()==Gtk::STATE_INSENSITIVE)) { iembedded->set_active (true); - igamma->set_sensitive (false); + igamma->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive (false); } else if ((pp->icm.input == "(cameraICC)") && icameraICC->get_state()!=Gtk::STATE_INSENSITIVE) { icameraICC->set_active (true); - igamma->set_sensitive (false); + igamma->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive (true); } else if ((pp->icm.input == "(camera)" || pp->icm.input=="") && icamera->get_state()!=Gtk::STATE_INSENSITIVE) { icamera->set_active (true); - igamma->set_sensitive (false); + igamma->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive (false); } else { ifromfile->set_active (true); oldip = pp->icm.input.substr(5); // cut of "file:" ipDialog->set_filename (pp->icm.input.substr(5)); - igamma->set_sensitive (true); + igamma->set_sensitive (true); ckbBlendCMSMatrix->set_sensitive (true); } wnames->set_active_text (pp->icm.working); @@ -221,12 +226,13 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) { onames->set_active_text (M("TP_ICM_NOICM")); igamma->set_active (pp->icm.gammaOnInput); + ckbBlendCMSMatrix->set_active (pp->icm.blendCMSMatrix); onames->set_sensitive(wgamma->get_active_row_number()==0 || freegamma->get_active()); //"default" wgamma->set_sensitive(!freegamma->get_active()); if (pedited) { iunchanged->set_active (!pedited->icm.input); - igamma->set_sensitive (false); + igamma->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive (false); if (!pedited->icm.working) wnames->set_active_text(M("GENERAL_UNCHANGED")); if (!pedited->icm.output) @@ -282,6 +288,7 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) { pp->icm.output = onames->get_active_text(); pp->icm.freegamma = freegamma->get_active(); pp->icm.gammaOnInput = igamma->get_active (); + pp->icm.blendCMSMatrix = ckbBlendCMSMatrix->get_active (); pp->icm.gampos =(double) g_ampos->getValue(); pp->icm.slpos =(double) s_lpos->getValue(); @@ -290,6 +297,7 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) { pedited->icm.working = wnames->get_active_text()!=M("GENERAL_UNCHANGED"); pedited->icm.output = onames->get_active_text()!=M("GENERAL_UNCHANGED"); pedited->icm.gammaOnInput = !ifromfile->get_active (); + pedited->icm.blendCMSMatrix = !ckbBlendCMSMatrix->get_inconsistent (); pedited->icm.gamma = wgamma->get_active_text()!=M("GENERAL_UNCHANGED"); pedited->icm.freegamma =!freegamma->get_inconsistent(); pedited->icm.gampos = g_ampos->getEditedState (); @@ -345,23 +353,23 @@ void ICMPanel::ipChanged () { std::string profname; if (inone->get_active()) { profname = "(none)"; - igamma->set_sensitive (false); + igamma->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive(false); } else if (iembedded->get_active ()) { profname = "(embedded)"; - igamma->set_sensitive (false); + igamma->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive(false); } else if (icamera->get_active ()) { profname = "(camera)"; - igamma->set_sensitive (false); + igamma->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive(false); } else if (icameraICC->get_active ()) { profname = "(cameraICC)"; - igamma->set_sensitive (false); + igamma->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive(true); } else { profname = ipDialog->get_filename (); - igamma->set_sensitive (true); + igamma->set_sensitive (true); ckbBlendCMSMatrix->set_sensitive(true); } if (listener && profname!=oldip) @@ -370,7 +378,7 @@ void ICMPanel::ipChanged () { oldip = profname; } -void ICMPanel::profAppGammaChanged() { +void ICMPanel::iccTogglesChanged() { if (listener) listener->panelChanged (EvIProfile, ""); } diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 496911399..e7b6605f4 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -47,6 +47,7 @@ class ICMPanel : public Gtk::VBox, public AdjusterListener, public FoldableToolP Gtk::RadioButton* icameraICC; Gtk::RadioButton* ifromfile; Gtk::CheckButton* igamma; + Gtk::CheckButton* ckbBlendCMSMatrix; Gtk::ComboBoxText* wnames; Gtk::ComboBoxText* wgamma; @@ -79,7 +80,7 @@ class ICMPanel : public Gtk::VBox, public AdjusterListener, public FoldableToolP void gpChanged (); void GamChanged (); void ipSelectionChanged (); - void profAppGammaChanged(); + void iccTogglesChanged(); void setRaw (bool raw); void saveReferencePressed (); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index fa9ad829a..bd3c0185b 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -146,6 +146,7 @@ void ParamsEdited::set (bool v) { resize.enabled = v; icm.input = v; icm.gammaOnInput = v; + icm.blendCMSMatrix = v; icm.working = v; icm.output = v; icm.gamma = v; @@ -321,6 +322,7 @@ void ParamsEdited::initFrom (const std::vector resize.enabled = resize.enabled && p.resize.enabled == other.resize.enabled; icm.input = icm.input && p.icm.input == other.icm.input; icm.gammaOnInput = icm.gammaOnInput && p.icm.gammaOnInput == other.icm.gammaOnInput; + icm.blendCMSMatrix = icm.blendCMSMatrix && p.icm.blendCMSMatrix == other.icm.blendCMSMatrix; icm.working = icm.working && p.icm.working == other.icm.working; icm.output = icm.output && p.icm.output == other.icm.output; icm.gamma = icm.gamma && p.icm.gamma == other.icm.gamma; @@ -486,6 +488,7 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if (resize.enabled) toEdit.resize.enabled = mods.resize.enabled; if (icm.input) toEdit.icm.input = mods.icm.input; if (icm.gammaOnInput) toEdit.icm.gammaOnInput = mods.icm.gammaOnInput; + if (icm.blendCMSMatrix) toEdit.icm.blendCMSMatrix = mods.icm.blendCMSMatrix; if (icm.working) toEdit.icm.working = mods.icm.working; if (icm.output) toEdit.icm.output = mods.icm.output; if (icm.gampos) toEdit.icm.gampos = mods.icm.gampos; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index f94a34a29..5adaca689 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -261,6 +261,7 @@ class ColorManagementParamsEdited { public: bool input; bool gammaOnInput; + bool blendCMSMatrix; bool working; bool output; bool gamma;