diff --git a/rtdata/languages/default b/rtdata/languages/default index 84586340e..9c703954a 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -886,7 +886,7 @@ PREFERENCES_CLIPPINGIND;Clipping Indication PREFERENCES_CLUTSCACHE;HaldCLUT Cache PREFERENCES_CLUTSCACHE_LABEL;Maximum number of cached CLUTs PREFERENCES_CLUTSDIR;HaldCLUT directory -PREFERENCES_CMETRICINTENT;Colorimetric intent +PREFERENCES_MONINTENT;Default monitor intent PREFERENCES_CURVEBBOXPOS;Position of curve copypasta buttons PREFERENCES_CURVEBBOXPOS_ABOVE;Above PREFERENCES_CURVEBBOXPOS_BELOW;Below @@ -981,7 +981,7 @@ PREFERENCES_MENUGROUPRANK;Group "Rank" PREFERENCES_MENUOPTIONS;Context Menu Options PREFERENCES_METADATA;Metadata PREFERENCES_MIN;Mini (100x115) -PREFERENCES_MONITORICC;Monitor color profile +PREFERENCES_MONPROFILE;Default monitor profile PREFERENCES_MULTITAB;Multiple Editor Tabs Mode PREFERENCES_MULTITABDUALMON;Multiple Editor Tabs In Own Window Mode PREFERENCES_NAVGUIDEBRUSH;Navigator guide color @@ -1010,6 +1010,7 @@ PREFERENCES_PROFILEPRCACHE;Profile in cache PREFERENCES_PROFILEPRFILE;Profile next to the input file PREFERENCES_PROFILESAVECACHE;Save processing profile to the cache PREFERENCES_PROFILESAVEINPUT;Save processing profile next to the input file +PREFERENCES_PROFILE_NONE;None PREFERENCES_PROPERTY;Property PREFERENCES_PSPATH;Adobe Photoshop installation directory PREFERENCES_REMEMBERZOOMPAN;Remember zoom % and pan offset diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 62255cd39..4306d4a6e 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -209,21 +209,23 @@ void ImProcFunctions::firstAnalysis (Imagefloat* original, const ProcParams* par lab2outputTransform = NULL; #if !defined(__APPLE__) // No support for monitor profiles on OS X, all data is sRGB - Glib::ustring monitorProfile = settings->monitorProfile; + #if defined(WIN32) - if (settings->autoMonitorProfile) { - monitorProfile = iccStore->getDefaultMonitorProfile (); - } + cmsHPROFILE monitor = iccStore->getProfile (settings->autoMonitorProfile + ? iccStore->getDefaultMonitorProfile () + : params->icm.monitorProfile); + +#else + + cmsHPROFILE monitor = iccStore->getProfile (params->icm.monitorProfile); #endif - cmsHPROFILE monitor = iccStore->getProfile ("file:" + monitorProfile); - if (monitor) { - lcmsMutex->lock (); + MyMutex::MyLock lcmsLock (*lcmsMutex); cmsHPROFILE iprof = cmsCreateLab4Profile(NULL); - monitorTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_8, settings->colorimetricIntent, + monitorTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_8, params->icm.monitorIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); // NOCACHE is for thread safety, NOOPTIMIZE for precision Glib::ustring outputProfile; @@ -236,13 +238,12 @@ void ImProcFunctions::firstAnalysis (Imagefloat* original, const ProcParams* par lab2outputTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, jprof, TYPE_RGB_FLT, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); if (monitor) { - output2monitorTransform = cmsCreateTransform (jprof, TYPE_RGB_FLT, monitor, TYPE_RGB_8, settings->colorimetricIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); + output2monitorTransform = cmsCreateTransform (jprof, TYPE_RGB_FLT, monitor, TYPE_RGB_8, params->icm.monitorIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE ); } } } cmsCloseProfile(iprof); - lcmsMutex->unlock (); } #endif diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index becd8932e..44c02a531 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -894,6 +894,8 @@ void ColorManagementParams::setDefaults() dcpIlluminant = 0; working = "ProPhoto"; output = "RT_sRGB"; + monitorProfile = Glib::ustring (); + monitorIntent = 1; gamma = "default"; gampos = 2.22; slpos = 4.5; diff --git a/rtengine/procparams.h b/rtengine/procparams.h index d46fd4181..77c1004e8 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -941,6 +941,8 @@ public: int dcpIlluminant; Glib::ustring working; Glib::ustring output; + Glib::ustring monitorProfile; // Not stored persistently as it is just an optional settings override. + int monitorIntent; // Not store persistently as it is just an optional settings override. static const Glib::ustring NoICMString; Glib::ustring gamma; diff --git a/rtengine/settings.h b/rtengine/settings.h index 373103d07..bd37faaf2 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -27,7 +27,6 @@ class Settings { public: Glib::ustring iccDirectory; ///< The directory containing the possible output icc profiles - int colorimetricIntent; ///< Colorimetric intent used at color space conversions int viewingdevice; // white of output device (D50...D65..) int viewingdevicegrey; // level of grey output device int viewinggreySc; // level of grey Scene @@ -37,7 +36,8 @@ public: int leveldnliss; // level of auto multi zone int leveldnautsimpl; // STD or EXPERT - Glib::ustring monitorProfile; ///< ICC profile of the monitor (full path recommended) + Glib::ustring monitorProfile; ///< ICC profile name used for the monitor + int monitorIntent; ///< Colorimetric intent used with the above profile bool autoMonitorProfile; ///< Try to auto-determine the correct monitor color profile bool autocielab; bool rgbcurveslumamode_gamut;// controls gamut enforcement for RGB curves in lumamode diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 82e8d9fcf..c6d2804c1 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -25,12 +25,102 @@ #include "procparamchangers.h" #include "../rtengine/safegtk.h" #include "../rtengine/imagesource.h" +#include "../rtengine/iccstore.h" #include "soundman.h" #include "rtimage.h" #include using namespace rtengine::procparams; +class MonitorProfileSelector +{ +private: + Gtk::ComboBoxText profileBox; + Gtk::ComboBoxText intentBox; + + rtengine::StagedImageProcessor* const& processor; + +private: + MonitorProfileSelector(const MonitorProfileSelector&); + MonitorProfileSelector& operator=(const MonitorProfileSelector&); + + void prepareProfileBox () + { + profileBox.append_text (M("PREFERENCES_PROFILE_NONE")); + profileBox.set_active (0); + + const std::vector profiles = rtengine::ICCStore::getInstance ()->getProfiles (); + for (std::vector::const_iterator iterator = profiles.begin (); iterator != profiles.end (); ++iterator) + profileBox.append_text (*iterator); + } + + void prepareIntentBox () + { + intentBox.append_text (M("PREFERENCES_INTENT_RELATIVE")); + intentBox.append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); + intentBox.set_active (0); + } + + void updateParameters () + { + const Glib::ustring profile = profileBox.get_active_row_number () > 0 ? profileBox.get_active_text () : Glib::ustring(); + + std::uint8_t supportedIntents = rtengine::ICCStore::getInstance ()->getProofIntents (profile); + const bool supportsPerceptual = supportedIntents & 1 << INTENT_PERCEPTUAL; + const bool supportsRelativeColorimetric = supportedIntents & 1 << INTENT_RELATIVE_COLORIMETRIC; + + if (supportsPerceptual && supportsRelativeColorimetric) { + intentBox.set_sensitive (true); + } + else { + intentBox.set_sensitive (false); + intentBox.set_active (supportsPerceptual ? 1 : 0); + } + + const int intent = intentBox.get_active_row_number () > 0 ? INTENT_PERCEPTUAL : INTENT_RELATIVE_COLORIMETRIC; + + if (!processor) + return; + + rtengine::ProcParams* parameters = processor->beginUpdateParams (); + + parameters->icm.monitorProfile = profile; + parameters->icm.monitorIntent = intent; + + processor->endUpdateParams (rtengine::EvOProfile); + } + +public: + MonitorProfileSelector (rtengine::StagedImageProcessor* const& ipc) : + profileBox (), + intentBox (), + processor (ipc) + { + prepareProfileBox (); + prepareIntentBox (); + + reset (); + + profileBox.signal_changed ().connect (sigc::mem_fun (this, &MonitorProfileSelector::updateParameters)); + intentBox.signal_changed ().connect (sigc::mem_fun (this, &MonitorProfileSelector::updateParameters)); + } + + void pack_end (Gtk::Box* box) + { + box->pack_end (intentBox, Gtk::PACK_SHRINK, 0); + box->pack_end (profileBox, Gtk::PACK_SHRINK, 0); + } + + void reset () + { + setActiveTextOrIndex (profileBox, options.rtSettings.monitorProfile, 0); + intentBox.set_active (options.rtSettings.monitorIntent == INTENT_PERCEPTUAL ? 1 : 0); + + updateParameters (); + } + +}; + EditorPanel::EditorPanel (FilePanel* filePanel) : realized(false), iHistoryShow(NULL), iHistoryHide(NULL), iTopPanel_1_Show(NULL), iTopPanel_1_Hide(NULL), iRightPanel_1_Show(NULL), iRightPanel_1_Hide(NULL), iBeforeLockON(NULL), iBeforeLockOFF(NULL), beforePreviewHandler(NULL), beforeIarea(NULL), beforeBox(NULL), afterBox(NULL), afterHeaderBox(NULL), parent(NULL), openThm(NULL), ipc(NULL), beforeIpc(NULL), isProcessing(false), catalogPane(NULL) { @@ -256,12 +346,15 @@ EditorPanel::EditorPanel (FilePanel* filePanel) navSync->set_relief(Gtk::RELIEF_NONE); navSync->set_tooltip_markup(M("MAIN_BUTTON_NAVSYNC_TOOLTIP")); - iops->pack_end (*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_SHRINK, 0); iops->pack_end (*navNext, Gtk::PACK_SHRINK, 0); iops->pack_end (*navSync, Gtk::PACK_SHRINK, 0); iops->pack_end (*navPrev, Gtk::PACK_SHRINK, 0); + iops->pack_end (*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_SHRINK, 0); } + monitorProfile.reset(new MonitorProfileSelector (ipc)); + monitorProfile->pack_end (iops); + editbox->pack_start (*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_SHRINK, 0); editbox->pack_start (*iops, Gtk::PACK_SHRINK, 0); editbox->show_all (); @@ -568,6 +661,8 @@ void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) } history->resetSnapShotNumber(); + + monitorProfile->reset (); } void EditorPanel::close () diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index cf446da97..ffb8a93a4 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -42,6 +42,8 @@ struct EditorPanelIdleHelper { int pending; }; +class MonitorProfileSelector; + class RTWindow; class EditorPanel : public Gtk::VBox, public PParamsChangeListener, @@ -84,6 +86,8 @@ protected: Gtk::Button* navNext; Gtk::Button* navPrev; + std::auto_ptr monitorProfile; + ImageAreaPanel* iareapanel; PreviewHandler* previewHandler; PreviewHandler* beforePreviewHandler; // for the before-after view diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 1e65f2753..80729b96b 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -496,5 +496,12 @@ public: } }; +inline void setActiveTextOrIndex (Gtk::ComboBoxText& comboBox, const Glib::ustring& text, int index) +{ + comboBox.set_active_text (text); + + if (comboBox.get_active_row_number () < 0) + comboBox.set_active (index); +} #endif diff --git a/rtgui/options.cc b/rtgui/options.cc index 6d0b6a0d0..ce85acc09 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -626,7 +626,6 @@ void Options::setDefaults () #else rtSettings.iccDirectory = "/usr/share/color/icc"; #endif - rtSettings.colorimetricIntent = 1; rtSettings.viewingdevice = 0; rtSettings.viewingdevicegrey = 3; rtSettings.viewinggreySc = 1; @@ -636,7 +635,8 @@ void Options::setDefaults () rtSettings.leveldnliss = 0; rtSettings.leveldnautsimpl = 0; - rtSettings.monitorProfile = ""; + rtSettings.monitorProfile = Glib::ustring(); + rtSettings.monitorIntent = 1; rtSettings.autoMonitorProfile = false; rtSettings.adobe = "RT_Medium_gsRGB"; // put the name of yours profiles (here windows) rtSettings.prophoto = "RT_Large_gBT709"; // these names appear in the menu "output profile" @@ -1461,7 +1461,7 @@ int Options::readFromFile (Glib::ustring fname) } if (keyFile.has_key ("Color Management", "Intent")) { - rtSettings.colorimetricIntent = keyFile.get_integer("Color Management", "Intent"); + rtSettings.monitorIntent = keyFile.get_integer("Color Management", "Intent"); } if (keyFile.has_key ("Color Management", "CRI")) { @@ -2008,7 +2008,7 @@ int Options::saveToFile (Glib::ustring fname) keyFile.set_boolean ("Color Management", "AutoMonitorProfile", rtSettings.autoMonitorProfile); keyFile.set_boolean ("Color Management", "Autocielab", rtSettings.autocielab); keyFile.set_boolean ("Color Management", "RGBcurvesLumamode_Gamut", rtSettings.rgbcurveslumamode_gamut); - keyFile.set_integer ("Color Management", "Intent", rtSettings.colorimetricIntent); + keyFile.set_integer ("Color Management", "Intent", rtSettings.monitorIntent); keyFile.set_integer ("Color Management", "view", rtSettings.viewingdevice); keyFile.set_integer ("Color Management", "grey", rtSettings.viewingdevicegrey); keyFile.set_integer ("Color Management", "greySc", rtSettings.viewinggreySc); diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 5c85ea18f..4aa1d2427 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -687,30 +687,27 @@ Gtk::Widget* Preferences::getColorManagementPanel () Gtk::VBox* mvbcm = Gtk::manage (new Gtk::VBox ()); mvbcm->set_border_width (4); - Gtk::Label* intlab = Gtk::manage (new Gtk::Label (M("PREFERENCES_CMETRICINTENT")+":", Gtk::ALIGN_LEFT)); - intent = Gtk::manage (new Gtk::ComboBoxText ()); - intent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); - intent->append_text (M("PREFERENCES_INTENT_RELATIVE")); - intent->append_text (M("PREFERENCES_INTENT_SATURATION")); - intent->append_text (M("PREFERENCES_INTENT_ABSOLUTE")); - iccDir = Gtk::manage (new Gtk::FileChooserButton (M("PREFERENCES_ICCDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); Gtk::Label* pdlabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_ICCDIR") + ":", Gtk::ALIGN_LEFT)); - Gtk::FileFilter monProfileFilter_colprof; - monProfileFilter_colprof.set_name(M("FILECHOOSER_FILTER_COLPROF")); - monProfileFilter_colprof.add_pattern("*.icc"); - monProfileFilter_colprof.add_pattern("*.ICC"); - monProfileFilter_colprof.add_pattern("*.icm"); - monProfileFilter_colprof.add_pattern("*.ICM"); - Gtk::FileFilter monProfileFilter_any; - monProfileFilter_any.set_name(M("FILECHOOSER_FILTER_ANY")); - monProfileFilter_any.add_pattern("*"); + monProfile = Gtk::manage (new Gtk::ComboBoxText ()); + Gtk::Label* mplabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_MONPROFILE") + ":", Gtk::ALIGN_LEFT)); - monProfile = Gtk::manage (new Gtk::FileChooserButton (M("PREFERENCES_MONITORICC"), Gtk::FILE_CHOOSER_ACTION_OPEN)); - monProfile->add_filter (monProfileFilter_colprof); - monProfile->add_filter (monProfileFilter_any); - Gtk::Label* mplabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_MONITORICC") + ":", Gtk::ALIGN_LEFT)); + monIntent = Gtk::manage (new Gtk::ComboBoxText ()); + Gtk::Label* milabel = Gtk::manage (new Gtk::Label (M("PREFERENCES_MONINTENT")+":", Gtk::ALIGN_LEFT)); + + monProfile->append_text (M("PREFERENCES_PROFILE_NONE")); + monProfile->set_active (0); + + const std::vector profiles = rtengine::ICCStore::getInstance ()->getProfiles (); + for (std::vector::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) + monProfile->append_text (*profile); + + monIntent->append_text (M("PREFERENCES_INTENT_RELATIVE")); + monIntent->append_text (M("PREFERENCES_INTENT_PERCEPTUAL")); + monIntent->set_active (0); + + iccDir->signal_selection_changed ().connect (sigc::mem_fun (this, &Preferences::iccDirChanged)); #if defined(WIN32) // Auto-detection not implemented for Linux, see issue 851 cbAutoMonProfile = Gtk::manage (new Gtk::CheckButton (M("PREFERENCES_AUTOMONPROFILE"))); @@ -731,8 +728,8 @@ Gtk::Widget* Preferences::getColorManagementPanel () #endif #endif ++row; - colt->attach (*intlab, 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 2, 2); - colt->attach (*intent, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); + colt->attach (*milabel, 0, 1, row, row + 1, Gtk::FILL, Gtk::SHRINK, 2, 2); + colt->attach (*monIntent, 1, 2, row, row + 1, Gtk::EXPAND | Gtk::FILL | Gtk::SHRINK, Gtk::SHRINK, 2, 2); mvbcm->pack_start (*colt, Gtk::PACK_SHRINK, 4); #if defined(WIN32) @@ -1435,12 +1432,15 @@ void Preferences::storePreferences () moptions.CPBPath = txtCustProfBuilderPath->get_text(); moptions.CPBKeys = CPBKeyType(custProfBuilderLabelType->get_active_row_number()); - moptions.rtSettings.monitorProfile = monProfile->get_filename (); +#if !defined(__APPLE__) // monitor profile not supported on apple + moptions.rtSettings.monitorProfile = monProfile->get_active_text (); + moptions.rtSettings.monitorIntent = monIntent->get_active_row_number () > 0 ? INTENT_PERCEPTUAL : INTENT_RELATIVE_COLORIMETRIC; #if defined(WIN32) moptions.rtSettings.autoMonitorProfile = cbAutoMonProfile->get_active (); #endif +#endif + moptions.rtSettings.iccDirectory = iccDir->get_filename (); - moptions.rtSettings.colorimetricIntent = intent->get_active_row_number (); moptions.rtSettings.viewingdevice = view->get_active_row_number (); moptions.rtSettings.viewingdevicegrey = grey->get_active_row_number (); moptions.rtSettings.viewinggreySc = greySc->get_active_row_number (); @@ -1550,16 +1550,10 @@ void Preferences::fillPreferences () panFactor->set_value (moptions.panAccelFactor); rememberZoomPanCheckbutton->set_active (moptions.rememberZoomAndPan); ctiffserialize->set_active(moptions.serializeTiffRead); + #if !defined(__APPLE__) // monitor profile not supported on apple - - if (safe_file_test (moptions.rtSettings.monitorProfile, Glib::FILE_TEST_EXISTS)) { - monProfile->set_filename (moptions.rtSettings.monitorProfile); - } - - if (moptions.rtSettings.monitorProfile.empty()) { - monProfile->set_current_folder (moptions.rtSettings.iccDirectory); - } - + setActiveTextOrIndex (*monProfile, moptions.rtSettings.monitorProfile, 0); + monIntent->set_active (moptions.rtSettings.monitorIntent == INTENT_PERCEPTUAL ? 1 : 0); #if defined(WIN32) cbAutoMonProfile->set_active(moptions.rtSettings.autoMonitorProfile); #endif @@ -1569,7 +1563,6 @@ void Preferences::fillPreferences () iccDir->set_current_folder (moptions.rtSettings.iccDirectory); } - intent->set_active (moptions.rtSettings.colorimetricIntent); view->set_active (moptions.rtSettings.viewingdevice); grey->set_active (moptions.rtSettings.viewingdevicegrey); greySc->set_active (moptions.rtSettings.viewinggreySc); @@ -1921,6 +1914,22 @@ void Preferences::bundledProfilesChanged () rpconn.block (false); } +void Preferences::iccDirChanged () +{ + const Glib::ustring currentSelection = monProfile->get_active_text (); + + monProfile->clear(); + + monProfile->append_text (M("PREFERENCES_PROFILE_NONE")); + monProfile->set_active (0); + + const std::vector profiles = rtengine::ICCStore::getInstance ()->getProfilesFromDir (iccDir->get_filename ()); + for (std::vector::const_iterator profile = profiles.begin (); profile != profiles.end (); ++profile) + monProfile->append_text (*profile); + + monProfile->set_active_text (currentSelection); +} + void Preferences::storeCurrentValue() { // TODO: Find a way to get and restore the current selection; the following line can't work anymore diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 76abd0a19..2bf118459 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -95,7 +95,8 @@ protected: Gtk::CheckButton* showExpComp; Gtk::FileChooserButton* iccDir; - Gtk::FileChooserButton* monProfile; + Gtk::ComboBoxText* monProfile; + Gtk::ComboBoxText* monIntent; Gtk::CheckButton* cbAutoMonProfile; //Gtk::CheckButton* cbAutocielab; Gtk::CheckButton* cbciecamfloat; @@ -106,7 +107,6 @@ protected: Gtk::SpinButton* panFactor; Gtk::CheckButton* rememberZoomPanCheckbutton; - Gtk::ComboBoxText* intent; Gtk::ComboBoxText* view; Gtk::ComboBoxText* grey; Gtk::ComboBoxText* greySc; @@ -210,7 +210,8 @@ protected: void forRAWComboChanged (); void forImageComboChanged (); void layoutComboChanged (); - void bundledProfilesChanged(); + void bundledProfilesChanged (); + void iccDirChanged (); void switchThemeTo (Glib::ustring newTheme, bool slimInterface); void switchFontTo (Glib::ustring newFont); bool splashClosed(GdkEventAny* event);