From 1450b9bb7aebcff58389415f21db1b0af3f78989 Mon Sep 17 00:00:00 2001 From: Bezierr Date: Wed, 20 Jul 2022 12:14:05 +0200 Subject: [PATCH 01/14] Camera and Lens profiles directories In "Preferences", added the possibility to define a "Camera profiles directory" and a "Lens profiles directory" as base paths which enable storing relative paths in the .pp3 files. --- rtdata/languages/default | 2 ++ rtengine/procparams.cc | 36 ++++++++++++++++++++++++++++++++---- rtengine/settings.h | 2 ++ rtgui/options.cc | 19 +++++++++++++++++++ rtgui/options.h | 2 ++ rtgui/preferences.cc | 29 +++++++++++++++++++++++++++-- rtgui/preferences.h | 2 ++ 7 files changed, 86 insertions(+), 6 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index c50b49ddf..d67e6a12b 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1845,6 +1845,7 @@ PREFERENCES_CACHECLEAR_SAFETY;Only files in the cache are cleared. Processing pr PREFERENCES_CACHEMAXENTRIES;Maximum number of cache entries PREFERENCES_CACHEOPTS;Cache Options PREFERENCES_CACHETHUMBHEIGHT;Maximum thumbnail height +PREFERENCES_CAMERAPROFILESDIR;Camera profiles directory PREFERENCES_CHUNKSIZES;Tiles per thread PREFERENCES_CHUNKSIZE_RAW_AMAZE;AMaZE demosaic PREFERENCES_CHUNKSIZE_RAW_CA;Raw CA correction @@ -1927,6 +1928,7 @@ PREFERENCES_INTENT_SATURATION;Saturation PREFERENCES_INTERNALTHUMBIFUNTOUCHED;Show embedded JPEG thumbnail if raw is unedited PREFERENCES_LANG;Language PREFERENCES_LANGAUTODETECT;Use system language +PREFERENCES_LENSPROFILESDIR;Lens profiles directory PREFERENCES_MAXRECENTFOLDERS;Maximum number of recent folders PREFERENCES_MENUGROUPEXTPROGS;Group "Open with" PREFERENCES_MENUGROUPFILEOPERATIONS;Group "File operations" diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 9a9e4fef1..30a2e303c 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -6287,7 +6287,14 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo // Lens profile saveToKeyfile(!pedited || pedited->lensProf.lcMode, "LensProfile", "LcMode", lensProf.getMethodString(lensProf.lcMode), keyFile); - saveToKeyfile(!pedited || pedited->lensProf.lcpFile, "LensProfile", "LCPFile", relativePathIfInside(fname, fnameAbsolute, lensProf.lcpFile), keyFile); + if (options.rtSettings.lensProfilesPath.empty() + || !Glib::path_is_absolute(options.rtSettings.lensProfilesPath)) { + saveToKeyfile(!pedited || pedited->lensProf.lcpFile, "LensProfile", "LCPFile", relativePathIfInside(fname, fnameAbsolute, lensProf.lcpFile), keyFile); + } else { + // if the "lens profiles directory" in Preferences exists and is an absolute path, try to save + // the path to the LCP file as relative to this directory + saveToKeyfile(!pedited || pedited->lensProf.lcpFile, "LensProfile", "LCPFile", relativePathIfInside(options.rtSettings.lensProfilesPath + G_DIR_SEPARATOR_S, false, lensProf.lcpFile), keyFile); + } saveToKeyfile(!pedited || pedited->lensProf.useDist, "LensProfile", "UseDistortion", lensProf.useDist, keyFile); saveToKeyfile(!pedited || pedited->lensProf.useVign, "LensProfile", "UseVignette", lensProf.useVign, keyFile); saveToKeyfile(!pedited || pedited->lensProf.useCA, "LensProfile", "UseCA", lensProf.useCA, keyFile); @@ -7108,7 +7115,14 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->prsharpening.deconviter, "PostResizeSharpening", "DeconvIterations", prsharpening.deconviter, keyFile); // Color management - saveToKeyfile(!pedited || pedited->icm.inputProfile, "Color Management", "InputProfile", relativePathIfInside(fname, fnameAbsolute, icm.inputProfile), keyFile); + if (options.rtSettings.cameraProfilesPath.empty() + || !Glib::path_is_absolute(options.rtSettings.cameraProfilesPath)) { + saveToKeyfile(!pedited || pedited->icm.inputProfile, "Color Management", "InputProfile", relativePathIfInside(fname, fnameAbsolute, icm.inputProfile), keyFile); + } else { + // if the "camera profiles directory" in Preferences exists and is an absolute path, try to save + // the path to the Custom Input Profile as relative to this directory + saveToKeyfile(!pedited || pedited->icm.inputProfile, "Color Management", "InputProfile", relativePathIfInside(options.rtSettings.cameraProfilesPath + G_DIR_SEPARATOR_S, false, icm.inputProfile), keyFile); + } saveToKeyfile(!pedited || pedited->icm.toneCurve, "Color Management", "ToneCurve", icm.toneCurve, keyFile); saveToKeyfile(!pedited || pedited->icm.applyLookTable, "Color Management", "ApplyLookTable", icm.applyLookTable, keyFile); saveToKeyfile(!pedited || pedited->icm.applyBaselineExposureOffset, "Color Management", "ApplyBaselineExposureOffset", icm.applyBaselineExposureOffset, keyFile); @@ -8320,7 +8334,14 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } if (keyFile.has_key("LensProfile", "LCPFile")) { - lensProf.lcpFile = expandRelativePath(fname, "", keyFile.get_string("LensProfile", "LCPFile")); + if (options.rtSettings.lensProfilesPath.empty() + || !Glib::path_is_absolute(options.rtSettings.lensProfilesPath)) { + lensProf.lcpFile = expandRelativePath(fname, "", keyFile.get_string("LensProfile", "LCPFile")); + } else { + // if the "lens profiles directory" in Preferences exists and is an absolute path, + // use it as a prefix if the path to the LCP file is relative + lensProf.lcpFile = expandRelativePath(options.rtSettings.lensProfilesPath + G_DIR_SEPARATOR_S, "", keyFile.get_string("LensProfile", "LCPFile")); + } if (pedited) { pedited->lensProf.lcpFile = true; @@ -9350,7 +9371,14 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("Color Management")) { if (keyFile.has_key("Color Management", "InputProfile")) { - icm.inputProfile = expandRelativePath(fname, "file:", keyFile.get_string("Color Management", "InputProfile")); + if (options.rtSettings.cameraProfilesPath.empty() + || !Glib::path_is_absolute(options.rtSettings.cameraProfilesPath)) { + icm.inputProfile = expandRelativePath(fname, "file:", keyFile.get_string("Color Management", "InputProfile")); + } else { + // if the "camera profiles directory" in Preferences exists and is an absolute path, + // use it as a prefix if the path to the Custom Input Profile is relative + icm.inputProfile = expandRelativePath(options.rtSettings.cameraProfilesPath + G_DIR_SEPARATOR_S, "file:", keyFile.get_string("Color Management", "InputProfile")); + } if (pedited) { pedited->icm.inputProfile = true; diff --git a/rtengine/settings.h b/rtengine/settings.h index bc49a2281..19d3b6ed6 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -48,6 +48,8 @@ public: bool verbose; Glib::ustring darkFramesPath; ///< The default directory for dark frames Glib::ustring flatFieldsPath; ///< The default directory for flat fields + Glib::ustring cameraProfilesPath; ///< The default directory for camera profiles + Glib::ustring lensProfilesPath; ///< The default directory for lens profiles Glib::ustring adobe; // filename of AdobeRGB1998 profile (default to the bundled one) Glib::ustring prophoto; // filename of Prophoto profile (default to the bundled one) diff --git a/rtgui/options.cc b/rtgui/options.cc index fc543709f..fd9e87c8d 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -566,6 +566,9 @@ void Options::setDefaults() rtSettings.darkFramesPath = ""; rtSettings.flatFieldsPath = ""; + rtSettings.cameraProfilesPath = ""; + rtSettings.lensProfilesPath = ""; + #ifdef WIN32 const gchar* sysRoot = g_getenv("SystemRoot"); // Returns e.g. "c:\Windows" @@ -663,6 +666,8 @@ void Options::setDefaults() lastIccDir = rtSettings.iccDirectory; lastDarkframeDir = rtSettings.darkFramesPath; lastFlatfieldDir = rtSettings.flatFieldsPath; + lastCameraProfilesDir = rtSettings.cameraProfilesPath; + lastLensProfilesDir = rtSettings.lensProfilesPath; // rtSettings.bw_complementary = true; // There is no reasonable default for curves. We can still suppose that they will take place // in a subdirectory of the user's own ProcParams presets, i.e. in a subdirectory @@ -791,6 +796,14 @@ void Options::readFromFile(Glib::ustring fname) rtSettings.flatFieldsPath = keyFile.get_string("General", "FlatFieldsPath"); } + if (keyFile.has_key("General", "CameraProfilesPath")) { + rtSettings.cameraProfilesPath = keyFile.get_string("General", "CameraProfilesPath"); + } + + if (keyFile.has_key("General", "LensProfilesPath")) { + rtSettings.lensProfilesPath = keyFile.get_string("General", "LensProfilesPath"); + } + if (keyFile.has_key("General", "Verbose")) { rtSettings.verbose = keyFile.get_boolean("General", "Verbose"); } @@ -2047,6 +2060,8 @@ void Options::readFromFile(Glib::ustring fname) safeDirGet(keyFile, "Dialogs", "LastIccDir", lastIccDir); safeDirGet(keyFile, "Dialogs", "LastDarkframeDir", lastDarkframeDir); safeDirGet(keyFile, "Dialogs", "LastFlatfieldDir", lastFlatfieldDir); + safeDirGet(keyFile, "Dialogs", "LastCameraProfilesDir", lastCameraProfilesDir); + safeDirGet(keyFile, "Dialogs", "LastLensProfilesDir", lastLensProfilesDir); safeDirGet(keyFile, "Dialogs", "LastRgbCurvesDir", lastRgbCurvesDir); safeDirGet(keyFile, "Dialogs", "LastLabCurvesDir", lastLabCurvesDir); safeDirGet(keyFile, "Dialogs", "LastRetinexDir", lastRetinexDir); @@ -2150,6 +2165,8 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_string("General", "Version", RTVERSION); keyFile.set_string("General", "DarkFramesPath", rtSettings.darkFramesPath); keyFile.set_string("General", "FlatFieldsPath", rtSettings.flatFieldsPath); + keyFile.set_string("General", "CameraProfilesPath", rtSettings.cameraProfilesPath); + keyFile.set_string("General", "LensProfilesPath", rtSettings.lensProfilesPath); keyFile.set_boolean("General", "Verbose", rtSettings.verbose); keyFile.set_integer("General", "Cropsleep", rtSettings.cropsleep); keyFile.set_double("General", "Reduchigh", rtSettings.reduchigh); @@ -2484,6 +2501,8 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_string("Dialogs", "LastIccDir", lastIccDir); keyFile.set_string("Dialogs", "LastDarkframeDir", lastDarkframeDir); keyFile.set_string("Dialogs", "LastFlatfieldDir", lastFlatfieldDir); + keyFile.set_string("Dialogs", "LastCameraProfilesDir", lastCameraProfilesDir); + keyFile.set_string("Dialogs", "LastLensProfilesDir", lastLensProfilesDir); keyFile.set_string("Dialogs", "LastRgbCurvesDir", lastRgbCurvesDir); keyFile.set_string("Dialogs", "LastLabCurvesDir", lastLabCurvesDir); keyFile.set_string("Dialogs", "LastRetinexDir", lastRetinexDir); diff --git a/rtgui/options.h b/rtgui/options.h index bc5e41c91..6385709db 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -432,6 +432,8 @@ public: Glib::ustring lastIccDir; Glib::ustring lastDarkframeDir; Glib::ustring lastFlatfieldDir; + Glib::ustring lastCameraProfilesDir; + Glib::ustring lastLensProfilesDir; Glib::ustring lastRgbCurvesDir; Glib::ustring lastLabCurvesDir; Glib::ustring lastRetinexDir; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index c6c2eb61b..a4c7410da 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -589,6 +589,7 @@ Gtk::Widget* Preferences::getImageProcessingPanel () Gtk::Grid* dirgrid = Gtk::manage(new Gtk::Grid()); setExpandAlignProperties(dirgrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + // Dark Frames Dir Gtk::Label *dfLab = Gtk::manage(new Gtk::Label(M("PREFERENCES_DIRDARKFRAMES") + ":")); setExpandAlignProperties(dfLab, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); darkFrameDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_DIRDARKFRAMES"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); @@ -602,7 +603,7 @@ Gtk::Widget* Preferences::getImageProcessingPanel () dfconn = darkFrameDir->signal_selection_changed().connect ( sigc::mem_fun (*this, &Preferences::darkFrameChanged)); - // FLATFIELD + // Flatfield Dir Gtk::Label *ffLab = Gtk::manage(new Gtk::Label(M("PREFERENCES_FLATFIELDSDIR") + ":")); setExpandAlignProperties(ffLab, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); flatFieldDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_FLATFIELDSDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); @@ -628,6 +629,25 @@ Gtk::Widget* Preferences::getImageProcessingPanel () dirgrid->attach_next_to(*clutsDir, *clutsDirLabel, Gtk::POS_RIGHT, 1, 1); dirgrid->attach_next_to(*clutsRestartNeeded, *clutsDir, Gtk::POS_RIGHT, 1, 1); + //Camera Profiles Dir + Gtk::Label *cameraProfilesDirLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_CAMERAPROFILESDIR") + ":")); + setExpandAlignProperties(cameraProfilesDirLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + cameraProfilesDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_CAMERAPROFILESDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + setExpandAlignProperties(cameraProfilesDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + + dirgrid->attach_next_to(*cameraProfilesDirLabel, *clutsDirLabel, Gtk::POS_BOTTOM, 1, 1); + dirgrid->attach_next_to(*cameraProfilesDir, *cameraProfilesDirLabel, Gtk::POS_RIGHT, 1, 1); + + //Lens Profiles Dir + Gtk::Label *lensProfilesDirLabel = Gtk::manage(new Gtk::Label(M("PREFERENCES_LENSPROFILESDIR") + ":")); + setExpandAlignProperties(lensProfilesDirLabel, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + lensProfilesDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_LENSPROFILESDIR"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); + setExpandAlignProperties(lensProfilesDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + + dirgrid->attach_next_to(*lensProfilesDirLabel, *cameraProfilesDirLabel, Gtk::POS_BOTTOM, 1, 1); + dirgrid->attach_next_to(*lensProfilesDir, *lensProfilesDirLabel, Gtk::POS_RIGHT, 1, 1); + + //Pack directories to Image Processing panel cdf->add(*dirgrid); vbImageProcessing->pack_start (*cdf, Gtk::PACK_SHRINK, 4 ); @@ -1889,8 +1909,9 @@ void Preferences::storePreferences() moptions.rtSettings.darkFramesPath = darkFrameDir->get_filename(); moptions.rtSettings.flatFieldsPath = flatFieldDir->get_filename(); - moptions.clutsDir = clutsDir->get_filename(); + moptions.rtSettings.cameraProfilesPath = cameraProfilesDir->get_filename(); + moptions.rtSettings.lensProfilesPath = lensProfilesDir->get_filename(); moptions.baBehav.resize(ADDSET_PARAM_NUM); @@ -2162,6 +2183,10 @@ void Preferences::fillPreferences() flatFieldChanged(); clutsDir->set_current_folder(moptions.clutsDir); + + cameraProfilesDir->set_current_folder(moptions.rtSettings.cameraProfilesPath); + + lensProfilesDir->set_current_folder(moptions.rtSettings.lensProfilesPath); addc.block(true); setc.block(true); diff --git a/rtgui/preferences.h b/rtgui/preferences.h index dfe1e008d..6b0d372af 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -112,6 +112,8 @@ class Preferences final : MyFileChooserButton* darkFrameDir; MyFileChooserButton* flatFieldDir; MyFileChooserButton* clutsDir; + MyFileChooserButton* cameraProfilesDir; + MyFileChooserButton* lensProfilesDir; Gtk::Label *dfLabel; Gtk::Label *ffLabel; From a974fc06f3d06e9cd28c649c38a78104cc7a40d1 Mon Sep 17 00:00:00 2001 From: Bezierr Date: Wed, 27 Jul 2022 16:50:30 +0200 Subject: [PATCH 02/14] replaceBackslash for lens profiles and camera profiles directories When saving .pp3, replace all "\\" by "/" in paths for LCPFile and InputProfile, so they are compatible between Windows and Linux. --- rtengine/procparams.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 30a2e303c..afce81e7a 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -42,6 +42,19 @@ using namespace std; namespace { +Glib::ustring replaceBackslash(Glib::ustring path) +{ + size_t pos; + + pos = path.find("\\"); + while (pos != string::npos) { + path.replace(pos, 1, "/"); + pos = path.find("\\", pos); + } + return path; +} + + Glib::ustring expandRelativePath(const Glib::ustring &procparams_fname, const Glib::ustring &prefix, Glib::ustring embedded_fname) { if (embedded_fname.empty() || !Glib::path_is_absolute(procparams_fname)) { @@ -6293,7 +6306,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo } else { // if the "lens profiles directory" in Preferences exists and is an absolute path, try to save // the path to the LCP file as relative to this directory - saveToKeyfile(!pedited || pedited->lensProf.lcpFile, "LensProfile", "LCPFile", relativePathIfInside(options.rtSettings.lensProfilesPath + G_DIR_SEPARATOR_S, false, lensProf.lcpFile), keyFile); + saveToKeyfile(!pedited || pedited->lensProf.lcpFile, "LensProfile", "LCPFile", replaceBackslash(relativePathIfInside(options.rtSettings.lensProfilesPath + G_DIR_SEPARATOR_S, false, lensProf.lcpFile)), keyFile); } saveToKeyfile(!pedited || pedited->lensProf.useDist, "LensProfile", "UseDistortion", lensProf.useDist, keyFile); saveToKeyfile(!pedited || pedited->lensProf.useVign, "LensProfile", "UseVignette", lensProf.useVign, keyFile); @@ -7121,7 +7134,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo } else { // if the "camera profiles directory" in Preferences exists and is an absolute path, try to save // the path to the Custom Input Profile as relative to this directory - saveToKeyfile(!pedited || pedited->icm.inputProfile, "Color Management", "InputProfile", relativePathIfInside(options.rtSettings.cameraProfilesPath + G_DIR_SEPARATOR_S, false, icm.inputProfile), keyFile); + saveToKeyfile(!pedited || pedited->icm.inputProfile, "Color Management", "InputProfile", replaceBackslash(relativePathIfInside(options.rtSettings.cameraProfilesPath + G_DIR_SEPARATOR_S, false, icm.inputProfile)), keyFile); } saveToKeyfile(!pedited || pedited->icm.toneCurve, "Color Management", "ToneCurve", icm.toneCurve, keyFile); saveToKeyfile(!pedited || pedited->icm.applyLookTable, "Color Management", "ApplyLookTable", icm.applyLookTable, keyFile); From 1c95dfe099768801fc2df3692f5b0b413c66d542 Mon Sep 17 00:00:00 2001 From: Bezierr Date: Fri, 29 Jul 2022 15:29:35 +0200 Subject: [PATCH 03/14] In filmSimulation.clutFilename, use "/" or "\" depending on OS For OS-independent use of .pp3 files: If OS is WIN32, replace any "/" in filmSimulation.clutFilename with "\\". If OS is not WIN32, replace any "\\" in filmSimulation.clutFilename with "/". --- rtengine/procparams.cc | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index afce81e7a..e875124e3 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -9978,7 +9978,23 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("Film Simulation")) { assignFromKeyfile(keyFile, "Film Simulation", "Enabled", pedited, filmSimulation.enabled, pedited->filmSimulation.enabled); - assignFromKeyfile(keyFile, "Film Simulation", "ClutFilename", pedited, filmSimulation.clutFilename, pedited->filmSimulation.clutFilename); + assignFromKeyfile(keyFile, "Film Simulation", "ClutFilename", pedited, filmSimulation.clutFilename, pedited->filmSimulation.clutFilename); + #if defined (WIN32) + // if this is Windows, replace any "/" in the filename with "\\" + size_t pos = filmSimulation.clutFilename.find("/"); + while (pos != string::npos) { + filmSimulation.clutFilename.replace(pos, 1, "\\"); + pos = filmSimulation.clutFilename.find("/", pos); + } + #endif + #if !defined (WIN32) + // if this is not Windows, replace any "\\" in the filename with "/" + size_t pos = filmSimulation.clutFilename.find("\\"); + while (pos != string::npos) { + filmSimulation.clutFilename.replace(pos, 1, "/"); + pos = filmSimulation.clutFilename.find("\\", pos); + } + #endif if (keyFile.has_key("Film Simulation", "Strength")) { if (ppVersion < 321) { From 24f5d85c8d2cb57c4405ddbc573167f52dc2d69a Mon Sep 17 00:00:00 2001 From: Bezierr Date: Tue, 23 Aug 2022 16:27:47 +0200 Subject: [PATCH 04/14] Squashed commit of the following: commit e293f0890866ddf934ba1a9dd9fa372364766bb3 Author: Bezierr Date: Tue Aug 23 16:16:23 2022 +0200 Added comment commit 20a50b248dc110eeb4b526c7242920a68216c88c Author: Bezierr Date: Tue Aug 23 14:35:47 2022 +0200 Follow dynamicprofile.cfg symlink instead of overwriting it If dynamicprofile.cfg is a symlink, write the contents to this symlink's target instead of overwriting it. commit bad2f8c37a0d27e612150dce3219593b2f996f9c Author: Bezierr Date: Thu Aug 11 17:20:08 2022 +0200 Make dynamicprofile.cfg OS independent dynamicprofile.cfg contains OS-dependent paths to the profiles. To fix this, replace "/" or "\", depending on OS, with the correct delimiter. commit cd84120876be111c23dac5376eb5b6f6cb0a7328 Author: Bezierr Date: Thu Aug 11 16:33:39 2022 +0200 Relative paths also for Dark Frame and Flat File (a) Extended the "relative path" functionality to the (already existing, but apparently not used) directories for FlatField and DarkFrame (b) Simpler, cleaner implementation commit a338b8726451323505bb4cff1888c562fd88929d Author: Bezierr Date: Sun Aug 7 18:03:46 2022 +0200 Preference of RAW path over rtSettings path (a) Give path relative to a camera or lens profile in the same folder as the raw file precendence over path relative to rtSettings. (b) Replace backslash/slash when reading file paths, not when writing them. --- rtengine/dynamicprofile.cc | 26 ++++++++- rtengine/procparams.cc | 116 ++++++++++++++++++++----------------- rtgui/options.cc | 4 +- 3 files changed, 89 insertions(+), 57 deletions(-) diff --git a/rtengine/dynamicprofile.cc b/rtengine/dynamicprofile.cc index 28516a1ee..db1baf4b8 100644 --- a/rtengine/dynamicprofile.cc +++ b/rtengine/dynamicprofile.cc @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -218,6 +219,22 @@ bool DynamicProfileRules::loadRules() try { rule.profilepath = kf.get_string (group, "profilepath"); + #if defined (WIN32) + // if this is Windows, replace any "/" in the path with "\\" + int pos = rule.profilepath.find("/"); + while (pos != -1) { + rule.profilepath.replace(pos, 1, "\\"); + pos = rule.profilepath.find("/", pos); + } + #endif + #if !defined (WIN32) + // if this is not Windows, replace any "\\" in the path with "/" + int pos = rule.profilepath.find("\\"); + while (pos != -1) { + rule.profilepath.replace(pos, 1, "/"); + pos = rule.profilepath.find("\\", pos); + } + #endif } catch (Glib::KeyFileError &) { dynamicRules.pop_back(); } @@ -251,7 +268,14 @@ bool DynamicProfileRules::storeRules() kf.set_string (group, "profilepath", rule.profilepath); } - return kf.save_to_file (Glib::build_filename (Options::rtdir, "dynamicprofile.cfg")); + std::string fn = Glib::build_filename (Options::rtdir, "dynamicprofile.cfg"); + if (Glib::file_test(fn, Glib::FILE_TEST_IS_SYMLINK)) { + // file is symlink; use target instead + // symlinks apparently are not recognízed on Windows + return kf.save_to_file (g_file_read_link (fn.c_str(), NULL)); + } else { + return kf.save_to_file (fn); + } } const std::vector &DynamicProfileRules::getRules() diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index e875124e3..c787c7b0c 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -42,19 +42,6 @@ using namespace std; namespace { -Glib::ustring replaceBackslash(Glib::ustring path) -{ - size_t pos; - - pos = path.find("\\"); - while (pos != string::npos) { - path.replace(pos, 1, "/"); - pos = path.find("\\", pos); - } - return path; -} - - Glib::ustring expandRelativePath(const Glib::ustring &procparams_fname, const Glib::ustring &prefix, Glib::ustring embedded_fname) { if (embedded_fname.empty() || !Glib::path_is_absolute(procparams_fname)) { @@ -77,6 +64,40 @@ Glib::ustring expandRelativePath(const Glib::ustring &procparams_fname, const Gl return absPath; } +Glib::ustring expandRelativePath2(const Glib::ustring &procparams_fname, const Glib::ustring &procparams_fname2, const Glib::ustring &prefix, Glib::ustring embedded_fname) +{ + #if defined (WIN32) + // if this is Windows, replace any "/" in the filename with "\\" + size_t pos = embedded_fname.find("/"); + while (pos != string::npos) { + embedded_fname.replace(pos, 1, "\\"); + pos = embedded_fname.find("/", pos); + } + #endif + #if !defined (WIN32) + // if this is not Windows, replace any "\\" in the filename with "/" + size_t pos = embedded_fname.find("\\"); + while (pos != string::npos) { + embedded_fname.replace(pos, 1, "/"); + pos = embedded_fname.find("\\", pos); + } + #endif + + // if embedded_fname is not already an absolute path, + // try to convert it using procparams_fname (the directory of the raw file) as prefix + Glib::ustring rPath = expandRelativePath(procparams_fname, prefix, embedded_fname); + if (rPath.length() >= prefix.length() + && !Glib::file_test(rPath.substr(prefix.length()), Glib::FILE_TEST_IS_REGULAR) + && !procparams_fname2.empty() + && Glib::path_is_absolute(procparams_fname2)) { + // embedded_fname is not a valid path; + // try with procparams_fname2 (the path defined in Preferences) as a prefix + rPath = expandRelativePath(procparams_fname2 + G_DIR_SEPARATOR_S, prefix, embedded_fname); + } + return(rPath); +} + + Glib::ustring relativePathIfInside(const Glib::ustring &procparams_fname, bool fnameAbsolute, Glib::ustring embedded_fname) { if (fnameAbsolute || embedded_fname.empty() || !Glib::path_is_absolute(procparams_fname)) { @@ -105,6 +126,25 @@ Glib::ustring relativePathIfInside(const Glib::ustring &procparams_fname, bool f return prefix + embedded_fname.substr(dir1.length()); } +Glib::ustring relativePathIfInside2(const Glib::ustring &procparams_fname, const Glib::ustring &procparams_fname2, bool fnameAbsolute, Glib::ustring embedded_fname) +{ + // try to convert embedded_fname to a path relative to procparams_fname + // (the directory of the raw file) + // (note: fnameAbsolute seems to be always true, so this will never return a relative path) + Glib::ustring rPath = relativePathIfInside(procparams_fname, fnameAbsolute, embedded_fname); + if ((Glib::path_is_absolute(rPath) + || (rPath.length() >= 5 && rPath.substr(0, 5) == "file:" && Glib::path_is_absolute(rPath.substr(5)))) + && !procparams_fname2.empty() + && Glib::path_is_absolute(procparams_fname2)) { + // if path is not relative to the directory of the raw file, + // try to convert embedded_fname to a path relative to procparams_fname2 + // (the path defined in Preferences) + rPath = relativePathIfInside(procparams_fname2 + G_DIR_SEPARATOR_S, false, embedded_fname); + } + return(rPath); +} + + void getFromKeyfile( const Glib::KeyFile& keyfile, const Glib::ustring& group_name, @@ -6300,14 +6340,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo // Lens profile saveToKeyfile(!pedited || pedited->lensProf.lcMode, "LensProfile", "LcMode", lensProf.getMethodString(lensProf.lcMode), keyFile); - if (options.rtSettings.lensProfilesPath.empty() - || !Glib::path_is_absolute(options.rtSettings.lensProfilesPath)) { - saveToKeyfile(!pedited || pedited->lensProf.lcpFile, "LensProfile", "LCPFile", relativePathIfInside(fname, fnameAbsolute, lensProf.lcpFile), keyFile); - } else { - // if the "lens profiles directory" in Preferences exists and is an absolute path, try to save - // the path to the LCP file as relative to this directory - saveToKeyfile(!pedited || pedited->lensProf.lcpFile, "LensProfile", "LCPFile", replaceBackslash(relativePathIfInside(options.rtSettings.lensProfilesPath + G_DIR_SEPARATOR_S, false, lensProf.lcpFile)), keyFile); - } + saveToKeyfile(!pedited || pedited->lensProf.lcpFile, "LensProfile", "LCPFile", relativePathIfInside2(fname, options.rtSettings.lensProfilesPath, fnameAbsolute, lensProf.lcpFile), keyFile); saveToKeyfile(!pedited || pedited->lensProf.useDist, "LensProfile", "UseDistortion", lensProf.useDist, keyFile); saveToKeyfile(!pedited || pedited->lensProf.useVign, "LensProfile", "UseVignette", lensProf.useVign, keyFile); saveToKeyfile(!pedited || pedited->lensProf.useCA, "LensProfile", "UseCA", lensProf.useCA, keyFile); @@ -7128,14 +7161,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->prsharpening.deconviter, "PostResizeSharpening", "DeconvIterations", prsharpening.deconviter, keyFile); // Color management - if (options.rtSettings.cameraProfilesPath.empty() - || !Glib::path_is_absolute(options.rtSettings.cameraProfilesPath)) { - saveToKeyfile(!pedited || pedited->icm.inputProfile, "Color Management", "InputProfile", relativePathIfInside(fname, fnameAbsolute, icm.inputProfile), keyFile); - } else { - // if the "camera profiles directory" in Preferences exists and is an absolute path, try to save - // the path to the Custom Input Profile as relative to this directory - saveToKeyfile(!pedited || pedited->icm.inputProfile, "Color Management", "InputProfile", replaceBackslash(relativePathIfInside(options.rtSettings.cameraProfilesPath + G_DIR_SEPARATOR_S, false, icm.inputProfile)), keyFile); - } + saveToKeyfile(!pedited || pedited->icm.inputProfile, "Color Management", "InputProfile", relativePathIfInside2(fname, options.rtSettings.cameraProfilesPath, fnameAbsolute, icm.inputProfile), keyFile); saveToKeyfile(!pedited || pedited->icm.toneCurve, "Color Management", "ToneCurve", icm.toneCurve, keyFile); saveToKeyfile(!pedited || pedited->icm.applyLookTable, "Color Management", "ApplyLookTable", icm.applyLookTable, keyFile); saveToKeyfile(!pedited || pedited->icm.applyBaselineExposureOffset, "Color Management", "ApplyBaselineExposureOffset", icm.applyBaselineExposureOffset, keyFile); @@ -7507,9 +7533,9 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->colorToning.labregionsShowMask, "ColorToning", "LabRegionsShowMask", colorToning.labregionsShowMask, keyFile); // Raw - saveToKeyfile(!pedited || pedited->raw.darkFrame, "RAW", "DarkFrame", relativePathIfInside(fname, fnameAbsolute, raw.dark_frame), keyFile); + saveToKeyfile(!pedited || pedited->raw.darkFrame, "RAW", "DarkFrame", relativePathIfInside2(fname, options.rtSettings.darkFramesPath, fnameAbsolute, raw.dark_frame), keyFile); saveToKeyfile(!pedited || pedited->raw.df_autoselect, "RAW", "DarkFrameAuto", raw.df_autoselect, keyFile); - saveToKeyfile(!pedited || pedited->raw.ff_file, "RAW", "FlatFieldFile", relativePathIfInside(fname, fnameAbsolute, raw.ff_file), keyFile); + saveToKeyfile(!pedited || pedited->raw.ff_file, "RAW", "FlatFieldFile", relativePathIfInside2(fname, options.rtSettings.flatFieldsPath, fnameAbsolute, raw.ff_file), keyFile); saveToKeyfile(!pedited || pedited->raw.ff_AutoSelect, "RAW", "FlatFieldAutoSelect", raw.ff_AutoSelect, keyFile); saveToKeyfile(!pedited || pedited->raw.ff_BlurRadius, "RAW", "FlatFieldBlurRadius", raw.ff_BlurRadius, keyFile); saveToKeyfile(!pedited || pedited->raw.ff_BlurType, "RAW", "FlatFieldBlurType", raw.ff_BlurType, keyFile); @@ -8347,14 +8373,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } if (keyFile.has_key("LensProfile", "LCPFile")) { - if (options.rtSettings.lensProfilesPath.empty() - || !Glib::path_is_absolute(options.rtSettings.lensProfilesPath)) { - lensProf.lcpFile = expandRelativePath(fname, "", keyFile.get_string("LensProfile", "LCPFile")); - } else { - // if the "lens profiles directory" in Preferences exists and is an absolute path, - // use it as a prefix if the path to the LCP file is relative - lensProf.lcpFile = expandRelativePath(options.rtSettings.lensProfilesPath + G_DIR_SEPARATOR_S, "", keyFile.get_string("LensProfile", "LCPFile")); - } + lensProf.lcpFile = expandRelativePath2(fname, options.rtSettings.lensProfilesPath, "", keyFile.get_string("LensProfile", "LCPFile")); if (pedited) { pedited->lensProf.lcpFile = true; @@ -9384,20 +9403,12 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("Color Management")) { if (keyFile.has_key("Color Management", "InputProfile")) { - if (options.rtSettings.cameraProfilesPath.empty() - || !Glib::path_is_absolute(options.rtSettings.cameraProfilesPath)) { - icm.inputProfile = expandRelativePath(fname, "file:", keyFile.get_string("Color Management", "InputProfile")); - } else { - // if the "camera profiles directory" in Preferences exists and is an absolute path, - // use it as a prefix if the path to the Custom Input Profile is relative - icm.inputProfile = expandRelativePath(options.rtSettings.cameraProfilesPath + G_DIR_SEPARATOR_S, "file:", keyFile.get_string("Color Management", "InputProfile")); - } + icm.inputProfile = expandRelativePath2(fname, options.rtSettings.cameraProfilesPath, "file:", keyFile.get_string("Color Management", "InputProfile")); if (pedited) { pedited->icm.inputProfile = true; } - } - + } assignFromKeyfile(keyFile, "Color Management", "ToneCurve", pedited, icm.toneCurve, pedited->icm.toneCurve); assignFromKeyfile(keyFile, "Color Management", "ApplyLookTable", pedited, icm.applyLookTable, pedited->icm.applyLookTable); assignFromKeyfile(keyFile, "Color Management", "ApplyBaselineExposureOffset", pedited, icm.applyBaselineExposureOffset, pedited->icm.applyBaselineExposureOffset); @@ -10169,23 +10180,20 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (keyFile.has_group("RAW")) { if (keyFile.has_key("RAW", "DarkFrame")) { - raw.dark_frame = expandRelativePath(fname, "", keyFile.get_string("RAW", "DarkFrame")); + raw.dark_frame = expandRelativePath2(fname, options.rtSettings.darkFramesPath, "", keyFile.get_string("RAW", "DarkFrame")); if (pedited) { pedited->raw.darkFrame = true; } } - assignFromKeyfile(keyFile, "RAW", "DarkFrameAuto", pedited, raw.df_autoselect, pedited->raw.df_autoselect); - if (keyFile.has_key("RAW", "FlatFieldFile")) { - raw.ff_file = expandRelativePath(fname, "", keyFile.get_string("RAW", "FlatFieldFile")); + raw.ff_file = expandRelativePath2(fname, options.rtSettings.flatFieldsPath, "", keyFile.get_string("RAW", "FlatFieldFile")); if (pedited) { pedited->raw.ff_file = true; } } - assignFromKeyfile(keyFile, "RAW", "FlatFieldAutoSelect", pedited, raw.ff_AutoSelect, pedited->raw.ff_AutoSelect); assignFromKeyfile(keyFile, "RAW", "FlatFieldBlurRadius", pedited, raw.ff_BlurRadius, pedited->raw.ff_BlurRadius); assignFromKeyfile(keyFile, "RAW", "FlatFieldBlurType", pedited, raw.ff_BlurType, pedited->raw.ff_BlurType); diff --git a/rtgui/options.cc b/rtgui/options.cc index fd9e87c8d..b4729f9d5 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -659,8 +659,8 @@ void Options::setDefaults() rtSettings.leveldnliss = 0; rtSettings.leveldnautsimpl = 0; -// rtSettings.colortoningab =0.7; -//rtSettings.decaction =0.3; +// rtSettings.colortoningab =0.7; +// rtSettings.decaction =0.3; // rtSettings.ciebadpixgauss=false; rtSettings.rgbcurveslumamode_gamut = true; lastIccDir = rtSettings.iccDirectory; From 136bc371546b878fc6c8133f8f92ad6de8131b89 Mon Sep 17 00:00:00 2001 From: Bezierr Date: Thu, 1 Sep 2022 14:48:29 +0200 Subject: [PATCH 05/14] Change according to review --- rtengine/dynamicprofile.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rtengine/dynamicprofile.cc b/rtengine/dynamicprofile.cc index db1baf4b8..64dc14d3c 100644 --- a/rtengine/dynamicprofile.cc +++ b/rtengine/dynamicprofile.cc @@ -221,16 +221,16 @@ bool DynamicProfileRules::loadRules() rule.profilepath = kf.get_string (group, "profilepath"); #if defined (WIN32) // if this is Windows, replace any "/" in the path with "\\" - int pos = rule.profilepath.find("/"); - while (pos != -1) { + size_t pos = rule.profilepath.find("/"); + while (pos != Glib::ustring::npos) { rule.profilepath.replace(pos, 1, "\\"); pos = rule.profilepath.find("/", pos); } #endif #if !defined (WIN32) // if this is not Windows, replace any "\\" in the path with "/" - int pos = rule.profilepath.find("\\"); - while (pos != -1) { + size_t pos = rule.profilepath.find("\\"); + while (pos != Glib::ustring::npos) { rule.profilepath.replace(pos, 1, "/"); pos = rule.profilepath.find("\\", pos); } From 69c1caafa10f5996a1213c1c851bf727a356b855 Mon Sep 17 00:00:00 2001 From: Desmis Date: Sun, 19 Mar 2023 07:47:58 +0100 Subject: [PATCH 06/14] Whitebalance - Removed GUI Itcwb from whitebalance and preferences (#6710) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Change Preferences for observer whitebalance * Change label white balance preferences * Added Preferences 2 parameters Whitebalance auto correlation * Add Preference Temperature correlation - sort and tooltip * Change to rtengine cmakelist * Apply patch from Lawrence37 * Small comment code * Change defaut order prefrences wba * Added force extra algoritm to Preferences * Harmonize itcwb sorted * Add fields to Preferences Itcwb * Change settings precision Itcwb in Preferences * Change tooltip Itcwb preferences * First stage Itwcwb settings in main with pp3 and selction in preferences * Second stage Itwcwb settings in main with pp3 and selction in preferences * Third stage Itwcwb settings in main with pp3 and selction in preferences * Add itcwb_fgreen student - green optimize * Add Itcwb green range * Itcwb history msg - first tooltips * Remove force-extra because always used * reused force-extra to use entire CIExy for sampling datas * Removed inwanted text in console * Set sensitive for Itcwbframe * Various change - comment .. * Small code review - chnage tooltips * Remove settings itcwb_delta in Rawimagesource.cc to simplify * Remove Itcwb Observer - put a single observer for everything - general - itcwb * Fixed conflicts in colortemp.cc * Various change - fixed bug - simplify * Fixed limits for settings pp3 - chnage tooltip * Clean unused code * Put itcwb_findgreen in GUI * Added checkbox 'Low sampling' to find the settings of 5.9 * Set Observer to Observer 10° - preferences default * Missing setting Low sampling * Show white balance multipliers * Change default settings - Itcwb_sorted * Move observer from preferences to WB * Make observer selectable for camera WB * Ensure observer checkbox is in sync with PP3 * Set default ITCWB low sampling for PP3s from <=5.9 Ensure temperature correlation white balance algorithm 1 is used when opening edits from versions 5.9 and earlier. * Removed unused White-balance frame in Preferences * Comment some GUI sliders checkbox * Removed all GUI itcwb in preferences and whitebalance * Removed forgotten code in preferences * Remove labels tooltips history Itcwb --------- Co-authored-by: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> --- rtdata/languages/default | 6 + rtengine/colortemp.cc | 57 +-- rtengine/colortemp.h | 34 +- rtengine/filmnegativeproc.cc | 4 +- rtengine/histmatching.cc | 4 +- rtengine/imagesource.h | 6 +- rtengine/improccoordinator.cc | 68 ++-- rtengine/improccoordinator.h | 5 +- rtengine/improcfun.cc | 8 +- rtengine/iplocallab.cc | 6 +- rtengine/previewimage.cc | 6 +- rtengine/procparams.cc | 75 +++- rtengine/procparams.h | 23 +- rtengine/rawimagesource.cc | 657 ++++++++++++++++++++++++++++++---- rtengine/rawimagesource.h | 6 +- rtengine/rtengine.h | 6 +- rtengine/rtthumbnail.cc | 36 +- rtengine/rtthumbnail.h | 11 +- rtengine/settings.h | 13 +- rtengine/simpleprocess.cc | 6 +- rtengine/stdimagesource.cc | 6 +- rtengine/stdimagesource.h | 4 +- rtgui/batchtoolpanelcoord.cc | 8 +- rtgui/batchtoolpanelcoord.h | 4 +- rtgui/checkbox.cc | 2 +- rtgui/filmnegative.cc | 13 +- rtgui/options.cc | 68 +--- rtgui/paramsedited.cc | 66 ++++ rtgui/paramsedited.h | 12 + rtgui/ppversion.h | 4 +- rtgui/preferences.cc | 5 + rtgui/preferences.h | 12 +- rtgui/thumbnail.cc | 20 +- rtgui/thumbnail.h | 4 +- rtgui/toolpanelcoord.h | 8 +- rtgui/wbprovider.h | 11 +- rtgui/whitebalance.cc | 90 ++++- rtgui/whitebalance.h | 10 +- 38 files changed, 1073 insertions(+), 311 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 10d0a89c3..9fe9975d9 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1528,6 +1528,7 @@ HISTORY_MSG_WAVSTREND;Strength soft HISTORY_MSG_WAVTHRDEN;Threshold local contrast HISTORY_MSG_WAVTHREND;Threshold local contrast HISTORY_MSG_WAVUSHAMET;Clarity method +HISTORY_MSG_WBALANCE_OBSERVER10;Observer 10° HISTORY_NEWSNAPSHOT;Add HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: Alt-s HISTORY_SNAPSHOT;Snapshot @@ -1831,6 +1832,7 @@ PREFERENCES_CHUNKSIZE_RAW_XT;Xtrans demosaic PREFERENCES_CHUNKSIZE_RGB;RGB processing PREFERENCES_CIE;Ciecam PREFERENCES_CIEARTIF;Avoid artifacts +PREFERENCES_WBA;White Balance PREFERENCES_CLIPPINGIND;Clipping Indication PREFERENCES_CLUTSCACHE;HaldCLUT Cache PREFERENCES_CLUTSCACHE_LABEL;Maximum number of cached CLUTs @@ -4079,6 +4081,10 @@ TP_WBALANCE_LED_CRS;CRS SP12 WWMR16 TP_WBALANCE_LED_HEADER;LED TP_WBALANCE_LED_LSI;LSI Lumelex 2040 TP_WBALANCE_METHOD;Method +TP_WBALANCE_MULLABEL;Multipliers: r=%1 g=%2 b=%3 +TP_WBALANCE_MULLABEL_TOOLTIP;Values given for information purposes. You cannot change them. +TP_WBALANCE_OBSERVER10;Observer 10° instead of Observer 2° +TP_WBALANCE_OBSERVER10_TOOLTIP;The color management in Rawtherapee (White balance, channel multipliers, highlight recovery,...) uses the spectral data of the illuminants and colors. Observer is an important parameter of this management which takes into account the angle of perception of the eye. In 1931 it was fixed at 2° (privileges the use of the cones). In 1964 it was fixed at 10° (privileges the use of the cones, but partially takes into account the rods).\nTo avoid a (rare) drift of the colors due to the choice Observer 10° - probably due to the conversion matrix - Observer 2° must be selected.\nIn a majority of cases Observer 10° (default) will be a more relevant choice. TP_WBALANCE_PICKER;Pick TP_WBALANCE_SHADE;Shade TP_WBALANCE_SIZE;Size: diff --git a/rtengine/colortemp.cc b/rtengine/colortemp.cc index f6e980f2a..756fdf906 100644 --- a/rtengine/colortemp.cc +++ b/rtengine/colortemp.cc @@ -171,7 +171,7 @@ static const color_match_type cie_colour_match_jd = {//350nm to 830nm 5 nm J.D -ColorTemp::ColorTemp (double t, double g, double e, const std::string &m) : temp(t), green(g), equal(e), method(m) +ColorTemp::ColorTemp (double t, double g, double e, const std::string &m, StandardObserver o) : temp(t), green(g), equal(e), method(m), observer(o) { clip (temp, green, equal); } @@ -189,12 +189,24 @@ void ColorTemp::clip (double &temp, double &green, double &equal) equal = rtengine::LIM(equal, MINEQUAL, MAXEQUAL); } -ColorTemp::ColorTemp (double mulr, double mulg, double mulb, double e) : equal(e), method("Custom") +ColorTemp::ColorTemp (double mulr, double mulg, double mulb, double e, StandardObserver observer) : equal(e), method("Custom"), observer(observer) { - mul2temp (mulr, mulg, mulb, equal, temp, green); + mul2temp (mulr, mulg, mulb, equal, observer, temp, green); } -void ColorTemp::mul2temp (const double rmul, const double gmul, const double bmul, const double equal, double& temp, double& green) const +ColorTemp ColorTemp::convertObserver(StandardObserver observer) const +{ + if (observer == this->observer) { + return *this; + } + double r; + double g; + double b; + getMultipliers(r, g, b); + return ColorTemp(r, g, b, equal, observer); +} + +void ColorTemp::mul2temp (const double rmul, const double gmul, const double bmul, const double equal, StandardObserver observer, double& temp, double& green) const { double maxtemp = MAXTEMP, mintemp = MINTEMP; @@ -202,7 +214,7 @@ void ColorTemp::mul2temp (const double rmul, const double gmul, const double bmu temp = (maxtemp + mintemp) / 2; while (maxtemp - mintemp > 1) { - temp2mul (temp, 1.0, equal, tmpr, tmpg, tmpb); + temp2mul (temp, 1.0, equal, observer, tmpr, tmpg, tmpb); if (tmpb / tmpr > bmul / rmul) { maxtemp = temp; @@ -2957,14 +2969,19 @@ void ColorTemp::icieCAT02float(float Xw, float Yw, float Zw, float &iCAM02BB00, } -void ColorTemp::temp2mulxyz (double temp, const std::string &method, double &Xxyz, double &Zxyz) +void ColorTemp::temp2mulxyz (double temp, const std::string &method, StandardObserver observer, double &Xxyz, double &Zxyz) { double x, y, z; // We first test for specially handled methods const auto iterator = spectMap.find(method); - const auto &color_match = (settings->observer10 == true) ? cie_colour_match_jd : cie_colour_match_jd2; - + const auto &color_match = (observer == StandardObserver::TEN_DEGREES) ? cie_colour_match_jd : cie_colour_match_jd2; +/* if(observer == StandardObserver::TEN_DEGREES){ + printf("General Observer 10°\n"); + } else { + printf("General Observer 2°\n"); + } +*/ if (iterator != spectMap.end()) { spectrum_to_xyz_preset(iterator->second, x, y, z, color_match); } else { @@ -2999,11 +3016,11 @@ void ColorTemp::temp2mulxyz (double temp, const std::string &method, double &Xxy Zxyz = (1.0 - x - y) / y; } -void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul, double& gmul, double& bmul) const +void ColorTemp::temp2mul (double temp, double green, double equal, StandardObserver observer, double& rmul, double& gmul, double& bmul) const { clip(temp, green, equal); double Xwb, Zwb; - temp2mulxyz(temp, method, Xwb, Zwb); + temp2mulxyz(temp, method, observer, Xwb, Zwb); double adj = 1.0; @@ -3170,7 +3187,13 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul, float CRI_RT = 0.0, CRI[50]; float CRI_RTs = 0.0, CRIs[8]; - const auto &color_match = (settings->observer10 == true) ? cie_colour_match_jd : cie_colour_match_jd2; + const auto &color_match = (observer == StandardObserver::TEN_DEGREES) ? cie_colour_match_jd : cie_colour_match_jd2; + //exceptional must be used by advice people + if(observer == StandardObserver::TEN_DEGREES){ + printf("CRI Observer 10°\n"); + } else { + printf("CRI Observer 2°\n"); + } for(int i = 0; i < N_c; i++) { spectrum_to_color_xyz_preset(spec_color[i], spect_illum[illum + 3], XchkLamp[i], YchkLamp[i], ZchkLamp[i], color_match); @@ -3764,17 +3787,9 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float Refxyz[i].Zref = 0.f; } -/* if (settings->verbose) { + const color_match_type &color_match = (wbpar.observer == StandardObserver::TEN_DEGREES) ? cie_colour_match_jd : cie_colour_match_jd2; - if (settings->itcwb_stdobserver10 == false) {//I will try to change settings by main - printf("Use standard observer 2°\n"); - } else { - printf("Use standard observer 10°\n"); - } - } -*/ - const color_match_type &color_match = (settings->observer10 == true) ? cie_colour_match_jd : cie_colour_match_jd2; - // const color_match_type &color_match = (settings->itcwb_stdobserver10 == true) ? cie_colour_match_jd : cie_colour_match_jd2; + // const color_match_type &color_match = (wbpar.observer == StandardObserver::TEN_DEGREES) ? cie_colour_match_jd : cie_colour_match_jd2; if (separated) { const double tempw = Txyz[repref].Tem; diff --git a/rtengine/colortemp.h b/rtengine/colortemp.h index 78091f51d..0fe56b7cd 100644 --- a/rtengine/colortemp.h +++ b/rtengine/colortemp.h @@ -36,6 +36,10 @@ constexpr double MINEQUAL = 0.8; constexpr double MAXEQUAL = 1.5; constexpr double INITIALBLACKBODY = 4000.0; +enum class StandardObserver { + TWO_DEGREES, + TEN_DEGREES, +}; class ColorTemp { @@ -45,32 +49,36 @@ private: double green; double equal; std::string method; + StandardObserver observer{StandardObserver::TEN_DEGREES}; static void clip (double &temp, double &green); static void clip (double &temp, double &green, double &equal); int XYZtoCorColorTemp(double x0, double y0 , double z0, double &temp) const; - void temp2mul (double temp, double green, double equal, double& rmul, double& gmul, double& bmul) const; + void temp2mul (double temp, double green, double equal, StandardObserver observer, double& rmul, double& gmul, double& bmul) const; const static std::map spectMap; public: + static constexpr StandardObserver DEFAULT_OBSERVER = StandardObserver::TEN_DEGREES; ColorTemp () : temp(-1.), green(-1.), equal (1.), method("Custom") {} explicit ColorTemp (double e) : temp(-1.), green(-1.), equal (e), method("Custom") {} - ColorTemp (double t, double g, double e, const std::string &m); - ColorTemp (double mulr, double mulg, double mulb, double e); + ColorTemp (double t, double g, double e, const std::string &m, StandardObserver o); + ColorTemp (double mulr, double mulg, double mulb, double e, StandardObserver observer); static void tempxy(bool separated, int repref, float **Tx, float **Ty, float **Tz, float **Ta, float **Tb, float **TL, double *TX, double *TY, double *TZ, const procparams::WBParams & wbpar); - void update (const double rmul, const double gmul, const double bmul, const double equal, const double tempBias=0.0) + void update (const double rmul, const double gmul, const double bmul, const double equal, StandardObserver observer, const double tempBias=0.0) { this->equal = equal; - mul2temp (rmul, gmul, bmul, this->equal, temp, green); + this->observer = observer; + mul2temp (rmul, gmul, bmul, this->equal, observer, temp, green); if (tempBias != 0.0 && tempBias >= -1.0 && tempBias <= 1.0) { temp += temp * tempBias; } } - void useDefaults (const double equal) + void useDefaults (const double equal, StandardObserver observer) { temp = 6504; // Values copied from procparams.cc green = 1.0; this->equal = equal; + this->observer = observer; } inline std::string getMethod() const @@ -89,14 +97,20 @@ public: { return equal; } + inline StandardObserver getObserver() const + { + return observer; + } + + ColorTemp convertObserver(StandardObserver observer) const; void getMultipliers (double &mulr, double &mulg, double &mulb) const { - temp2mul (temp, green, equal, mulr, mulg, mulb); + temp2mul (temp, green, equal, observer, mulr, mulg, mulb); } - void mul2temp (const double rmul, const double gmul, const double bmul, const double equal, double& temp, double& green) const; - static void temp2mulxyz (double tem, const std::string &method, double &Xxyz, double &Zxyz); + void mul2temp (const double rmul, const double gmul, const double bmul, const double equal, StandardObserver observer, double& temp, double& green) const; + static void temp2mulxyz (double tem, const std::string &method, StandardObserver observer, double &Xxyz, double &Zxyz); static void cieCAT02(double Xw, double Yw, double Zw, double &CAM02BB00, double &CAM02BB01, double &CAM02BB02, double &CAM02BB10, double &CAM02BB11, double &CAM02BB12, double &CAM02BB20, double &CAM02BB21, double &CAM02BB22, double adap ); static void cieCAT02float(float Xw, float Yw, float Zw, float &CAM02BB00, float &CAM02BB01, float &CAM02BB02, float &CAM02BB10, float &CAM02BB11, float &CAM02BB12, float &CAM02BB20, float &CAM02BB21, float &CAM02BB22, float adap); @@ -104,7 +118,7 @@ public: bool operator== (const ColorTemp& other) const { - return fabs(temp - other.temp) < 1e-10 && fabs(green - other.green) < 1e-10; + return fabs(temp - other.temp) < 1e-10 && fabs(green - other.green) < 1e-10 && observer != other.observer; } bool operator!= (const ColorTemp& other) const { diff --git a/rtengine/filmnegativeproc.cc b/rtengine/filmnegativeproc.cc index c33dc4a9a..eb029d77a 100644 --- a/rtengine/filmnegativeproc.cc +++ b/rtengine/filmnegativeproc.cc @@ -340,7 +340,7 @@ bool rtengine::ImProcFunctions::filmNegativeProcess( imgsrc->getWBMults(currWB, params->raw, scale_mul, autoGainComp, rm, gm, bm); float rm2, gm2, bm2; - imgsrc->getWBMults(rtengine::ColorTemp(3500., 1., 1., "Custom"), params->raw, scale_mul, autoGainComp, rm2, gm2, bm2); + imgsrc->getWBMults(rtengine::ColorTemp(3500., 1., 1., "Custom", currWB.getObserver()), params->raw, scale_mul, autoGainComp, rm2, gm2, bm2); float mg = rtengine::max(rm2, gm2, bm2); rm2 /= mg; gm2 /= mg; @@ -611,7 +611,7 @@ void rtengine::Thumbnail::processFilmNegativeV2( // as in the main image processing. double r, g, b; - ColorTemp(3500., 1., 1., "Custom").getMultipliers(r, g, b); + ColorTemp(3500., 1., 1., "Custom", params.wb.observer).getMultipliers(r, g, b); //iColorMatrix is cam_rgb const double rm = camwbRed / (iColorMatrix[0][0] * r + iColorMatrix[0][1] * g + iColorMatrix[0][2] * b); const double gm = camwbGreen / (iColorMatrix[1][0] * r + iColorMatrix[1][1] * g + iColorMatrix[1][2] * b); diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index d3c5d0190..350dbbfab 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -229,7 +229,7 @@ void mappingToCurve(const std::vector &mapping, std::vector &curve) } // namespace -void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, std::vector &outCurve) +void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, StandardObserver observer, std::vector &outCurve) { BENCHFUN @@ -313,7 +313,7 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st eSensorType sensor_type; double scale; int w = fw / skip, h = fh / skip; - std::unique_ptr thumb(Thumbnail::loadFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, false, true)); + std::unique_ptr thumb(Thumbnail::loadFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, observer, false, true)); if (!thumb) { if (settings->verbose) { std::cout << "histogram matching: raw decoding failed, generating a neutral curve" << std::endl; diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index d6d22c269..1f4c2179a 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -119,9 +119,9 @@ public: virtual void getAutoWBMultipliers (double &rm, double &gm, double &bm) = 0; virtual void getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double & greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const procparams::WBParams & wbpar, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) = 0; virtual ColorTemp getWB () const = 0; - virtual ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal) = 0; + virtual ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal, StandardObserver observer) = 0; virtual void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) = 0; - virtual void getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) = 0; + virtual void getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, const procparams::WBParams & wbpar) = 0; virtual double getDefGain () const { @@ -167,7 +167,7 @@ public: } // for RAW files, compute a tone curve using histogram matching on the embedded thumbnail - virtual void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, std::vector &outCurve) + virtual void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, StandardObserver observer, std::vector &outCurve) { outCurve = { 0.0 }; } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 9437f1a75..664029a5e 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -489,7 +489,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (todo & (M_INIT | M_LINDENOISE | M_HDR)) { if (params->wb.method == "autitcgreen") { - imgsrc->getrgbloc(0, 0, fh, fw, 0, 0, fh, fw); + imgsrc->getrgbloc(0, 0, fh, fw, 0, 0, fh, fw, params->wb); } } @@ -522,7 +522,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) printf("Applying white balance, color correction & sRBG conversion...\n"); } - currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method); + currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method, params->wb.observer); float studgood = 1000.f; if (!params->wb.enabled) { @@ -531,7 +531,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) currWB = imgsrc->getWB(); lastAwbauto = ""; //reinitialize auto } else if (autowb) { - if (params->wb.method == "autitcgreen" || lastAwbEqual != params->wb.equal || lastAwbTempBias != params->wb.tempBias || lastAwbauto != params->wb.method) { + if (params->wb.method == "autitcgreen" || lastAwbEqual != params->wb.equal || lastAwbObserver != params->wb.observer || lastAwbTempBias != params->wb.tempBias || lastAwbauto != params->wb.method) { double rm, gm, bm; double tempitc = 5000.f; double greenitc = 1.; @@ -547,7 +547,9 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (params->wb.method == "autitcgreen") { params->wb.temperature = tempitc; params->wb.green = greenitc; - currWB = ColorTemp(params->wb.temperature, params->wb.green, 1., params->wb.method); + currWB = ColorTemp(params->wb.temperature, params->wb.green, 1., params->wb.method, params->wb.observer); + //printf("tempitc=%f greitc=%f\n", tempitc, greenitc); + currWB.getMultipliers(rm, gm, bm); } @@ -558,15 +560,17 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) bias = 0.; } - autoWB.update(rm, gm, bm, params->wb.equal, bias); + autoWB.update(rm, gm, bm, params->wb.equal, params->wb.observer, bias); lastAwbEqual = params->wb.equal; + lastAwbObserver = params->wb.observer; lastAwbTempBias = params->wb.tempBias; lastAwbauto = params->wb.method; } else { lastAwbEqual = -1.; + lastAwbObserver = ColorTemp::DEFAULT_OBSERVER; lastAwbTempBias = 0.0; lastAwbauto = ""; - autoWB.useDefaults(params->wb.equal); + autoWB.useDefaults(params->wb.equal, params->wb.observer); } @@ -574,17 +578,24 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) currWB = autoWB; } + double rw = 1.; + double gw = 1.; + double bw = 1.; if (params->wb.enabled) { - params->wb.temperature = currWB.getTemp(); + currWB = currWB.convertObserver(params->wb.observer); + params->wb.temperature = static_cast(currWB.getTemp()); params->wb.green = currWB.getGreen(); + currWB.getMultipliers(rw, gw, bw); + imgsrc->wbMul2Camera(rw, gw, bw); + // printf("ra=%f ga=%f ba=%f\n", rw, gw, bw); } - if (autowb && awbListener) { + if (awbListener) { if (params->wb.method == "autitcgreen") { - awbListener->WBChanged(params->wb.temperature, params->wb.green, studgood); - } else if (params->wb.method == "autold") { - awbListener->WBChanged(params->wb.temperature, params->wb.green, -1.f); + awbListener->WBChanged(params->wb.temperature, params->wb.green, rw, gw, bw, studgood); + } else { + awbListener->WBChanged(params->wb.temperature, params->wb.green, rw, gw, bw, -1.f); } } @@ -621,7 +632,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) PreviewProps pp(0, 0, fw, fh, scale); // Tells to the ImProcFunctions' tools what is the preview scale, which may lead to some simplifications ipf.setScale(scale); - int inpaintopposed = 1;//force getimage to use inpaint-opposed if enable, only once + int inpaintopposed = 1;//force getimage to use inpaint-opposed if enable, only once imgsrc->getImage(currWB, tr, orig_prev, pp, params->toneCurve, params->raw, inpaintopposed); if ((todo & M_SPOT) && params->spot.enabled && !params->spot.entries.empty()) { @@ -782,7 +793,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (params->toneCurve.histmatching) { if (!params->toneCurve.fromHistMatching) { - imgsrc->getAutoMatchedToneCurve(params->icm, params->toneCurve.curve); + imgsrc->getAutoMatchedToneCurve(params->icm, params->wb.observer, params->toneCurve.curve); } if (params->toneCurve.autoexp) { @@ -2452,11 +2463,11 @@ bool ImProcCoordinator::updateWaveforms() return true; } -bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, double tempBias) +bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, StandardObserver observer, double tempBias) { if (imgsrc) { - if (lastAwbEqual != equal || lastAwbTempBias != tempBias || lastAwbauto != params->wb.method) { + if (lastAwbEqual != equal || lastAwbObserver != observer || lastAwbTempBias != tempBias || lastAwbauto != params->wb.method) { // Issue 2500 MyMutex::MyLock lock(minit); // Also used in crop window double rm, gm, bm; params->wb.method = "autold";//same result as before multiple Auto WB @@ -2469,13 +2480,15 @@ bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, dou imgsrc->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc, studgood, 0, 0, fh, fw, 0, 0, fh, fw, rm, gm, bm, params->wb, params->icm, params->raw, params->toneCurve); if (rm != -1) { - autoWB.update(rm, gm, bm, equal, tempBias); + autoWB.update(rm, gm, bm, equal, observer, tempBias); lastAwbEqual = equal; + lastAwbObserver = observer; lastAwbTempBias = tempBias; lastAwbauto = params->wb.method; } else { lastAwbEqual = -1.; - autoWB.useDefaults(equal); + lastAwbObserver = ColorTemp::DEFAULT_OBSERVER; + autoWB.useDefaults(equal, observer); lastAwbauto = ""; lastAwbTempBias = 0.0; } @@ -2492,12 +2505,13 @@ bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, dou } } -void ImProcCoordinator::getCamWB(double& temp, double& green) +void ImProcCoordinator::getCamWB(double& temp, double& green, StandardObserver observer) { if (imgsrc) { - temp = imgsrc->getWB().getTemp(); - green = imgsrc->getWB().getGreen(); + const ColorTemp color_temp = imgsrc->getWB().convertObserver(observer); + temp = color_temp.getTemp(); + green = color_temp.getGreen(); } } @@ -2519,8 +2533,8 @@ void ImProcCoordinator::getSpotWB(int x, int y, int rect, double& temp, double& int tr = getCoarseBitMask(params->coarse); - ret = imgsrc->getSpotWB(red, green, blue, tr, params->wb.equal); - currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method); + ret = imgsrc->getSpotWB(red, green, blue, tr, params->wb.equal, params->wb.observer); + currWB = ColorTemp(params->wb.temperature, params->wb.green, params->wb.equal, params->wb.method, params->wb.observer); //double rr,gg,bb; //currWB.getMultipliers(rr,gg,bb); @@ -2626,23 +2640,25 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a imgsrc->preprocess(ppar.raw, ppar.lensProf, ppar.coarse); double dummy = 0.0; imgsrc->demosaic(ppar.raw, false, dummy); - ColorTemp currWB = ColorTemp(validParams->wb.temperature, validParams->wb.green, validParams->wb.equal, validParams->wb.method); + ColorTemp currWB = ColorTemp(validParams->wb.temperature, validParams->wb.green, validParams->wb.equal, validParams->wb.method, validParams->wb.observer); if (validParams->wb.method == "Camera") { currWB = imgsrc->getWB(); } else if (validParams->wb.method == "autold") { - if (lastAwbEqual != validParams->wb.equal || lastAwbTempBias != validParams->wb.tempBias) { + if (lastAwbEqual != validParams->wb.equal || lastAwbObserver != validParams->wb.observer || lastAwbTempBias != validParams->wb.tempBias) { double rm, gm, bm; imgsrc->getAutoWBMultipliers(rm, gm, bm); if (rm != -1.) { - autoWB.update(rm, gm, bm, validParams->wb.equal, validParams->wb.tempBias); + autoWB.update(rm, gm, bm, validParams->wb.equal, validParams->wb.observer, validParams->wb.tempBias); lastAwbEqual = validParams->wb.equal; + lastAwbObserver = validParams->wb.observer; lastAwbTempBias = validParams->wb.tempBias; } else { lastAwbEqual = -1.; + lastAwbObserver = ColorTemp::DEFAULT_OBSERVER; lastAwbTempBias = 0.0; - autoWB.useDefaults(validParams->wb.equal); + autoWB.useDefaults(validParams->wb.equal, validParams->wb.observer); } } diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index 85f28004a..92cdd91c7 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -80,6 +80,7 @@ protected: ColorTemp currWBitc; double lastAwbEqual; + StandardObserver lastAwbObserver{ColorTemp::DEFAULT_OBSERVER}; double lastAwbTempBias; Glib::ustring lastAwbauto; @@ -433,8 +434,8 @@ public: void setTweakOperator (TweakOperator *tOperator) override; void unsetTweakOperator (TweakOperator *tOperator) override; - bool getAutoWB (double& temp, double& green, double equal, double tempBias) override; - void getCamWB (double& temp, double& green) override; + bool getAutoWB (double& temp, double& green, double equal, StandardObserver observer, double tempBias) override; + void getCamWB (double& temp, double& green, StandardObserver observer) override; void getSpotWB (int x, int y, int rectSize, double& temp, double& green) override; bool getFilmNegativeSpot(int x, int y, int spotSize, FilmNegativeParams::RGB &refInput, FilmNegativeParams::RGB &refOutput) override; void getAutoCrop (double ratio, int &x, int &y, int &w, int &h) override; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 0e08a28eb..c3e11c076 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -552,9 +552,9 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb || (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab) || (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab)); - ColorTemp::temp2mulxyz(params->wb.temperature, params->wb.method, Xw, Zw); //compute white Xw Yw Zw : white current WB - ColorTemp::temp2mulxyz(params->colorappearance.tempout, "Custom", Xwout, Zwout); - ColorTemp::temp2mulxyz(params->colorappearance.tempsc, "Custom", Xwsc, Zwsc); + ColorTemp::temp2mulxyz(params->wb.temperature, params->wb.method, params->wb.observer, Xw, Zw); //compute white Xw Yw Zw : white current WB + ColorTemp::temp2mulxyz(params->colorappearance.tempout, "Custom", params->wb.observer, Xwout, Zwout); + ColorTemp::temp2mulxyz(params->colorappearance.tempsc, "Custom", params->wb.observer, Xwsc, Zwsc); //viewing condition for surrsrc if (params->colorappearance.surrsrc == "Average") { @@ -5589,7 +5589,7 @@ double ImProcFunctions::getAutoDistor(const Glib::ustring &fname, int thumb_size return 0.0; } - Thumbnail* raw = rtengine::Thumbnail::loadFromRaw(fname, ri, sensorType, w_raw, h_raw, 1, 1.0, FALSE); + Thumbnail* raw = rtengine::Thumbnail::loadFromRaw(fname, ri, sensorType, w_raw, h_raw, 1, 1.0, ColorTemp::DEFAULT_OBSERVER, FALSE); if (!raw) { delete thumb; diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 243f3595d..b9e82cc5d 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -2804,9 +2804,9 @@ void ImProcFunctions::ciecamloc_02float(const struct local_params& lp, int sp, L } } - ColorTemp::temp2mulxyz(params->wb.temperature, params->wb.method, Xw, Zw); //compute white Xw Yw Zw : white current WB - ColorTemp::temp2mulxyz(tempo, "Custom", Xwout, Zwout); - ColorTemp::temp2mulxyz(5000, "Custom", Xwsc, Zwsc); + ColorTemp::temp2mulxyz(params->wb.temperature, params->wb.method, params->wb.observer, Xw, Zw); //compute white Xw Yw Zw : white current WB + ColorTemp::temp2mulxyz(tempo, "Custom", params->wb.observer, Xwout, Zwout); + ColorTemp::temp2mulxyz(5000, "Custom", params->wb.observer, Xwsc, Zwsc); //viewing condition for surrsrc f = 1.00f; diff --git a/rtengine/previewimage.cc b/rtengine/previewimage.cc index 1afe72c92..afaf0cbca 100644 --- a/rtengine/previewimage.cc +++ b/rtengine/previewimage.cc @@ -42,20 +42,20 @@ PreviewImage::PreviewImage (const Glib::ustring &fname, const Glib::ustring &ext if (ext.lowercase() == "jpg" || ext.lowercase() == "jpeg") { // int deg = infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., true); + tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., ColorTemp::DEFAULT_OBSERVER, true); if (tpp) { data = tpp->getImage8Data(); } } else if (ext.lowercase() == "png") { - tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., true); + tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., ColorTemp::DEFAULT_OBSERVER, true); if (tpp) { data = tpp->getImage8Data(); } } else if (ext.lowercase() == "tif" || ext.lowercase() == "tiff") { // int deg = infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., true); + tpp = rtengine::Thumbnail::loadFromImage (fname, width, height, 1, 1., ColorTemp::DEFAULT_OBSERVER, true); if (tpp) { data = tpp->getImage8Data(); diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 9323bd9e7..c47723662 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -27,6 +27,7 @@ #include #include "color.h" +#include "colortemp.h" #include "curves.h" #include "procparams.h" #include "utils.h" @@ -1331,7 +1332,19 @@ WBParams::WBParams() : temperature(6504), green(1.0), equal(1.0), - tempBias(0.0) + tempBias(0.0), + observer(ColorTemp::DEFAULT_OBSERVER), + itcwb_thres(34), + itcwb_precis(3), + itcwb_size(3), + itcwb_delta(2), + itcwb_fgreen(5), + itcwb_rgreen(1), + itcwb_nopurple(true), + itcwb_sorted(false), + itcwb_forceextra(false), + itcwb_sampling(false) + { } @@ -1351,6 +1364,7 @@ bool WBParams::isPanningRelatedChange(const WBParams& other) const && green == other.green && equal == other.equal && tempBias == other.tempBias + && observer == other.observer ) ) ); @@ -1364,7 +1378,19 @@ bool WBParams::operator ==(const WBParams& other) const && temperature == other.temperature && green == other.green && equal == other.equal - && tempBias == other.tempBias; + && tempBias == other.tempBias + && observer == other.observer + && itcwb_thres == other.itcwb_thres + && itcwb_precis == other.itcwb_precis + && itcwb_size == other.itcwb_size + && itcwb_delta == other.itcwb_delta + && itcwb_fgreen == other.itcwb_fgreen + && itcwb_rgreen == other.itcwb_rgreen + && itcwb_nopurple == other.itcwb_nopurple + && itcwb_sorted == other.itcwb_sorted + && itcwb_forceextra == other.itcwb_forceextra + && itcwb_sampling == other.itcwb_sampling; + } bool WBParams::operator !=(const WBParams& other) const @@ -6108,6 +6134,17 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->wb.green, "White Balance", "Green", wb.green, keyFile); saveToKeyfile(!pedited || pedited->wb.equal, "White Balance", "Equal", wb.equal, keyFile); saveToKeyfile(!pedited || pedited->wb.tempBias, "White Balance", "TemperatureBias", wb.tempBias, keyFile); + saveToKeyfile(!pedited || pedited->wb.observer, "White Balance", "StandardObserver", Glib::ustring(wb.observer == StandardObserver::TWO_DEGREES ? "TWO_DEGREES" : "TEN_DEGREES"), keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_thres, "White Balance", "Itcwb_thres", wb.itcwb_thres, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_precis, "White Balance", "Itcwb_precis", wb.itcwb_precis, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_size, "White Balance", "Itcwb_size", wb.itcwb_size, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_delta, "White Balance", "Itcwb_delta", wb.itcwb_delta, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_fgreen, "White Balance", "Itcwb_findgreen", wb.itcwb_fgreen, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_rgreen, "White Balance", "Itcwb_rangegreen", wb.itcwb_rgreen, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_nopurple, "White Balance", "Itcwb_nopurple", wb.itcwb_nopurple, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_sorted, "White Balance", "Itcwb_sorted", wb.itcwb_sorted, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_forceextra, "White Balance", "Itcwb_forceextra", wb.itcwb_forceextra, keyFile); + saveToKeyfile(!pedited || pedited->wb.itcwb_sampling, "White Balance", "Itcwb_sampling", wb.itcwb_sampling, keyFile); // Colorappearance saveToKeyfile(!pedited || pedited->colorappearance.enabled, "Color appearance", "Enabled", colorappearance.enabled, keyFile); @@ -8039,6 +8076,17 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Vibrance", "PastSatTog", pedited, vibrance.pastsattog, pedited->vibrance.pastsattog); assignFromKeyfile(keyFile, "Vibrance", "SkinTonesCurve", pedited, vibrance.skintonescurve, pedited->vibrance.skintonescurve); } + if (ppVersion <= 346) { // 5.8 and earlier. + wb.observer = StandardObserver::TWO_DEGREES; + if (pedited) { + pedited->wb.observer = true; + } + } else if (ppVersion <= 349) { // 5.9 + wb.observer = StandardObserver::TEN_DEGREES; + if (pedited) { + pedited->wb.observer = true; + } + } if (keyFile.has_group("White Balance")) { assignFromKeyfile(keyFile, "White Balance", "Enabled", pedited, wb.enabled, pedited->wb.enabled); assignFromKeyfile(keyFile, "White Balance", "Setting", pedited, wb.method, pedited->wb.method); @@ -8049,6 +8097,29 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "White Balance", "Green", pedited, wb.green, pedited->wb.green); assignFromKeyfile(keyFile, "White Balance", "Equal", pedited, wb.equal, pedited->wb.equal); assignFromKeyfile(keyFile, "White Balance", "TemperatureBias", pedited, wb.tempBias, pedited->wb.tempBias); + Glib::ustring standard_observer; + assignFromKeyfile(keyFile, "White Balance", "StandardObserver", pedited, standard_observer, pedited->wb.observer); + if (standard_observer == "TEN_DEGREES") { + wb.observer = StandardObserver::TEN_DEGREES; + } else if (standard_observer == "TWO_DEGREES") { + wb.observer = StandardObserver::TWO_DEGREES; + } + assignFromKeyfile(keyFile, "White Balance", "Itcwb_thres", pedited, wb.itcwb_thres, pedited->wb.itcwb_thres); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_precis", pedited, wb.itcwb_precis, pedited->wb.itcwb_precis); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_size", pedited, wb.itcwb_size, pedited->wb.itcwb_size); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_delta", pedited, wb.itcwb_delta, pedited->wb.itcwb_delta); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_findgreen", pedited, wb.itcwb_fgreen, pedited->wb.itcwb_fgreen); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_rangegreen", pedited, wb.itcwb_rgreen, pedited->wb.itcwb_rgreen); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_nopurple", pedited, wb.itcwb_nopurple, pedited->wb.itcwb_nopurple); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_sorted", pedited, wb.itcwb_sorted, pedited->wb.itcwb_sorted); + assignFromKeyfile(keyFile, "White Balance", "Itcwb_forceextra", pedited, wb.itcwb_forceextra, pedited->wb.itcwb_forceextra); + if (ppVersion <= 349) { // 5.9 and earlier. + wb.itcwb_sampling = true; + if (pedited) { + pedited->wb.itcwb_sampling = true; + } + } + assignFromKeyfile(keyFile, "White Balance", "Itcwb_sampling", pedited, wb.itcwb_sampling, pedited->wb.itcwb_sampling); } if (keyFile.has_group("Defringing")) { diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 33d95a619..48b68f598 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -59,6 +59,8 @@ class LocLLmaskexpCurve; class LocCCmaskexpCurve; class LocHHmaskexpCurve; +enum class StandardObserver; + enum RenderingIntent : int { RI_PERCEPTUAL = INTENT_PERCEPTUAL, RI_RELATIVE = INTENT_RELATIVE_COLORIMETRIC, @@ -634,11 +636,22 @@ struct WBEntry { struct WBParams { bool enabled; - Glib::ustring method; - int temperature; - double green; - double equal; - double tempBias; + Glib::ustring method; + int temperature; + double green; + double equal; + double tempBias; + StandardObserver observer; + int itcwb_thres; + int itcwb_precis; + int itcwb_size; + int itcwb_delta; + int itcwb_fgreen; + int itcwb_rgreen; + bool itcwb_nopurple; + bool itcwb_sorted; + bool itcwb_forceextra; + bool itcwb_sampling; WBParams(); diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 75757d325..06aa701e8 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -843,28 +843,27 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima int maxx = this->W, maxy = this->H, skip = pp.getSkip(); - bool iscolor = (hrp.method == "Color" || hrp.method == "Coloropp"); - const bool doClip = (chmax[0] >= clmax[0] || chmax[1] >= clmax[1] || chmax[2] >= clmax[2]) && !hrp.hrenabled && hrp.clampOOG; + bool iscolor = (hrp.method == "Color" || hrp.method == "Coloropp"); + const bool doClip = (chmax[0] >= clmax[0] || chmax[1] >= clmax[1] || chmax[2] >= clmax[2]) && !hrp.hrenabled && hrp.clampOOG; bool doHr = (hrp.hrenabled && !iscolor); - if (hrp.hrenabled && iscolor) { - - if(hrp.method == "Coloropp" && opposed == 1) {//force Inpaint opposed if WB change, and opposed limited tne number to 1 - rgbSourceModified = false; - } + if (hrp.hrenabled && iscolor) { + if(hrp.method == "Coloropp" && opposed == 1) {//force Inpaint opposed if WB change, and opposed limited tne number to 1 + rgbSourceModified = false; + } if (!rgbSourceModified) { - if(hrp.method == "Color") { - if (settings->verbose) { - printf ("Applying Highlight Recovery: Color propagation.\n"); - } - HLRecovery_inpaint (red, green, blue, hrp.hlbl); - } else if(hrp.method == "Coloropp" && ctemp.getTemp() >= 0) { - float s[3] = { rm, gm, bm }; - highlight_recovery_opposed(s, ctemp, hrp.hlth); - } + if(hrp.method == "Color") { + if (settings->verbose) { + printf ("Applying Highlight Recovery: Color propagation.\n"); + } + HLRecovery_inpaint (red, green, blue, hrp.hlbl); + } else if(hrp.method == "Coloropp" && ctemp.getTemp() >= 0) { + float s[3] = { rm, gm, bm }; + highlight_recovery_opposed(s, ctemp, hrp.hlth); + } rgbSourceModified = true; } } - + // now apply the wb coefficients if (ctemp.getTemp() >= 0) { double r, g, b; @@ -1297,7 +1296,7 @@ int RawImageSource::load (const Glib::ustring &fname, bool firstFrameOnly) double cam_r = imatrices.rgb_cam[0][0] * camwb_red + imatrices.rgb_cam[0][1] * camwb_green + imatrices.rgb_cam[0][2] * camwb_blue; double cam_g = imatrices.rgb_cam[1][0] * camwb_red + imatrices.rgb_cam[1][1] * camwb_green + imatrices.rgb_cam[1][2] * camwb_blue; double cam_b = imatrices.rgb_cam[2][0] * camwb_red + imatrices.rgb_cam[2][1] * camwb_green + imatrices.rgb_cam[2][2] * camwb_blue; - camera_wb = ColorTemp (cam_r, cam_g, cam_b, 1.); // as shot WB + camera_wb = ColorTemp (cam_r, cam_g, cam_b, 1., ColorTemp::DEFAULT_OBSERVER); // as shot WB if (settings->verbose) { printf("Raw As Shot White balance: temp %f, tint %f\n", camera_wb.getTemp(), camera_wb.getGreen()); @@ -1384,7 +1383,7 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le const double ref_r = imatrices.rgb_cam[0][0] * refwb_red + imatrices.rgb_cam[0][1] * refwb_green + imatrices.rgb_cam[0][2] * refwb_blue; const double ref_g = imatrices.rgb_cam[1][0] * refwb_red + imatrices.rgb_cam[1][1] * refwb_green + imatrices.rgb_cam[1][2] * refwb_blue; const double ref_b = imatrices.rgb_cam[2][0] * refwb_red + imatrices.rgb_cam[2][1] * refwb_green + imatrices.rgb_cam[2][2] * refwb_blue; - const ColorTemp ReferenceWB = ColorTemp (ref_r, ref_g, ref_b, 1.); + const ColorTemp ReferenceWB = ColorTemp (ref_r, ref_g, ref_b, 1., ColorTemp::DEFAULT_OBSERVER); if (settings->verbose) { printf("Raw Reference white balance: temp %f, tint %f, multipliers [%f %f %f | %f %f %f]\n", ReferenceWB.getTemp(), ReferenceWB.getGreen(), ref_r, ref_g, ref_b, refwb_red, refwb_blue, refwb_green); @@ -4037,6 +4036,475 @@ void RawImageSource::getRowStartEnd (int x, int &start, int &end) } } + +static void histoxyY_low(int bfhitc, int bfwitc, const array2D & xc, const array2D & yc, const array2D & Yc, LUTf &xxx, LUTf &yyy, LUTf &YYY, LUTu &histxy) +{ + //calculate histogram x y in a range of 190 colors + //this "choice" are guided by generally colors who are in nature skin, sky, etc. in those cases "steps" are small + // of course we can change to be more precise +#ifdef _OPENMP + #pragma omp parallel +#endif + { + LUTu histxythr(histxy.getSize()); + histxythr.clear(); + LUTf xxxthr(xxx.getSize()); + xxxthr.clear(); + LUTf yyythr(yyy.getSize()); + yyythr.clear(); + LUTf YYYthr(YYY.getSize()); + YYYthr.clear(); +#ifdef _OPENMP + #pragma omp for schedule(dynamic, 4) nowait +#endif + for (int y = 0; y < bfhitc ; y++) { + for (int x = 0; x < bfwitc ; x++) { + int nh = -1; + if (xc[y][x] < 0.12f && xc[y][x] > 0.03f && yc[y][x] > 0.1f) { // near Prophoto + if (yc[y][x] < 0.2f) { + nh = 0; + //blue hard + } else if (yc[y][x] < 0.3f) { + nh = 1; + //blue + } else if (yc[y][x] < 0.4f) { + nh = 2; + + } else if (yc[y][x] < 0.5f) { + //blue green + nh = 3; + } else if (yc[y][x] < 0.6f) { + nh = 4; + } else if (yc[y][x] < 0.82f) { + //green + nh = 5; + } + } else if (xc[y][x] < 0.24f && yc[y][x] > 0.05f) { + if (yc[y][x] < 0.2f) { + nh = 6; + } else if (yc[y][x] < 0.3f) { + nh = 7; + } else if (yc[y][x] < 0.4f) { + nh = 8; + } else if (yc[y][x] < 0.5f) { + nh = 9; + } else if (yc[y][x] < 0.6f) { + nh = 10; + } else if (yc[y][x] < 0.75f) { + nh = 11; + } + } else if (xc[y][x] < 0.28f && yc[y][x] > 0.1f) {//blue sky and other + if (yc[y][x] < 0.2f) { + nh = 12; + } else if (yc[y][x] < 0.25f) { + nh = 13; + } else if (yc[y][x] < 0.29f) { + nh = 14; + } else if (yc[y][x] < 0.33f) { + nh = 15; + } else if (yc[y][x] < 0.37f) { + nh = 16; + } else if (yc[y][x] < 0.4f) { + nh = 17; + } else if (yc[y][x] < 0.45f) { + nh = 18; + } else if (yc[y][x] < 0.5f) { + nh = 19; + } else if (yc[y][x] < 0.6f) { + nh = 20; + } else if (yc[y][x] < 0.75f) { + nh = 21; + } + } else if (xc[y][x] < 0.31f && yc[y][x] > 0.1f) {//near neutral others + if (yc[y][x] < 0.2f) { + nh = 22; + } else if (yc[y][x] < 0.24f) { + nh = 23; + } else if (yc[y][x] < 0.29f) { + nh = 24; + } else if (yc[y][x] < 0.32f) { + nh = 25; + } else if (yc[y][x] < 0.36f) { + nh = 26; + } else if (yc[y][x] < 0.4f) { + nh = 27; + } else if (yc[y][x] < 0.5f) { + nh = 28; + } else if (yc[y][x] < 0.7f) { + nh = 29; + } + } else if (xc[y][x] < 0.325f && yc[y][x] > 0.1f) {//neutral 34 + if (yc[y][x] < 0.2f) { + nh = 30; + } else if (yc[y][x] < 0.24f) { + nh = 31; + } else if (yc[y][x] < 0.29f) { + nh = 32; + } else if (yc[y][x] < 0.32f) { + nh = 33; + } else if (yc[y][x] < 0.33f) { + nh = 34; + } else if (yc[y][x] < 0.335f) { + nh = 35; + } else if (yc[y][x] < 0.34f) { + nh = 36; + } else if (yc[y][x] < 0.35f) { + nh = 37; + } else if (yc[y][x] < 0.37f) { + nh = 38; + } else if (yc[y][x] < 0.4f) { + nh = 39; + } else if (yc[y][x] < 0.45f) { + nh = 40; + } else if (yc[y][x] < 0.5f) { + nh = 41; + } else if (yc[y][x] < 0.55f) { + nh = 42; + } else if (yc[y][x] < 0.7f) { + nh = 43; + } + } else if (xc[y][x] < 0.335f && yc[y][x] > 0.1f) {//neutral + if (yc[y][x] < 0.2f) { + nh = 44; + } else if (yc[y][x] < 0.24f) { + nh = 45; + } else if (yc[y][x] < 0.29f) { + nh = 46; + } else if (yc[y][x] < 0.32f) { + nh = 47; + } else if (yc[y][x] < 0.33f) { + nh = 48; + } else if (yc[y][x] < 0.335f) { + nh = 49; + } else if (yc[y][x] < 0.34f) { + nh = 50; + } else if (yc[y][x] < 0.345f) { + nh = 51; + } else if (yc[y][x] < 0.35f) { + nh = 52; + } else if (yc[y][x] < 0.355f) { + nh = 53; + } else if (yc[y][x] < 0.36f) { + nh = 54; + } else if (yc[y][x] < 0.37f) { + nh = 55; + } else if (yc[y][x] < 0.38f) { + nh = 56; + } else if (yc[y][x] < 0.4f) { + nh = 57; + } else if (yc[y][x] < 0.45f) { + nh = 58; + } else if (yc[y][x] < 0.5f) { + nh = 59; + } else if (yc[y][x] < 0.55f) { + nh = 60; + } else if (yc[y][x] < 0.7f) { + nh = 61; + } + } else if (xc[y][x] < 0.340f && yc[y][x] > 0.1f) {//neutral + if (yc[y][x] < 0.2f) { + nh = 62; + } else if (yc[y][x] < 0.24f) { + nh = 63; + } else if (yc[y][x] < 0.29f) { + nh = 64; + } else if (yc[y][x] < 0.32f) { + nh = 65; + } else if (yc[y][x] < 0.325f) { + nh = 66; + } else if (yc[y][x] < 0.33f) { + nh = 67; + } else if (yc[y][x] < 0.335f) { + nh = 68; + } else if (yc[y][x] < 0.34f) { + nh = 69; + } else if (yc[y][x] < 0.345f) { + nh = 70; + } else if (yc[y][x] < 0.35f) { + nh = 71; + } else if (yc[y][x] < 0.355f) { + nh = 72; + } else if (yc[y][x] < 0.36f) { + nh = 73; + } else if (yc[y][x] < 0.37f) { + nh = 74; + } else if (yc[y][x] < 0.38f) { + nh = 75; + } else if (yc[y][x] < 0.4f) { + nh = 76; + } else if (yc[y][x] < 0.45f) { + nh = 77; + } else if (yc[y][x] < 0.5f) { + nh = 78; + } else if (yc[y][x] < 0.55f) { + nh = 79; + } else if (yc[y][x] < 0.7f) { + nh = 80; + } + } else if (xc[y][x] < 0.345f && yc[y][x] > 0.1f) {//neutral 37 + if (yc[y][x] < 0.2f) { + nh = 81; + } else if (yc[y][x] < 0.24f) { + nh = 82; + } else if (yc[y][x] < 0.29f) { + nh = 83; + } else if (yc[y][x] < 0.32f) { + nh = 84; + } else if (yc[y][x] < 0.33f) { + nh = 85; + } else if (yc[y][x] < 0.335f) { + nh = 86; + } else if (yc[y][x] < 0.34f) { + nh = 87; + } else if (yc[y][x] < 0.345f) { + nh = 88; + } else if (yc[y][x] < 0.35f) { + nh = 89; + } else if (yc[y][x] < 0.355f) { + nh = 90; + } else if (yc[y][x] < 0.36f) { + nh = 91; + } else if (yc[y][x] < 0.37f) { + nh = 92; + } else if (yc[y][x] < 0.38f) { + nh = 93; + } else if (yc[y][x] < 0.39f) { + nh = 94; + } else if (yc[y][x] < 0.4f) { + nh = 95; + } else if (yc[y][x] < 0.42f) { + nh = 96; + } else if (yc[y][x] < 0.45f) { + nh = 97; + } else if (yc[y][x] < 0.48f) { + nh = 98; + } else if (yc[y][x] < 0.5f) { + nh = 99; + } else if (yc[y][x] < 0.55f) { + nh = 100; + } else if (yc[y][x] < 0.65f) { + nh = 101; + } + } else if (xc[y][x] < 0.355f && yc[y][x] > 0.1f) {//neutral 37 + if (yc[y][x] < 0.2f) { + nh = 102; + } else if (yc[y][x] < 0.24f) { + nh = 103; + } else if (yc[y][x] < 0.29f) { + nh = 104; + } else if (yc[y][x] < 0.32f) { + nh = 105; + } else if (yc[y][x] < 0.33f) { + nh = 106; + } else if (yc[y][x] < 0.335f) { + nh = 107; + } else if (yc[y][x] < 0.34f) { + nh = 108; + } else if (yc[y][x] < 0.345f) { + nh = 109; + } else if (yc[y][x] < 0.35f) { + nh = 110; + } else if (yc[y][x] < 0.355f) { + nh = 111; + } else if (yc[y][x] < 0.36f) { + nh = 112; + } else if (yc[y][x] < 0.37f) { + nh = 113; + } else if (yc[y][x] < 0.38f) { + nh = 114; + } else if (yc[y][x] < 0.39f) { + nh = 115; + } else if (yc[y][x] < 0.4f) { + nh = 116; + } else if (yc[y][x] < 0.42f) { + nh = 117; + } else if (yc[y][x] < 0.45f) { + nh = 118; + } else if (yc[y][x] < 0.48f) { + nh = 119; + } else if (yc[y][x] < 0.5f) { + nh = 120; + } else if (yc[y][x] < 0.55f) { + nh = 121; + } else if (yc[y][x] < 0.65f) { + nh = 122; + } + } else if (xc[y][x] < 0.365f && yc[y][x] > 0.15f) { //0.4 + if (yc[y][x] < 0.2f) { + nh = 123; + } else if (yc[y][x] < 0.24f) { + nh = 124; + } else if (yc[y][x] < 0.29f) { + nh = 125; + } else if (yc[y][x] < 0.32f) { + nh = 126; + } else if (yc[y][x] < 0.33f) { + nh = 127; + } else if (yc[y][x] < 0.34f) { + nh = 128; + } else if (yc[y][x] < 0.35f) { + nh = 129; + } else if (yc[y][x] < 0.36f) { + nh = 130; + } else if (yc[y][x] < 0.37f) { + nh = 131; + } else if (yc[y][x] < 0.38f) { + nh = 132; + } else if (yc[y][x] < 0.39f) { + nh = 133; + } else if (yc[y][x] < 0.4f) { + nh = 134; + } else if (yc[y][x] < 0.42f) { + nh = 135; + } else if (yc[y][x] < 0.45f) { + nh = 136; + } else if (yc[y][x] < 0.5f) { + nh = 137; + } else if (yc[y][x] < 0.55f) { + nh = 138; + } else if (yc[y][x] < 0.63f) { + nh = 139; + } + } else if (xc[y][x] < 0.405f && yc[y][x] > 0.15f) {//45 + if (yc[y][x] < 0.2f) { + nh = 140; + } else if (yc[y][x] < 0.24f) { + nh = 141; + } else if (yc[y][x] < 0.29f) { + nh = 142; + } else if (yc[y][x] < 0.32f) { + nh = 143; + } else if (yc[y][x] < 0.34f) { + nh = 144; + } else if (yc[y][x] < 0.37f) { + nh = 145; + } else if (yc[y][x] < 0.4f) { + nh = 146; + } else if (yc[y][x] < 0.45f) { + nh = 147; + } else if (yc[y][x] < 0.5f) { + nh = 148; + } else if (yc[y][x] < 0.55f) { + nh = 149; + } else if (yc[y][x] < 0.6f) { + nh = 150; + } + } else if (xc[y][x] < 0.445f && yc[y][x] > 0.15f) {//45 + if (yc[y][x] < 0.2f) { + nh = 151; + } else if (yc[y][x] < 0.24f) { + nh = 152; + } else if (yc[y][x] < 0.29f) { + nh = 153; + } else if (yc[y][x] < 0.32f) { + nh = 154; + } else if (yc[y][x] < 0.34f) { + nh = 155; + } else if (yc[y][x] < 0.37f) { + nh = 156; + } else if (yc[y][x] < 0.4f) { + nh = 157; + } else if (yc[y][x] < 0.45f) { + nh = 158; + } else if (yc[y][x] < 0.5f) { + nh = 159; + } else if (yc[y][x] < 0.55f) { + nh = 160; + } else if (yc[y][x] < 0.58f) { + nh = 161; + } + } else if (xc[y][x] < 0.495f && yc[y][x] > 0.15f) { + if (yc[y][x] < 0.2f) { + nh = 162; + } else if (yc[y][x] < 0.24f) { + nh = 163; + } else if (yc[y][x] < 0.29f) { + nh = 164; + } else if (yc[y][x] < 0.32f) { + nh = 165; + } else if (yc[y][x] < 0.34f) { + nh = 166; + } else if (yc[y][x] < 0.37f) { + nh = 167; + } else if (yc[y][x] < 0.4f) { + nh = 168; + } else if (yc[y][x] < 0.45f) { + nh = 169; + } else if (yc[y][x] < 0.5f) { + nh = 170; + } else if (yc[y][x] < 0.55f) { + nh = 171; + } + } else if (xc[y][x] < 0.545f && yc[y][x] > 0.15f) { + if (yc[y][x] < 0.2f) { + nh = 172; + } else if (yc[y][x] < 0.24f) { + nh = 173; + } else if (yc[y][x] < 0.29f) { + nh = 174; + } else if (yc[y][x] < 0.32f) { + nh = 175; + } else if (yc[y][x] < 0.34f) { + nh = 176; + } else if (yc[y][x] < 0.37f) { + nh = 177; + } else if (yc[y][x] < 0.4f) { + nh = 178; + } else if (yc[y][x] < 0.45f) { + nh = 179; + } else if (yc[y][x] < 0.5f) { + nh = 180; + } + } else if (xc[y][x] < 0.595f && yc[y][x] > 0.15f) { + if (yc[y][x] < 0.22f) { + nh = 181; + } else if (yc[y][x] < 0.25f) { + nh = 182; + } else if (yc[y][x] < 0.3f) { + nh = 183; + } else if (yc[y][x] < 0.35f) { + nh = 184; + } else if (yc[y][x] < 0.4f) { + nh = 185; + } else if (yc[y][x] < 0.45f) { + nh = 186; + } + } else if (xc[y][x] < 0.65f && yc[y][x] > 0.12f) { + if (yc[y][x] < 0.25f) { + nh = 187; + } else if (yc[y][x] < 0.3f) { + nh = 188; + } else if (yc[y][x] < 0.35f) { + nh = 189; + } else if (yc[y][x] < 0.45f) { + nh = 190; + } + } else if (xc[y][x] < 0.75f && yc[y][x] > 0.1f) { + nh = 191; + } + if (nh >= 0) { + histxythr[nh]++; + xxxthr[nh] += xc[y][x]; + yyythr[nh] += yc[y][x]; + YYYthr[nh] += Yc[y][x]; + } + } + } +#ifdef _OPENMP + #pragma omp critical +#endif + { + histxy += histxythr; + xxx += xxxthr; + yyy += yyythr; + YYY += YYYthr; + } + } +} + + + + static void histoxyY(int bfhitc, int bfwitc, const array2D & xc, const array2D & yc, const array2D & Yc, LUTf &xxx, LUTf &yyy, LUTf &YYY, LUTu &histxy, bool purp) { // calculate histogram x y in a range of 236 colors @@ -4654,7 +5122,7 @@ float static studentXY(const array2D & YYcurr, const array2D & ref void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, const ColorManagementParams &cmp, const RAWParams &raw, const WBParams & wbpar, const ToneCurveParams &hrp) { /* - Copyright (c) Jacques Desmis 6 - 2018 jdesmis@gmail.com, update 1 - 2023 + Copyright (c) Jacques Desmis 6 - 2018 jdesmis@gmail.com, update 2 - 2023 Copyright (c) Ingo Weyrich 3 - 2020 (heckflosse67@gmx.de) This algorithm try to find temperature correlation between 20 to 80 colors between 201 spectral color and about 20 to 55 color found in the image between 236, I just found the idea in the web "correlate with chroma" instead of RGB grey point,but I don't use any algo found on the web. @@ -4693,7 +5161,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double 22) we re-adjust references color for these xyY from 20) 23) then find all Student correlation for each couple green / temp 24) sort these Student values, and choose the minimum - 25) then for the 3 better couple "temp / green" choose the one where green is nearest from 1. + 25) then for the 5 better couple "temp / green" choose the one where green is nearest from 1. Some variables or function are not used, keep in case of I have test with cat02 but result are not stable enough ! why ??, therefore cat02 neutralized @@ -4704,28 +5172,37 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double You can used it in images :flowers, landscape, portrait, skin, where illuminants are "normal" (daylight, blackbody) You must avoid when illuminant is non standard (fluorescent, LED...) and also, when the subject is lost in the image (some target to generate profiles). - You can change parameters in option.cc + You can change parameters in White Balance - Frame adapted to Itcwb Itcwb_thres : 34 by default ==> number of color used in final algorithm - between 10 and max 55 Itcwb_sorted : true by default, can improve algorithm if true, ==> sort value in something near chroma order, instead of histogram number Itcwb_greenrange : 0 amplitude of green variation - between 0 to 2 - Itcwb_greendeltatemp : 1 - delta temp in green iterate loop for "extra" - between 0 to 4 - Itcwb_forceextra : true by default - if true force algorithm "extra" ("extra" is used when camera wbsettings are wrong) to all images - Itcwb_sizereference : 3 by default, can be set to 5 ==> size of reference color compare to size of histogram real color + Itcwb_greendelta : 1 - delta temp in green iterate loop for "extra" - between 0 to 4 + Itcwb_forceextra : false by default - Use all Ciexy diagram instead of sRGB + //Itcwb_sizereference : repalce by int maxnb 3 by default, can be set to 5 ==> size of reference color compare to size of histogram real color itcwb_delta : 1 by default can be set between 0 to 5 ==> delta temp to build histogram xy - if camera temp is not probably good - itcwb_stdobserver10 : true by default - use standard observer 10°, false = standard observer 2° - itcwb_precis : 3 by default - can be set to 3 or 9 - 3 best sampling but more time...9 "old" settings - but low differences in times with 3 instead of 9 about twice time 160ms instead of 80ms for a big raw file + //itcwb_precis : replace by int precision = 3 by default - can be set to 3 or 9 - 3 best sampling but more time...9 "old" settings - but low differences in times with 3 instead of 9 about twice time 160ms instead of 80ms for a big raw file itcwb_nopurple : true default - allow to bypass highlight recovery and inpait opposed when need flowers and not purple due to highlights... + itcwb_fgreen : 5 by default - between 3 to 6 - find the compromise student / green to reach green near of 1 + + In file options. + use standard observer 10°, false = standard observer 2° */ // BENCHFUN - TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix("sRGB"); + Glib::ustring profuse; + profuse = "sRGB";//or "Adobe RGB" + if( wbpar.itcwb_forceextra && wbpar.itcwb_sampling == false) {//Adobe RGB + profuse = "ACESp0";//cover all CIE xy diagram + } + + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(profuse); //ACESp0 or sRGB const float wp[3][3] = { {static_cast(wprof[0][0]), static_cast(wprof[0][1]), static_cast(wprof[0][2])}, {static_cast(wprof[1][0]), static_cast(wprof[1][1]), static_cast(wprof[1][2])}, {static_cast(wprof[2][0]), static_cast(wprof[2][1]), static_cast(wprof[2][2])} }; - TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix("sRGB"); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix(profuse);//ACESp0 or sRGB //inverse matrix user select const float wip[3][3] = { {static_cast(wiprof[0][0]), static_cast(wiprof[0][1]), static_cast(wiprof[0][2])}, @@ -4766,7 +5243,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {0.680, 1.f}, {0.690, 1.f}, {0.700, 1.f}, - {0.714, 1.f},//usual range + {0.714, 1.f},//usual 2 range {0.727, 1.f}, {0.741, 1.f}, {0.755, 1.f}, @@ -4775,7 +5252,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {0.800, 1.f}, {0.806, 1.f}, {0.813, 1.f}, - {0.820, 1.f}, + {0.820, 1.f},//usual range {0.826, 1.f}, {0.833, 1.f}, {0.840, 1.f}, @@ -4822,13 +5299,13 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {1.220, 1.f}, {1.230, 1.f}, {1.240, 1.f}, - {1.250, 1.f}, + {1.250, 1.f},// usual range {1.275, 1.f}, {1.300, 1.f}, {1.325, 1.f}, {1.350, 1.f}, {1.375, 1.f}, - {1.400, 1.f},//usual range + {1.400, 1.f},//usual 2 range {1.425, 1.f}, {1.450, 1.f}, {1.475, 1.f}, @@ -4884,20 +5361,25 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double int end; } RangeGreen; - constexpr RangeGreen Rangestandard = {24, 86};//usual green range + constexpr RangeGreen Rangestandard = {33, 80};//usual green range + constexpr RangeGreen Rangestandard2 = {24, 86};//usual 2 green range constexpr RangeGreen Rangeextended = {15, 93}; const RangeGreen Rangemax = {0, N_g}; RangeGreen Rangegreenused; - if (settings->itcwb_greenrange == 0) { + if (wbpar.itcwb_rgreen == 0) { Rangegreenused = Rangestandard; - } else if (settings->itcwb_greenrange == 1) { + } else if (wbpar.itcwb_rgreen == 1) { + Rangegreenused = Rangestandard2; + } else if (wbpar.itcwb_rgreen == 2) { Rangegreenused = Rangeextended; } else { Rangegreenused = Rangemax; } - + if(wbpar.itcwb_sampling == true) { + Rangegreenused = Rangestandard2; + } typedef struct WbTxyz { double Tem; double XX; @@ -5044,8 +5526,10 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double float gmm[N_t]; float bmm[N_t]; - constexpr int siza = 237; //192 untill 01/2023 size of histogram - + int siza = 237; //192 untill 01/2023 size of histogram + if(wbpar.itcwb_sampling == true) { + siza = 192;//old sampling 5.9 and before... + } // tempref and greenref are camera wb values. // I used them by default to select good spectral values !! but they are changed after tempref = rtengine::min(tempref, 12000.0); @@ -5062,12 +5546,12 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double //calculate R G B multiplier in function illuminant and temperature const bool isMono = (ri->getSensorType() == ST_FUJI_XTRANS && raw.xtranssensor.method == RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::MONO)) || (ri->getSensorType() == ST_BAYER && raw.bayersensor.method == RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::MONO)); - for (int tt = 0; tt < N_t; ++tt) { double r, g, b; float rm, gm, bm; - ColorTemp WBiter = ColorTemp(Txyz[tt].Tem, greenitc, 1.f, "Custom"); + ColorTemp WBiter = ColorTemp(Txyz[tt].Tem, greenitc, 1.f, "Custom", wbpar.observer); WBiter.getMultipliers(r, g, b); + rm = imatrices.cam_rgb[0][0] * r + imatrices.cam_rgb[0][1] * g + imatrices.cam_rgb[0][2] * b; gm = imatrices.cam_rgb[1][0] * r + imatrices.cam_rgb[1][1] * g + imatrices.cam_rgb[1][2] * b; bm = imatrices.cam_rgb[2][0] * r + imatrices.cam_rgb[2][1] * g + imatrices.cam_rgb[2][2] * b; @@ -5151,7 +5635,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double array2D yc(bfwitc, bfhitc); array2D Yc(bfwitc, bfhitc); - const int deltarepref = settings->itcwb_delta; + const int deltarepref = 1; //settings->itcwb_delta; for (int nn = 0, drep = -deltarepref; nn <= 2; ++nn, drep += deltarepref) { //three loop to refine color if temp camera is probably not very good @@ -5167,7 +5651,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double const float RR = rmm[rep] * redloc[y][x]; const float GG = gmm[rep] * greenloc[y][x]; const float BB = bmm[rep] * blueloc[y][x]; - Color::rgbxyY(RR, GG, BB, xc[y][x], yc[y][x], Yc[y][x], wp); + Color::rgbxyY(RR, GG, BB, xc[y][x], yc[y][x], Yc[y][x], wp);//use sRGB or ACESp0 } } @@ -5182,12 +5666,18 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double bool purp = true;//if inpaint-opposed or something else enable purp - if (hrp.hrenabled && hrp.method == "Coloropp" && settings->itcwb_nopurple == true) {//we disabled (user) with settings if image are naturally with purple (flowers...) + // if (hrp.hrenabled && hrp.method == "Coloropp" && settings->itcwb_nopurple == true) {//we disabled (user) with settings if image are naturally with purple (flowers...) + if (hrp.hrenabled && hrp.method == "Coloropp" && wbpar.itcwb_nopurple == true) {//we disabled (user) with settings if image are naturally with purple (flowers...) purp = false; } - - histoxyY(bfhitc, bfwitc, xc, yc, Yc, xxx, yyy, YYY, histxy, purp);//purp enable, enable purple color in WB - //return histogram x and y for each temp and in a range of 235 colors (siza) + if(wbpar.itcwb_sampling == false) { + //printf("Use high smapling\n"); + histoxyY(bfhitc, bfwitc, xc, yc, Yc, xxx, yyy, YYY, histxy, purp);//purp enable, enable purple color in WB + //return histogram x and y for each temp and in a range of 235 colors (siza) + } else { + //printf("Use low smapling - 5.9\n"); + histoxyY_low(bfhitc, bfwitc, xc, yc, Yc, xxx, yyy, YYY, histxy);//low scaling + } } // free some memory @@ -5255,7 +5745,11 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double int sizcurr2ref = sizcurrref - ntr; const int sizcu30 = sizcurrref - n30; - const int sizcu4 = rtengine::min(sizcu30, 55);// + int nbm = 77;//number max of color used = 1.4 * 55 in case all CIExy diagram + if(profuse == "sRGB" || wbpar.itcwb_sampling == true) { + nbm = 55; + } + const int sizcu4 = rtengine::min(sizcu30, nbm);//size of chroma values if (settings->verbose) { printf("ntr=%i sizcurr2ref=%i sizcu30=%i sizcu4=%i\n", ntr, sizcurr2ref, sizcu30, sizcu4); @@ -5292,12 +5786,21 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double if (settings->verbose) { printf("estimchrom=%f\n", estimchrom); } + bool issorted = wbpar.itcwb_sorted; - if (settings->itcwb_sorted) { //sort in ascending with chroma values + if(wbpar.itcwb_sampling == true) { + issorted = false; + } + + + if (issorted) { //sort in ascending with chroma values std::sort(wbchro, wbchro + sizcu4, wbchro[0]); } - const int maxval = rtengine::LIM(settings->itcwb_thres, 10, 55);//max values of color to find correlation + int maxval = rtengine::LIM(wbpar.itcwb_thres, 10, 55);//max values of color to find correlation + if(wbpar.itcwb_sampling == true) { + maxval = 34; + } sizcurr2ref = rtengine::min(sizcurr2ref, maxval); //keep about the biggest values, @@ -5312,10 +5815,13 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } //calculate deltaE xx to find best values of spectrals data - limited to chroma values - int maxnb = rtengine::LIM(settings->itcwb_sizereference, 1, 5); + // int maxnb = rtengine::LIM(settings->itcwb_sizereference, 1, 5); + // int maxnb = rtengine::LIM(wbpar.itcwb_size, 1, 5); + int maxnb = 3; + //wbpar.itcwb_size to verify if this setting is usefull...diificulties with High gamut and limited patch spectral colors. - if (settings->itcwb_thres > 55) { - maxnb = 201 / settings->itcwb_thres; + if (wbpar.itcwb_thres > 55) {//normally never used + maxnb = 201 / wbpar.itcwb_thres; } for (int nb = 1; nb <= maxnb; ++nb) { //max 5 iterations for Itcwb_thres=33, after trial 3 is good in most cases but in some cases 5 @@ -5423,10 +5929,12 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double Tgstud[i].student = 1000.f;//max value to initialize Tgstud[i].tempref = 57;//5002K position in the list Tgstud[i].greenref = 55;// 1.f position in the list - } - const int dgoodref = rtengine::min(settings->itcwb_greendeltatemp, 4); + int dgoodref = rtengine::LIM(wbpar.itcwb_delta,1, 4); + if(wbpar.itcwb_sampling == true) { + dgoodref = 2; + } const int scantempbeg = rtengine::max(goodref - (dgoodref + 1), 1); const int scantempend = rtengine::min(goodref + dgoodref, N_t - 1); @@ -5436,7 +5944,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double for (int tt = scantempbeg; tt < scantempend; ++tt) { double r, g, b; - ColorTemp WBiter(Txyz[tt].Tem, gree[gr].green, 1.f, "Custom"); + ColorTemp WBiter(Txyz[tt].Tem, gree[gr].green, 1.f, "Custom", wbpar.observer); WBiter.getMultipliers(r, g, b); float rm = imatrices.cam_rgb[0][0] * r + imatrices.cam_rgb[0][1] * g + imatrices.cam_rgb[0][2] * b; float gm = imatrices.cam_rgb[1][0] * r + imatrices.cam_rgb[1][1] * g + imatrices.cam_rgb[1][2] * b; @@ -5508,7 +6016,12 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double // perhaps we can used a Snedecor test ? but why...at least we have confidence interval > 90% int greengood = 55; - int maxkgood = 5;//we can change ...to test 3, 4, 5. High values perhaps less good student, but it is a compromise... + int maxkgood = wbpar.itcwb_fgreen;//we can change ...to test 3, 4, 5. High values perhaps less good student, but it is a compromise... + maxkgood = rtengine::LIM(maxkgood, 3, 6); + if(wbpar.itcwb_sampling == true) { + maxkgood = 3; // force to 3 with old low sampling + } + int mingood = std::min(std::fabs(Tgstud[0].greenref - 55), std::fabs(Tgstud[1].greenref - 55)); for (int k = 2; k < maxkgood; ++k) { @@ -5558,14 +6071,11 @@ void RawImageSource::WBauto(double & tempref, double & greenref, array2D //put green (tint) in reasonable limits for an Daylight illuminant // avoid too bi or too low values if (wbpar.method == "autitcgreen") { - bool extra = false; + bool extra = true; if (greenref > 0.5 && greenref < 1.3) {// 0.5 and 1.3 arbitraties values greenitc = greenref; - if (settings->itcwb_forceextra) { - extra = true; - } } else { greenitc = 1.; extra = true; @@ -5576,22 +6086,16 @@ void RawImageSource::WBauto(double & tempref, double & greenref, array2D } } -void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) +void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, const WBParams & wbpar) { // BENCHFUN //used by auto WB local to calculate red, green, blue in local region - int precision = 5; - - if (settings->itcwb_precis == 5) { + int precision = 3;//must be 3 5 or 9 + if(wbpar.itcwb_sampling == true) { precision = 5; - } else if (settings->itcwb_precis < 5) { - precision = 3; - } else if (settings->itcwb_precis > 5) { - precision = 9; } - const int bfw = W / precision + ((W % precision) > 0 ? 1 : 0);// 5 arbitrary value can be change to 3 or 9 ; const int bfh = H / precision + ((H % precision) > 0 ? 1 : 0); @@ -5851,14 +6355,9 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref if (wbpar.method == "autitcgreen") { bool twotimes = false; - int precision = 5; - - if (settings->itcwb_precis == 5) { + int precision = 3;//must be 3 5 or 9 + if(wbpar.itcwb_sampling == true) { precision = 5; - } else if (settings->itcwb_precis < 5) { - precision = 3; - } else if (settings->itcwb_precis > 5) { - precision = 9; } const int bfw = W / precision + ((W % precision) > 0 ? 1 : 0);// 5 arbitrary value can be change to 3 or 9 ; @@ -6106,7 +6605,7 @@ void RawImageSource::getAutoWBMultipliers(double &rm, double &gm, double &bm) blueAWBMul = bm = imatrices.rgb_cam[2][0] * reds + imatrices.rgb_cam[2][1] * greens + imatrices.rgb_cam[2][2] * blues; } -ColorTemp RawImageSource::getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal) +ColorTemp RawImageSource::getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal, StandardObserver observer) { int x; @@ -6314,7 +6813,7 @@ ColorTemp RawImageSource::getSpotWB (std::vector &red, std::vector &rawData); // raw for cblack void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) override; void getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const procparams::WBParams & wbpar, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) override; - void getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) override; + void getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, const procparams::WBParams & wbpar) override; void getWBMults (const ColorTemp &ctemp, const procparams::RAWParams &raw, std::array& scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const override; void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw, int opposed) override; @@ -154,7 +154,7 @@ public: return camera_wb; } void getAutoWBMultipliers (double &rm, double &gm, double &bm) override; - ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal) override; + ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal, StandardObserver observer) override; bool isWBProviderReady () override { return rawData; @@ -186,7 +186,7 @@ public: } void getAutoExpHistogram (LUTu & histogram, int& histcompr) override; void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) override; - void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, std::vector &outCurve) override; + void getAutoMatchedToneCurve(const procparams::ColorManagementParams &cp, StandardObserver observer, std::vector &outCurve) override; DCPProfile *getDCP(const procparams::ColorManagementParams &cmp, DCPProfileApplyState &as) override; void convertColorSpace(Imagefloat* image, const procparams::ColorManagementParams &cmp, const ColorTemp &wb) override; diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index 989ca3354..f86950457 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -472,7 +472,7 @@ class AutoWBListener { public: virtual ~AutoWBListener() = default; - virtual void WBChanged(double temp, double green, float studgood) = 0; + virtual void WBChanged(double temp, double green, double rw, double gw, double bw, float studgood) = 0; }; class FrameCountListener @@ -619,8 +619,8 @@ public: * @return a pointer to the Crop object that handles the image data trough its own pipeline */ virtual DetailedCrop* createCrop (::EditDataProvider *editDataProvider, bool isDetailWindow) = 0; - virtual bool getAutoWB (double& temp, double& green, double equal, double tempBias) = 0; - virtual void getCamWB (double& temp, double& green) = 0; + virtual bool getAutoWB (double& temp, double& green, double equal, StandardObserver observer, double tempBias) = 0; + virtual void getCamWB (double& temp, double& green, StandardObserver observer) = 0; virtual void getSpotWB (int x, int y, int rectSize, double& temp, double& green) = 0; virtual bool getFilmNegativeSpot(int x, int y, int spotSize, procparams::FilmNegativeParams::RGB &refInput, procparams::FilmNegativeParams::RGB &refOutput) = 0; diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 84c33a734..11dae8018 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -194,7 +194,7 @@ namespace rtengine using namespace procparams; -Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, bool inspectorMode) +Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool inspectorMode) { StdImageSource imgSrc; @@ -310,8 +310,9 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, tpp->blueAWBMul = avg_b / double (n); tpp->wbEqual = wbEq; tpp->wbTempBias = 0.0; + tpp->wbObserver = wbObserver; - cTemp.mul2temp (tpp->redAWBMul, tpp->greenAWBMul, tpp->blueAWBMul, tpp->wbEqual, tpp->autoWBTemp, tpp->autoWBGreen); + cTemp.mul2temp (tpp->redAWBMul, tpp->greenAWBMul, tpp->blueAWBMul, tpp->wbEqual, tpp->wbObserver, tpp->autoWBTemp, tpp->autoWBGreen); } tpp->init (); @@ -543,7 +544,7 @@ RawMetaDataLocation Thumbnail::loadMetaDataFromRaw (const Glib::ustring& fname) return rml; } -Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, bool rotate, bool forHistogramMatching) +Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool rotate, bool forHistogramMatching) { RawImage *ri = new RawImage (fname); unsigned int tempImageNum = 0; @@ -982,9 +983,10 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati tpp->blueAWBMul = ri->get_rgb_cam (2, 0) * reds + ri->get_rgb_cam (2, 1) * greens + ri->get_rgb_cam (2, 2) * blues; tpp->wbEqual = wbEq; tpp->wbTempBias = 0.0; + tpp->wbObserver = wbObserver; ColorTemp cTemp; - cTemp.mul2temp (tpp->redAWBMul, tpp->greenAWBMul, tpp->blueAWBMul, tpp->wbEqual, tpp->autoWBTemp, tpp->autoWBGreen); + cTemp.mul2temp (tpp->redAWBMul, tpp->greenAWBMul, tpp->blueAWBMul, tpp->wbEqual, tpp->wbObserver, tpp->autoWBTemp, tpp->autoWBGreen); } if (rotate && ri->get_rotateDegree() > 0) { @@ -1121,18 +1123,19 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT float iso = metadata->getISOSpeed(imgNum); float fcomp = metadata->getExpComp(imgNum); - // check if the WB's equalizer value has changed - if (wbEqual < (params.wb.equal - 5e-4) || wbEqual > (params.wb.equal + 5e-4) || wbTempBias < (params.wb.tempBias - 5e-4) || wbTempBias > (params.wb.tempBias + 5e-4)) { + // check if the WB's equalizer, temperature bias, or observer value has changed + if (wbEqual < (params.wb.equal - 5e-4) || wbEqual > (params.wb.equal + 5e-4) || wbTempBias < (params.wb.tempBias - 5e-4) || wbTempBias > (params.wb.tempBias + 5e-4) || wbObserver != params.wb.observer) { wbEqual = params.wb.equal; wbTempBias = params.wb.tempBias; + wbObserver = params.wb.observer; // recompute the autoWB ColorTemp cTemp; - cTemp.mul2temp (redAWBMul, greenAWBMul, blueAWBMul, wbEqual, autoWBTemp, autoWBGreen); + cTemp.mul2temp (redAWBMul, greenAWBMul, blueAWBMul, wbEqual, wbObserver, autoWBTemp, autoWBGreen); autoWBTemp += autoWBTemp * wbTempBias; } // compute WB multipliers - ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method); + ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method, params.wb.observer); if (!params.wb.enabled) { currWB = ColorTemp(); @@ -1141,9 +1144,9 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT double cam_r = colorMatrix[0][0] * camwbRed + colorMatrix[0][1] * camwbGreen + colorMatrix[0][2] * camwbBlue; double cam_g = colorMatrix[1][0] * camwbRed + colorMatrix[1][1] * camwbGreen + colorMatrix[1][2] * camwbBlue; double cam_b = colorMatrix[2][0] * camwbRed + colorMatrix[2][1] * camwbGreen + colorMatrix[2][2] * camwbBlue; - currWB = ColorTemp (cam_r, cam_g, cam_b, params.wb.equal); + currWB = ColorTemp (cam_r, cam_g, cam_b, params.wb.equal, params.wb.observer); } else if (params.wb.method == "autold") { - currWB = ColorTemp (autoWBTemp, autoWBGreen, wbEqual, "Custom"); + currWB = ColorTemp (autoWBTemp, autoWBGreen, wbEqual, "Custom", wbObserver); } double rm, gm, bm; @@ -1588,27 +1591,28 @@ void Thumbnail::getDimensions (int& w, int& h, double& scaleFac) } } -void Thumbnail::getCamWB (double& temp, double& green) +void Thumbnail::getCamWB (double& temp, double& green, StandardObserver observer) { double cam_r = colorMatrix[0][0] * camwbRed + colorMatrix[0][1] * camwbGreen + colorMatrix[0][2] * camwbBlue; double cam_g = colorMatrix[1][0] * camwbRed + colorMatrix[1][1] * camwbGreen + colorMatrix[1][2] * camwbBlue; double cam_b = colorMatrix[2][0] * camwbRed + colorMatrix[2][1] * camwbGreen + colorMatrix[2][2] * camwbBlue; - ColorTemp currWB = ColorTemp (cam_r, cam_g, cam_b, 1.0); // we do not take the equalizer into account here, because we want camera's WB + ColorTemp currWB = ColorTemp (cam_r, cam_g, cam_b, 1.0, observer); // we do not take the equalizer into account here, because we want camera's WB temp = currWB.getTemp (); green = currWB.getGreen (); } -void Thumbnail::getAutoWB (double& temp, double& green, double equal, double tempBias) +void Thumbnail::getAutoWB (double& temp, double& green, double equal, double tempBias, StandardObserver observer) { - if (equal != wbEqual || tempBias != wbTempBias) { + if (equal != wbEqual || tempBias != wbTempBias || observer != wbObserver) { // compute the values depending on equal ColorTemp cTemp; wbEqual = equal; wbTempBias = tempBias; + wbObserver = observer; // compute autoWBTemp and autoWBGreen - cTemp.mul2temp (redAWBMul, greenAWBMul, blueAWBMul, wbEqual, autoWBTemp, autoWBGreen); + cTemp.mul2temp (redAWBMul, greenAWBMul, blueAWBMul, wbEqual, wbObserver, autoWBTemp, autoWBGreen); autoWBTemp += autoWBTemp * tempBias; } @@ -1665,7 +1669,7 @@ void Thumbnail::getSpotWB (const procparams::ProcParams& params, int xp, int yp, double gm = colorMatrix[1][0] * reds + colorMatrix[1][1] * greens + colorMatrix[1][2] * blues; double bm = colorMatrix[2][0] * reds + colorMatrix[2][1] * greens + colorMatrix[2][2] * blues; - ColorTemp ct (rm, gm, bm, params.wb.equal); + ColorTemp ct (rm, gm, bm, params.wb.equal, params.wb.observer); rtemp = ct.getTemp (); rgreen = ct.getGreen (); } diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index 6ec1dfb34..535613ca2 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -38,6 +38,8 @@ class ustring; namespace rtengine { +enum class StandardObserver; + class Thumbnail { @@ -55,6 +57,7 @@ class Thumbnail double camwbBlue; double redAWBMul, greenAWBMul, blueAWBMul; // multipliers for auto WB double autoWBTemp, autoWBGreen, wbEqual, wbTempBias; // autoWBTemp and autoWBGreen are updated each time autoWB is requested and if wbEqual has been modified + StandardObserver wbObserver; LUTu aeHistogram; int aeHistCompression; bool aeValid; @@ -95,12 +98,12 @@ public: void getDimensions (int& w, int& h, double& scaleFac); static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode = false, bool forHistogramMatching = false); - static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, bool rotate, bool forHistogramMatching = false); - static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, bool inspectorMode = false); + static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool rotate, bool forHistogramMatching = false); + static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, StandardObserver wbObserver, bool inspectorMode = false); static RawMetaDataLocation loadMetaDataFromRaw (const Glib::ustring& fname); - void getCamWB (double& temp, double& green); - void getAutoWB (double& temp, double& green, double equal, double tempBias); + void getCamWB (double& temp, double& green, StandardObserver observer); + void getAutoWB (double& temp, double& green, double equal, double tempBias, StandardObserver observer); void getAutoWBMultipliers (double& rm, double& gm, double& bm); void getSpotWB (const procparams::ProcParams& params, int x, int y, int rect, double& temp, double& green); void applyAutoExp (procparams::ProcParams& pparams); diff --git a/rtengine/settings.h b/rtengine/settings.h index 6e787a112..e831fa1a4 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -44,7 +44,6 @@ public: bool monitorBPC; ///< Black Point Compensation for the Labimage->Monitor transform (directly, i.e. not soft-proofing and no WCS in between) bool autoMonitorProfile; ///< Try to auto-determine the correct monitor color profile bool autocielab; - bool observer10; bool rgbcurveslumamode_gamut;// controls gamut enforcement for RGB curves in lumamode bool verbose; Glib::ustring darkFramesPath; ///< The default directory for dark frames @@ -93,17 +92,7 @@ public: int previewselection; double cbdlsensi; // bool showtooltip; - - int itcwb_thres; - bool itcwb_sorted; - int itcwb_greenrange; - int itcwb_greendeltatemp; - bool itcwb_forceextra; - int itcwb_sizereference; - int itcwb_delta; - bool itcwb_stdobserver10; - int itcwb_precis; - bool itcwb_nopurple; + bool itcwb_enable; //wavelet levels double edghi; double edglo; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 5de3b08b0..78dd84042 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -269,7 +269,7 @@ private: } // set the color temperature - currWB = ColorTemp(params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method); + currWB = ColorTemp(params.wb.temperature, params.wb.green, params.wb.equal, params.wb.method, params.wb.observer); if (!params.wb.enabled) { currWB = ColorTemp(); @@ -278,7 +278,7 @@ private: } else if (params.wb.method == "autold") { double rm, gm, bm; imgsrc->getAutoWBMultipliers(rm, gm, bm); - currWB.update(rm, gm, bm, params.wb.equal, params.wb.tempBias); + currWB.update(rm, gm, bm, params.wb.equal, params.wb.observer, params.wb.tempBias); } calclum = nullptr ; @@ -781,7 +781,7 @@ private: if (params.toneCurve.histmatching) { if (!params.toneCurve.fromHistMatching) { - imgsrc->getAutoMatchedToneCurve(params.icm, params.toneCurve.curve); + imgsrc->getAutoMatchedToneCurve(params.icm, params.wb.observer, params.toneCurve.curve); } if (params.toneCurve.autoexp) { diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index a3f2502f0..411b1de32 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -187,7 +187,7 @@ int StdImageSource::load (const Glib::ustring &fname) plistener->setProgress (1.0); } - wb = ColorTemp (1.0, 1.0, 1.0, 1.0); + wb = ColorTemp (1.0, 1.0, 1.0, 1.0, ColorTemp::DEFAULT_OBSERVER); //this is probably a mistake if embedded profile is not D65 return 0; @@ -348,7 +348,7 @@ void StdImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm) blueAWBMul = bm; } -ColorTemp StdImageSource::getSpotWB (std::vector &red, std::vector &green, std::vector& blue, int tran, double equal) +ColorTemp StdImageSource::getSpotWB (std::vector &red, std::vector &green, std::vector& blue, int tran, double equal, StandardObserver observer) { int rn, gn, bn; double reds, greens, blues; @@ -360,7 +360,7 @@ ColorTemp StdImageSource::getSpotWB (std::vector &red, std::vector& scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const override {}; void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw, int opposed) override; - void getrgbloc (int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) override {}; + void getrgbloc (int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, const procparams::WBParams & wbpar) override {}; ColorTemp getWB () const override { return wb; } void getAutoWBMultipliers (double &rm, double &gm, double &bm) override; - ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal) override; + ColorTemp getSpotWB (std::vector &red, std::vector &green, std::vector &blue, int tran, double equal, StandardObserver observer) override; void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) override; void getAutoWBMultipliersitc(double &tempref, double &greenref, double &tempitc, double &greenitc, float &studgood, int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w, double &rm, double &gm, double &bm, const procparams::WBParams & wbpar, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::ToneCurveParams &hrp) override; diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index 9e74ddb90..58532f68a 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -586,19 +586,19 @@ void BatchToolPanelCoordinator::unsetTweakOperator (rtengine::TweakOperator *tOp { } -void BatchToolPanelCoordinator::getAutoWB (double& temp, double& green, double equal, double tempBias) +void BatchToolPanelCoordinator::getAutoWB (double& temp, double& green, double equal, rtengine::StandardObserver observer, double tempBias) { if (!selected.empty()) { - selected[0]->getAutoWB (temp, green, equal, tempBias); + selected[0]->getAutoWB (temp, green, equal, observer, tempBias); } } -void BatchToolPanelCoordinator::getCamWB (double& temp, double& green) +void BatchToolPanelCoordinator::getCamWB (double& temp, double& green, rtengine::StandardObserver observer) { if (!selected.empty()) { - selected[0]->getCamWB (temp, green); + selected[0]->getCamWB (temp, green, observer); } } diff --git a/rtgui/batchtoolpanelcoord.h b/rtgui/batchtoolpanelcoord.h index 0009724e8..f421793ac 100644 --- a/rtgui/batchtoolpanelcoord.h +++ b/rtgui/batchtoolpanelcoord.h @@ -69,8 +69,8 @@ public: ) override; // wbprovider interface - void getAutoWB (double& temp, double& green, double equal, double tempBias) override; - void getCamWB (double& temp, double& green) override; + void getAutoWB (double& temp, double& green, double equal, rtengine::StandardObserver observer, double tempBias) override; + void getCamWB (double& temp, double& green, rtengine::StandardObserver observer) override; // thumbnaillistener interface void procParamsChanged (Thumbnail* thm, int whoChangedIt) override; diff --git a/rtgui/checkbox.cc b/rtgui/checkbox.cc index e05ba061a..265123b23 100644 --- a/rtgui/checkbox.cc +++ b/rtgui/checkbox.cc @@ -80,7 +80,7 @@ void CheckBox::setValue (CheckValue newValue) break; case CheckValue::off: set_inconsistent (false); - set_active(true); + set_active(false); lastActive = false; break; case CheckValue::unchanged: diff --git a/rtgui/filmnegative.cc b/rtgui/filmnegative.cc index 292fa98ae..4f1ae9311 100644 --- a/rtgui/filmnegative.cc +++ b/rtgui/filmnegative.cc @@ -33,6 +33,12 @@ const Glib::ustring FilmNegative::TOOL_NAME = "filmnegative"; namespace { +/** + * Observer to use for displaying the temperature and tint equivalent of the + * multipliers. + */ +constexpr rtengine::StandardObserver standard_observer = rtengine::ColorTemp::DEFAULT_OBSERVER; + double toAdjuster(double v) { return CLAMP(std::log2(v), 6, 16) - 6; @@ -154,7 +160,7 @@ RGB getFilmNegativeExponents(const RGB &ref1, const RGB &ref2) // , const RGB &c void temp2rgb(double outLev, double temp, double green, RGB &refOut) { - rtengine::ColorTemp ct = rtengine::ColorTemp(temp, green, 1., "Custom"); + rtengine::ColorTemp ct = rtengine::ColorTemp(temp, green, 1., "Custom", standard_observer); double rm, gm, bm; ct.getMultipliers(rm, gm, bm); @@ -175,7 +181,8 @@ void rgb2temp(const RGB &refOut, double &outLev, double &temp, double &green) refOut.r / maxVal, refOut.g / maxVal, refOut.b / maxVal, - 1.); + 1., + standard_observer); outLev = maxVal; temp = ct.getTemp(); @@ -188,7 +195,7 @@ void rgb2temp(const RGB &refOut, double &outLev, double &temp, double &green) FilmNegative::FilmNegative() : FoldableToolPanel(this, TOOL_NAME, M("TP_FILMNEGATIVE_LABEL"), false, true), EditSubscriber(ET_OBJECTS), - NEUTRAL_TEMP(rtengine::ColorTemp(1., 1., 1., 1.)), + NEUTRAL_TEMP(rtengine::ColorTemp(1., 1., 1., 1., rtengine::ColorTemp::DEFAULT_OBSERVER)), evFilmNegativeExponents(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_VALUES")), evFilmNegativeEnabled(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_ENABLED")), evFilmNegativeRefSpot(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_REF_SPOT")), diff --git a/rtgui/options.cc b/rtgui/options.cc index e230dcf8a..7d823eda4 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -595,7 +595,6 @@ void Options::setDefaults() rtSettings.monitorIntent = rtengine::RI_RELATIVE; rtSettings.monitorBPC = true; rtSettings.autocielab = false; - rtSettings.observer10 = false; rtSettings.autoMonitorProfile = false; rtSettings.adobe = "RTv2_Medium"; // put the name of yours profiles (here windows) rtSettings.prophoto = "RTv2_Large"; // these names appear in the menu "output profile" @@ -623,18 +622,8 @@ void Options::setDefaults() rtSettings.previewselection = 5;//between 1 to 40 rtSettings.cbdlsensi = 1.0;//between 0.001 to 1 rtSettings.fftwsigma = true; //choice between sigma^2 or empirical formula - - rtSettings.itcwb_thres = 34;//between 10 to 55 - rtSettings.itcwb_sorted = true; - rtSettings.itcwb_greenrange = 0;//between 0 to 2 - rtSettings.itcwb_greendeltatemp = 2;//between 0 and 4 - rtSettings.itcwb_forceextra = true; - rtSettings.itcwb_sizereference = 3;//between 1 and 5 - rtSettings.itcwb_delta = 1;//between 0 and 5 - rtSettings.itcwb_stdobserver10 = true; - rtSettings.itcwb_precis = 3;//3 or 5 or 9 - rtSettings.itcwb_nopurple = true; // end locallab + rtSettings.itcwb_enable = true; //wavelet rtSettings.edghi = 3.0;//1.1 and 5. @@ -1767,10 +1756,6 @@ void Options::readFromFile(Glib::ustring fname) rtSettings.autocielab = keyFile.get_boolean("Color Management", "Autocielab"); } - if (keyFile.has_key("Color Management", "Observer10")) { - rtSettings.observer10 = keyFile.get_boolean("Color Management", "Observer10"); - } - if (keyFile.has_key("Color Management", "CRI")) { rtSettings.CRI_color = keyFile.get_integer("Color Management", "CRI"); } @@ -1802,45 +1787,10 @@ void Options::readFromFile(Glib::ustring fname) rtSettings.level123_cbdl = keyFile.get_double("Color Management", "CBDLlevel123"); } - if (keyFile.has_key("Color Management", "Itcwb_thres")) { - rtSettings.itcwb_thres = keyFile.get_integer("Color Management", "Itcwb_thres"); + if (keyFile.has_key("Color Management", "Itcwb_enable")) { + rtSettings.itcwb_enable = keyFile.get_boolean("Color Management", "Itcwb_enable"); } - if (keyFile.has_key("Color Management", "Itcwb_sorted")) { - rtSettings.itcwb_sorted = keyFile.get_boolean("Color Management", "Itcwb_sorted"); - } - - if (keyFile.has_key("Color Management", "Itcwb_forceextra")) { - rtSettings.itcwb_forceextra = keyFile.get_boolean("Color Management", "Itcwb_forceextra"); - } - - if (keyFile.has_key("Color Management", "Itcwb_nopurple")) { - rtSettings.itcwb_nopurple = keyFile.get_boolean("Color Management", "Itcwb_nopurple"); - } - - if (keyFile.has_key("Color Management", "Itcwb_stdobserver10")) { - rtSettings.itcwb_stdobserver10 = keyFile.get_boolean("Color Management", "Itcwb_stdobserver10"); - } - - if (keyFile.has_key("Color Management", "Itcwb_greenrange")) { - rtSettings.itcwb_greenrange = keyFile.get_integer("Color Management", "Itcwb_greenrange"); - } - - if (keyFile.has_key("Color Management", "Itcwb_greendeltatemp")) { - rtSettings.itcwb_greendeltatemp = keyFile.get_integer("Color Management", "Itcwb_greendeltatemp"); - } - - if (keyFile.has_key("Color Management", "Itcwb_sizereference")) { - rtSettings.itcwb_sizereference = keyFile.get_integer("Color Management", "Itcwb_sizereference"); - } - - if (keyFile.has_key("Color Management", "Itcwb_delta")) { - rtSettings.itcwb_delta = keyFile.get_integer("Color Management", "Itcwb_delta"); - } - - if (keyFile.has_key("Color Management", "Itcwb_precis")) { - rtSettings.itcwb_precis = keyFile.get_integer("Color Management", "Itcwb_precis"); - } //if (keyFile.has_key ("Color Management", "Colortoningab")) rtSettings.colortoningab = keyFile.get_double("Color Management", "Colortoningab"); //if (keyFile.has_key ("Color Management", "Decaction")) rtSettings.decaction = keyFile.get_double("Color Management", "Decaction"); @@ -2579,7 +2529,6 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_string("Color Management", "MonitorProfile", rtSettings.monitorProfile); keyFile.set_boolean("Color Management", "AutoMonitorProfile", rtSettings.autoMonitorProfile); keyFile.set_boolean("Color Management", "Autocielab", rtSettings.autocielab); - keyFile.set_boolean("Color Management", "Observer10", rtSettings.observer10); keyFile.set_boolean("Color Management", "RGBcurvesLumamode_Gamut", rtSettings.rgbcurveslumamode_gamut); keyFile.set_integer("Color Management", "Intent", rtSettings.monitorIntent); keyFile.set_boolean("Color Management", "MonitorBPC", rtSettings.monitorBPC); @@ -2612,16 +2561,7 @@ void Options::saveToFile(Glib::ustring fname) //keyFile.set_boolean ("Color Management", "Ciebadpixgauss", rtSettings.ciebadpixgauss); keyFile.set_double("Color Management", "CBDLlevel0", rtSettings.level0_cbdl); keyFile.set_double("Color Management", "CBDLlevel123", rtSettings.level123_cbdl); - keyFile.set_integer("Color Management", "Itcwb_thres", rtSettings.itcwb_thres); - keyFile.set_boolean("Color Management", "Itcwb_sorted", rtSettings.itcwb_sorted); - keyFile.set_integer("Color Management", "Itcwb_greenrange", rtSettings.itcwb_greenrange); - keyFile.set_integer("Color Management", "Itcwb_greendeltatemp", rtSettings.itcwb_greendeltatemp); - keyFile.set_boolean("Color Management", "Itcwb_forceextra", rtSettings.itcwb_forceextra); - keyFile.set_boolean("Color Management", "Itcwb_nopurple", rtSettings.itcwb_nopurple); - keyFile.set_integer("Color Management", "Itcwb_sizereference", rtSettings.itcwb_sizereference); - keyFile.set_integer("Color Management", "Itcwb_delta", rtSettings.itcwb_delta); - keyFile.set_boolean("Color Management", "Itcwb_stdobserver10", rtSettings.itcwb_stdobserver10); - keyFile.set_integer("Color Management", "Itcwb_precis", rtSettings.itcwb_precis); + keyFile.set_boolean("Color Management", "Itcwb_enable", rtSettings.itcwb_enable); //keyFile.set_double ("Color Management", "Colortoningab", rtSettings.colortoningab); //keyFile.set_double ("Color Management", "Decaction", rtSettings.decaction); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index abd4e8608..c3638cc5f 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -266,6 +266,17 @@ void ParamsEdited::set(bool v) wb.temperature = v; wb.equal = v; wb.tempBias = v; + wb.observer = v; + wb.itcwb_thres = v; + wb.itcwb_precis = v; + wb.itcwb_size = v; + wb.itcwb_delta = v; + wb.itcwb_fgreen = v; + wb.itcwb_rgreen = v; + wb.itcwb_nopurple = v; + wb.itcwb_sorted = v; + wb.itcwb_forceextra = v; + wb.itcwb_sampling = v; //colorShift.a = v; //colorShift.b = v; //lumaDenoise.enabled = v; @@ -967,6 +978,17 @@ void ParamsEdited::initFrom(const std::vector& wb.equal = wb.equal && p.wb.equal == other.wb.equal; wb.temperature = wb.temperature && p.wb.temperature == other.wb.temperature; wb.tempBias = wb.tempBias && p.wb.tempBias == other.wb.tempBias; + wb.observer = wb.observer && p.wb.observer == other.wb.observer; + wb.itcwb_thres = wb.itcwb_thres && p.wb.itcwb_thres == other.wb.itcwb_thres; + wb.itcwb_precis = wb.itcwb_precis && p.wb.itcwb_precis == other.wb.itcwb_precis; + wb.itcwb_size = wb.itcwb_size && p.wb.itcwb_size == other.wb.itcwb_size; + wb.itcwb_delta = wb.itcwb_delta && p.wb.itcwb_delta == other.wb.itcwb_delta; + wb.itcwb_fgreen = wb.itcwb_fgreen && p.wb.itcwb_fgreen == other.wb.itcwb_fgreen; + wb.itcwb_rgreen = wb.itcwb_rgreen && p.wb.itcwb_rgreen == other.wb.itcwb_rgreen; + wb.itcwb_nopurple = wb.itcwb_nopurple && p.wb.itcwb_nopurple == other.wb.itcwb_nopurple; + wb.itcwb_sorted = wb.itcwb_sorted && p.wb.itcwb_sorted == other.wb.itcwb_sorted; + wb.itcwb_forceextra = wb.itcwb_forceextra && p.wb.itcwb_forceextra == other.wb.itcwb_forceextra; + wb.itcwb_sampling = wb.itcwb_sampling && p.wb.itcwb_sampling == other.wb.itcwb_sampling; //colorShift.a = colorShift.a && p.colorShift.a == other.colorShift.a; //colorShift.b = colorShift.b && p.colorShift.b == other.colorShift.b; //lumaDenoise.enabled = lumaDenoise.enabled && p.lumaDenoise.enabled == other.lumaDenoise.enabled; @@ -2829,6 +2851,50 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.wb.tempBias = dontforceSet && options.baBehav[ADDSET_WB_TEMPBIAS] ? toEdit.wb.tempBias + mods.wb.tempBias : mods.wb.tempBias; } + if (wb.observer) { + toEdit.wb.observer = mods.wb.observer; + } + + if (wb.itcwb_thres) { + toEdit.wb.itcwb_thres = mods.wb.itcwb_thres; + } + + if (wb.itcwb_precis) { + toEdit.wb.itcwb_precis = mods.wb.itcwb_precis; + } + + if (wb.itcwb_size) { + toEdit.wb.itcwb_size = mods.wb.itcwb_size; + } + + if (wb.itcwb_delta) { + toEdit.wb.itcwb_delta = mods.wb.itcwb_delta; + } + + if (wb.itcwb_fgreen) { + toEdit.wb.itcwb_fgreen = mods.wb.itcwb_fgreen; + } + + if (wb.itcwb_rgreen) { + toEdit.wb.itcwb_rgreen = mods.wb.itcwb_rgreen; + } + + if (wb.itcwb_nopurple) { + toEdit.wb.itcwb_nopurple = mods.wb.itcwb_nopurple; + } + + if (wb.itcwb_sorted) { + toEdit.wb.itcwb_sorted = mods.wb.itcwb_sorted; + } + + if (wb.itcwb_forceextra) { + toEdit.wb.itcwb_forceextra = mods.wb.itcwb_forceextra; + } + + if (wb.itcwb_sampling) { + toEdit.wb.itcwb_sampling = mods.wb.itcwb_sampling; + } + if (wb.green) { toEdit.wb.green = dontforceSet && options.baBehav[ADDSET_WB_GREEN] ? toEdit.wb.green + mods.wb.green : mods.wb.green; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 66db8346f..d85bec701 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -246,7 +246,19 @@ struct WBParamsEdited { bool temperature; bool green; bool equal; + bool observer; bool tempBias; + bool itcwb_thres; + bool itcwb_precis; + bool itcwb_size; + bool itcwb_delta; + bool itcwb_fgreen; + bool itcwb_rgreen; + bool itcwb_nopurple; + bool itcwb_sorted; + bool itcwb_forceextra; + bool itcwb_sampling; + }; struct DefringeParamsEdited { diff --git a/rtgui/ppversion.h b/rtgui/ppversion.h index 162e63f9e..f2455699c 100644 --- a/rtgui/ppversion.h +++ b/rtgui/ppversion.h @@ -1,11 +1,13 @@ #pragma once // This number has to be incremented whenever the PP3 file format is modified or the behaviour of a tool changes -#define PPVERSION 349 +#define PPVERSION 350 #define PPVERSION_AEXP 301 //value of PPVERSION when auto exposure algorithm was modified /* Log of version changes + 350 2023-03-05 + introduced white balance standard observer 349 2020-10-29 replaced Haze removal Luminance checkbox with an adjuster to blend between luminance and normal mode 348 2018-09-25 diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index b04bee237..8c3290e5c 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -928,6 +928,10 @@ Gtk::Widget* Preferences::getColorManPanel () fcie->add(*gcie); vbColorMan->pack_start (*fcie, Gtk::PACK_SHRINK); + + + //------------- + swColorMan->add(*vbColorMan); return swColorMan; } @@ -1954,6 +1958,7 @@ void Preferences::fillPreferences() monBPC->set_active(moptions.rtSettings.monitorBPC); mcie->set_active(moptions.rtSettings.autocielab); + cbAutoMonProfile->set_active(moptions.rtSettings.autoMonitorProfile); #endif diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 90ea20da7..039c4d58a 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -135,6 +135,15 @@ class Preferences final : Gtk::CheckButton* cbdaubech; Gtk::SpinButton* hlThresh; Gtk::SpinButton* shThresh; +// Gtk::CheckButton* mwbacorr; + // Gtk::CheckButton* mwbaforc; + // Gtk::CheckButton* mwbanopurp; + +// Gtk::CheckButton* mwbasort; +// Gtk::SpinButton* wbacorrnb; +// Gtk::SpinButton* wbaprecis; +// Gtk::SpinButton* wbasizeref; +// Gtk::SpinButton* wbagreendelta; Gtk::SpinButton* panFactor; Gtk::CheckButton* rememberZoomPanCheckbutton; @@ -240,7 +249,7 @@ class Preferences final : Options moptions; sigc::connection tconn, sconn, fconn, cpfconn, addc, setc, dfconn, ffconn, bpconn, rpconn, ipconn; - sigc::connection autoMonProfileConn, sndEnableConn, langAutoDetectConn, autocielabConn; + sigc::connection autoMonProfileConn, sndEnableConn, langAutoDetectConn, autocielabConn, observer10Conn; Glib::ustring initialTheme; Glib::ustring initialFontFamily; int initialFontSize; @@ -305,6 +314,7 @@ public: void sndEnableToggled (); void langAutoDetectToggled (); void autocielabToggled (); + void observer10Toggled (); void selectStartupDir (); void addExtPressed (); diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 30766ebc9..dd7995feb 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -139,20 +139,20 @@ void Thumbnail::_generateThumbnailImage () if (ext == "jpg" || ext == "jpeg") { infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal, pparams->wb.observer); if (tpp) { cfs.format = FT_Jpeg; } } else if (ext == "png") { - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal, pparams->wb.observer); if (tpp) { cfs.format = FT_Png; } } else if (ext == "tif" || ext == "tiff") { infoFromImage (fname); - tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal); + tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, -1, pparams->wb.equal, pparams->wb.observer); if (tpp) { cfs.format = FT_Tiff; @@ -173,7 +173,7 @@ void Thumbnail::_generateThumbnailImage () if ( tpp == nullptr ) { quick = false; - tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, sensorType, tw, th, 1, pparams->wb.equal, TRUE); + tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, sensorType, tw, th, 1, pparams->wb.equal, pparams->wb.observer, TRUE); } cfs.sensortype = sensorType; @@ -216,11 +216,11 @@ const ProcParams& Thumbnail::getProcParamsU () if (pparams->wb.method == "Camera") { double ct; - getCamWB (ct, pparams->wb.green); + getCamWB (ct, pparams->wb.green, pparams->wb.observer); pparams->wb.temperature = ct; } else if (pparams->wb.method == "autold") { double ct; - getAutoWB (ct, pparams->wb.green, pparams->wb.equal, pparams->wb.tempBias); + getAutoWB (ct, pparams->wb.green, pparams->wb.equal, pparams->wb.observer, pparams->wb.tempBias); pparams->wb.temperature = ct; } } @@ -785,10 +785,10 @@ const Glib::DateTime& Thumbnail::getDateTime () const return dateTime; } -void Thumbnail::getAutoWB (double& temp, double& green, double equal, double tempBias) +void Thumbnail::getAutoWB (double& temp, double& green, double equal, rtengine::StandardObserver observer, double tempBias) { if (cfs.redAWBMul != -1.0) { - rtengine::ColorTemp ct(cfs.redAWBMul, cfs.greenAWBMul, cfs.blueAWBMul, equal); + rtengine::ColorTemp ct(cfs.redAWBMul, cfs.greenAWBMul, cfs.blueAWBMul, equal, observer); temp = ct.getTemp(); green = ct.getGreen(); } else { @@ -1155,10 +1155,10 @@ bool Thumbnail::imageLoad(bool loading) return false; } -void Thumbnail::getCamWB(double& temp, double& green) const +void Thumbnail::getCamWB(double& temp, double& green, rtengine::StandardObserver observer) const { if (tpp) { - tpp->getCamWB (temp, green); + tpp->getCamWB (temp, green, observer); } else { temp = green = -1.0; } diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index 491151028..4d0355747 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -127,8 +127,8 @@ public: const Glib::ustring& getExifString () const; const Glib::ustring& getDateTimeString () const; const Glib::DateTime& getDateTime () const; - void getCamWB (double& temp, double& green) const; - void getAutoWB (double& temp, double& green, double equal, double tempBias); + void getCamWB (double& temp, double& green, rtengine::StandardObserver observer) const; + void getAutoWB (double& temp, double& green, double equal, rtengine::StandardObserver observer, double tempBias); void getSpotWB (int x, int y, int rect, double& temp, double& green); void applyAutoExp (rtengine::procparams::ProcParams& pparams); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 276d9654e..7542343eb 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -398,16 +398,16 @@ public: void updateShowtooltipVisibility (bool showtooltip); // wbprovider interface - void getAutoWB (double& temp, double& green, double equal, double tempBias) override + void getAutoWB (double& temp, double& green, double equal, rtengine::StandardObserver observer, double tempBias) override { if (ipc) { - ipc->getAutoWB(temp, green, equal, tempBias); + ipc->getAutoWB(temp, green, equal, observer, tempBias); } } - void getCamWB (double& temp, double& green) override + void getCamWB (double& temp, double& green, rtengine::StandardObserver observer) override { if (ipc) { - ipc->getCamWB(temp, green); + ipc->getCamWB(temp, green, observer); } } diff --git a/rtgui/wbprovider.h b/rtgui/wbprovider.h index a56d93cd3..514a71300 100644 --- a/rtgui/wbprovider.h +++ b/rtgui/wbprovider.h @@ -18,12 +18,19 @@ */ #pragma once +namespace rtengine +{ + +enum class StandardObserver; + +} + class WBProvider { public: virtual ~WBProvider() {} - virtual void getAutoWB (double& temp, double& green, double equal, double tempBias) {} - virtual void getCamWB (double& temp, double& green) {} + virtual void getAutoWB (double& temp, double& green, double equal, rtengine::StandardObserver observer, double tempBias) {} + virtual void getCamWB (double& temp, double& green, rtengine::StandardObserver observer) {} virtual void spotWBRequested (int size) {} }; diff --git a/rtgui/whitebalance.cc b/rtgui/whitebalance.cc index f6a26e335..761f2402a 100644 --- a/rtgui/whitebalance.cc +++ b/rtgui/whitebalance.cc @@ -22,6 +22,9 @@ #include "rtimage.h" #include "options.h" +#include "eventmapper.h" + +#include "../rtengine/colortemp.h" #define MINTEMP 1500 //1200 #define MAXTEMP 60000 //12000 @@ -242,6 +245,10 @@ WhiteBalance::WhiteBalance () : FoldableToolPanel(this, TOOL_NAME, M("TP_WBALANC custom_equal = 1.0; } + auto m = ProcEventMapper::getInstance(); + EvWBObserver10 = m->newEvent(ALLNORAW, "HISTORY_MSG_WBALANCE_OBSERVER10"); + + //Add the model columns to the Combo (which is a kind of view), //rendering them in the default way: method->pack_start(methodColumns.colIcon, false); @@ -336,26 +343,35 @@ WhiteBalance::WhiteBalance () : FoldableToolPanel(this, TOOL_NAME, M("TP_WBALANC StudLabel = Gtk::manage(new Gtk::Label("---", Gtk::ALIGN_CENTER)); StudLabel->set_tooltip_text(M("TP_WBALANCE_STUDLABEL_TOOLTIP")); + mulLabel = Gtk::manage(new Gtk::Label("---", Gtk::ALIGN_CENTER)); + mulLabel->set_tooltip_text(M("TP_WBALANCE_MULLABEL_TOOLTIP")); + mulLabel->show(); + temp = Gtk::manage (new Adjuster (M("TP_WBALANCE_TEMPERATURE"), MINTEMP, MAXTEMP, 5, CENTERTEMP, itempL, itempR, &wbSlider2Temp, &wbTemp2Slider)); green = Gtk::manage (new Adjuster (M("TP_WBALANCE_GREEN"), MINGREEN, MAXGREEN, 0.001, 1.0, igreenL, igreenR)); equal = Gtk::manage (new Adjuster (M("TP_WBALANCE_EQBLUERED"), MINEQUAL, MAXEQUAL, 0.001, 1.0, iblueredL, iblueredR)); tempBias = Gtk::manage (new Adjuster(M("TP_WBALANCE_TEMPBIAS"), -0.5, 0.5, 0.01, 0.0, itempbiasL, itempbiasR)); + observer10 = Gtk::manage(new CheckBox(M("TP_WBALANCE_OBSERVER10"), multiImage)); + cache_customTemp (0); cache_customGreen (0); cache_customEqual (0); equal->set_tooltip_markup (M("TP_WBALANCE_EQBLUERED_TOOLTIP")); tempBias->set_tooltip_markup (M("TP_WBALANCE_TEMPBIAS_TOOLTIP")); + observer10->set_tooltip_text(M("TP_WBALANCE_OBSERVER10_TOOLTIP")); temp->show (); green->show (); equal->show (); tempBias->show (); - + observer10->show(); + /* Gtk::Box* boxgreen = Gtk::manage (new Gtk::Box ()); boxgreen->show (); boxgreen->pack_start(*igreenL); boxgreen->pack_start(*green); boxgreen->pack_start(*igreenR);*/ + pack_start(*mulLabel); pack_start(*StudLabel); pack_start (*temp); @@ -363,11 +379,14 @@ WhiteBalance::WhiteBalance () : FoldableToolPanel(this, TOOL_NAME, M("TP_WBALANC pack_start (*green); pack_start (*equal); pack_start (*tempBias); + pack_start(*observer10); + temp->setAdjusterListener (this); green->setAdjusterListener (this); equal->setAdjusterListener (this); tempBias->setAdjusterListener (this); + observer10->setCheckBoxListener(this); spotbutton->signal_pressed().connect( sigc::mem_fun(*this, &WhiteBalance::spotPressed) ); methconn = method->signal_changed().connect( sigc::mem_fun(*this, &WhiteBalance::optChanged) ); @@ -394,6 +413,8 @@ void WhiteBalance::enabledChanged() } + + void WhiteBalance::adjusterChanged(Adjuster* a, double newval) { int tVal = (int)temp->getValue(); @@ -456,6 +477,36 @@ void WhiteBalance::adjusterChanged(Adjuster* a, double newval) } } +void WhiteBalance::checkBoxToggled(CheckBox* c, CheckValue newval) +{ + if (!(getEnabled() && listener)) { + return; + } + + if (c == observer10) { + // If camera WB, update the temperature and tint according to observer. + const Gtk::TreeModel::Row row = getActiveMethod(); + unsigned int methodId = findWBEntryId(row[methodColumns.colLabel], WBLT_GUI); + const WBEntry &currMethod = WBParams::getWbEntries()[methodId]; + if (row[methodColumns.colLabel] != M("GENERAL_UNCHANGED") && currMethod.type == WBEntry::Type::CAMERA && wbp) { + double ctemp, cgreen; + wbp->getCamWB(ctemp, cgreen, + observer10->getValue() == CheckValue::off + ? rtengine::StandardObserver::TWO_DEGREES + : rtengine::StandardObserver::TEN_DEGREES); + temp->setValue(temp->getAddMode() ? 0.0 : static_cast(ctemp)); + green->setValue(green->getAddMode() ? 0.0 : cgreen); + } + + listener->panelChanged( + EvWBObserver10, + c->getValue() == CheckValue::on ? M("GENERAL_ENABLED") + : c->getValue() == CheckValue::off + ? M("GENERAL_DISABLED") + : M("GENERAL_UNCHANGED")); + } +} + void WhiteBalance::optChanged () { Gtk::TreeModel::Row row = getActiveMethod(); @@ -472,6 +523,7 @@ void WhiteBalance::optChanged () return; } StudLabel->hide(); + mulLabel->show(); if (opt != row[methodColumns.colId]) { @@ -482,6 +534,7 @@ void WhiteBalance::optChanged () green->setEditedState (UnEdited); equal->setEditedState (UnEdited); tempBias->setEditedState (UnEdited); + observer10->setEdited(false); } else { unsigned int methodId = findWBEntryId (row[methodColumns.colLabel], WBLT_GUI); const WBEntry& currMethod = WBParams::getWbEntries()[methodId]; @@ -498,7 +551,10 @@ void WhiteBalance::optChanged () case WBEntry::Type::CAMERA: if (wbp) { double ctemp, cgreen; - wbp->getCamWB (ctemp, cgreen); + wbp->getCamWB(ctemp, cgreen, + observer10->getValue() == CheckValue::off + ? rtengine::StandardObserver::TWO_DEGREES + : rtengine::StandardObserver::TEN_DEGREES); temp->setValue (temp->getAddMode() ? 0.0 : (int)ctemp); green->setValue (green->getAddMode() ? 0.0 : cgreen); equal->setValue (equal->getAddMode() ? 0.0 : 1.0); @@ -507,6 +563,7 @@ void WhiteBalance::optChanged () temp->setEditedState (UnEdited); green->setEditedState (UnEdited); equal->setEditedState (UnEdited); + observer10->setEdited(false); } } @@ -517,7 +574,7 @@ void WhiteBalance::optChanged () if (batchMode) { temp->setEditedState (UnEdited); green->setEditedState (UnEdited); - // equal remain as is + // equal and observer remain as is } // Recomputing AutoWB will happen in improccoordinator.cc @@ -540,6 +597,7 @@ void WhiteBalance::optChanged () temp->setEditedState (Edited); green->setEditedState (Edited); equal->setEditedState (Edited); + observer10->setEdited(true); } break; @@ -563,6 +621,7 @@ void WhiteBalance::optChanged () temp->setEditedState (Edited); green->setEditedState (Edited); equal->setEditedState (Edited); + observer10->setEdited(true); } break; @@ -578,6 +637,7 @@ void WhiteBalance::optChanged () void WhiteBalance::spotPressed () { StudLabel->hide(); + mulLabel->show(); if (wblistener) { wblistener->spotWBRequested (getSize()); @@ -599,6 +659,7 @@ void WhiteBalance::read (const ProcParams* pp, const ParamsEdited* pedited) methconn.block (true); equal->setValue (pp->wb.equal); + observer10->setValue(rtengine::StandardObserver::TEN_DEGREES == pp->wb.observer); tempBias->setValue (pp->wb.tempBias); tempBias->set_sensitive(true); @@ -608,6 +669,7 @@ void WhiteBalance::read (const ProcParams* pp, const ParamsEdited* pedited) green->setEditedState (UnEdited); equal->setEditedState (pedited->wb.equal ? Edited : UnEdited); tempBias->setEditedState (pedited->wb.tempBias ? Edited : UnEdited); + observer10->setEdited(pedited->wb.observer); } if (pedited && !pedited->wb.method) { @@ -648,7 +710,7 @@ void WhiteBalance::read (const ProcParams* pp, const ParamsEdited* pedited) if (wbp) { double ctemp = -1.0; double cgreen = -1.0; - wbp->getCamWB (ctemp, cgreen); + wbp->getCamWB (ctemp, cgreen, pp->wb.observer); if (ctemp != -1.0) { // Set the camera's temperature value, or 0.0 if in ADD mode @@ -720,6 +782,7 @@ void WhiteBalance::read (const ProcParams* pp, const ParamsEdited* pedited) StudLabel->show(); } else { StudLabel->hide(); + mulLabel->show(); } } @@ -744,6 +807,7 @@ void WhiteBalance::write (ProcParams* pp, ParamsEdited* pedited) pedited->wb.green = green->getEditedState (); pedited->wb.equal = equal->getEditedState (); pedited->wb.tempBias = tempBias->getEditedState (); + pedited->wb.observer = observer10->getEdited(); pedited->wb.method = row[methodColumns.colLabel] != M("GENERAL_UNCHANGED"); pedited->wb.enabled = !get_inconsistent(); } @@ -759,6 +823,12 @@ void WhiteBalance::write (ProcParams* pp, ParamsEdited* pedited) pp->wb.temperature = temp->getIntValue (); pp->wb.green = green->getValue (); pp->wb.equal = equal->getValue (); + pp->wb.observer = + observer10->getValue() == CheckValue::on + ? rtengine::StandardObserver::TEN_DEGREES + : observer10->getValue() == CheckValue::off + ? rtengine::StandardObserver::TWO_DEGREES + : pp->wb.observer; pp->wb.tempBias = tempBias->getValue (); } @@ -771,7 +841,7 @@ void WhiteBalance::setDefaults (const ProcParams* defParams, const ParamsEdited* if (wbp && defParams->wb.method == "Camera") { double ctemp; double cgreen; - wbp->getCamWB (ctemp, cgreen); + wbp->getCamWB (ctemp, cgreen, defParams->wb.observer); // FIXME: Seems to be always -1.0, called too early? Broken! if (ctemp != -1.0) { @@ -945,14 +1015,20 @@ inline Gtk::TreeRow WhiteBalance::getActiveMethod () return *(method->get_active()); } -void WhiteBalance::WBChanged(double temperature, double greenVal, float studgood) +void WhiteBalance::WBChanged(double temperature, double greenVal, double rw, double gw, double bw, float studgood) { idle_register.add( - [this, temperature, greenVal, studgood]() -> bool + [this, temperature, greenVal, rw, gw, bw, studgood]() -> bool { disableListener(); temp->setValue(temperature); green->setValue(greenVal); + mulLabel->set_text( + Glib::ustring::compose(M("TP_WBALANCE_MULLABEL"), + Glib::ustring::format(std::fixed, std::setprecision(4), rw), + Glib::ustring::format(std::fixed, std::setprecision(2), gw), + Glib::ustring::format(std::fixed, std::setprecision(4), bw)) + ); StudLabel->set_text( Glib::ustring::compose(M("TP_WBALANCE_STUDLABEL"), Glib::ustring::format(std::fixed, std::setprecision(4), studgood)) diff --git a/rtgui/whitebalance.h b/rtgui/whitebalance.h index f172590c8..56d8b646c 100644 --- a/rtgui/whitebalance.h +++ b/rtgui/whitebalance.h @@ -21,6 +21,7 @@ #include #include "adjuster.h" +#include "checkbox.h" #include "guiutils.h" #include "toolpanel.h" #include "wbprovider.h" @@ -35,7 +36,7 @@ public: virtual void spotWBRequested(int size) = 0; }; -class WhiteBalance final : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public rtengine::AutoWBListener +class WhiteBalance final : public ToolParamBlock, public AdjusterListener, public CheckBoxListener, public FoldableToolPanel, public rtengine::AutoWBListener { enum WB_LabelType { @@ -45,6 +46,7 @@ class WhiteBalance final : public ToolParamBlock, public AdjusterListener, publi private: Gtk::Label* StudLabel; + Gtk::Label* mulLabel; protected: class MethodColumns : public Gtk::TreeModel::ColumnRecord @@ -60,6 +62,8 @@ protected: add(colId); } }; + + rtengine::ProcEvent EvWBObserver10; static Glib::RefPtr wbPixbufs[rtengine::toUnderlying(rtengine::procparams::WBEntry::Type::CUSTOM) + 1]; Glib::RefPtr refTreeModel; @@ -71,6 +75,7 @@ protected: Adjuster* green; Adjuster* equal; Adjuster* tempBias; + CheckBox* observer10; Gtk::Button* spotbutton; int opt; @@ -114,6 +119,7 @@ public: void spotPressed (); void spotSizeChanged (); void adjusterChanged(Adjuster* a, double newval) override; + void checkBoxToggled(CheckBox* c, CheckValue newval) override; int getSize (); void setWBProvider (WBProvider* p) { @@ -125,7 +131,7 @@ public: } void setWB (int temp, double green); void resetWB (); - void WBChanged (double temp, double green, float studgood) override; + void WBChanged (double temp, double green, double rw, double gw, double bw, float studgood) override; void setAdjusterBehavior (bool tempadd, bool greenadd, bool equaladd, bool tempbiasadd); void trimValues (rtengine::procparams::ProcParams* pp) override; From 5481a8bbe1f9df2ae71a2aae4ddc67bed1390192 Mon Sep 17 00:00:00 2001 From: Desmis Date: Mon, 20 Mar 2023 07:38:48 +0100 Subject: [PATCH 07/14] Ciecam - Fixed issue #6713 and add some batch functions (#6717) * Try to solve issue 6713 ans add some batch functions * Missing setAddMode tempout --- rtdata/languages/default | 3 ++- rtgui/addsetids.h | 2 ++ rtgui/batchtoolpanelcoord.cc | 6 ++++-- rtgui/colorappearance.cc | 35 +++++++++++++++++++++-------------- rtgui/colorappearance.h | 2 +- rtgui/paramsedited.cc | 4 ++-- rtgui/preferences.cc | 7 +++++-- 7 files changed, 37 insertions(+), 22 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 9fe9975d9..541d94031 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2206,7 +2206,8 @@ TP_COLORAPP_CHROMA_M_TOOLTIP;Colorfulness in CIECAM is the perceived amount of h TP_COLORAPP_CHROMA_S;Saturation (S) TP_COLORAPP_CHROMA_S_TOOLTIP;Saturation in CIECAM corresponds to the color of a stimulus in relation to its own brightness. It differs from L*a*b* and RGB saturation. TP_COLORAPP_CHROMA_TOOLTIP;Chroma in CIECAM corresponds to the color of a stimulus relative to the clarity of a stimulus that appears white under identical conditions. It differs from L*a*b* and RGB chroma. -TP_COLORAPP_CIECAT_DEGREE;Adaptation +TP_COLORAPP_CIECAT_DEGREE;Chromatic Adaptation Scene +TP_COLORAPP_CIECAT_DEGREEOUT;Chromatic Adaptation Viewing TP_COLORAPP_CONTRAST;Contrast (J) TP_COLORAPP_CONTRAST_Q;Contrast (Q) TP_COLORAPP_CONTRAST_Q_TOOLTIP;Contrast (Q) in CIECAM is based on brightness. It differs from L*a*b* and RGB contrast. diff --git a/rtgui/addsetids.h b/rtgui/addsetids.h index 6f68c6ae7..31097931a 100644 --- a/rtgui/addsetids.h +++ b/rtgui/addsetids.h @@ -65,6 +65,8 @@ enum { ADDSET_CAT_CHROMA_S, ADDSET_CAT_CHROMA_M, ADDSET_CAT_HUE, + ADDSET_CAT_DEGREEOUT, + ADDSET_CAT_TEMPOUT, ADDSET_CAT_BADPIX, ADDSET_WB_EQUAL, ADDSET_GRADIENT_DEGREE, diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index 58532f68a..297608896 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -148,7 +148,7 @@ void BatchToolPanelCoordinator::initSession () whitebalance->setAdjusterBehavior (false, false, false, false); vibrance->setAdjusterBehavior (false, false); vignetting->setAdjusterBehavior (false, false, false, false); - colorappearance->setAdjusterBehavior (false, false, false, false, false, false, false, false, false, false, false, false, false); + colorappearance->setAdjusterBehavior (false, false, false, false, false, false, false, false, false, false, false, false, false, false, false); rotate->setAdjusterBehavior (false); resize->setAdjusterBehavior (false); distortion->setAdjusterBehavior (false); @@ -193,7 +193,7 @@ void BatchToolPanelCoordinator::initSession () whitebalance->setAdjusterBehavior (options.baBehav[ADDSET_WB_TEMPERATURE], options.baBehav[ADDSET_WB_GREEN], options.baBehav[ADDSET_WB_EQUAL], options.baBehav[ADDSET_WB_TEMPBIAS]); vibrance->setAdjusterBehavior (options.baBehav[ADDSET_VIBRANCE_PASTELS], options.baBehav[ADDSET_VIBRANCE_SATURATED]); vignetting->setAdjusterBehavior (options.baBehav[ADDSET_VIGN_AMOUNT], options.baBehav[ADDSET_VIGN_RADIUS], options.baBehav[ADDSET_VIGN_STRENGTH], options.baBehav[ADDSET_VIGN_CENTER]); - colorappearance->setAdjusterBehavior (options.baBehav[ADDSET_CAT_DEGREE], options.baBehav[ADDSET_CAT_ADAPTSCENE], options.baBehav[ADDSET_CAT_ADAPTVIEWING], options.baBehav[ADDSET_CAT_BADPIX], options.baBehav[ADDSET_CAT_LIGHT], options.baBehav[ADDSET_CAT_CHROMA], options.baBehav[ADDSET_CAT_CONTRAST], options.baBehav[ADDSET_CAT_RSTPRO], options.baBehav[ADDSET_CAT_BRIGHT], options.baBehav[ADDSET_CAT_CONTRAST_Q], options.baBehav[ADDSET_CAT_CHROMA_S], options.baBehav[ADDSET_CAT_CHROMA_M], options.baBehav[ADDSET_CAT_HUE]); + colorappearance->setAdjusterBehavior (options.baBehav[ADDSET_CAT_DEGREE], options.baBehav[ADDSET_CAT_ADAPTSCENE], options.baBehav[ADDSET_CAT_ADAPTVIEWING], options.baBehav[ADDSET_CAT_BADPIX], options.baBehav[ADDSET_CAT_LIGHT], options.baBehav[ADDSET_CAT_CHROMA], options.baBehav[ADDSET_CAT_CONTRAST], options.baBehav[ADDSET_CAT_RSTPRO], options.baBehav[ADDSET_CAT_BRIGHT], options.baBehav[ADDSET_CAT_CONTRAST_Q], options.baBehav[ADDSET_CAT_CHROMA_S], options.baBehav[ADDSET_CAT_CHROMA_M], options.baBehav[ADDSET_CAT_HUE],options.baBehav[ADDSET_CAT_DEGREEOUT], options.baBehav[ADDSET_CAT_TEMPOUT] ); rotate->setAdjusterBehavior (options.baBehav[ADDSET_ROTATE_DEGREE]); resize->setAdjusterBehavior (options.baBehav[ADDSET_RESIZE_SCALE]); distortion->setAdjusterBehavior (options.baBehav[ADDSET_DIST_AMOUNT]); @@ -289,6 +289,8 @@ void BatchToolPanelCoordinator::initSession () if (options.baBehav[ADDSET_CAT_CONTRAST]) { pparams.colorappearance.contrast = 0; } if (options.baBehav[ADDSET_CAT_CONTRAST_Q]) { pparams.colorappearance.qcontrast = 0; } if (options.baBehav[ADDSET_CAT_HUE]) { pparams.colorappearance.colorh = 0; } + if (options.baBehav[ADDSET_CAT_DEGREEOUT]) { pparams.colorappearance.degreeout = 0; } + if (options.baBehav[ADDSET_CAT_TEMPOUT]) { pparams.colorappearance.tempout = 0; } //if (options.baBehav[ADDSET_CBOOST_AMOUNT]) pparams.colorBoost.amount = 0; //if (options.baBehav[ADDSET_CS_BLUEYELLOW]) pparams.colorShift.a = 0; //if (options.baBehav[ADDSET_CS_GREENMAGENTA]) pparams.colorShift.b = 0; diff --git a/rtgui/colorappearance.cc b/rtgui/colorappearance.cc index 5531a55c8..41f6952a7 100644 --- a/rtgui/colorappearance.cc +++ b/rtgui/colorappearance.cc @@ -662,7 +662,7 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, TOOL_NAME, M ("TP // Gtk::Image* iblueredL = Gtk::manage (new RTImage ("circle-blue-small.png")); // Gtk::Image* iblueredR = Gtk::manage (new RTImage ("circle-red-small.png")); - degreeout = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CIECAT_DEGREE"), 0., 100., 1., 90.)); + degreeout = Gtk::manage (new Adjuster (M ("TP_COLORAPP_CIECAT_DEGREEOUT"), 0., 100., 1., 90.)); // degreeout->setDelay(std::max(options.adjusterMinDelay, options.adjusterMaxDelay)); @@ -683,9 +683,9 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, TOOL_NAME, M ("TP ybout->set_tooltip_markup (M ("TP_COLORAPP_YBOUT_TOOLTIP")); tempout->set_tooltip_markup (M ("TP_COLORAPP_TEMP2_TOOLTIP")); - tempout->throwOnButtonRelease(); +// tempout->throwOnButtonRelease(); tempout->addAutoButton (M ("TP_COLORAPP_TEMPOUT_TOOLTIP")); - // I renable tempout with addautobutton to work properly (and all code disabled). There are certainly some redundancies, but it doesn't matter + // I renable tempout with addautobutton to work properly (and all code disabled). There are certainly some redundancies, but it doesn't matter tempout->show(); greenout->show(); ybout->show(); @@ -696,8 +696,8 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, TOOL_NAME, M ("TP tempgreenVBox = Gtk::manage ( new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); tempgreenVBox->set_spacing (2); tempgreenVBox->pack_start (*tempout); - tempgreenVBox->pack_start (*greenout); - tempgreenFrame->add(*tempgreenVBox); + tempgreenVBox->pack_start (*greenout); + tempgreenFrame->add(*tempgreenVBox); p3VBox->pack_start(*tempgreenFrame); p3VBox->pack_start (*ybout); @@ -832,7 +832,7 @@ void ColorAppearance::neutral_pressed () qcontrast->resetValue (false); colorh->resetValue (false); tempout->resetValue (false); - tempout->setAutoValue (true); + tempout->setAutoValue (true); greenout->resetValue (false); ybout->resetValue (false); tempsc->resetValue (false); @@ -893,6 +893,7 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) if (pedited) { degree->setEditedState (pedited->colorappearance.degree ? Edited : UnEdited); degreeout->setEditedState (pedited->colorappearance.degreeout ? Edited : UnEdited); + tempout->setEditedState (pedited->colorappearance.tempout ? Edited : UnEdited); adapscen->setEditedState (pedited->colorappearance.adapscen ? Edited : UnEdited); ybscen->setEditedState (pedited->colorappearance.ybscen ? Edited : UnEdited); adaplum->setEditedState (pedited->colorappearance.adaplum ? Edited : UnEdited); @@ -1131,7 +1132,7 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) qcontrast->setValue (pp->colorappearance.qcontrast); colorh->setValue (pp->colorappearance.colorh); tempout->setValue (pp->colorappearance.tempout); - tempout->setAutoValue (pp->colorappearance.autotempout); + tempout->setAutoValue (pp->colorappearance.autotempout); greenout->setValue (pp->colorappearance.greenout); ybout->setValue (pp->colorappearance.ybout); tempsc->setValue (pp->colorappearance.tempsc); @@ -1483,12 +1484,14 @@ void ColorAppearance::catmethodChanged() ybout->setValue(18); tempout->setValue (nexttemp); - if(tempout->getAutoValue()) { - tempout->resetValue (false); - } else { - tempout->setValue (nexttemp); - tempout->setAutoValue (true); - } + if(tempout->getAutoValue()) { + tempout->resetValue (false); + tempout->setAutoValue (true); + } else { + tempout->resetValue (false); + tempout->setValue (nexttemp); + tempout->setAutoValue (true); + } greenout->setValue (nextgreen); enableListener(); @@ -1515,6 +1518,7 @@ void ColorAppearance::catmethodChanged() degreeout->resetValue (false); ybout->resetValue (false); tempout->resetValue (false); + tempout->setAutoValue (true); greenout->resetValue (false); enableListener(); } else if (catmethod->get_active_row_number() == 2) { @@ -2311,7 +2315,7 @@ void ColorAppearance::updateCurveBackgroundHistogram( -void ColorAppearance::setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool badpixsladd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd) +void ColorAppearance::setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool badpixsladd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd, bool degreeoutadd, bool tempoutadd) { degree->setAddMode (degreeadd); @@ -2327,6 +2331,9 @@ void ColorAppearance::setAdjusterBehavior (bool degreeadd, bool adapscenadd, boo contrast->setAddMode (contrastadd); qcontrast->setAddMode (qcontrastadd); colorh->setAddMode (colorhadd); + degreeout->setAddMode (degreeoutadd); + tempout->setAddMode (tempoutadd); + } void ColorAppearance::trimValues (rtengine::procparams::ProcParams* pp) diff --git a/rtgui/colorappearance.h b/rtgui/colorappearance.h index dcf19b977..714f3e557 100644 --- a/rtgui/colorappearance.h +++ b/rtgui/colorappearance.h @@ -88,7 +88,7 @@ public: bool isCurveExpanded (); void autoOpenCurve () override; - void setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool badpixsladd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd); + void setAdjusterBehavior (bool degreeadd, bool adapscenadd, bool adaplumadd, bool badpixsladd, bool jlightadd, bool chromaadd, bool contrastadd, bool rstprotectionadd, bool qbrightadd, bool qcontrastadd, bool schromaadd, bool mchromaadd, bool colorhadd, bool degreeoutadd, bool tempoutadd); void trimValues (rtengine::procparams::ProcParams* pp) override; void updateCurveBackgroundHistogram( const LUTu& histToneCurve, diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index c3638cc5f..20450fa24 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -2976,7 +2976,7 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng } if (colorappearance.degreeout) { - toEdit.colorappearance.degreeout = mods.colorappearance.degreeout; + toEdit.colorappearance.degreeout = dontforceSet && options.baBehav[ADDSET_CAT_DEGREEOUT] ? toEdit.colorappearance.degreeout + mods.colorappearance.degreeout : mods.colorappearance.degreeout; } if (colorappearance.autodegreeout) { @@ -3028,7 +3028,7 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng } if (colorappearance.tempout) { - toEdit.colorappearance.tempout = mods.colorappearance.tempout; + toEdit.colorappearance.tempout = dontforceSet && options.baBehav[ADDSET_CAT_TEMPOUT] ? toEdit.colorappearance.tempout + mods.colorappearance.tempout : mods.colorappearance.tempout; } if (colorappearance.autotempout) { diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 8c3290e5c..9a5937881 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -291,15 +291,18 @@ Gtk::Widget* Preferences::getBatchProcPanel() mi->set_value(behavColumns.label, M("TP_COLORAPP_LABEL")); appendBehavList (mi, M("TP_COLORAPP_LABEL_SCENE") + " - " + M("TP_COLORAPP_ABSOLUTELUMINANCE"), ADDSET_CAT_ADAPTSCENE, true); appendBehavList (mi, M("TP_COLORAPP_LABEL_VIEWING") + " - " + M("TP_COLORAPP_ABSOLUTELUMINANCE"), ADDSET_CAT_ADAPTVIEWING, true); + appendBehavList(mi, M("TP_COLORAPP_CIECAT_DEGREE"), ADDSET_CAT_DEGREE, true); appendBehavList(mi, M("TP_COLORAPP_LIGHT"), ADDSET_CAT_LIGHT, true); appendBehavList(mi, M("TP_COLORAPP_BRIGHT"), ADDSET_CAT_BRIGHT, true); appendBehavList(mi, M("TP_COLORAPP_CHROMA"), ADDSET_CAT_CHROMA, true); - appendBehavList (mi, M ("TP_COLORAPP_CHROMA_S"), ADDSET_CAT_CHROMA_S, true); - appendBehavList (mi, M ("TP_COLORAPP_CHROMA_M"), ADDSET_CAT_CHROMA_M, true); + appendBehavList(mi, M ("TP_COLORAPP_CHROMA_S"), ADDSET_CAT_CHROMA_S, true); + appendBehavList(mi, M ("TP_COLORAPP_CHROMA_M"), ADDSET_CAT_CHROMA_M, true); appendBehavList(mi, M("TP_COLORAPP_RSTPRO"), ADDSET_CAT_RSTPRO, true); appendBehavList(mi, M("TP_COLORAPP_CONTRAST"), ADDSET_CAT_CONTRAST, true); appendBehavList(mi, M("TP_COLORAPP_CONTRAST_Q"), ADDSET_CAT_CONTRAST_Q, true); appendBehavList(mi, M("TP_COLORAPP_HUE"), ADDSET_CAT_HUE, true); + appendBehavList(mi, M("TP_COLORAPP_CIECAT_DEGREEOUT"), ADDSET_CAT_DEGREEOUT, true); + appendBehavList(mi, M("TP_WBALANCE_TEMPERATURE"), ADDSET_CAT_TEMPOUT, true); appendBehavList(mi, M("TP_COLORAPP_BADPIXSL"), ADDSET_CAT_BADPIX, true); mi = behModel->append(); From cfabedc4e9b476f37aa5779d828cb211b0289b3f Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 19 Mar 2023 15:37:33 -0700 Subject: [PATCH 08/14] Add pre-dev publishing to Actions workflows --- .github/workflows/appimage.yml | 32 +++++++++++++++++++++++++ .github/workflows/windows.yml | 43 ++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index cc0d16b8f..8fd7608f9 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -10,6 +10,8 @@ on: branches: - dev workflow_dispatch: +env: + publish_pre_dev_labels: '[]' jobs: build: runs-on: ubuntu-18.04 @@ -167,3 +169,33 @@ jobs: files: | ${{env.PUBLISH_NAME}}.AppImage ${{env.PUBLISH_NAME}}-AboutThisBuild.txt + + - name: Prepare for publishing pre-dev + id: prepare-publish-pre-dev + if: ${{github.event_name == 'pull_request' && contains(fromJSON(env.publish_pre_dev_labels), github.event.pull_request.head.label)}} + run: | + echo "Making ref name." + REF_NAME_FILTERED="$(echo '${{github.event.pull_request.head.label}}' | tr ':' '_' | sed 's/[^A-z0-9_.-]//g')" + echo "Ref name is '$REF_NAME_FILTERED'." + + echo "Setting publish name." + PUBLISH_NAME="RawTherapee_${REF_NAME_FILTERED}_${{matrix.build_type}}" + echo "Publish name is '$PUBLISH_NAME'." + + echo "Renaming AppImage." + cp "build/$ARTIFACT_NAME.AppImage" "$PUBLISH_NAME.AppImage" + + echo "Creating version file." + cp "build/AboutThisBuild.txt" "$PUBLISH_NAME-AppImage-AboutThisBuild.txt" + + echo "Recording publish name." + echo "PUBLISH_NAME=$PUBLISH_NAME" >> $GITHUB_ENV + + - name: Publish pre-dev artifacts + uses: softprops/action-gh-release@v1 + if: ${{steps.prepare-publish-pre-dev.outcome == 'success'}} + with: + tag_name: pre-dev-github-actions + files: | + ${{env.PUBLISH_NAME}}.AppImage + ${{env.PUBLISH_NAME}}-AppImage-AboutThisBuild.txt diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 49fdf5999..a14c23993 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -10,6 +10,8 @@ on: branches: - dev workflow_dispatch: +env: + publish_pre_dev_labels: '[]' jobs: build: runs-on: windows-2022 @@ -300,3 +302,44 @@ jobs: with: tag_name: nightly-github-actions files: build/${{env.PUBLISH_NAME}}.exe + + - name: Prepare for publishing pre-dev + id: prepare-publish-pre-dev + if: ${{github.event_name == 'pull_request' && contains(fromJSON(env.publish_pre_dev_labels), github.event.pull_request.head.label)}} + run: | + echo "Making ref name." + REF_NAME_FILTERED="$(echo '${{github.event.pull_request.head.label}}' | tr ':' '_' | sed 's/[^A-z0-9_.-]//g')" + echo "Ref name is '$REF_NAME_FILTERED'." + + echo "Setting publish name." + PUBLISH_NAME="RawTherapee_${REF_NAME_FILTERED}_win64_${{matrix.build_type}}" + echo "Publish name is '$PUBLISH_NAME'." + if [ "$ARTIFACT_NAME" != "$PUBLISH_NAME" ]; then + echo "Renaming ZIP file." + cp "build/$ARTIFACT_NAME.zip" "build/$PUBLISH_NAME.zip" + if [ -e "./build/$ARTIFACT_NAME.exe" ]; then + echo "Renaming installer." + mv "./build/$ARTIFACT_NAME.exe" "./build/$PUBLISH_NAME.exe" + fi + fi + echo "Creating version file." + cp "build/$ARTIFACT_NAME/AboutThisBuild.txt" "build/$PUBLISH_NAME-AboutThisBuild.txt" + + echo "Recording publish name." + echo "PUBLISH_NAME=$PUBLISH_NAME" >> "$(cygpath -u $GITHUB_ENV)" + + - name: Publish pre-dev artifacts + uses: softprops/action-gh-release@v1 + if: ${{steps.prepare-publish-pre-dev.outcome == 'success'}} + with: + tag_name: pre-dev-github-actions + files: | + build/${{env.PUBLISH_NAME}}.zip + build/${{env.PUBLISH_NAME}}-AboutThisBuild.txt + + - name: Publish pre-dev installer + uses: softprops/action-gh-release@v1 + if: ${{steps.prepare-publish-pre-dev.outcome == 'success' && matrix.build_type == 'release'}} + with: + tag_name: pre-dev-github-actions + files: build/${{env.PUBLISH_NAME}}.exe From 223b136082ba2d61273058351232a6b37ea7a283 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 25 Mar 2023 12:11:19 -0700 Subject: [PATCH 09/14] Fix Windows workflow Adwaita error Update paths to match those of the Adwaita icon theme library. --- .github/workflows/windows.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index a14c23993..4ab10212c 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -178,15 +178,15 @@ jobs: echo "Copying Adwaita theme." mkdir -p "$BUILD_DIR/share/icons/Adwaita" cd 'share/icons/Adwaita/' - mkdir -p "$BUILD_DIR/share/icons/Adwaita/scalable" + mkdir -p "$BUILD_DIR/share/icons/Adwaita/symbolic" cp -r \ - "scalable/actions" \ - "scalable/devices" \ - "scalable/mimetypes" \ - "scalable/places" \ - "scalable/status" \ - "scalable/ui" \ - "$BUILD_DIR/share/icons/Adwaita/scalable" + "symbolic/actions" \ + "symbolic/devices" \ + "symbolic/mimetypes" \ + "symbolic/places" \ + "symbolic/status" \ + "symbolic/ui" \ + "$BUILD_DIR/share/icons/Adwaita/symbolic" cp 'index.theme' "$BUILD_DIR/share/icons/Adwaita" mkdir -p "$BUILD_DIR/share/icons/Adwaita/cursors" cp -r \ From ae4de4701f5b0d8303d67e15822f453f99d3f02a Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sun, 6 Dec 2020 09:37:34 +0100 Subject: [PATCH 10/14] Fix color-cast regression Fix checking of existence of second masked area. Issue #6720. --- rtengine/camconst.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/rtengine/camconst.cc b/rtengine/camconst.cc index 64fc4d4ba..5cb56b2ae 100644 --- a/rtengine/camconst.cc +++ b/rtengine/camconst.cc @@ -224,7 +224,7 @@ CameraConst* CameraConst::parseEntry(const void *cJSON_, const char *make_model) const auto get_masked_areas = [](int w, int h, const cJSON *ji, CameraConst *cc) -> bool { - std::array, 2> rm; + std::array, 2> rm = {}; if (ji->type != cJSON_Array) { //fprintf(stderr, "\"masked_areas\" must be an array\n"); @@ -505,7 +505,15 @@ bool CameraConst::has_rawMask(int raw_width, int raw_height, int idx) const return false; } - return raw_mask.find(std::make_pair(raw_width, raw_height)) != raw_mask.end() || raw_mask.find(std::make_pair(0, 0)) != raw_mask.end(); + auto it = raw_mask.find(std::make_pair(raw_width, raw_height)); + if (it == raw_mask.end()) { + it = raw_mask.find(std::make_pair(0, 0)); + } + if (it != raw_mask.end()) { + return (it->second[idx][0] | it->second[idx][1] | it->second[idx][2] | it->second[idx][3]) != 0; + } else { + return false; + } } From 1abbfceb8e5a241efc12e28cff9f5e9a1d6e0b97 Mon Sep 17 00:00:00 2001 From: Bezierr Date: Mon, 27 Mar 2023 13:23:21 +0200 Subject: [PATCH 11/14] Name added to AUTHORS.txt As suggested by Lawrence37 --- AUTHORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 059bdce17..3d16899a6 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -5,6 +5,7 @@ Project initiator: Development contributors, in last name alphabetical order: + Harald Aust Roel Baars Martin Burri Pierre Cabrera From 1dbd9818cf6d0c2b8b77bb29ccc721cc86d096af Mon Sep 17 00:00:00 2001 From: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> Date: Mon, 3 Apr 2023 20:16:39 -0700 Subject: [PATCH 12/14] Set AppImage runner to Ubuntu 20.04 Ubuntu 18.04 is no longer available in GitHub Actions. --- .github/workflows/appimage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index 8fd7608f9..9ad9a6cbd 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -14,7 +14,7 @@ env: publish_pre_dev_labels: '[]' jobs: build: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 strategy: fail-fast: false matrix: From 19f12f3182d3c2e4a648c607da4a0ac7fb9346ec Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 8 Apr 2023 18:16:23 -0700 Subject: [PATCH 13/14] Allow native commands as external editors If an editor is marked as a native command, it is launched using the older method (native for Windows or Glib otherwise). Non-native commands are launched with Gio. When reading preferences containing the old style external editor settings, all commands are marked as native to avoid breaking them. Fix bug where the send to editor button shows the wrong editor. The bug happens when the other editor option is selected while the user edits the external editors in preferences. When saved, the button shows the first option is selected instead of the other editor option (the last entry). --- rtdata/languages/default | 3 ++- rtgui/editorpanel.cc | 4 ++- rtgui/editorpanel.h | 1 + rtgui/externaleditorpreferences.cc | 39 +++++++++++++++++++++------ rtgui/externaleditorpreferences.h | 10 +++++++ rtgui/extprog.cc | 14 +++++++++- rtgui/extprog.h | 2 +- rtgui/options.cc | 43 +++++++++++++++++++----------- rtgui/options.h | 3 ++- rtgui/preferences.cc | 10 ++++--- 10 files changed, 97 insertions(+), 32 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 8f3a59097..45471bb5c 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1883,8 +1883,9 @@ PREFERENCES_EXTEDITOR_FLOAT32;32-bit float TIFF output PREFERENCES_EXTERNALEDITOR;External Editor PREFERENCES_EXTERNALEDITOR_CHANGE;Change Application PREFERENCES_EXTERNALEDITOR_CHANGE_FILE;Change Executable -PREFERENCES_EXTERNALEDITOR_COLUMN_NAME;Name PREFERENCES_EXTERNALEDITOR_COLUMN_COMMAND;Command +PREFERENCES_EXTERNALEDITOR_COLUMN_NAME;Name +PREFERENCES_EXTERNALEDITOR_COLUMN_NATIVE_COMMAND;Native command PREFERENCES_FBROWSEROPTS;File Browser / Thumbnail Options PREFERENCES_FILEBROWSERTOOLBARSINGLEROW;Compact toolbars in File Browser PREFERENCES_FLATFIELDFOUND;Found diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index ffe13fea3..420717b7e 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2250,6 +2250,7 @@ void EditorPanel::sendToExternalPressed() } else { struct ExternalEditor editor = options.externalEditors.at(options.externalEditorIndex); external_editor_info = Gio::AppInfo::create_from_commandline(editor.command, editor.name, Gio::APP_INFO_CREATE_NONE); + external_editor_native_command = editor.native_command; sendToExternal(); } } @@ -2415,7 +2416,7 @@ bool EditorPanel::idle_sentToGimp (ProgressConnector *pc, rtengine::IImagef setUserOnlyPermission(Gio::File::create_for_path(filename), false); - success = ExtProgStore::openInExternalEditor(filename, external_editor_info); + success = ExtProgStore::openInExternalEditor(filename, external_editor_info, external_editor_native_command); if (!success) { Gtk::MessageDialog msgd (*parent, M ("MAIN_MSG_CANNOTSTARTEDITOR"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); @@ -2447,6 +2448,7 @@ void EditorPanel::onAppChooserDialogResponse(int responseId) case Gtk::RESPONSE_OK: getAppChooserDialog()->close(); external_editor_info = getAppChooserDialog()->get_app_info(); + external_editor_native_command = false; sendToExternal(); break; case Gtk::RESPONSE_CANCEL: diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 98a475a7c..309f14e8c 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -253,6 +253,7 @@ private: Gtk::Button* navNext; Gtk::Button* navPrev; Glib::RefPtr external_editor_info; + bool external_editor_native_command; std::unique_ptr app_chooser_dialog; ExternalEditorChangedSignal *externalEditorChangedSignal; sigc::connection externalEditorChangedSignalConnection; diff --git a/rtgui/externaleditorpreferences.cc b/rtgui/externaleditorpreferences.cc index 79dac52d2..55c9f7956 100644 --- a/rtgui/externaleditorpreferences.cc +++ b/rtgui/externaleditorpreferences.cc @@ -37,6 +37,7 @@ ExternalEditorPreferences::ExternalEditorPreferences(): list_view = Gtk::manage(new Gtk::TreeView()); list_view->set_model(list_model); list_view->append_column(*Gtk::manage(makeAppColumn())); + list_view->append_column(*Gtk::manage(makeNativeCommandColumn())); list_view->append_column(*Gtk::manage(makeCommandColumn())); for (auto &&column : list_view->get_columns()) { @@ -97,12 +98,12 @@ ExternalEditorPreferences::getEditors() const for (auto rowIter = children.begin(); rowIter != children.end(); rowIter++) { const Gio::Icon *const icon = rowIter->get_value(model_columns.icon).get(); const auto &icon_serialized = icon == nullptr ? "" : icon->serialize().print(); - editors.push_back(ExternalEditorPreferences::EditorInfo( - rowIter->get_value(model_columns.name), - rowIter->get_value(model_columns.command), - icon_serialized, - rowIter->get_value(model_columns.other_data) - )); + editors.emplace_back( + rowIter->get_value(model_columns.name), + rowIter->get_value(model_columns.command), + icon_serialized, + rowIter->get_value(model_columns.native_command), + rowIter->get_value(model_columns.other_data)); } return editors; @@ -138,6 +139,7 @@ void ExternalEditorPreferences::setEditors( row[model_columns.name] = editor.name; row[model_columns.icon] = icon; row[model_columns.command] = editor.command; + row[model_columns.native_command] = editor.native_command; row[model_columns.other_data] = editor.other_data; } } @@ -194,6 +196,24 @@ Gtk::TreeViewColumn *ExternalEditorPreferences::makeCommandColumn() return col; } +Gtk::TreeViewColumn *ExternalEditorPreferences::makeNativeCommandColumn() +{ + auto toggle_renderer = Gtk::manage(new Gtk::CellRendererToggle()); + auto col = Gtk::manage(new Gtk::TreeViewColumn()); + + col->set_title(M("PREFERENCES_EXTERNALEDITOR_COLUMN_NATIVE_COMMAND")); + col->pack_start(*toggle_renderer); + col->add_attribute(toggle_renderer->property_active(), model_columns.native_command); + + toggle_renderer->signal_toggled().connect([this](const Glib::ustring &path) { + const auto row_iter = list_model->get_iter(path); + bool new_value = !row_iter->get_value(model_columns.native_command); + row_iter->set_value(model_columns.native_command, new_value); + }); + + return col; +} + void ExternalEditorPreferences::onAppChooserDialogResponse( int response_id, RTAppChooserDialog *dialog) { @@ -224,6 +244,7 @@ void ExternalEditorPreferences::onFileChooserDialogResponse( for (const auto &selected : selection) { auto row = *list_model->get_iter(selected); row[model_columns.icon] = Glib::RefPtr(nullptr); + row[model_columns.native_command] = false; row[model_columns.command] = #ifdef WIN32 '"' + dialog->get_filename() + '"'; @@ -313,6 +334,7 @@ void ExternalEditorPreferences::setApp(const Glib::RefPtr app_info row[model_columns.icon] = app_info->get_icon(); row[model_columns.name] = app_info->get_name(); row[model_columns.command] = app_info->get_commandline(); + row[model_columns.native_command] = false; } } @@ -344,8 +366,8 @@ void ExternalEditorPreferences::updateToolbarSensitivity() } ExternalEditorPreferences::EditorInfo::EditorInfo( - Glib::ustring name, Glib::ustring command, Glib::ustring icon_serialized, void *other_data -) : name(name), icon_serialized(icon_serialized), command(command), other_data(other_data) + Glib::ustring name, Glib::ustring command, Glib::ustring icon_serialized, bool native_command, void *other_data +) : name(name), icon_serialized(icon_serialized), command(command), native_command(native_command), other_data(other_data) { } @@ -354,5 +376,6 @@ ExternalEditorPreferences::ModelColumns::ModelColumns() add(name); add(icon); add(command); + add(native_command); add(other_data); } diff --git a/rtgui/externaleditorpreferences.h b/rtgui/externaleditorpreferences.h index 34658d942..26903371c 100644 --- a/rtgui/externaleditorpreferences.h +++ b/rtgui/externaleditorpreferences.h @@ -50,6 +50,7 @@ public: Glib::ustring name = Glib::ustring(), Glib::ustring command = Glib::ustring(), Glib::ustring icon_serialized = Glib::ustring(), + bool native_command = false, void *other_data = nullptr ); /** @@ -65,6 +66,10 @@ public: * Gio::AppInfo::get_commandline() */ Glib::ustring command; + /** + * Use the OS native launcher instead of Gio. + */ + bool native_command; /** * Holds any other data associated with the editor. For example, it can * be used as a tag to uniquely identify the editor. @@ -96,6 +101,7 @@ private: Gtk::TreeModelColumn name; Gtk::TreeModelColumn> icon; Gtk::TreeModelColumn command; + Gtk::TreeModelColumn native_command; Gtk::TreeModelColumn other_data; }; @@ -124,6 +130,10 @@ private: * Constructs the column for displaying an editable commandline. */ Gtk::TreeViewColumn *makeCommandColumn(); + /** + * Constructs the column for displaying the native command toggle. + */ + Gtk::TreeViewColumn *makeNativeCommandColumn(); /** * Called when the user is done interacting with the app chooser dialog. * Closes the dialog and updates the selected entry if an app was chosen. diff --git a/rtgui/extprog.cc b/rtgui/extprog.cc index 9ec87c548..ea1800638 100644 --- a/rtgui/extprog.cc +++ b/rtgui/extprog.cc @@ -344,8 +344,20 @@ bool ExtProgStore::openInCustomEditor (const Glib::ustring& fileName, const Glib } -bool ExtProgStore::openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr &editorInfo) +bool ExtProgStore::openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr &editorInfo, bool nativeCommand) { + if (nativeCommand) { + if (rtengine::settings->verbose) { + std::cout << "Launching external editor as native command." << std::endl; + } + const Glib::ustring command = editorInfo->get_commandline(); + return openInCustomEditor(fileName, &command); + } + + if (rtengine::settings->verbose) { + std::cout << "Launching external editor with Gio." << std::endl; + } + bool success = false; try { diff --git a/rtgui/extprog.h b/rtgui/extprog.h index 6547896ef..5336c4703 100644 --- a/rtgui/extprog.h +++ b/rtgui/extprog.h @@ -70,7 +70,7 @@ public: static bool openInGimp (const Glib::ustring& fileName); static bool openInPhotoshop (const Glib::ustring& fileName); static bool openInCustomEditor (const Glib::ustring& fileName, const Glib::ustring* command = nullptr); - static bool openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr &editorInfo); + static bool openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr &editorInfo, bool nativeCommand); }; #define extProgStore ExtProgStore::getInstance() diff --git a/rtgui/options.cc b/rtgui/options.cc index b59e7c203..d6c3f7d25 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -873,6 +873,7 @@ void Options::readFromFile(Glib::ustring fname) if (keyFile.has_group("External Editor")) { if (keyFile.has_key("External Editor", "Names") || keyFile.has_key("External Editor", "Commands") + || keyFile.has_key("External Editor", "NativeCommands") || keyFile.has_key("External Editor", "IconsSerialized")) { // Multiple external editors. @@ -886,6 +887,11 @@ void Options::readFromFile(Glib::ustring fname) std::vector() : static_cast>( keyFile.get_string_list("External Editor", "Commands")); + const auto & native_commands = + !keyFile.has_key("External Editor", "NativeCommands") ? + std::vector() : + static_cast>( + keyFile.get_boolean_list("External Editor", "NativeCommands")); const auto & icons_serialized = !keyFile.has_key("External Editor", "IconsSerialized") ? std::vector() : @@ -899,6 +905,9 @@ void Options::readFromFile(Glib::ustring fname) for (unsigned i = 0; i < commands.size(); i++) { externalEditors[i].command = commands[i]; } + for (unsigned i = 0; i < native_commands.size(); i++) { + externalEditors[i].native_command = native_commands[i]; + } for (unsigned i = 0; i < icons_serialized.size(); i++) { externalEditors[i].icon_serialized = icons_serialized[i]; } @@ -938,7 +947,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 1) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", getIconSerialized(executable))); + externalEditors.emplace_back("GIMP", executable, true, getIconSerialized(executable)); } else { for (auto ver = 12; ver >= 0; --ver) { executable = Glib::build_filename(gimpDir, "bin", Glib::ustring::compose(Glib::ustring("gimp-2.%1.exe"), ver)); @@ -946,7 +955,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 1) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", getIconSerialized(executable))); + externalEditors.emplace_back("GIMP", executable, true, getIconSerialized(executable)); break; } } @@ -961,7 +970,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 2) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("Photoshop", "\"" + executable + "\"", getIconSerialized(executable))); + externalEditors.emplace_back("Photoshop", executable, true, getIconSerialized(executable)); } if (keyFile.has_key("External Editor", "CustomEditor")) { @@ -970,20 +979,20 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 3) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("-", "\"" + executable + "\"", "")); + externalEditors.emplace_back("-", executable, true, ""); } } #elif defined __APPLE__ if (editorToSendTo == 1) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("GIMP", "open -a GIMP", "gimp")); - externalEditors.push_back(ExternalEditor("GIMP-dev", "open -a GIMP-dev", "gimp")); + externalEditors.emplace_back("GIMP", "open -a GIMP", true, ""); + externalEditors.emplace_back("GIMP-dev", "open -a GIMP-dev", true, ""); if (editorToSendTo == 2) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("Photoshop", "open -a Photoshop", "")); + externalEditors.emplace_back("Photoshop", "open -a Photoshop", true, ""); if (keyFile.has_key("External Editor", "CustomEditor")) { auto executable = keyFile.get_string("External Editor", "CustomEditor"); @@ -991,20 +1000,21 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 3) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("-", executable, "")); + externalEditors.emplace_back("-", executable, true, ""); } } #else + const Glib::ustring gimp_icon_serialized = "('themed', <['gimp', 'gimp-symbolic']>)"; if (Glib::find_program_in_path("gimp").compare("")) { if (editorToSendTo == 1) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("GIMP", "gimp", "gimp")); + externalEditors.emplace_back("GIMP", "gimp", true, gimp_icon_serialized); } else if (Glib::find_program_in_path("gimp-remote").compare("")) { if (editorToSendTo == 1) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("GIMP", "gimp-remote", "gimp")); + externalEditors.emplace_back("GIMP", "gimp-remote", true, gimp_icon_serialized); } if (keyFile.has_key("External Editor", "CustomEditor")) { @@ -1013,7 +1023,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 3) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("-", executable, "")); + externalEditors.emplace_back("-", executable, true, ""); } } #endif @@ -2328,16 +2338,19 @@ void Options::saveToFile(Glib::ustring fname) { std::vector names; std::vector commands; + std::vector native_commands; std::vector icons_serialized; for (const auto & editor : externalEditors) { names.push_back(editor.name); commands.push_back(editor.command); + native_commands.push_back(editor.native_command); icons_serialized.push_back(editor.icon_serialized); } keyFile.set_string_list("External Editor", "Names", names); keyFile.set_string_list("External Editor", "Commands", commands); + keyFile.set_boolean_list("External Editor", "NativeCommands", native_commands); keyFile.set_string_list("External Editor", "IconsSerialized", icons_serialized); keyFile.set_integer("External Editor", "EditorIndex", externalEditorIndex); @@ -3009,15 +3022,15 @@ Glib::ustring Options::getICCProfileCopyright() return Glib::ustring::compose("Copyright RawTherapee %1, CC0", now.get_year()); } -ExternalEditor::ExternalEditor() {} +ExternalEditor::ExternalEditor() = default; ExternalEditor::ExternalEditor( - const Glib::ustring &name, const Glib::ustring &command, const Glib::ustring &icon_serialized -): name(name), command(command), icon_serialized(icon_serialized) {} + const Glib::ustring &name, const Glib::ustring &command, bool native_command, const Glib::ustring &icon_serialized +): name(name), command(command), native_command(native_command), icon_serialized(icon_serialized) {} bool ExternalEditor::operator==(const ExternalEditor &other) const { - return this->name == other.name && this->command == other.command && this->icon_serialized == other.icon_serialized; + return this->name == other.name && this->command == other.command && this->native_command == other.native_command && this->icon_serialized == other.icon_serialized; } bool ExternalEditor::operator!=(const ExternalEditor &other) const diff --git a/rtgui/options.h b/rtgui/options.h index 2c34260aa..78059357e 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -54,9 +54,10 @@ struct ExternalEditor { ExternalEditor(); - ExternalEditor(const Glib::ustring &name, const Glib::ustring &command, const Glib::ustring &icon_serialized); + ExternalEditor(const Glib::ustring &name, const Glib::ustring &command, bool native_command, const Glib::ustring &icon_serialized); Glib::ustring name; Glib::ustring command; + bool native_command; Glib::ustring icon_serialized; bool operator==(const ExternalEditor & other) const; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 7d95ef716..a97cb003d 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -1752,7 +1752,7 @@ void Preferences::storePreferences() moptions.externalEditorIndex = -1; for (unsigned i = 0; i < editors.size(); i++) { moptions.externalEditors[i] = (ExternalEditor( - editors[i].name, editors[i].command, editors[i].icon_serialized)); + editors[i].name, editors[i].command, editors[i].native_command, editors[i].icon_serialized)); if (editors[i].other_data) { // The current editor was marked before the list was edited. We // found the mark, so this is the editor that was active. @@ -2034,8 +2034,7 @@ void Preferences::fillPreferences() std::vector editorInfos; for (const auto &editor : moptions.externalEditors) { - editorInfos.push_back(ExternalEditorPreferences::EditorInfo( - editor.name, editor.command, editor.icon_serialized)); + editorInfos.emplace_back(editor.name, editor.command, editor.icon_serialized, editor.native_command); } if (moptions.externalEditorIndex >= 0) { // Mark the current editor so we can track it. @@ -2536,7 +2535,10 @@ void Preferences::workflowUpdate() } if (changed) { // Update the send to external editor widget. - parent->updateExternalEditorWidget(moptions.externalEditorIndex, moptions.externalEditors); + int selected_index = moptions.externalEditorIndex >= 0 + ? moptions.externalEditorIndex + : static_cast(moptions.externalEditors.size()); + parent->updateExternalEditorWidget(selected_index, moptions.externalEditors); } if (moptions.cloneFavoriteTools != options.cloneFavoriteTools || From 186995acf4fbfa28d6743a74ce1683bb410f06dd Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 9 Apr 2023 13:52:09 -0700 Subject: [PATCH 14/14] Improve code quality for external editor settings --- rtgui/externaleditorpreferences.cc | 22 +++++++++++++++------- rtgui/externaleditorpreferences.h | 18 ++++++++++++------ rtgui/preferences.cc | 4 ++-- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/rtgui/externaleditorpreferences.cc b/rtgui/externaleditorpreferences.cc index 55c9f7956..5d9b45c5d 100644 --- a/rtgui/externaleditorpreferences.cc +++ b/rtgui/externaleditorpreferences.cc @@ -91,7 +91,7 @@ ExternalEditorPreferences::ExternalEditorPreferences(): std::vector ExternalEditorPreferences::getEditors() const { - std::vector editors; + std::vector editors; auto children = list_model->children(); @@ -114,7 +114,7 @@ void ExternalEditorPreferences::setEditors( { list_model->clear(); - for (const ExternalEditorPreferences::EditorInfo & editor : editors) { + for (const EditorInfo & editor : editors) { auto row = *list_model->append(); Glib::RefPtr icon; @@ -169,8 +169,8 @@ Gtk::TreeViewColumn *ExternalEditorPreferences::makeAppColumn() col->set_resizable(); col->pack_start(*icon_renderer, false); col->pack_start(*name_renderer); - col->add_attribute(*icon_renderer, "gicon", model_columns.icon); - col->add_attribute(*name_renderer, "text", model_columns.name); + col->add_attribute(icon_renderer->property_gicon(), model_columns.icon); + col->add_attribute(name_renderer->property_text(), model_columns.name); col->set_min_width(20); name_renderer->property_editable() = true; @@ -187,7 +187,7 @@ Gtk::TreeViewColumn *ExternalEditorPreferences::makeCommandColumn() col->set_title(M("PREFERENCES_EXTERNALEDITOR_COLUMN_COMMAND")); col->pack_start(*command_renderer); - col->add_attribute(*command_renderer, "text", model_columns.command); + col->add_attribute(command_renderer->property_text(), model_columns.command); command_renderer->property_editable() = true; command_renderer->signal_edited().connect( @@ -366,8 +366,16 @@ void ExternalEditorPreferences::updateToolbarSensitivity() } ExternalEditorPreferences::EditorInfo::EditorInfo( - Glib::ustring name, Glib::ustring command, Glib::ustring icon_serialized, bool native_command, void *other_data -) : name(name), icon_serialized(icon_serialized), command(command), native_command(native_command), other_data(other_data) + const Glib::ustring &name, + const Glib::ustring &command, + const Glib::ustring &icon_serialized, + bool native_command, + EditorTag other_data) : + name(name), + icon_serialized(icon_serialized), + command(command), + native_command(native_command), + other_data(other_data) { } diff --git a/rtgui/externaleditorpreferences.h b/rtgui/externaleditorpreferences.h index 26903371c..a1e3c7e74 100644 --- a/rtgui/externaleditorpreferences.h +++ b/rtgui/externaleditorpreferences.h @@ -42,16 +42,22 @@ class FileChooserDialog; class ExternalEditorPreferences : public Gtk::Box { public: + struct EditorTag { + bool selected; + EditorTag(): selected(false) {} + explicit EditorTag(bool selected): selected(selected) {} + }; + /** * Data struct containing information about an external editor. */ struct EditorInfo { explicit EditorInfo( - Glib::ustring name = Glib::ustring(), - Glib::ustring command = Glib::ustring(), - Glib::ustring icon_serialized = Glib::ustring(), + const Glib::ustring &name = Glib::ustring(), + const Glib::ustring &command = Glib::ustring(), + const Glib::ustring &icon_serialized = Glib::ustring(), bool native_command = false, - void *other_data = nullptr + EditorTag other_data = EditorTag() ); /** * Name of the external editor. @@ -74,7 +80,7 @@ public: * Holds any other data associated with the editor. For example, it can * be used as a tag to uniquely identify the editor. */ - void *other_data; + EditorTag other_data; }; ExternalEditorPreferences(); @@ -102,7 +108,7 @@ private: Gtk::TreeModelColumn> icon; Gtk::TreeModelColumn command; Gtk::TreeModelColumn native_command; - Gtk::TreeModelColumn other_data; + Gtk::TreeModelColumn other_data; }; ModelColumns model_columns; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index a97cb003d..1ae01da2d 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -1753,7 +1753,7 @@ void Preferences::storePreferences() for (unsigned i = 0; i < editors.size(); i++) { moptions.externalEditors[i] = (ExternalEditor( editors[i].name, editors[i].command, editors[i].native_command, editors[i].icon_serialized)); - if (editors[i].other_data) { + if (editors[i].other_data.selected) { // The current editor was marked before the list was edited. We // found the mark, so this is the editor that was active. moptions.externalEditorIndex = i; @@ -2038,7 +2038,7 @@ void Preferences::fillPreferences() } if (moptions.externalEditorIndex >= 0) { // Mark the current editor so we can track it. - editorInfos[moptions.externalEditorIndex].other_data = (void *)1; + editorInfos[moptions.externalEditorIndex].other_data.selected = true; } externalEditors->setEditors(editorInfos);