From 453fb961f203af59e0cd3790bb16fab15f41bd32 Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Sun, 28 Mar 2021 18:12:47 -0700 Subject: [PATCH 001/134] Create a preferences widget for external editors The widget is intended to be embedded in the preferences dialog. It displays a list of external editors using an icon, name, and command for each editor. The name and command can be edited. Editors can be added, removed, and rearranged. A button allows one to set an editor's information by selecting from a list of installed applications. --- rtgui/externaleditorpreferences.cc | 261 +++++++++++++++++++++++++++++ rtgui/externaleditorpreferences.h | 147 ++++++++++++++++ 2 files changed, 408 insertions(+) create mode 100644 rtgui/externaleditorpreferences.cc create mode 100644 rtgui/externaleditorpreferences.h diff --git a/rtgui/externaleditorpreferences.cc b/rtgui/externaleditorpreferences.cc new file mode 100644 index 000000000..df6b6efc2 --- /dev/null +++ b/rtgui/externaleditorpreferences.cc @@ -0,0 +1,261 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 Lawrence Lee + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "externaleditorpreferences.h" +#include "multilangmgr.h" +#include "rtimage.h" + + +ExternalEditorPreferences::ExternalEditorPreferences(): + Box(Gtk::Orientation::ORIENTATION_VERTICAL), + list_model(Gtk::ListStore::create(model_columns)), + toolbar(Gtk::Orientation::ORIENTATION_HORIZONTAL) +{ + // List view. + list_view = Gtk::make_managed(); + list_view->set_model(list_model); + list_view->append_column(*Gtk::manage(makeAppColumn())); + list_view->append_column(*Gtk::manage(makeCommandColumn())); + + for (auto &&column : list_view->get_columns()) { + column->set_sizing(Gtk::TreeViewColumnSizing::TREE_VIEW_COLUMN_FIXED); + } + + list_view->set_grid_lines(Gtk::TREE_VIEW_GRID_LINES_VERTICAL); + list_view->set_reorderable(); + + // List scroll area. + list_scroll_area.set_hexpand(); + list_scroll_area.set_vexpand(); + list_scroll_area.add(*list_view); + + // Toolbar buttons. + auto add_image = Gtk::make_managed("add-small.png"); + auto remove_image = Gtk::make_managed("remove-small.png"); + button_add = Gtk::make_managed(); + button_remove = Gtk::make_managed(); + button_add->set_image(*add_image); + button_remove->set_image(*remove_image); + button_app_chooser = Gtk::make_managed(M("PREFERENCES_EXTERNALEDITOR_CHANGE")); + + button_app_chooser->signal_pressed().connect(sigc::mem_fun( + *this, &ExternalEditorPreferences::openAppChooserDialog)); + button_add->signal_pressed().connect(sigc::mem_fun( + *this, &ExternalEditorPreferences::addEditor)); + button_remove->signal_pressed().connect(sigc::mem_fun( + *this, &ExternalEditorPreferences::removeSelectedEditors)); + + list_view->get_selection()->signal_changed().connect(sigc::mem_fun( + *this, &ExternalEditorPreferences::updateToolbarSensitivity)); + updateToolbarSensitivity(); + + // Toolbar. + toolbar.set_halign(Gtk::Align::ALIGN_END); + toolbar.add(*button_app_chooser); + toolbar.add(*button_add); + toolbar.add(*button_remove); + + // This widget's children. + add(list_scroll_area); + add(toolbar); + show_all(); +} + +std::vector +ExternalEditorPreferences::getEditors() const +{ + std::vector editors; + + auto children = list_model->children(); + + for (auto rowIter = children.begin(); rowIter != children.end(); rowIter++) { + const Gio::Icon *const icon = rowIter->get_value(model_columns.icon).get(); + const auto &icon_name = icon == nullptr ? "" : icon->to_string(); + editors.push_back(ExternalEditorPreferences::EditorInfo( + rowIter->get_value(model_columns.name), + rowIter->get_value(model_columns.command), + icon_name, + rowIter->get_value(model_columns.other_data) + )); + } + + return editors; +} + +void ExternalEditorPreferences::setEditors( + const std::vector &editors) +{ + list_model->clear(); + + for (const ExternalEditorPreferences::EditorInfo & editor : editors) { + auto row = *list_model->append(); + row[model_columns.name] = editor.name; + row[model_columns.icon] = editor.icon_name.empty() ? Glib::RefPtr() : Gio::Icon::create(editor.icon_name); + row[model_columns.command] = editor.command; + row[model_columns.other_data] = editor.other_data; + } +} + +void ExternalEditorPreferences::addEditor() +{ + Gtk::TreeModel::Row row; + auto selected = list_view->get_selection()->get_selected_rows(); + + if (selected.size()) { + row = *list_model->insert_after(list_model->get_iter(selected.back())); + } else { + row = *list_model->append(); + } + + row[model_columns.name] = "-"; + list_view->get_selection()->select(row); +} + +Gtk::TreeViewColumn *ExternalEditorPreferences::makeAppColumn() +{ + auto name_renderer = Gtk::make_managed(); + auto icon_renderer = Gtk::make_managed(); + auto col = Gtk::make_managed(); + + col->set_title(M("PREFERENCES_EXTERNALEDITOR_COLUMN_NAME")); + 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->set_min_width(20); + + name_renderer->property_editable() = true; + name_renderer->signal_edited().connect( + sigc::mem_fun(*this, &ExternalEditorPreferences::setAppName)); + + return col; +} + +Gtk::TreeViewColumn *ExternalEditorPreferences::makeCommandColumn() +{ + auto command_renderer = Gtk::make_managed(); + auto col = Gtk::make_managed(); + + col->set_title(M("PREFERENCES_EXTERNALEDITOR_COLUMN_COMMAND")); + col->pack_start(*command_renderer); + col->add_attribute(*command_renderer, "text", model_columns.command); + + command_renderer->property_editable() = true; + command_renderer->signal_edited().connect( + sigc::mem_fun(*this, &ExternalEditorPreferences::setAppCommand)); + + return col; +} + +void ExternalEditorPreferences::onAppChooserDialogResponse( + int response_id, Gtk::AppChooserDialog *dialog) +{ + switch (response_id) { + case Gtk::RESPONSE_OK: + dialog->close(); + setApp(dialog->get_app_info()); + break; + + case Gtk::RESPONSE_CANCEL: + case Gtk::RESPONSE_CLOSE: + dialog->close(); + break; + + default: + break; + } +} + +void ExternalEditorPreferences::openAppChooserDialog() +{ + if (app_chooser_dialog.get()) { + app_chooser_dialog->refresh(); + app_chooser_dialog->show(); + return; + } + + app_chooser_dialog.reset(new Gtk::AppChooserDialog("image/tiff")); + app_chooser_dialog->signal_response().connect(sigc::bind( + sigc::mem_fun(*this, &ExternalEditorPreferences::onAppChooserDialogResponse), + app_chooser_dialog.get() + )); + app_chooser_dialog->set_modal(); + app_chooser_dialog->show(); +} + +void ExternalEditorPreferences::removeSelectedEditors() +{ + auto selection = list_view->get_selection()->get_selected_rows(); + + for (const auto &selected : selection) { + list_model->erase(list_model->get_iter(selected)); + } +} + +void ExternalEditorPreferences::setApp(const Glib::RefPtr app_info) +{ + auto selection = list_view->get_selection()->get_selected_rows(); + + for (const auto &selected : selection) { + auto row = *list_model->get_iter(selected); + row[model_columns.icon] = app_info->get_icon(); + row[model_columns.name] = app_info->get_name(); + row[model_columns.command] = app_info->get_commandline(); + } +} + +void ExternalEditorPreferences::setAppCommand( + const Glib::ustring & path, const Glib::ustring & new_text) +{ + auto row_iter = list_model->get_iter(path); + + if (!row_iter->get_value(model_columns.command).compare(new_text)) { + return; + } + + row_iter->set_value(model_columns.command, new_text); + row_iter->set_value(model_columns.icon, Glib::RefPtr(nullptr)); +} + +void ExternalEditorPreferences::setAppName( + const Glib::ustring & path, const Glib::ustring & new_text) +{ + list_model->get_iter(path)->set_value(model_columns.name, new_text); +} + +void ExternalEditorPreferences::updateToolbarSensitivity() +{ + bool selected = list_view->get_selection()->count_selected_rows(); + button_app_chooser->set_sensitive(selected); + button_remove->set_sensitive(selected); +} + +ExternalEditorPreferences::EditorInfo::EditorInfo( + Glib::ustring name, Glib::ustring command, Glib::ustring icon_name, void *other_data +) : name(name), icon_name(icon_name), command(command), other_data(other_data) +{ +} + +ExternalEditorPreferences::ModelColumns::ModelColumns() +{ + add(name); + add(icon); + add(command); + add(other_data); +} diff --git a/rtgui/externaleditorpreferences.h b/rtgui/externaleditorpreferences.h new file mode 100644 index 000000000..be988e901 --- /dev/null +++ b/rtgui/externaleditorpreferences.h @@ -0,0 +1,147 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 Lawrence Lee + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + + +/** + * Widget for editing the external editors options. + */ +class ExternalEditorPreferences : public Gtk::Box +{ +public: + /** + * 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_name = Glib::ustring(), + void *other_data = nullptr + ); + /** + * Name of the external editor. + */ + Glib::ustring name; + /** + * The string representation of the icon. See Gio::Icon::to_string(). + */ + Glib::ustring icon_name; + /** + * The commandline for running the program. See + * Gio::AppInfo::get_commandline() + */ + Glib::ustring command; + /** + * 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; + }; + + ExternalEditorPreferences(); + + /** + * Creates and returns a vector representing the external editors shown in + * this widget. + */ + std::vector getEditors() const; + /** + * Populates this widget with the external editors described in the + * argument. + */ + void setEditors(const std::vector &editors); + +private: + /** + * Model representing the data fields each external editor entry has. + */ + class ModelColumns : public Gtk::TreeModelColumnRecord + { + public: + ModelColumns(); + Gtk::TreeModelColumn name; + Gtk::TreeModelColumn> icon; + Gtk::TreeModelColumn command; + Gtk::TreeModelColumn other_data; + }; + + ModelColumns model_columns; + Glib::RefPtr list_model; // The list of editors. + Gtk::ScrolledWindow list_scroll_area; // Allows the list to be scrolled. + Gtk::TreeView *list_view; // Widget for displaying the list. + Gtk::Box toolbar; // Contains buttons for editing the list. + Gtk::Button *button_app_chooser; + Gtk::Button *button_add; + Gtk::Button *button_remove; + std::unique_ptr app_chooser_dialog; + + /** + * Inserts a new editor entry after the current selection, or at the end if + * no editor is selected. + */ + void addEditor(); + /** + * Constructs the column for displaying the external editor name (and icon). + */ + Gtk::TreeViewColumn *makeAppColumn(); + /** + * Constructs the column for displaying an editable commandline. + */ + Gtk::TreeViewColumn *makeCommandColumn(); + /** + * 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. + */ + void onAppChooserDialogResponse(int responseId, Gtk::AppChooserDialog *dialog); + /** + * Shows the app chooser dialog. + */ + void openAppChooserDialog(); + /** + * Removes all selected editors. + */ + void removeSelectedEditors(); + /** + * Sets the selected entries with the provided information. + */ + void setApp(const Glib::RefPtr app_info); + /** + * Updates the application command and removes the icon for the given row. + */ + void setAppCommand(const Glib::ustring & path, const Glib::ustring & new_text); + /** + * Updates the application name for the given row. + */ + void setAppName(const Glib::ustring & path, const Glib::ustring & new_text); + /** + * Sets the sensitivity of the widgets in the toolbar to reflect the current + * state of the list. For example, makes the remove button insensitive if no + * entries are selected. + */ + void updateToolbarSensitivity(); +}; From d2a280fbf361b804bbe70c4da46d21cf7827064a Mon Sep 17 00:00:00 2001 From: Lawrence Lee Date: Tue, 30 Mar 2021 21:45:20 -0700 Subject: [PATCH 002/134] Update language file and cmake list Update for the external editor preferences widget. --- rtdata/languages/default | 3 +++ rtgui/CMakeLists.txt | 1 + 2 files changed, 4 insertions(+) diff --git a/rtdata/languages/default b/rtdata/languages/default index 15aceb51b..2ff654ede 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1755,6 +1755,9 @@ PREFERENCES_DIRSOFTWARE;Installation directory PREFERENCES_EDITORCMDLINE;Custom command line PREFERENCES_EDITORLAYOUT;Editor layout PREFERENCES_EXTERNALEDITOR;External Editor +PREFERENCES_EXTERNALEDITOR_CHANGE;Change Application +PREFERENCES_EXTERNALEDITOR_COLUMN_NAME;Name +PREFERENCES_EXTERNALEDITOR_COLUMN_COMMAND;Command PREFERENCES_FBROWSEROPTS;File Browser / Thumbnail Options PREFERENCES_FILEBROWSERTOOLBARSINGLEROW;Compact toolbars in File Browser PREFERENCES_FLATFIELDFOUND;Found diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 5f8baed47..1d4b57553 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -62,6 +62,7 @@ set(NONCLISOURCEFILES exiffiltersettings.cc exifpanel.cc exportpanel.cc + externaleditorpreferences.cc extprog.cc fattaltonemap.cc filebrowser.cc From afe20fee0e0046083cd61abe28e8f44591baf212 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 4 Apr 2021 22:16:16 -0700 Subject: [PATCH 003/134] Add Gio::Icon based RTImages --- rtgui/rtimage.cc | 102 ++++++++++++++++++++++++++++++++++++++++++++++- rtgui/rtimage.h | 8 ++++ 2 files changed, 109 insertions(+), 1 deletion(-) diff --git a/rtgui/rtimage.cc b/rtgui/rtimage.cc index 44078ed3b..9a38c1885 100644 --- a/rtgui/rtimage.cc +++ b/rtgui/rtimage.cc @@ -22,12 +22,40 @@ #include #include +#include +#include #include "../rtengine/settings.h" namespace { +struct GIconKey { + Glib::RefPtr icon; + /** + * Icon size in pixels. + */ + int icon_size; + + GIconKey() {} + GIconKey(const Glib::RefPtr &icon, int icon_size): icon(icon), icon_size(icon_size) {} + + bool operator==(const GIconKey &other) const + { + bool icons_match = (icon.get() == nullptr && other.icon.get() == nullptr) || (icon.get() != nullptr && icon->equal(Glib::RefPtr::cast_const(other.icon))); + return icons_match && icon_size == other.icon_size; + } +}; + +struct GIconKeyHash { + size_t operator()(const GIconKey &key) const + { + const size_t icon_hash = key.icon ? key.icon->hash() : 0; + return icon_hash ^ std::hash()(key.icon_size); + } +}; + +std::unordered_map, GIconKeyHash> gIconPixbufCache; std::map > pixbufCache; std::map > surfaceCache; @@ -44,6 +72,8 @@ RTImage::RTImage (RTImage &other) : surface(other.surface), pixbuf(other.pixbuf) set(pixbuf); } else if (surface) { set(surface); + } else if (other.gIcon) { + changeImage(other.gIcon, other.gIconSize); } } @@ -80,13 +110,27 @@ RTImage::RTImage (Glib::RefPtr &other) if (other->get_surface()) { surface = other->get_surface(); set(surface); - } else { + } else if (other->pixbuf) { pixbuf = other->get_pixbuf(); set(pixbuf); + } else if (other->gIcon) { + changeImage(other->gIcon, other->gIconSize); } } } +RTImage::RTImage(const Glib::RefPtr &gIcon, Gtk::IconSize size) +{ + changeImage(gIcon, size); +} + +int RTImage::iconSizeToPixels(Gtk::IconSize size) const +{ + int width, height; + Gtk::IconSize::lookup(size, width, height); + return std::round(getTweakedDPI() / baseDPI * std::max(width, height)); +} + void RTImage::setImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName) { Glib::ustring imageName; @@ -113,10 +157,41 @@ void RTImage::setDPInScale (const double newDPI, const int newScale) } } +void RTImage::changeImage(const Glib::RefPtr &gIcon, int size) +{ + clear(); + + pixbuf.reset(); + surface.clear(); + this->gIcon = gIcon; + + if (!gIcon) { + return; + } + + gIconSize = size; + GIconKey key(gIcon, gIconSize); + auto iterator = gIconPixbufCache.find(key); + + if (iterator == gIconPixbufCache.end()) { + auto icon_pixbuf = createPixbufFromGIcon(gIcon, gIconSize); + iterator = gIconPixbufCache.emplace(key, icon_pixbuf).first; + } + + set(iterator->second); +} + +void RTImage::changeImage(const Glib::RefPtr &gIcon, Gtk::IconSize size) +{ + changeImage(gIcon, iconSizeToPixels(size)); +} + void RTImage::changeImage (const Glib::ustring& imageName) { clear (); + gIcon.reset(); + if (imageName.empty()) { return; } @@ -150,6 +225,11 @@ int RTImage::get_width() if (pixbuf) { return pixbuf->get_width(); } + + if (gIcon) { + return this->get_pixbuf()->get_width(); + } + return -1; } @@ -161,6 +241,11 @@ int RTImage::get_height() if (pixbuf) { return pixbuf->get_height(); } + + if (gIcon) { + return this->get_pixbuf()->get_height(); + } + return -1; } @@ -178,6 +263,11 @@ void RTImage::cleanup(bool all) for (auto& entry : surfaceCache) { entry.second.clear(); } + + for (auto& entry : gIconPixbufCache) { + entry.second.reset(); + } + RTScalable::cleanup(all); } @@ -189,6 +279,10 @@ void RTImage::updateImages() for (auto& entry : surfaceCache) { entry.second = createImgSurfFromFile(entry.first); } + + for (auto& entry : gIconPixbufCache) { + entry.second = createPixbufFromGIcon(entry.first.icon, entry.first.icon_size); + } } Glib::RefPtr RTImage::createPixbufFromFile (const Glib::ustring& fileName) @@ -197,6 +291,12 @@ Glib::RefPtr RTImage::createPixbufFromFile (const Glib::ustring& fi return Gdk::Pixbuf::create(imgSurf, 0, 0, imgSurf->get_width(), imgSurf->get_height()); } +Glib::RefPtr RTImage::createPixbufFromGIcon(const Glib::RefPtr &icon, int size) +{ + // TODO: Listen for theme changes and update icon, remove from cache. + return Gtk::IconTheme::get_default()->lookup_icon(icon, size, Gtk::ICON_LOOKUP_FORCE_SIZE).load_icon(); +} + Cairo::RefPtr RTImage::createImgSurfFromFile (const Glib::ustring& fileName) { Cairo::RefPtr surf; diff --git a/rtgui/rtimage.h b/rtgui/rtimage.h index eb1930d28..183a83a94 100644 --- a/rtgui/rtimage.h +++ b/rtgui/rtimage.h @@ -34,6 +34,11 @@ class RTImage final : public Gtk::Image, public RTScalable protected: Cairo::RefPtr surface; Glib::RefPtr pixbuf; + Glib::RefPtr gIcon; + int gIconSize; + + void changeImage(const Glib::RefPtr &gIcon, int size); + int iconSizeToPixels(Gtk::IconSize size) const; public: RTImage (); @@ -42,9 +47,11 @@ public: explicit RTImage (Cairo::RefPtr &surf); explicit RTImage(Cairo::RefPtr other); explicit RTImage (Glib::RefPtr &other); + explicit RTImage(const Glib::RefPtr &gIcon, Gtk::IconSize size); explicit RTImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName = Glib::ustring()); void setImage (const Glib::ustring& fileName, const Glib::ustring& rtlFileName = Glib::ustring()); + void changeImage(const Glib::RefPtr &gIcon, Gtk::IconSize size); void changeImage (const Glib::ustring& imageName); Cairo::RefPtr get_surface(); int get_width(); @@ -58,6 +65,7 @@ public: static void setScale (const int newScale); static Glib::RefPtr createPixbufFromFile (const Glib::ustring& fileName); + static Glib::RefPtr createPixbufFromGIcon(const Glib::RefPtr &icon, int size); static Cairo::RefPtr createImgSurfFromFile (const Glib::ustring& fileName); }; From f30f094a6c014976e6930ee6f4e8aa6d007e9c06 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 10 Apr 2021 17:41:33 -0700 Subject: [PATCH 004/134] Improve pop-up common with gicons and item ops Add ability to use gicon images, insert pop-up entries in any location, and remove entries. --- rtgui/popupcommon.cc | 157 +++++++++++++++++++++++++++++++++---------- rtgui/popupcommon.h | 19 +++++- 2 files changed, 141 insertions(+), 35 deletions(-) diff --git a/rtgui/popupcommon.cc b/rtgui/popupcommon.cc index 8c4c9dda1..fabc4d572 100644 --- a/rtgui/popupcommon.cc +++ b/rtgui/popupcommon.cc @@ -27,7 +27,7 @@ PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label) : buttonImage (nullptr) - , menu (nullptr) + , menu(new Gtk::Menu()) , selected (-1) // -1 means that the button is invalid { button = thisButton; @@ -48,59 +48,148 @@ PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label) setExpandAlignProperties(buttonGroup, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); buttonGroup->attach(*button, 0, 0, 1, 1); buttonGroup->get_style_context()->add_class("image-combo"); + + // Create the image for the button + buttonImage = Gtk::make_managed(); + setExpandAlignProperties(buttonImage, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + imageContainer->attach_next_to(*buttonImage, Gtk::POS_RIGHT, 1, 1); + buttonImage->set_no_show_all(); + + // Create the button for showing the pop-up. + arrowButton = Gtk::make_managed(); + Gtk::Image *arrowImage = Gtk::make_managed(); + arrowImage->set_from_icon_name("pan-down-symbolic", Gtk::ICON_SIZE_BUTTON); + setExpandAlignProperties(arrowButton, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); + arrowButton->add(*arrowImage); //menuSymbol); + arrowImage->show(); + buttonGroup->attach_next_to(*arrowButton, *button, Gtk::POS_RIGHT, 1, 1); + arrowButton->signal_button_release_event().connect_notify(sigc::mem_fun(*this, &PopUpCommon::showMenu)); + arrowButton->get_style_context()->add_class("Right"); + arrowButton->get_style_context()->add_class("popupbutton-arrow"); + arrowButton->set_no_show_all(); } PopUpCommon::~PopUpCommon () { - delete menu; - delete buttonImage; } bool PopUpCommon::addEntry (const Glib::ustring& fileName, const Glib::ustring& label) { - if (label.empty ()) - return false; + return insertEntry(getEntryCount(), fileName, label); +} + +bool PopUpCommon::insertEntry(int position, const Glib::ustring& fileName, const Glib::ustring& label) +{ + RTImage* image = nullptr; + if (!fileName.empty()) { + image = Gtk::make_managed(fileName); + } + bool success = insertEntryImpl(position, fileName, Glib::RefPtr(), image, label); + if (!success && image) { + delete image; + } + return success; +} + +bool PopUpCommon::insertEntry(int position, const Glib::RefPtr& gIcon, const Glib::ustring& label) +{ + RTImage* image = Gtk::make_managed(gIcon, Gtk::ICON_SIZE_BUTTON); + bool success = insertEntryImpl(position, "", gIcon, image, label); + if (!success) { + delete image; + } + return success; +} + +bool PopUpCommon::insertEntryImpl(int position, const Glib::ustring& fileName, const Glib::RefPtr& gIcon, RTImage* image, const Glib::ustring& label) +{ + if (label.empty() || position < 0 || position > getEntryCount()) + return false; // Create the menu item and image - MyImageMenuItem* newItem = Gtk::manage (new MyImageMenuItem (label, fileName)); - imageFilenames.push_back (fileName); - images.push_back (newItem->getImage ()); - - if (selected == -1) { - // Create the menu on the first item - menu = new Gtk::Menu (); - // Create the image for the button - buttonImage = new RTImage(fileName); - setExpandAlignProperties(buttonImage, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - // Use the first image by default - imageContainer->attach_next_to(*buttonImage, Gtk::POS_RIGHT, 1, 1); - selected = 0; - } + MyImageMenuItem *newItem = Gtk::make_managed(label, image); + imageIcons.insert(imageIcons.begin() + position, gIcon); + imageFilenames.insert(imageFilenames.begin() + position, fileName); + images.insert(images.begin() + position, newItem->getImage()); // When there is at least 1 choice, we add the arrow button if (images.size() == 1) { - Gtk::Button* arrowButton = Gtk::manage( new Gtk::Button() ); - Gtk::Image *arrowImage = Gtk::manage(new Gtk::Image()); - arrowImage->set_from_icon_name("pan-down-symbolic", Gtk::ICON_SIZE_BUTTON); - setExpandAlignProperties(arrowButton, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); - arrowButton->add(*arrowImage); //menuSymbol); - buttonGroup->attach_next_to(*arrowButton, *button, Gtk::POS_RIGHT, 1, 1); - arrowButton->signal_button_release_event().connect_notify( sigc::mem_fun(*this, &PopUpCommon::showMenu) ); + changeImage(fileName, gIcon); + buttonImage->show(); + selected = 0; button->get_style_context()->add_class("Left"); - arrowButton->get_style_context()->add_class("Right"); - arrowButton->get_style_context()->add_class("popupbutton-arrow"); + arrowButton->show(); hasMenu = true; + } else if (position <= selected) { + selected++; } - newItem->signal_activate ().connect (sigc::bind (sigc::mem_fun (*this, &PopUpCommon::entrySelected), images.size () - 1)); - menu->append (*newItem); - + void (PopUpCommon::*entrySelectedFunc)(Gtk::Widget *) = &PopUpCommon::entrySelected; + newItem->signal_activate ().connect (sigc::bind (sigc::mem_fun (*this, entrySelectedFunc), newItem)); + menu->insert(*newItem, position); return true; } -// TODO: 'PopUpCommon::removeEntry' method to be created... +void PopUpCommon::removeEntry(int position) +{ + if (position < 0 || position >= getEntryCount()) { + return; + } -void PopUpCommon::entrySelected (int i) + if (getEntryCount() == 1) { // Last of the entries. + // Hide the arrow button. + button->get_style_context()->remove_class("Left"); + arrowButton->hide(); + hasMenu = false; + // Remove the button image. + buttonImage->hide(); + selected = -1; + } + else if (position < selected) { + selected--; + } + else if (position == selected) { // Select a different entry before removing. + int nextSelection = position + (position == getEntryCount() - 1 ? -1 : 1); + changeImage(nextSelection); + setButtonHint(); + } + + MyImageMenuItem *menuItem = dynamic_cast(menu->get_children()[position]); + menu->remove(*menuItem); + delete menuItem; + imageIcons.erase(imageIcons.begin() + position); + imageFilenames.erase(imageFilenames.begin() + position); + images.erase(images.begin() + position); +} + +void PopUpCommon::changeImage(int position) +{ + changeImage(imageFilenames.at(position), imageIcons.at(position)); +} + +void PopUpCommon::changeImage(const Glib::ustring& fileName, const Glib::RefPtr& gIcon) +{ + if (!fileName.empty()) { + buttonImage->changeImage(fileName); + } else { + buttonImage->changeImage(gIcon, static_cast(Gtk::ICON_SIZE_BUTTON)); + } +} + +void PopUpCommon::entrySelected(Gtk::Widget* widget) +{ + int i = 0; + for (const auto & child : menu->get_children()) { + if (widget == child) { + break; + } + i++; + } + + entrySelected(i); +} + +void PopUpCommon::entrySelected(int i) { // Emit a signal if the selected item has changed if (setSelected (posToIndex(i))) @@ -130,7 +219,7 @@ bool PopUpCommon::setSelected (int entryNum) return false; } else { // Maybe we could do something better than loading the image file each time the selection is changed !? - buttonImage->changeImage(imageFilenames.at(entryNum)); + changeImage(entryNum); selected = entryNum; setButtonHint(); return true; diff --git a/rtgui/popupcommon.h b/rtgui/popupcommon.h index b4cf4d7e0..59a5b8d0e 100644 --- a/rtgui/popupcommon.h +++ b/rtgui/popupcommon.h @@ -20,12 +20,19 @@ */ #pragma once +#include "glibmm/refptr.h" +#include #include #include #include +namespace Gio +{ +class Icon; +} + namespace Gtk { @@ -33,6 +40,7 @@ class Grid; class Menu; class Button; class ImageMenuItem; +class Widget; } @@ -53,9 +61,12 @@ public: explicit PopUpCommon (Gtk::Button* button, const Glib::ustring& label = ""); virtual ~PopUpCommon (); bool addEntry (const Glib::ustring& fileName, const Glib::ustring& label); + bool insertEntry(int position, const Glib::ustring& fileName, const Glib::ustring& label); + bool insertEntry(int position, const Glib::RefPtr& gIcon, const Glib::ustring& label); int getEntryCount () const; bool setSelected (int entryNum); int getSelected () const; + void removeEntry(int position); void setButtonHint(); void show (); void set_tooltip_text (const Glib::ustring &text); @@ -65,16 +76,22 @@ private: type_signal_changed messageChanged; type_signal_item_selected messageItemSelected; + std::vector> imageIcons; std::vector imageFilenames; std::vector images; Glib::ustring buttonHint; RTImage* buttonImage; Gtk::Grid* imageContainer; - Gtk::Menu* menu; + std::unique_ptr menu; Gtk::Button* button; + Gtk::Button* arrowButton; int selected; bool hasMenu; + void changeImage(int position); + void changeImage(const Glib::ustring& fileName, const Glib::RefPtr& gIcon); + void entrySelected(Gtk::Widget* menuItem); + bool insertEntryImpl(int position, const Glib::ustring& fileName, const Glib::RefPtr& gIcon, RTImage* image, const Glib::ustring& label); void showMenu(GdkEventButton* event); protected: From be7aecac40e5e91ae4047dd84bcc7219b0d4615a Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 11 Apr 2021 18:24:39 -0700 Subject: [PATCH 005/134] Add multiple external editors to options --- rtgui/options.cc | 170 +++++++++++++++++++++++++++++++++++++++++++++++ rtgui/options.h | 13 ++++ 2 files changed, 183 insertions(+) diff --git a/rtgui/options.cc b/rtgui/options.cc index ce03db434..2a00af525 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -413,6 +413,8 @@ void Options::setDefaults() gimpDir = ""; psDir = ""; customEditorProg = ""; + externalEditors.clear(); + externalEditorIndex = -1; CPBKeys = CPBKT_TID; editorToSendTo = 1; favoriteDirs.clear(); @@ -808,6 +810,7 @@ void Options::readFromFile(Glib::ustring fname) } } + // TODO: Remove. if (keyFile.has_group("External Editor")) { if (keyFile.has_key("External Editor", "EditorKind")) { editorToSendTo = keyFile.get_integer("External Editor", "EditorKind"); @@ -826,6 +829,138 @@ 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", "IconNames")) { + // Multiple external editors. + + const auto & names = + !keyFile.has_key("External Editor", "Names") ? + std::vector() : + static_cast>( + keyFile.get_string_list("External Editor", "Names")); + const auto & commands = + !keyFile.has_key("External Editor", "Commands") ? + std::vector() : + static_cast>( + keyFile.get_string_list("External Editor", "Commands")); + const auto & icon_names = + !keyFile.has_key("External Editor", "IconNames") ? + std::vector() : + static_cast>( + keyFile.get_string_list("External Editor", "IconNames")); + externalEditors = std::vector(std::max(std::max( + names.size(), commands.size()), icon_names.size())); + for (unsigned i = 0; i < names.size(); i++) { + externalEditors[i].name = names[i]; + } + for (unsigned i = 0; i < commands.size(); i++) { + externalEditors[i].command = commands[i]; + } + for (unsigned i = 0; i < icon_names.size(); i++) { + externalEditors[i].icon_name = icon_names[i]; + } + + if (keyFile.has_key("External Editor", "EditorIndex")) { + int index = keyFile.get_integer("External Editor", "EditorIndex"); + externalEditorIndex = std::min( + std::max(-1, index), + static_cast(externalEditors.size()) + ); + } + } else if (keyFile.has_key("External Editor", "EditorKind")) { + // Legacy fixed external editors. Convert to flexible. + + // GIMP == 1, Photoshop == 2, Custom == 3. + editorToSendTo = keyFile.get_integer("External Editor", "EditorKind"); + + #ifdef WIN32 + Glib::ustring gimpDir = ""; + if (keyFile.has_key("External Editor", "GimpDir")) { + gimpDir = keyFile.get_string("External Editor", "GimpDir"); + } + auto executable = Glib::build_filename(options.gimpDir, "bin", "gimp-win-remote"); + if (Glib::file_test(executable, Glib::FILE_TEST_IS_EXECUTABLE)) { + if (editorToSendTo == 1) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("GIMP", executable, "gimp")); + } else { + for (auto ver = 12; ver >= 0; --ver) { + executable = Glib::build_filename(gimpDir, "bin", Glib::ustring::compose(Glib::ustring("gimp-2.%1.exe"), ver)); + if (Glib::file_test(executable, Glib::FILE_TEST_IS_EXECUTABLE)) { + if (editorToSendTo == 1) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("GIMP", executable, "gimp")); + break; + } + } + } + + Glib::ustring psDir = ""; + if (keyFile.has_key("External Editor", "PhotoshopDir")) { + psDir = keyFile.get_string("External Editor", "PhotoshopDir"); + } + auto executable = Glib::build_filename(psDir, "Photoshop.exe"); + if (Glib::file_test(executable, Glib::FILE_TEST_IS_EXECUTABLE)) { + if (editorToSendTo == 2) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("Photoshop", executable, "")); + } + + if (keyFile.has_key("External Editor", "CustomEditor")) { + executable = keyFile.get_string("External Editor", "CustomEditor"); + if (editorToSendTo == 3) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("-", executable, ""); + } + #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")); + + if (editorToSendTo == 2) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("Photoshop", "open -a Photoshop", "")); + + if (keyFile.has_key("External Editor", "CustomEditor")) { + auto executable = keyFile.get_string("External Editor", "CustomEditor"); + if (editorToSendTo == 3) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("-", executable, "")); + } + #else + if (Glib::find_program_in_path("gimp").compare("")) { + if (editorToSendTo == 1) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("GIMP", "gimp", "gimp")); + } else if (Glib::find_program_in_path("gimp-remote").compare("")) { + if (editorToSendTo == 1) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("GIMP", "gimp-remote", "gimp")); + } + + if (keyFile.has_key("External Editor", "CustomEditor")) { + auto executable = keyFile.get_string("External Editor", "CustomEditor"); + if (editorToSendTo == 3) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("-", executable, "")); + } + #endif + } + } + if (keyFile.has_group("Output")) { if (keyFile.has_key("Output", "Format")) { saveFormat.format = keyFile.get_string("Output", "Format"); @@ -2111,11 +2246,30 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_boolean("General", "Detectshape", rtSettings.detectshape); keyFile.set_boolean("General", "Fftwsigma", rtSettings.fftwsigma); + // TODO: Remove. keyFile.set_integer("External Editor", "EditorKind", editorToSendTo); keyFile.set_string("External Editor", "GimpDir", gimpDir); keyFile.set_string("External Editor", "PhotoshopDir", psDir); keyFile.set_string("External Editor", "CustomEditor", customEditorProg); + { + std::vector names; + std::vector commands; + std::vector icon_names; + + for (const auto & editor : externalEditors) { + names.push_back(editor.name); + commands.push_back(editor.command); + icon_names.push_back(editor.icon_name); + } + + keyFile.set_string_list("External Editor", "Names", names); + keyFile.set_string_list("External Editor", "Commands", commands); + keyFile.set_string_list("External Editor", "IconNames", icon_names); + + keyFile.set_integer("External Editor", "EditorIndex", externalEditorIndex); + } + keyFile.set_boolean("File Browser", "BrowseOnlyRaw", fbOnlyRaw); keyFile.set_boolean("File Browser", "BrowserShowsDate", fbShowDateTime); keyFile.set_boolean("File Browser", "BrowserShowsExif", fbShowBasicExif); @@ -2778,3 +2932,19 @@ Glib::ustring Options::getICCProfileCopyright() now.set_time_current(); return Glib::ustring::compose("Copyright RawTherapee %1, CC0", now.get_year()); } + +ExternalEditor::ExternalEditor() {} + +ExternalEditor::ExternalEditor( + const Glib::ustring &name, const Glib::ustring &command, const Glib::ustring &icon_name +): name(name), command(command), icon_name(icon_name) {} + +bool ExternalEditor::operator==(const ExternalEditor &other) const +{ + return this->name == other.name && this->command == other.command && this->icon_name == other.icon_name; +} + +bool ExternalEditor::operator!=(const ExternalEditor &other) const +{ + return !(*this == other); +} diff --git a/rtgui/options.h b/rtgui/options.h index 03b551efe..be2ba70ab 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -52,6 +52,17 @@ // Special name for the Dynamic profile #define DEFPROFILE_DYNAMIC "Dynamic" +struct ExternalEditor { + ExternalEditor(); + ExternalEditor(const Glib::ustring &name, const Glib::ustring &command, const Glib::ustring &icon_name); + Glib::ustring name; + Glib::ustring command; + Glib::ustring icon_name; + + bool operator==(const ExternalEditor & other) const; + bool operator!=(const ExternalEditor & other) const; +}; + struct SaveFormat { SaveFormat( const Glib::ustring& _format, @@ -277,6 +288,8 @@ public: Glib::ustring gimpDir; Glib::ustring psDir; Glib::ustring customEditorProg; + std::vector externalEditors; + int externalEditorIndex; Glib::ustring CPBPath; // Custom Profile Builder's path CPBKeyType CPBKeys; // Custom Profile Builder's key type int editorToSendTo; From 3efbb99ba9eedd4942a5ba34f8d8ce54fbdc07d6 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Mon, 12 Apr 2021 21:48:54 -0700 Subject: [PATCH 006/134] Make MyImageMenuItem constructable from an RTImage --- rtgui/guiutils.cc | 19 +++++++++++++++++-- rtgui/guiutils.h | 3 +++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index f415d770f..52ad2d6d4 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -1466,13 +1466,28 @@ TextOrIcon::TextOrIcon (const Glib::ustring &fname, const Glib::ustring &labelTx } MyImageMenuItem::MyImageMenuItem(Glib::ustring label, Glib::ustring imageFileName) +{ + RTImage* itemImage = nullptr; + + if (!imageFileName.empty()) { + itemImage = Gtk::manage(new RTImage(imageFileName)); + } + + construct(label, itemImage); +} + +MyImageMenuItem::MyImageMenuItem(Glib::ustring label, RTImage* itemImage) { + construct(label, itemImage); +} + +void MyImageMenuItem::construct(Glib::ustring label, RTImage* itemImage) { box = Gtk::manage (new Gtk::Grid()); this->label = Gtk::manage( new Gtk::Label(label)); box->set_orientation(Gtk::ORIENTATION_HORIZONTAL); - if (!imageFileName.empty()) { - image = Gtk::manage( new RTImage(imageFileName) ); + if (itemImage) { + image = itemImage; box->attach_next_to(*image, Gtk::POS_LEFT, 1, 1); } else { image = nullptr; diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index d90d45370..2077d505d 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -489,8 +489,11 @@ private: RTImage *image; Gtk::Label *label; + void construct(Glib::ustring label, RTImage* image); + public: MyImageMenuItem (Glib::ustring label, Glib::ustring imageFileName); + MyImageMenuItem (Glib::ustring label, RTImage* image); const RTImage *getImage () const; const Gtk::Label* getLabel () const; }; From 349ceb933627955a8ea7238e2b0c1ecb904e6103 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Mon, 12 Apr 2021 21:53:04 -0700 Subject: [PATCH 007/134] Add function for opening images with Gio::AppInfo --- rtgui/extprog.cc | 5 +++++ rtgui/extprog.h | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/rtgui/extprog.cc b/rtgui/extprog.cc index 57d57ecd8..939ead608 100644 --- a/rtgui/extprog.cc +++ b/rtgui/extprog.cc @@ -339,3 +339,8 @@ bool ExtProgStore::openInCustomEditor (const Glib::ustring& fileName) #endif } + +bool ExtProgStore::openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr &editorInfo) +{ + return editorInfo->launch(Gio::File::create_for_path(fileName)); +} diff --git a/rtgui/extprog.h b/rtgui/extprog.h index c5e00bb1b..86dbc1674 100644 --- a/rtgui/extprog.h +++ b/rtgui/extprog.h @@ -24,6 +24,11 @@ #include "threadutils.h" +namespace Gio +{ + class AppInfo; +} + struct ExtProgAction { Glib::ustring filePathEXE; @@ -64,6 +69,7 @@ public: static bool openInGimp (const Glib::ustring& fileName); static bool openInPhotoshop (const Glib::ustring& fileName); static bool openInCustomEditor (const Glib::ustring& fileName); + static bool openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr &editorInfo); }; #define extProgStore ExtProgStore::getInstance() From 927e9500ff98ba642a9e31d4b1fcf6348bfdf752 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 17 Apr 2021 12:55:17 -0700 Subject: [PATCH 008/134] Change GUI to support multiple external editors Replace radio selector in external editor section of preferences with external editor preferences widget. Replace send-to-GIMP button with pop-up button for exporting to a selectable application. --- rtdata/languages/default | 3 +- rtgui/editorpanel.cc | 116 +++++++++++++++++++++++++++++++-------- rtgui/editorpanel.h | 12 +++- rtgui/popupcommon.cc | 2 +- rtgui/preferences.cc | 58 ++++++++++++++++++++ rtgui/preferences.h | 2 + rtgui/rtwindow.cc | 7 +++ rtgui/rtwindow.h | 2 + 8 files changed, 175 insertions(+), 27 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 2ff654ede..605f0d95d 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -235,6 +235,7 @@ GENERAL_NO;No GENERAL_NONE;None GENERAL_OK;OK GENERAL_OPEN;Open +GENERAL_OTHER;Other GENERAL_PORTRAIT;Portrait GENERAL_RESET;Reset GENERAL_SAVE;Save @@ -1513,7 +1514,7 @@ MAIN_BUTTON_PREFERENCES;Preferences MAIN_BUTTON_PUTTOQUEUE_TOOLTIP;Put current image to processing queue.\nShortcut: Ctrl+b MAIN_BUTTON_SAVE_TOOLTIP;Save current image.\nShortcut: Ctrl+s\nSave current profile (.pp3).\nShortcut: Ctrl+Shift+s MAIN_BUTTON_SENDTOEDITOR;Edit image in external editor -MAIN_BUTTON_SENDTOEDITOR_TOOLTIP;Edit current image in external editor.\nShortcut: Ctrl+e +MAIN_BUTTON_SENDTOEDITOR_TOOLTIP;Edit current image in external editor.\nShortcut: Ctrl+e\nCurrent editor: MAIN_BUTTON_SHOWHIDESIDEPANELS_TOOLTIP;Show/hide all side panels.\nShortcut: m MAIN_BUTTON_UNFULLSCREEN;Exit fullscreen MAIN_FRAME_EDITOR;Editor diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 7553a7353..e5543105c 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -666,12 +666,15 @@ EditorPanel::EditorPanel (FilePanel* filePanel) queueimg->set_tooltip_markup (M ("MAIN_BUTTON_PUTTOQUEUE_TOOLTIP")); setExpandAlignProperties (queueimg, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); - Gtk::Image *sendToEditorButtonImage = Gtk::manage (new RTImage ("palette-brush.png")); - sendtogimp = Gtk::manage (new Gtk::Button ()); - sendtogimp->set_relief(Gtk::RELIEF_NONE); - sendtogimp->add (*sendToEditorButtonImage); - sendtogimp->set_tooltip_markup (M ("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP")); - setExpandAlignProperties (sendtogimp, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); + send_to_external = Gtk::make_managed("", false); + send_to_external->set_tooltip_text(M("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP")); + setExpandAlignProperties(send_to_external->buttonGroup, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); + send_to_external->addEntry("palette-brush.png", M("GENERAL_OTHER")); + updateExternalEditorWidget( + options.externalEditorIndex >= 0 ? options.externalEditorIndex : options.externalEditors.size(), + options.externalEditors + ); + send_to_external->show(); // Status box progressLabel = Gtk::manage (new MyProgressBar (300)); @@ -736,7 +739,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel) iops->attach_next_to (*vsep1, Gtk::POS_LEFT, 1, 1); if (!gimpPlugin) { - iops->attach_next_to (*sendtogimp, Gtk::POS_LEFT, 1, 1); + iops->attach_next_to(*send_to_external->buttonGroup, Gtk::POS_LEFT, 1, 1); } if (!gimpPlugin && !simpleEditor) { @@ -840,7 +843,8 @@ EditorPanel::EditorPanel (FilePanel* filePanel) tbRightPanel_1->signal_toggled().connect ( sigc::mem_fun (*this, &EditorPanel::tbRightPanel_1_toggled) ); saveimgas->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::saveAsPressed) ); queueimg->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::queueImgPressed) ); - sendtogimp->signal_pressed().connect ( sigc::mem_fun (*this, &EditorPanel::sendToGimpPressed) ); + send_to_external->signal_changed().connect(sigc::mem_fun(*this, &EditorPanel::sendToExternalChanged)); + send_to_external->signal_pressed().connect(sigc::mem_fun(*this, &EditorPanel::sendToExternalPressed)); toggleHistogramProfile->signal_toggled().connect( sigc::mem_fun (*this, &EditorPanel::histogramProfile_toggled) ); if (navPrev) { @@ -1673,7 +1677,7 @@ bool EditorPanel::handleShortcutKey (GdkEventKey* event) case GDK_KEY_e: if (!gimpPlugin) { - sendToGimpPressed(); + sendToExternalPressed(); } return true; @@ -1791,7 +1795,7 @@ bool EditorPanel::idle_saveImage (ProgressConnector *pc, msgd.run (); saveimgas->set_sensitive (true); - sendtogimp->set_sensitive (true); + send_to_external->set_sensitive(true); isProcessing = false; } @@ -1819,7 +1823,7 @@ bool EditorPanel::idle_imageSaved (ProgressConnector *pc, rtengine::IImagef } saveimgas->set_sensitive (true); - sendtogimp->set_sensitive (true); + send_to_external->set_sensitive(true); parent->setProgressStr (""); parent->setProgress (0.); @@ -1930,7 +1934,7 @@ void EditorPanel::saveAsPressed () ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ), sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_saveImage ), ld, fnameOut, sf, pparams)); saveimgas->set_sensitive (false); - sendtogimp->set_sensitive (false); + send_to_external->set_sensitive(false); } } else { BatchQueueEntry* bqe = createBatchQueueEntry (); @@ -1961,7 +1965,7 @@ void EditorPanel::queueImgPressed () parent->addBatchQueueJob (createBatchQueueEntry ()); } -void EditorPanel::sendToGimpPressed () +void EditorPanel::sendToExternal() { if (!ipc || !openThm) { return; @@ -1975,7 +1979,29 @@ void EditorPanel::sendToGimpPressed () ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ), sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_sendToGimp ), ld, openThm->getFileName() )); saveimgas->set_sensitive (false); - sendtogimp->set_sensitive (false); + send_to_external->set_sensitive(false); +} + +void EditorPanel::sendToExternalChanged(int) +{ + int index = send_to_external->getSelected(); + if (index >= 0 && static_cast(index) == options.externalEditors.size()) { + index = -1; + } + options.externalEditorIndex = index; +} + +void EditorPanel::sendToExternalPressed() +{ + if (options.externalEditorIndex == -1) { + // "Other" external editor. Show app chooser dialog to let user pick. + Gtk::AppChooserDialog *dialog = getAppChooserDialog(); + dialog->show(); + } 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); + sendToExternal(); + } } @@ -2078,7 +2104,7 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector *p Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); msgd.run (); saveimgas->set_sensitive (true); - sendtogimp->set_sensitive (true); + send_to_external->set_sensitive(true); } return false; @@ -2093,18 +2119,12 @@ bool EditorPanel::idle_sentToGimp (ProgressConnector *pc, rtengine::IImagef if (!errore) { saveimgas->set_sensitive (true); - sendtogimp->set_sensitive (true); + send_to_external->set_sensitive(true); parent->setProgressStr (""); parent->setProgress (0.); bool success = false; - if (options.editorToSendTo == 1) { - success = ExtProgStore::openInGimp (filename); - } else if (options.editorToSendTo == 2) { - success = ExtProgStore::openInPhotoshop (filename); - } else if (options.editorToSendTo == 3) { - success = ExtProgStore::openInCustomEditor (filename); - } + success = ExtProgStore::openInExternalEditor(filename, external_editor_info); if (!success) { Gtk::MessageDialog msgd (*parent, M ("MAIN_MSG_CANNOTSTARTEDITOR"), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); @@ -2117,6 +2137,36 @@ bool EditorPanel::idle_sentToGimp (ProgressConnector *pc, rtengine::IImagef return false; } +Gtk::AppChooserDialog *EditorPanel::getAppChooserDialog() +{ + if (!app_chooser_dialog.get()) { + app_chooser_dialog.reset(new Gtk::AppChooserDialog("image/tiff")); + app_chooser_dialog->signal_response().connect( + sigc::mem_fun(*this, &EditorPanel::onAppChooserDialogResponse) + ); + app_chooser_dialog->set_modal(); + } + + return app_chooser_dialog.get(); +} + +void EditorPanel::onAppChooserDialogResponse(int responseId) +{ + switch (responseId) { + case Gtk::RESPONSE_OK: + getAppChooserDialog()->close(); + external_editor_info = getAppChooserDialog()->get_app_info(); + sendToExternal(); + break; + case Gtk::RESPONSE_CANCEL: + case Gtk::RESPONSE_CLOSE: + getAppChooserDialog()->close(); + break; + default: + break; + } +} + void EditorPanel::historyBeforeLineChanged (const rtengine::procparams::ProcParams& params) { @@ -2392,6 +2442,26 @@ void EditorPanel::tbShowHideSidePanels_managestate() ShowHideSidePanelsconn.block (false); } +void EditorPanel::updateExternalEditorWidget(int selectedIndex, const std::vector &editors) +{ + // Remove the editors and leave the "Other" entry. + while (send_to_external->getEntryCount() > 1) { + send_to_external->removeEntry(0); + } + // Add the editors. + for (unsigned i = 0; i < editors.size(); i++) { + const auto & name = editors[i].name.empty() ? Glib::ustring(" ") : editors[i].name; + if (!editors[i].icon_name.empty()) { + Glib::RefPtr gioIcon = Gio::Icon::create(editors[i].icon_name); + send_to_external->insertEntry(i, gioIcon, name); + } else { + send_to_external->insertEntry(i, "palette-brush.png", name); + } + } + send_to_external->setSelected(selectedIndex); + send_to_external->show(); +} + void EditorPanel::updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC) { } diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 7675face5..0008786fa 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -43,6 +43,7 @@ class EditorPanel; class FilePanel; class MyProgressBar; class Navigator; +class PopUpButton; class Thumbnail; class ToolPanelCoordinator; @@ -162,7 +163,9 @@ public: void tbBeforeLock_toggled(); void saveAsPressed (); void queueImgPressed (); - void sendToGimpPressed (); + void sendToExternal(); + void sendToExternalChanged(int); + void sendToExternalPressed(); void openNextEditorImage (); void openPreviousEditorImage (); void syncFileBrowser (); @@ -182,6 +185,7 @@ public: { return isProcessing; } + void updateExternalEditorWidget(int selectedIndex, const std::vector &editors); void updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC); void updateTPVScrollbar (bool hide); void updateHistogramPosition (int oldPosition, int newPosition); @@ -201,6 +205,8 @@ private: bool idle_sendToGimp ( ProgressConnector *pc, Glib::ustring fname); bool idle_sentToGimp (ProgressConnector *pc, rtengine::IImagefloat* img, Glib::ustring filename); void histogramProfile_toggled (); + Gtk::AppChooserDialog *getAppChooserDialog(); + void onAppChooserDialogResponse(int resposneId); Glib::ustring lastSaveAsFileName; @@ -230,10 +236,12 @@ private: Gtk::Button* queueimg; Gtk::Button* saveimgas; - Gtk::Button* sendtogimp; + PopUpButton* send_to_external; Gtk::Button* navSync; Gtk::Button* navNext; Gtk::Button* navPrev; + Glib::RefPtr external_editor_info; + std::unique_ptr app_chooser_dialog; class ColorManagementToolbar; std::unique_ptr colorMgmtToolBar; diff --git a/rtgui/popupcommon.cc b/rtgui/popupcommon.cc index fabc4d572..c33ac068e 100644 --- a/rtgui/popupcommon.cc +++ b/rtgui/popupcommon.cc @@ -251,7 +251,7 @@ void PopUpCommon::setButtonHint() auto item = dynamic_cast(widget); if (item) { - hint += item->getLabel ()->get_text (); + hint += escapeHtmlChars(item->getLabel()->get_text()); } } diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 9d9603297..d4f550dd3 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -17,6 +17,7 @@ * along with RawTherapee. If not, see . */ #include +#include "externaleditorpreferences.h" #include "preferences.h" #include "multilangmgr.h" #include "splash.h" @@ -33,6 +34,8 @@ #include #endif +//#define EXT_EDITORS_RADIOS // TODO: Remove the corresponding code after testing. + namespace { void placeSpinBox(Gtk::Container* where, Gtk::SpinButton* &spin, const std::string &labelText, int digits, int inc0, int inc1, int maxLength, int range0, int range1, const std::string &toolTip = "") { Gtk::Box* HB = Gtk::manage ( new Gtk::Box () ); @@ -1188,6 +1191,7 @@ Gtk::Widget* Preferences::getGeneralPanel() Gtk::Frame* fdg = Gtk::manage(new Gtk::Frame(M("PREFERENCES_EXTERNALEDITOR"))); setExpandAlignProperties(fdg, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); +#ifdef EXT_EDITORS_RADIOS Gtk::Grid* externaleditorGrid = Gtk::manage(new Gtk::Grid()); externaleditorGrid->set_column_spacing(4); externaleditorGrid->set_row_spacing(4); @@ -1243,8 +1247,17 @@ Gtk::Widget* Preferences::getGeneralPanel() externaleditorGrid->attach_next_to(*edOther, *edGimp, Gtk::POS_BOTTOM, 1, 1); externaleditorGrid->attach_next_to(*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1); #endif +#endif + + externalEditors = Gtk::make_managed(); + externalEditors->set_size_request(-1, 200); +#ifdef EXT_EDITORS_RADIOS + externaleditorGrid->attach_next_to(*externalEditors, *edOther, Gtk::POS_BOTTOM, 2, 1); fdg->add(*externaleditorGrid); +#else + fdg->add(*externalEditors); +#endif vbGeneral->attach_next_to (*fdg, *fclip, Gtk::POS_BOTTOM, 2, 1); langAutoDetectConn = ckbLangAutoDetect->signal_toggled().connect(sigc::mem_fun(*this, &Preferences::langAutoDetectToggled)); tconn = themeCBT->signal_changed().connect ( sigc::mem_fun (*this, &Preferences::themeChanged) ); @@ -1700,6 +1713,7 @@ void Preferences::storePreferences() moptions.pseudoHiDPISupport = pseudoHiDPI->get_active(); +#ifdef EXT_EDITORS_RADIOS #ifdef WIN32 moptions.gimpDir = gimpDir->get_filename(); moptions.psDir = psDir->get_filename(); @@ -1726,6 +1740,20 @@ void Preferences::storePreferences() else if (edOther->get_active()) { moptions.editorToSendTo = 3; } +#endif + + const std::vector &editors = externalEditors->getEditors(); + moptions.externalEditors.resize(editors.size()); + moptions.externalEditorIndex = -1; + for (unsigned i = 0; i < editors.size(); i++) { + moptions.externalEditors[i] = (ExternalEditor( + editors[i].name, editors[i].command, editors[i].icon_name)); + 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. + moptions.externalEditorIndex = i; + } + } moptions.CPBPath = txtCustProfBuilderPath->get_text(); moptions.CPBKeys = CPBKeyType(custProfBuilderLabelType->get_active_row_number()); @@ -1981,6 +2009,7 @@ void Preferences::fillPreferences() hlThresh->set_value(moptions.highlightThreshold); shThresh->set_value(moptions.shadowThreshold); +#ifdef EXT_EDITORS_RADIOS edGimp->set_active(moptions.editorToSendTo == 1); edOther->set_active(moptions.editorToSendTo == 3); #ifdef WIN32 @@ -2009,6 +2038,18 @@ void Preferences::fillPreferences() #endif editorToSendTo->set_text(moptions.customEditorProg); +#endif + + std::vector editorInfos; + for (const auto &editor : moptions.externalEditors) { + editorInfos.push_back(ExternalEditorPreferences::EditorInfo( + editor.name, editor.command, editor.icon_name)); + } + if (moptions.externalEditorIndex >= 0) { + // Mark the current editor so we can track it. + editorInfos[moptions.externalEditorIndex].other_data = (void *)1; + } + externalEditors->setEditors(editorInfos); txtCustProfBuilderPath->set_text(moptions.CPBPath); custProfBuilderLabelType->set_active(moptions.CPBKeys); @@ -2474,6 +2515,23 @@ void Preferences::workflowUpdate() parent->updateProfiles (moptions.rtSettings.printerProfile, rtengine::RenderingIntent(moptions.rtSettings.printerIntent), moptions.rtSettings.printerBPC); } + bool changed = moptions.externalEditorIndex != options.externalEditorIndex + || moptions.externalEditors.size() != options.externalEditors.size(); + if (!changed) { + auto &editors = options.externalEditors; + auto &meditors = moptions.externalEditors; + for (unsigned i = 0; i < editors.size(); i++) { + if (editors[i] != meditors[i]) { + changed = true; + break; + } + } + } + if (changed) { + // Update the send to external editor widget. + parent->updateExternalEditorWidget(moptions.externalEditorIndex, moptions.externalEditors); + } + } void Preferences::addExtPressed() diff --git a/rtgui/preferences.h b/rtgui/preferences.h index df4e3327a..9e0730c04 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -26,6 +26,7 @@ #include "options.h" #include "../rtengine/profilestore.h" +class ExternalEditorPreferences; class RTWindow; class Splash; @@ -101,6 +102,7 @@ class Preferences final : Gtk::RadioButton* edGimp; Gtk::RadioButton* edPS; Gtk::RadioButton* edOther; + ExternalEditorPreferences *externalEditors; MyFileChooserButton* darkFrameDir; MyFileChooserButton* flatFieldDir; MyFileChooserButton* clutsDir; diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index c0042f949..0822c0aad 100644 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -1030,6 +1030,13 @@ void RTWindow::MoveFileBrowserToEditor() } } +void RTWindow::updateExternalEditorWidget(int selectedIndex, const std::vector & editors) +{ + if (epanel) { + epanel->updateExternalEditorWidget(selectedIndex, editors); + } +} + void RTWindow::updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC) { if (epanel) { diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h index e5e180747..32d0756b5 100644 --- a/rtgui/rtwindow.h +++ b/rtgui/rtwindow.h @@ -33,6 +33,7 @@ class BatchQueueEntry; class BatchQueuePanel; class EditorPanel; +class ExternalEditor; class FilePanel; class PLDBridge; class RTWindow final : @@ -114,6 +115,7 @@ public: void MoveFileBrowserToEditor(); void MoveFileBrowserToMain(); + void updateExternalEditorWidget(int selectedIndex, const std::vector &editors); void updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC); void updateTPVScrollbar (bool hide); void updateHistogramPosition (int oldPosition, int newPosition); From 044451868ac623bda15a5b8d1a6d02f37b5b31b4 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 17 Apr 2021 22:11:17 -0700 Subject: [PATCH 009/134] Add missing parenthesis --- rtgui/options.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/options.cc b/rtgui/options.cc index 2a00af525..a967ed873 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -916,7 +916,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 3) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("-", executable, ""); + externalEditors.push_back(ExternalEditor("-", executable, "")); } #elif defined __APPLE__ if (editorToSendTo == 1) { From e6b2c9e7b06bf67b511db5ae53a172d08c8ab6fb Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 18 Apr 2021 12:33:32 -0700 Subject: [PATCH 010/134] Make options ignore empty custom editor command --- rtgui/options.cc | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/rtgui/options.cc b/rtgui/options.cc index a967ed873..cf577fe7d 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -875,7 +875,7 @@ void Options::readFromFile(Glib::ustring fname) // GIMP == 1, Photoshop == 2, Custom == 3. editorToSendTo = keyFile.get_integer("External Editor", "EditorKind"); - #ifdef WIN32 +#ifdef WIN32 Glib::ustring gimpDir = ""; if (keyFile.has_key("External Editor", "GimpDir")) { gimpDir = keyFile.get_string("External Editor", "GimpDir"); @@ -903,7 +903,7 @@ void Options::readFromFile(Glib::ustring fname) if (keyFile.has_key("External Editor", "PhotoshopDir")) { psDir = keyFile.get_string("External Editor", "PhotoshopDir"); } - auto executable = Glib::build_filename(psDir, "Photoshop.exe"); + executable = Glib::build_filename(psDir, "Photoshop.exe"); if (Glib::file_test(executable, Glib::FILE_TEST_IS_EXECUTABLE)) { if (editorToSendTo == 2) { externalEditorIndex = externalEditors.size(); @@ -913,12 +913,14 @@ void Options::readFromFile(Glib::ustring fname) if (keyFile.has_key("External Editor", "CustomEditor")) { executable = keyFile.get_string("External Editor", "CustomEditor"); - if (editorToSendTo == 3) { - externalEditorIndex = externalEditors.size(); + if (!executable.empty()) { + if (editorToSendTo == 3) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("-", executable, "")); } - externalEditors.push_back(ExternalEditor("-", executable, "")); } - #elif defined __APPLE__ +#elif defined __APPLE__ if (editorToSendTo == 1) { externalEditorIndex = externalEditors.size(); } @@ -932,12 +934,14 @@ void Options::readFromFile(Glib::ustring fname) if (keyFile.has_key("External Editor", "CustomEditor")) { auto executable = keyFile.get_string("External Editor", "CustomEditor"); - if (editorToSendTo == 3) { - externalEditorIndex = externalEditors.size(); + if (!executable.empty()) { + if (editorToSendTo == 3) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("-", executable, "")); } - externalEditors.push_back(ExternalEditor("-", executable, "")); } - #else +#else if (Glib::find_program_in_path("gimp").compare("")) { if (editorToSendTo == 1) { externalEditorIndex = externalEditors.size(); @@ -952,12 +956,14 @@ void Options::readFromFile(Glib::ustring fname) if (keyFile.has_key("External Editor", "CustomEditor")) { auto executable = keyFile.get_string("External Editor", "CustomEditor"); - if (editorToSendTo == 3) { - externalEditorIndex = externalEditors.size(); + if (!executable.empty()) { + if (editorToSendTo == 3) { + externalEditorIndex = externalEditors.size(); + } + externalEditors.push_back(ExternalEditor("-", executable, "")); } - externalEditors.push_back(ExternalEditor("-", executable, "")); } - #endif +#endif } } From d9fe87569dabbbc5ee561c93e230b75e88ea3ee7 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 18 Apr 2021 17:23:40 -0700 Subject: [PATCH 011/134] Cache most recent send-to-editor temp file Caches the name of the most recently generated temporary file used for exporting to external editors and uses that file if the processing parameters are identical and the file exists. This can dramatically improve speed when exporting to multiple different editors. --- rtgui/editorpanel.cc | 22 ++++++++++++++++++---- rtgui/editorpanel.h | 3 +++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index e5543105c..021333503 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -1974,6 +1974,14 @@ void EditorPanel::sendToExternal() // develop image rtengine::procparams::ProcParams pparams; ipc->getParams (&pparams); + + if (!cached_exported_filename.empty() && pparams == cached_exported_pparams && Glib::file_test(cached_exported_filename, Glib::FILE_TEST_IS_REGULAR)) { + idle_sentToGimp(nullptr, nullptr, cached_exported_filename); + return; + } + + cached_exported_pparams = pparams; + cached_exported_filename.clear(); rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); ProgressConnector *ld = new ProgressConnector(); ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ), @@ -2112,12 +2120,18 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector *p bool EditorPanel::idle_sentToGimp (ProgressConnector *pc, rtengine::IImagefloat* img, Glib::ustring filename) { - delete img; - int errore = pc->returnValue(); + if (img) { + delete img; + cached_exported_filename = filename; + } + int errore = 0; setProgressState(false); - delete pc; + if (pc) { + errore = pc->returnValue(); + delete pc; + } - if (!errore) { + if ((!img && Glib::file_test(filename, Glib::FILE_TEST_IS_REGULAR)) || (img && !errore)) { saveimgas->set_sensitive (true); send_to_external->set_sensitive(true); parent->setProgressStr (""); diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 0008786fa..1e6eaaa1f 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -243,6 +243,9 @@ private: Glib::RefPtr external_editor_info; std::unique_ptr app_chooser_dialog; + rtengine::procparams::ProcParams cached_exported_pparams; + Glib::ustring cached_exported_filename; + class ColorManagementToolbar; std::unique_ptr colorMgmtToolBar; From 4044f67c0ff73dd793bd62908a198754978ef6a6 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Mon, 5 Jul 2021 11:01:51 -0700 Subject: [PATCH 012/134] Align External Editor > Output directory to top Prevents the frame from expanding vertically. --- rtgui/preferences.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index d19481ea1..786262896 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -1271,7 +1271,7 @@ Gtk::Widget* Preferences::getGeneralPanel() editor_bypass_output_profile = Gtk::manage(new Gtk::CheckButton(M("PREFERENCES_EXTEDITOR_BYPASS_OUTPUT_PROFILE"))); { Gtk::Frame *f = Gtk::manage(new Gtk::Frame(M("PREFERENCES_EXTEDITOR_DIR"))); - setExpandAlignProperties(f, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + setExpandAlignProperties(f, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); Gtk::Box *vb = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); vb->pack_start(*editor_dir_temp); vb->pack_start(*editor_dir_current); From c62597545374b3427ae137a103584aa3f81afc7a Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 11 Jul 2021 21:38:52 -0700 Subject: [PATCH 013/134] Surround Windows commands in quotes When external editors are launched in Windows OS, the command is surrounded by quotes. This commit fixes the translation of commands for use by the multiple custom external editors feature so that the translated commands are also surrounded by quotes. --- rtgui/options.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rtgui/options.cc b/rtgui/options.cc index 88406452b..3bb3bb08f 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -912,7 +912,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 1) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("GIMP", executable, "gimp")); + externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", "gimp")); } else { for (auto ver = 12; ver >= 0; --ver) { executable = Glib::build_filename(gimpDir, "bin", Glib::ustring::compose(Glib::ustring("gimp-2.%1.exe"), ver)); @@ -920,7 +920,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 1) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("GIMP", executable, "gimp")); + externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", "gimp")); break; } } @@ -935,7 +935,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 2) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("Photoshop", executable, "")); + externalEditors.push_back(ExternalEditor("Photoshop", "\"" + executable + "\"", "")); } if (keyFile.has_key("External Editor", "CustomEditor")) { @@ -944,7 +944,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 3) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("-", executable, "")); + externalEditors.push_back(ExternalEditor("-", "\"" + executable + "\"", "")); } } #elif defined __APPLE__ From 02e3e0129453a37fa666ff85c793469a6b4fd6f8 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 11 Jul 2021 21:45:39 -0700 Subject: [PATCH 014/134] Use correct GIMP and Photoshop icons for Windows Icon names in Windows are typically the executable path followed by the string ",0". --- rtgui/options.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rtgui/options.cc b/rtgui/options.cc index 3bb3bb08f..6a944faa6 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -912,7 +912,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 1) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", "gimp")); + externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", executable + ",0")); } else { for (auto ver = 12; ver >= 0; --ver) { executable = Glib::build_filename(gimpDir, "bin", Glib::ustring::compose(Glib::ustring("gimp-2.%1.exe"), ver)); @@ -920,7 +920,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 1) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", "gimp")); + externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", executable + ",0")); break; } } @@ -935,7 +935,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 2) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("Photoshop", "\"" + executable + "\"", "")); + externalEditors.push_back(ExternalEditor("Photoshop", "\"" + executable + "\"", executable + ",0")); } if (keyFile.has_key("External Editor", "CustomEditor")) { From c4a8554db3da65d50497703ccd4951dbb16a86b9 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 11 Jul 2021 22:13:27 -0700 Subject: [PATCH 015/134] Catch exceptions when launching external editor Catch all Glib::Errors and print the error code and message to stderr. --- rtgui/extprog.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/rtgui/extprog.cc b/rtgui/extprog.cc index 148eee944..e4cf63733 100644 --- a/rtgui/extprog.cc +++ b/rtgui/extprog.cc @@ -342,5 +342,13 @@ bool ExtProgStore::openInCustomEditor (const Glib::ustring& fileName) bool ExtProgStore::openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr &editorInfo) { - return editorInfo->launch(Gio::File::create_for_path(fileName)); + try { + return editorInfo->launch(Gio::File::create_for_path(fileName)); + } catch (const Glib::Error &e) { + std::cerr + << "Error launching external editor.\n" + << "Error code #" << e.code() << ": " << e.what() + << std::endl; + return false; + } } From a0711ebc8c528e2b79706f4421c6181f1c71cce8 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 25 Jul 2021 16:03:13 -0700 Subject: [PATCH 016/134] Fix tmp image reuse when exporting different image If two images have identical processing parameters, then sending one to an external editor followed by sending the other one will cause the first temporary image to be reused. This commit associates the image in the editor with the "cached" temporary image so that the temporary image only gets used if the editor image matches. --- rtgui/editorpanel.cc | 3 ++- rtgui/editorpanel.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 5c61e672e..e52dab5db 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -1980,11 +1980,12 @@ void EditorPanel::sendToExternal() pparams.icm.outputProfile = rtengine::procparams::ColorManagementParams::NoProfileString; } - if (!cached_exported_filename.empty() && pparams == cached_exported_pparams && Glib::file_test(cached_exported_filename, Glib::FILE_TEST_IS_REGULAR)) { + if (!cached_exported_filename.empty() && cached_exported_image == ipc->getInitialImage() && pparams == cached_exported_pparams && Glib::file_test(cached_exported_filename, Glib::FILE_TEST_IS_REGULAR)) { idle_sentToGimp(nullptr, nullptr, cached_exported_filename); return; } + cached_exported_image = ipc->getInitialImage(); cached_exported_pparams = pparams; cached_exported_filename.clear(); rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams); diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 1e6eaaa1f..1372a2171 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -243,6 +243,7 @@ private: Glib::RefPtr external_editor_info; std::unique_ptr app_chooser_dialog; + rtengine::InitialImage *cached_exported_image; rtengine::procparams::ProcParams cached_exported_pparams; Glib::ustring cached_exported_filename; From db7d56c253433e94d892f5bbeaa5226008a410f5 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 25 Jul 2021 17:45:20 -0700 Subject: [PATCH 017/134] Synchronize send to external editor buttons Keep all buttons updated when using a multiple editor tabs mode. --- rtgui/editorpanel.cc | 32 ++++++++++++++++++++++++++++++++ rtgui/editorpanel.h | 10 ++++++++++ rtgui/editwindow.cc | 2 ++ rtgui/editwindow.h | 2 ++ 4 files changed, 46 insertions(+) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index e52dab5db..6649fc970 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2003,6 +2003,9 @@ void EditorPanel::sendToExternalChanged(int) index = -1; } options.externalEditorIndex = index; + if (externalEditorChangedSignal) { + externalEditorChangedSignal->emit(); + } } void EditorPanel::sendToExternalPressed() @@ -2069,6 +2072,23 @@ void EditorPanel::syncFileBrowser() // synchronize filebrowser with image in E } } +ExternalEditorChangedSignal * EditorPanel::getExternalEditorChangedSignal() +{ + return externalEditorChangedSignal; +} + +void EditorPanel::setExternalEditorChangedSignal(ExternalEditorChangedSignal *signal) +{ + if (externalEditorChangedSignal) { + externalEditorChangedSignalConnection.disconnect(); + } + externalEditorChangedSignal = signal; + if (signal) { + externalEditorChangedSignalConnection = signal->connect( + sigc::mem_fun(*this, &EditorPanel::updateExternalEditorSelection)); + } +} + void EditorPanel::histogramProfile_toggled() { options.rtSettings.HistogramWorking = toggleHistogramProfile->get_active(); @@ -2203,6 +2223,18 @@ void EditorPanel::onAppChooserDialogResponse(int responseId) } } +void EditorPanel::updateExternalEditorSelection() +{ + int index = send_to_external->getSelected(); + if (index >= 0 && static_cast(index) == options.externalEditors.size()) { + index = -1; + } + if (options.externalEditorIndex != index) { + send_to_external->setSelected( + options.externalEditorIndex >= 0 ? options.externalEditorIndex : options.externalEditors.size()); + } +} + void EditorPanel::historyBeforeLineChanged (const rtengine::procparams::ProcParams& params) { diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 1372a2171..1bbb95a6e 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -38,6 +38,8 @@ template class array2D; } +using ExternalEditorChangedSignal = sigc::signal; + class BatchQueueEntry; class EditorPanel; class FilePanel; @@ -66,6 +68,7 @@ class EditorPanel final : public rtengine::NonCopyable { public: + explicit EditorPanel (FilePanel* filePanel = nullptr); ~EditorPanel () override; @@ -170,6 +173,10 @@ public: void openPreviousEditorImage (); void syncFileBrowser (); + // Signals. + ExternalEditorChangedSignal * getExternalEditorChangedSignal(); + void setExternalEditorChangedSignal(ExternalEditorChangedSignal *signal); + void tbTopPanel_1_visible (bool visible); bool CheckSidePanelsVisibility(); void tbShowHideSidePanels_managestate(); @@ -207,6 +214,7 @@ private: void histogramProfile_toggled (); Gtk::AppChooserDialog *getAppChooserDialog(); void onAppChooserDialogResponse(int resposneId); + void updateExternalEditorSelection(); Glib::ustring lastSaveAsFileName; @@ -242,6 +250,8 @@ private: Gtk::Button* navPrev; Glib::RefPtr external_editor_info; std::unique_ptr app_chooser_dialog; + ExternalEditorChangedSignal *externalEditorChangedSignal; + sigc::connection externalEditorChangedSignalConnection; rtengine::InitialImage *cached_exported_image; rtengine::procparams::ProcParams cached_exported_pparams; diff --git a/rtgui/editwindow.cc b/rtgui/editwindow.cc index d0e53d730..0584edf77 100644 --- a/rtgui/editwindow.cc +++ b/rtgui/editwindow.cc @@ -250,6 +250,7 @@ void EditWindow::addEditorPanel (EditorPanel* ep, const std::string &name) { ep->setParent (parent); ep->setParentWindow(this); + ep->setExternalEditorChangedSignal(&externalEditorChangedSignal); // construct closeable tab for the image Gtk::Box* hb = Gtk::manage (new Gtk::Box ()); @@ -288,6 +289,7 @@ void EditWindow::remEditorPanel (EditorPanel* ep) return; // Will crash if destroyed while loading } + ep->setExternalEditorChangedSignal(nullptr); epanels.erase (ep->getFileName()); filesEdited.erase (ep->getFileName ()); parent->fpanel->refreshEditedState (filesEdited); diff --git a/rtgui/editwindow.h b/rtgui/editwindow.h index b8eeaee82..27d4598c1 100644 --- a/rtgui/editwindow.h +++ b/rtgui/editwindow.h @@ -39,6 +39,8 @@ private: std::set filesEdited; std::map epanels; + sigc::signal externalEditorChangedSignal; + bool isFullscreen; bool isClosed; bool isMinimized; From 9423ebc97c4839c40ca8e9a75b22f1f0f028e6c0 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 14 Aug 2021 11:32:25 -0700 Subject: [PATCH 018/134] Fix crash when changing external editors Initialize a pointer to nullptr. --- rtgui/editorpanel.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 6649fc970..775e6a935 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -470,7 +470,9 @@ public: EditorPanel::EditorPanel (FilePanel* filePanel) : catalogPane (nullptr), realized (false), tbBeforeLock (nullptr), iHistoryShow (nullptr), iHistoryHide (nullptr), iTopPanel_1_Show (nullptr), iTopPanel_1_Hide (nullptr), iRightPanel_1_Show (nullptr), iRightPanel_1_Hide (nullptr), - iBeforeLockON (nullptr), iBeforeLockOFF (nullptr), previewHandler (nullptr), beforePreviewHandler (nullptr), + iBeforeLockON (nullptr), iBeforeLockOFF (nullptr), + externalEditorChangedSignal (nullptr), + previewHandler (nullptr), beforePreviewHandler (nullptr), beforeIarea (nullptr), beforeBox (nullptr), afterBox (nullptr), beforeLabel (nullptr), afterLabel (nullptr), beforeHeaderBox (nullptr), afterHeaderBox (nullptr), parent (nullptr), parentWindow (nullptr), openThm (nullptr), selectedFrame(0), isrc (nullptr), ipc (nullptr), beforeIpc (nullptr), err (0), isProcessing (false), From d3e524a491c900adac72ef10fde01c5c5c626127 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 14 Aug 2021 16:05:11 -0700 Subject: [PATCH 019/134] Fix crash when adding an external editor On some platforms, the app chooser dialog causes a crash after selecting an application. The application information returned by the dialog may also trigger crashes when accessed. See https://gitlab.gnome.org/GNOME/glib/-/issues/1104 and https://gitlab.gnome.org/GNOME/glibmm/-/issues/94. This commit overrides gtkmm's app chooser dialog to work around these bugs. --- rtgui/CMakeLists.txt | 1 + rtgui/editorpanel.cc | 7 +-- rtgui/editorpanel.h | 5 +- rtgui/externaleditorpreferences.cc | 4 +- rtgui/externaleditorpreferences.h | 7 +-- rtgui/rtappchooserdialog.cc | 77 ++++++++++++++++++++++++++++++ rtgui/rtappchooserdialog.h | 39 +++++++++++++++ 7 files changed, 130 insertions(+), 10 deletions(-) create mode 100644 rtgui/rtappchooserdialog.cc create mode 100644 rtgui/rtappchooserdialog.h diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index ed6a0b364..3ca04dc2b 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -135,6 +135,7 @@ set(NONCLISOURCEFILES retinex.cc rgbcurves.cc rotate.cc + rtappchooserdialog.cc rtimage.cc rtscalable.cc rtsurface.cc diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 775e6a935..6cb90a444 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -39,6 +39,7 @@ #include "procparamchangers.h" #include "placesbrowser.h" #include "pathutils.h" +#include "rtappchooserdialog.h" #include "thumbnail.h" #include "toolpanelcoord.h" @@ -2014,7 +2015,7 @@ void EditorPanel::sendToExternalPressed() { if (options.externalEditorIndex == -1) { // "Other" external editor. Show app chooser dialog to let user pick. - Gtk::AppChooserDialog *dialog = getAppChooserDialog(); + RTAppChooserDialog *dialog = getAppChooserDialog(); dialog->show(); } else { struct ExternalEditor editor = options.externalEditors.at(options.externalEditorIndex); @@ -2195,10 +2196,10 @@ bool EditorPanel::idle_sentToGimp (ProgressConnector *pc, rtengine::IImagef return false; } -Gtk::AppChooserDialog *EditorPanel::getAppChooserDialog() +RTAppChooserDialog *EditorPanel::getAppChooserDialog() { if (!app_chooser_dialog.get()) { - app_chooser_dialog.reset(new Gtk::AppChooserDialog("image/tiff")); + app_chooser_dialog.reset(new RTAppChooserDialog("image/tiff")); app_chooser_dialog->signal_response().connect( sigc::mem_fun(*this, &EditorPanel::onAppChooserDialogResponse) ); diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 1bbb95a6e..e822f1677 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -46,6 +46,7 @@ class FilePanel; class MyProgressBar; class Navigator; class PopUpButton; +class RTAppChooserDialog; class Thumbnail; class ToolPanelCoordinator; @@ -212,7 +213,7 @@ private: bool idle_sendToGimp ( ProgressConnector *pc, Glib::ustring fname); bool idle_sentToGimp (ProgressConnector *pc, rtengine::IImagefloat* img, Glib::ustring filename); void histogramProfile_toggled (); - Gtk::AppChooserDialog *getAppChooserDialog(); + RTAppChooserDialog *getAppChooserDialog(); void onAppChooserDialogResponse(int resposneId); void updateExternalEditorSelection(); @@ -249,7 +250,7 @@ private: Gtk::Button* navNext; Gtk::Button* navPrev; Glib::RefPtr external_editor_info; - std::unique_ptr app_chooser_dialog; + std::unique_ptr app_chooser_dialog; ExternalEditorChangedSignal *externalEditorChangedSignal; sigc::connection externalEditorChangedSignalConnection; diff --git a/rtgui/externaleditorpreferences.cc b/rtgui/externaleditorpreferences.cc index df6b6efc2..b64cdcf9f 100644 --- a/rtgui/externaleditorpreferences.cc +++ b/rtgui/externaleditorpreferences.cc @@ -164,7 +164,7 @@ Gtk::TreeViewColumn *ExternalEditorPreferences::makeCommandColumn() } void ExternalEditorPreferences::onAppChooserDialogResponse( - int response_id, Gtk::AppChooserDialog *dialog) + int response_id, RTAppChooserDialog *dialog) { switch (response_id) { case Gtk::RESPONSE_OK: @@ -190,7 +190,7 @@ void ExternalEditorPreferences::openAppChooserDialog() return; } - app_chooser_dialog.reset(new Gtk::AppChooserDialog("image/tiff")); + app_chooser_dialog.reset(new RTAppChooserDialog("image/tiff")); app_chooser_dialog->signal_response().connect(sigc::bind( sigc::mem_fun(*this, &ExternalEditorPreferences::onAppChooserDialogResponse), app_chooser_dialog.get() diff --git a/rtgui/externaleditorpreferences.h b/rtgui/externaleditorpreferences.h index be988e901..dbd0f1648 100644 --- a/rtgui/externaleditorpreferences.h +++ b/rtgui/externaleditorpreferences.h @@ -18,7 +18,6 @@ */ #pragma once -#include #include #include #include @@ -26,6 +25,8 @@ #include #include +#include "rtappchooserdialog.h" + /** * Widget for editing the external editors options. @@ -98,7 +99,7 @@ private: Gtk::Button *button_app_chooser; Gtk::Button *button_add; Gtk::Button *button_remove; - std::unique_ptr app_chooser_dialog; + std::unique_ptr app_chooser_dialog; /** * Inserts a new editor entry after the current selection, or at the end if @@ -117,7 +118,7 @@ private: * 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. */ - void onAppChooserDialogResponse(int responseId, Gtk::AppChooserDialog *dialog); + void onAppChooserDialogResponse(int responseId, RTAppChooserDialog *dialog); /** * Shows the app chooser dialog. */ diff --git a/rtgui/rtappchooserdialog.cc b/rtgui/rtappchooserdialog.cc new file mode 100644 index 000000000..50a71ee38 --- /dev/null +++ b/rtgui/rtappchooserdialog.cc @@ -0,0 +1,77 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 Lawrence Lee + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "rtappchooserdialog.h" + +#if !(defined WIN32 || defined __APPLE__) +#define GTKMM_APPCHOOSERDIALOG +#endif + +RTAppChooserDialog::~RTAppChooserDialog() {} + +#ifdef GTKMM_APPCHOOSERDIALOG // Use Gtk::AppChooserDialog directly. + +RTAppChooserDialog::RTAppChooserDialog(const Glib::ustring &content_type) : + Gtk::AppChooserDialog(content_type) +{ +} + +Glib::RefPtr RTAppChooserDialog::get_app_info() +{ + return Gtk::AppChooserDialog::get_app_info(); +} + +Glib::RefPtr RTAppChooserDialog::get_app_info() const +{ + return Gtk::AppChooserDialog::get_app_info(); +} + +#else // Work around bugs with GLib and glibmm. + +RTAppChooserDialog::RTAppChooserDialog(const Glib::ustring &content_type) : + Gtk::AppChooserDialog(content_type) +{ + // GTK calls a faulty GLib function to update the most recently selected + // application after an application is selected. This removes all signal + // handlers to prevent the function call. + auto signal_id = g_signal_lookup("response", GTK_TYPE_APP_CHOOSER_DIALOG); + while (true) { + auto handler_id = g_signal_handler_find(gobj(), G_SIGNAL_MATCH_ID, signal_id, GQuark(), nullptr, nullptr, nullptr); + if (!handler_id) { + break; + } + g_signal_handler_disconnect(gobj(), handler_id); + } +} + +Glib::RefPtr RTAppChooserDialog::get_app_info() +{ + // glibmm wrapping of GAppInfo does not work on some platforms. Manually + // wrap it here. + GAppInfo *gAppInfo = gtk_app_chooser_get_app_info(GTK_APP_CHOOSER(gobj())); + return Glib::wrap(gAppInfo, true); +} + +Glib::RefPtr RTAppChooserDialog::get_app_info() const +{ + GAppInfo *gAppInfo = gtk_app_chooser_get_app_info(GTK_APP_CHOOSER( + const_cast(gobj()))); + return Glib::wrap(gAppInfo, true); +} + +#endif diff --git a/rtgui/rtappchooserdialog.h b/rtgui/rtappchooserdialog.h new file mode 100644 index 000000000..9d0e3b041 --- /dev/null +++ b/rtgui/rtappchooserdialog.h @@ -0,0 +1,39 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 Lawrence Lee + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#pragma once + +#include +#include +#include +#include + +/** + * Custom version of gtkmm's Gtk::AppChooserDialog to work around crashes + * (https://gitlab.gnome.org/GNOME/glib/-/issues/1104 and + * https://gitlab.gnome.org/GNOME/glibmm/-/issues/94). + */ +class RTAppChooserDialog : public Gtk::AppChooserDialog +{ +public: + RTAppChooserDialog(const Glib::ustring &content_type); + ~RTAppChooserDialog(); + + Glib::RefPtr get_app_info(); + Glib::RefPtr get_app_info() const; +}; From 672d6302f37aefae0e8341761a54d31042035210 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 14 Aug 2021 17:11:07 -0700 Subject: [PATCH 020/134] Fix storage of external editor icons De-serialize and serialize icons instead of using their names. --- rtgui/editorpanel.cc | 18 +++++++++++++-- rtgui/externaleditorpreferences.cc | 32 ++++++++++++++++++++++----- rtgui/externaleditorpreferences.h | 6 ++--- rtgui/options.cc | 35 ++++++++++++++++-------------- rtgui/options.h | 4 ++-- rtgui/preferences.cc | 4 ++-- rtgui/rtimage.cc | 7 +++++- 7 files changed, 75 insertions(+), 31 deletions(-) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 6cb90a444..987852891 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2522,8 +2522,22 @@ void EditorPanel::updateExternalEditorWidget(int selectedIndex, const std::vecto // Add the editors. for (unsigned i = 0; i < editors.size(); i++) { const auto & name = editors[i].name.empty() ? Glib::ustring(" ") : editors[i].name; - if (!editors[i].icon_name.empty()) { - Glib::RefPtr gioIcon = Gio::Icon::create(editors[i].icon_name); + if (!editors[i].icon_serialized.empty()) { + Glib::RefPtr gioIcon; + GError *e = nullptr; + GVariant *icon_variant = g_variant_parse( + nullptr, editors[i].icon_serialized.c_str(), nullptr, nullptr, &e); + + if (e) { + std::cerr + << "Error loading external editor icon from \"" + << editors[i].icon_serialized << "\": " << e->message + << std::endl; + gioIcon = Glib::RefPtr(); + } else { + gioIcon = Gio::Icon::deserialize(Glib::VariantBase(icon_variant)); + } + send_to_external->insertEntry(i, gioIcon, name); } else { send_to_external->insertEntry(i, "palette-brush.png", name); diff --git a/rtgui/externaleditorpreferences.cc b/rtgui/externaleditorpreferences.cc index b64cdcf9f..61bf8dc3a 100644 --- a/rtgui/externaleditorpreferences.cc +++ b/rtgui/externaleditorpreferences.cc @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include + #include "externaleditorpreferences.h" #include "multilangmgr.h" #include "rtimage.h" @@ -85,11 +87,11 @@ 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_name = icon == nullptr ? "" : icon->to_string(); + 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_name, + icon_serialized, rowIter->get_value(model_columns.other_data) )); } @@ -104,8 +106,28 @@ void ExternalEditorPreferences::setEditors( for (const ExternalEditorPreferences::EditorInfo & editor : editors) { auto row = *list_model->append(); + Glib::RefPtr icon; + + // Get icon. + if (editor.icon_serialized.empty()) { + icon = Glib::RefPtr(); + } else { + GError *e = nullptr; + GVariant *icon_variant = g_variant_parse( + nullptr, editor.icon_serialized.c_str(), nullptr, nullptr, &e); + if (e) { + std::cerr + << "Error loading external editor icon from \"" + << editor.icon_serialized << "\": " << e->message + << std::endl; + icon = Glib::RefPtr(); + } else { + icon = Gio::Icon::deserialize(Glib::VariantBase(icon_variant)); + } + } + row[model_columns.name] = editor.name; - row[model_columns.icon] = editor.icon_name.empty() ? Glib::RefPtr() : Gio::Icon::create(editor.icon_name); + row[model_columns.icon] = icon; row[model_columns.command] = editor.command; row[model_columns.other_data] = editor.other_data; } @@ -247,8 +269,8 @@ void ExternalEditorPreferences::updateToolbarSensitivity() } ExternalEditorPreferences::EditorInfo::EditorInfo( - Glib::ustring name, Glib::ustring command, Glib::ustring icon_name, void *other_data -) : name(name), icon_name(icon_name), command(command), other_data(other_data) + 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) { } diff --git a/rtgui/externaleditorpreferences.h b/rtgui/externaleditorpreferences.h index dbd0f1648..5761d8b63 100644 --- a/rtgui/externaleditorpreferences.h +++ b/rtgui/externaleditorpreferences.h @@ -41,7 +41,7 @@ public: explicit EditorInfo( Glib::ustring name = Glib::ustring(), Glib::ustring command = Glib::ustring(), - Glib::ustring icon_name = Glib::ustring(), + Glib::ustring icon_serialized = Glib::ustring(), void *other_data = nullptr ); /** @@ -49,9 +49,9 @@ public: */ Glib::ustring name; /** - * The string representation of the icon. See Gio::Icon::to_string(). + * The string representation of the icon. See Gio::Icon::serialize(). */ - Glib::ustring icon_name; + Glib::ustring icon_serialized; /** * The commandline for running the program. See * Gio::AppInfo::get_commandline() diff --git a/rtgui/options.cc b/rtgui/options.cc index 6a944faa6..53cedea95 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -859,7 +859,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", "IconNames")) { + || keyFile.has_key("External Editor", "IconsSerialized")) { // Multiple external editors. const auto & names = @@ -872,21 +872,21 @@ void Options::readFromFile(Glib::ustring fname) std::vector() : static_cast>( keyFile.get_string_list("External Editor", "Commands")); - const auto & icon_names = - !keyFile.has_key("External Editor", "IconNames") ? + const auto & icons_serialized = + !keyFile.has_key("External Editor", "IconsSerialized") ? std::vector() : static_cast>( - keyFile.get_string_list("External Editor", "IconNames")); + keyFile.get_string_list("External Editor", "IconsSerialized")); externalEditors = std::vector(std::max(std::max( - names.size(), commands.size()), icon_names.size())); + names.size(), commands.size()), icons_serialized.size())); for (unsigned i = 0; i < names.size(); i++) { externalEditors[i].name = names[i]; } for (unsigned i = 0; i < commands.size(); i++) { externalEditors[i].command = commands[i]; } - for (unsigned i = 0; i < icon_names.size(); i++) { - externalEditors[i].icon_name = icon_names[i]; + for (unsigned i = 0; i < icons_serialized.size(); i++) { + externalEditors[i].icon_serialized = icons_serialized[i]; } if (keyFile.has_key("External Editor", "EditorIndex")) { @@ -903,6 +903,9 @@ void Options::readFromFile(Glib::ustring fname) editorToSendTo = keyFile.get_integer("External Editor", "EditorKind"); #ifdef WIN32 + auto getIconSerialized = [](const Glib::ustring &executable) { + return Glib::ustring::compose("('themed', <['%1,0', '%1,0-symbolic']>)", executable); + }; Glib::ustring gimpDir = ""; if (keyFile.has_key("External Editor", "GimpDir")) { gimpDir = keyFile.get_string("External Editor", "GimpDir"); @@ -912,7 +915,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 1) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", executable + ",0")); + externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", 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)); @@ -920,7 +923,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 1) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", executable + ",0")); + externalEditors.push_back(ExternalEditor("GIMP", "\"" + executable + "\"", getIconSerialized(executable))); break; } } @@ -935,7 +938,7 @@ void Options::readFromFile(Glib::ustring fname) if (editorToSendTo == 2) { externalEditorIndex = externalEditors.size(); } - externalEditors.push_back(ExternalEditor("Photoshop", "\"" + executable + "\"", executable + ",0")); + externalEditors.push_back(ExternalEditor("Photoshop", "\"" + executable + "\"", getIconSerialized(executable))); } if (keyFile.has_key("External Editor", "CustomEditor")) { @@ -2296,17 +2299,17 @@ void Options::saveToFile(Glib::ustring fname) { std::vector names; std::vector commands; - std::vector icon_names; + std::vector icons_serialized; for (const auto & editor : externalEditors) { names.push_back(editor.name); commands.push_back(editor.command); - icon_names.push_back(editor.icon_name); + 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_string_list("External Editor", "IconNames", icon_names); + keyFile.set_string_list("External Editor", "IconsSerialized", icons_serialized); keyFile.set_integer("External Editor", "EditorIndex", externalEditorIndex); } @@ -2978,12 +2981,12 @@ Glib::ustring Options::getICCProfileCopyright() ExternalEditor::ExternalEditor() {} ExternalEditor::ExternalEditor( - const Glib::ustring &name, const Glib::ustring &command, const Glib::ustring &icon_name -): name(name), command(command), icon_name(icon_name) {} + const Glib::ustring &name, const Glib::ustring &command, const Glib::ustring &icon_serialized +): name(name), command(command), icon_serialized(icon_serialized) {} bool ExternalEditor::operator==(const ExternalEditor &other) const { - return this->name == other.name && this->command == other.command && this->icon_name == other.icon_name; + return this->name == other.name && this->command == other.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 38d3f3d76..d6b546d40 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -54,10 +54,10 @@ struct ExternalEditor { ExternalEditor(); - ExternalEditor(const Glib::ustring &name, const Glib::ustring &command, const Glib::ustring &icon_name); + ExternalEditor(const Glib::ustring &name, const Glib::ustring &command, const Glib::ustring &icon_serialized); Glib::ustring name; Glib::ustring command; - Glib::ustring icon_name; + Glib::ustring icon_serialized; bool operator==(const ExternalEditor & other) const; bool operator!=(const ExternalEditor & other) const; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 786262896..a8f5c64a3 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -1793,7 +1793,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_name)); + editors[i].name, editors[i].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. @@ -2100,7 +2100,7 @@ void Preferences::fillPreferences() std::vector editorInfos; for (const auto &editor : moptions.externalEditors) { editorInfos.push_back(ExternalEditorPreferences::EditorInfo( - editor.name, editor.command, editor.icon_name)); + editor.name, editor.command, editor.icon_serialized)); } if (moptions.externalEditorIndex >= 0) { // Mark the current editor so we can track it. diff --git a/rtgui/rtimage.cc b/rtgui/rtimage.cc index 9a38c1885..98e61b897 100644 --- a/rtgui/rtimage.cc +++ b/rtgui/rtimage.cc @@ -294,7 +294,12 @@ Glib::RefPtr RTImage::createPixbufFromFile (const Glib::ustring& fi Glib::RefPtr RTImage::createPixbufFromGIcon(const Glib::RefPtr &icon, int size) { // TODO: Listen for theme changes and update icon, remove from cache. - return Gtk::IconTheme::get_default()->lookup_icon(icon, size, Gtk::ICON_LOOKUP_FORCE_SIZE).load_icon(); + Gtk::IconInfo iconInfo = Gtk::IconTheme::get_default()->lookup_icon(icon, size, Gtk::ICON_LOOKUP_FORCE_SIZE); + try { + return iconInfo.load_icon(); + } catch (Glib::Exception &e) { + return Glib::RefPtr(); + } } Cairo::RefPtr RTImage::createImgSurfFromFile (const Glib::ustring& fileName) From 732316dcafc1fdb16ea27c0c5af1707dffcd80b4 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Tue, 5 Oct 2021 21:49:42 -0700 Subject: [PATCH 021/134] Fix initial generation of external editor icons In Windows, escape backslashes and quotes in the serialized GVariants of the icons. --- rtgui/options.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/rtgui/options.cc b/rtgui/options.cc index 53cedea95..a6b693f53 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -904,7 +904,16 @@ void Options::readFromFile(Glib::ustring fname) #ifdef WIN32 auto getIconSerialized = [](const Glib::ustring &executable) { - return Glib::ustring::compose("('themed', <['%1,0', '%1,0-symbolic']>)", executable); + // Backslashes and quotes must be escaped in the text representation of GVariant strings. + // See https://www.freedesktop.org/software/gstreamer-sdk/data/docs/2012.5/glib/gvariant-text.html#gvariant-text-strings + Glib::ustring exec_escaped = ""; + for (const auto character : executable) { + if (character == '\\' || character == '\'') { + exec_escaped += '\\'; + } + exec_escaped += character; + } + return Glib::ustring::compose("('themed', <['%1,0', '%1,0-symbolic']>)", exec_escaped); }; Glib::ustring gimpDir = ""; if (keyFile.has_key("External Editor", "GimpDir")) { From 0f894656a0a9c751efc5a6f45bcb1d7932e1c16f Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 21 Nov 2021 17:47:41 -0800 Subject: [PATCH 022/134] Add favorites customizer to preferences UI --- rtdata/languages/default | 5 + rtgui/CMakeLists.txt | 1 + rtgui/preferences.cc | 12 + rtgui/preferences.h | 4 + rtgui/toollocationpref.cc | 596 ++++++++++++++++++++++++++++++++++++++ rtgui/toollocationpref.h | 34 +++ rtgui/toolpanelcoord.cc | 250 ++++++++++++++++ rtgui/toolpanelcoord.h | 78 +++++ 8 files changed, 980 insertions(+) create mode 100644 rtgui/toollocationpref.cc create mode 100644 rtgui/toollocationpref.h diff --git a/rtdata/languages/default b/rtdata/languages/default index 747dfa863..525fa2d09 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1891,6 +1891,7 @@ PREFERENCES_STARTUPIMDIR;Image Directory at Startup PREFERENCES_TAB_BROWSER;File Browser PREFERENCES_TAB_COLORMGR;Color Management PREFERENCES_TAB_DYNAMICPROFILE;Dynamic Profile Rules +PREFERENCES_TAB_FAVORITES;Favorites PREFERENCES_TAB_GENERAL;General PREFERENCES_TAB_IMPROC;Image Processing PREFERENCES_TAB_PERFORMANCE;Performance @@ -1899,6 +1900,10 @@ PREFERENCES_THUMBNAIL_INSPECTOR_JPEG;Embedded JPEG preview PREFERENCES_THUMBNAIL_INSPECTOR_MODE;Image to show PREFERENCES_THUMBNAIL_INSPECTOR_RAW;Neutral raw rendering PREFERENCES_THUMBNAIL_INSPECTOR_RAW_IF_NO_JPEG_FULLSIZE;Embedded JPEG if fullsize, neutral raw otherwise +PREFERENCES_TOOLPANEL_AVAILABLETOOLS;Available Tools +PREFERENCES_TOOLPANEL_FAVORITE;Favorite +PREFERENCES_TOOLPANEL_FAVORITESPANEL;Favorites Panel +PREFERENCES_TOOLPANEL_TOOL;Tool PREFERENCES_TP_LABEL;Tool panel: PREFERENCES_TP_VSCROLLBAR;Hide vertical scrollbar PREFERENCES_USEBUNDLEDPROFILES;Use bundled profiles diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 7976bdc7a..cfb06ff0f 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -160,6 +160,7 @@ set(NONCLISOURCEFILES thumbnail.cc tonecurve.cc toolbar.cc + toollocationpref.cc toolpanel.cc toolpanelcoord.cc vibrance.cc diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index c6c2eb61b..556201732 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -29,6 +29,7 @@ #include #include "rtimage.h" #include "rtwindow.h" +#include "toollocationpref.h" #ifdef _OPENMP #include #endif @@ -65,6 +66,7 @@ Preferences::Preferences(RTWindow *rtwindow) , parent(rtwindow) , newFont(false) , newCPFont(false) + , toolLocationPreference(nullptr) { moptions.copyFrom(&options); @@ -102,6 +104,7 @@ Preferences::Preferences(RTWindow *rtwindow) nb->append_page(*getGeneralPanel(), M("PREFERENCES_TAB_GENERAL")); nb->append_page(*getImageProcessingPanel(), M("PREFERENCES_TAB_IMPROC")); + nb->append_page(*getFavoritesPanel(), M("PREFERENCES_TAB_FAVORITES")); nb->append_page(*getDynamicProfilePanel(), M("PREFERENCES_TAB_DYNAMICPROFILE")); nb->append_page(*getFileBrowserPanel(), M("PREFERENCES_TAB_BROWSER")); nb->append_page(*getColorManPanel(), M("PREFERENCES_TAB_COLORMGR")); @@ -492,6 +495,13 @@ void Preferences::behSetRadioToggled(const Glib::ustring& path) behAddSetRadioToggled(path, false); } +Gtk::Widget *Preferences::getFavoritesPanel() +{ + if (!toolLocationPreference) { + toolLocationPreference = Gtk::make_managed(moptions); + } + return toolLocationPreference; +} Gtk::Widget *Preferences::getDynamicProfilePanel() { @@ -1938,6 +1948,8 @@ void Preferences::storePreferences() moptions.cropGuides = Options::CropGuidesMode(cropGuidesCombo->get_active_row_number()); moptions.cropAutoFit = cropAutoFitCB->get_active(); + + toolLocationPreference->updateOptions(); } void Preferences::fillPreferences() diff --git a/rtgui/preferences.h b/rtgui/preferences.h index dfe1e008d..18d7a0581 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -28,6 +28,7 @@ class RTWindow; class Splash; +class ToolLocationPreference; class Preferences final : public Gtk::Dialog, @@ -244,6 +245,8 @@ class Preferences final : bool newFont; bool newCPFont; + ToolLocationPreference *toolLocationPreference; + void fillPreferences (); void storePreferences (); void parseDir (Glib::ustring dirname, std::vector& items, Glib::ustring ext); @@ -278,6 +281,7 @@ class Preferences final : Gtk::Widget *getGeneralPanel(); Gtk::Widget *getImageProcessingPanel(); + Gtk::Widget *getFavoritesPanel(); Gtk::Widget *getDynamicProfilePanel(); Gtk::Widget *getFileBrowserPanel(); Gtk::Widget *getColorManPanel(); diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc new file mode 100644 index 000000000..719a72a66 --- /dev/null +++ b/rtgui/toollocationpref.cc @@ -0,0 +1,596 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 Lawrence Lee + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include + +#include "guiutils.h" +#include "options.h" +#include "toollocationpref.h" +#include "toolpanelcoord.h" + +using Tool = ToolPanelCoordinator::Tool; + +std::string getToolName(Tool tool) +{ + switch (tool) { + case Tool::TONE_CURVE: + return "tonecurve"; + case Tool::SHADOWS_HIGHLIGHTS: + return "shadowshighlights"; + case Tool::IMPULSE_DENOISE: + return "impulsedenoise"; + case Tool::DEFRINGE_TOOL: + return "defringe"; + case Tool::SPOT: + return "spot"; + case Tool::DIR_PYR_DENOISE: + return "dirpyrdenoise"; + case Tool::EPD: + return "epd"; + case Tool::SHARPENING_TOOL: + return "sharpening"; + case Tool::LOCAL_CONTRAST: + return "localcontrast"; + case Tool::SHARPEN_EDGE: + return "sharpenedge"; + case Tool::SHARPEN_MICRO: + return "sharpenmicro"; + case Tool::L_CURVE: + return "labcurves"; + case Tool::RGB_CURVES: + return "rgbcurves"; + case Tool::COLOR_TONING: + return "colortoning"; + case Tool::LENS_GEOM: + return "lensgeom"; + case Tool::LENS_PROF: + return "lensprof"; + case Tool::DISTORTION: + return "distortion"; + case Tool::ROTATE: + return "rotate"; + case Tool::VIBRANCE: + return "vibrance"; + case Tool::COLOR_APPEARANCE: + return "colorappearance"; + case Tool::WHITE_BALANCE: + return "whitebalance"; + case Tool::VIGNETTING: + return "vignetting"; + case Tool::RETINEX_TOOL: + return "retinex"; + case Tool::GRADIENT: + return "gradient"; + case Tool::LOCALLAB: + return "locallab"; + case Tool::PC_VIGNETTE: + return "pcvignette"; + case Tool::PERSPECTIVE: + return "perspective"; + case Tool::CA_CORRECTION: + return "cacorrection"; + case Tool::CH_MIXER: + return "chmixer"; + case Tool::BLACK_WHITE: + return "blackwhite"; + case Tool::RESIZE_TOOL: + return "resize"; + case Tool::PR_SHARPENING: + return "prsharpening"; + case Tool::CROP_TOOL: + return "crop"; + case Tool::ICM: + return "icm"; + case Tool::WAVELET: + return "wavelet"; + case Tool::DIR_PYR_EQUALIZER: + return "dirpyrdenoise"; + case Tool::HSV_EQUALIZER: + return "hsvequalizer"; + case Tool::FILM_SIMULATION: + return "filmsimulation"; + case Tool::SOFT_LIGHT: + return "softlight"; + case Tool::DEHAZE: + return "dehaze"; + case Tool::SENSOR_BAYER: + return "sensorbayer"; + case Tool::SENSOR_XTRANS: + return "sensorxtrans"; + case Tool::BAYER_PROCESS: + return "bayerprocess"; + case Tool::XTRANS_PROCESS: + return "xtransprocess"; + case Tool::BAYER_PREPROCESS: + return "bayerpreprocess"; + case Tool::PREPROCESS: + return "preprocess"; + case Tool::DARKFRAME_TOOL: + return "darkframe"; + case Tool::FLATFIELD_TOOL: + return "flatfield"; + case Tool::RAW_CA_CORRECTION: + return "rawcacorrection"; + case Tool::RAW_EXPOSURE: + return "rawexposure"; + case Tool::PREPROCESS_WB: + return "preprocesswb"; + case Tool::BAYER_RAW_EXPOSURE: + return "bayerrawexposure"; + case Tool::XTRANS_RAW_EXPOSURE: + return "xtransrawexposure"; + case Tool::FATTAL: + return "fattal"; + case Tool::FILM_NEGATIVE: + return "filmnegative"; + case Tool::PD_SHARPENING: + return "capturesharpening"; + }; + return ""; +}; + +class FavoritesColumns : public Gtk::TreeModelColumnRecord +{ +public: + Gtk::TreeModelColumn toolName; + Gtk::TreeModelColumn tool; + + FavoritesColumns() + { + add(toolName); + add(tool); + } +}; + +class ToolListColumns : public Gtk::TreeModelColumnRecord +{ +public: + Gtk::TreeModelColumn toolName; + Gtk::TreeModelColumn tool; + Gtk::TreeModelColumn isFavorite; + Gtk::TreeModelColumn isEditable; + + ToolListColumns() + { + add(toolName); + add(tool); + add(isFavorite); + add(isEditable); + } +}; + +struct ToolLocationPreference::Impl { + static std::unordered_map toolNamesReverseMap; + + Options &options; + + // Tool list. + ToolListColumns toolListColumns; + Glib::RefPtr toolListModelPtr; + Gtk::CellRendererToggle toolListCellRendererFavorite; + Gtk::CellRendererText toolListCellRendererToolName; + Gtk::TreeViewColumn toolListViewColumnFavorite; + Gtk::TreeViewColumn toolListViewColumnToolName; + Gtk::TreeView *toolListViewPtr; + + // Favorites list. + FavoritesColumns favoritesColumns; + Glib::RefPtr favoritesModelPtr; + Gtk::CellRendererText favoritesCellRendererToolName; + Gtk::TreeViewColumn favoritesViewColumnToolName; + Gtk::TreeView *favoritesViewPtr; + + explicit Impl(Options &options); + + void addToolListRowGroup( + const std::vector &tools, + const Gtk::TreeIter &parentRowIter, + const std::unordered_set &favorites); + void favoriteToggled(const Glib::ustring &row_path); + Tool getToolFromName(const std::string &name) const; + void initFavoritesRows(const std::vector &favorites); + void initToolListRows(const std::vector &favorites); + std::vector toolNamesToTools( + const std::vector &tool_names) const; + void updateOptions(); +}; + +std::unordered_map + ToolLocationPreference::Impl::toolNamesReverseMap; + +Glib::ustring getToolPanelTitleKey(ToolPanelCoordinator::Panel panel) +{ + switch (panel) { + case ToolPanelCoordinator::Panel::FAVORITE: + return "MAIN_TAB_FAVORITES"; + case ToolPanelCoordinator::Panel::EXPOSURE: + return "MAIN_TAB_EXPOSURE"; + case ToolPanelCoordinator::Panel::DETAILS: + return "MAIN_TAB_DETAIL"; + case ToolPanelCoordinator::Panel::COLOR: + return "MAIN_TAB_COLOR"; + case ToolPanelCoordinator::Panel::ADVANCED: + return "MAIN_TAB_ADVANCED"; + case ToolPanelCoordinator::Panel::LOCALLAB: + return "MAIN_TAB_LOCALLAB"; + case ToolPanelCoordinator::Panel::TRANSFORM_PANEL: + return "MAIN_TAB_TRANSFORM"; + case ToolPanelCoordinator::Panel::RAW: + return "MAIN_TAB_RAW"; + } + return ""; +} + +Glib::ustring getToolTitleKey(Tool tool) +{ + using Tool = Tool; + switch (tool) { + case Tool::TONE_CURVE: + return "TP_EXPOSURE_LABEL"; + case Tool::SHADOWS_HIGHLIGHTS: + return "TP_SHADOWSHLIGHTS_LABEL"; + case Tool::IMPULSE_DENOISE: + return "TP_IMPULSEDENOISE_LABEL"; + case Tool::DEFRINGE_TOOL: + return "TP_DEFRINGE_LABEL"; + case Tool::SPOT: + return "TP_SPOT_LABEL"; + case Tool::DIR_PYR_DENOISE: + return "TP_DIRPYRDENOISE_LABEL"; + case Tool::EPD: + return "TP_EPD_LABEL"; + case Tool::SHARPENING_TOOL: + return "TP_SHARPENING_LABEL"; + case Tool::LOCAL_CONTRAST: + return "TP_LOCALCONTRAST_LABEL"; + case Tool::SHARPEN_EDGE: + return "TP_SHARPENEDGE_LABEL"; + case Tool::SHARPEN_MICRO: + return "TP_SHARPENMICRO_LABEL"; + case Tool::L_CURVE: + return "TP_LABCURVE_LABEL"; + case Tool::RGB_CURVES: + return "TP_RGBCURVES_LABEL"; + case Tool::COLOR_TONING: + return "TP_COLORTONING_LABEL"; + case Tool::LENS_GEOM: + return "TP_LENSGEOM_LABEL"; + case Tool::LENS_PROF: + return "TP_LENSPROFILE_LABEL"; + case Tool::DISTORTION: + return "TP_DISTORTION_LABEL"; + case Tool::ROTATE: + return "TP_ROTATE_LABEL"; + case Tool::VIBRANCE: + return "TP_VIBRANCE_LABEL"; + case Tool::COLOR_APPEARANCE: + return "TP_COLORAPP_LABEL"; + case Tool::WHITE_BALANCE: + return "TP_WBALANCE_LABEL"; + case Tool::VIGNETTING: + return "TP_VIGNETTING_LABEL"; + case Tool::RETINEX_TOOL: + return "TP_RETINEX_LABEL"; + case Tool::GRADIENT: + return "TP_GRADIENT_LABEL"; + case Tool::LOCALLAB: + return "TP_LOCALLAB_LABEL"; + case Tool::PC_VIGNETTE: + return "TP_PCVIGNETTE_LABEL"; + case Tool::PERSPECTIVE: + return "TP_PERSPECTIVE_LABEL"; + case Tool::CA_CORRECTION: + return "TP_CACORRECTION_LABEL"; + case Tool::CH_MIXER: + return "TP_CHMIXER_LABEL"; + case Tool::BLACK_WHITE: + return "TP_BWMIX_LABEL"; + case Tool::RESIZE_TOOL: + return "TP_RESIZE_LABEL"; + case Tool::PR_SHARPENING: + return "TP_PRSHARPENING_LABEL"; + case Tool::CROP_TOOL: + return "TP_CROP_LABEL"; + case Tool::ICM: + return "TP_ICM_LABEL"; + case Tool::WAVELET: + return "TP_WAVELET_LABEL"; + case Tool::DIR_PYR_EQUALIZER: + return "TP_DIRPYRDENOISE_LABEL"; + case Tool::HSV_EQUALIZER: + return "TP_HSVEQUALIZER_LABEL"; + case Tool::FILM_SIMULATION: + return "TP_FILMSIMULATION_LABEL"; + case Tool::SOFT_LIGHT: + return "TP_SOFTLIGHT_LABEL"; + case Tool::DEHAZE: + return "TP_DEHAZE_LABEL"; + case Tool::SENSOR_BAYER: + return "TP_RAW_SENSOR_BAYER_LABEL"; + case Tool::SENSOR_XTRANS: + return "TP_RAW_SENSOR_XTRANS_LABEL"; + case Tool::BAYER_PROCESS: + return "TP_RAW_LABEL"; + case Tool::XTRANS_PROCESS: + return "TP_RAW_LABEL"; + case Tool::BAYER_PREPROCESS: + return "TP_PREPROCESS_LABEL"; + case Tool::PREPROCESS: + return "TP_PREPROCESS_LABEL"; + case Tool::DARKFRAME_TOOL: + return "TP_DARKFRAME_LABEL"; + case Tool::FLATFIELD_TOOL: + return "TP_FLATFIELD_LABEL"; + case Tool::RAW_CA_CORRECTION: + return "TP_RAWCACORR_LABEL"; + case Tool::RAW_EXPOSURE: + return "TP_EXPOS_WHITEPOINT_LABEL"; + case Tool::PREPROCESS_WB: + return "TP_PREPROCWB_LABEL"; + case Tool::BAYER_RAW_EXPOSURE: + return "TP_EXPOS_BLACKPOINT_LABEL"; + case Tool::XTRANS_RAW_EXPOSURE: + return "TP_EXPOS_BLACKPOINT_LABEL"; + case Tool::FATTAL: + return "TP_TM_FATTAL_LABEL"; + case Tool::FILM_NEGATIVE: + return "TP_FILMNEGATIVE_LABEL"; + case Tool::PD_SHARPENING: + return "TP_PDSHARPENING_LABEL"; + }; + return ""; +} + +ToolLocationPreference::Impl::Impl(Options &options) : + options(options), + + toolListModelPtr(Gtk::TreeStore::create(toolListColumns)), + toolListViewColumnFavorite( + Gtk::TreeViewColumn(M("PREFERENCES_TOOLPANEL_FAVORITE"))), + toolListViewColumnToolName( + Gtk::TreeViewColumn(M("PREFERENCES_TOOLPANEL_TOOL"))), + toolListViewPtr(Gtk::make_managed()), + + favoritesModelPtr(Gtk::ListStore::create(favoritesColumns)), + favoritesViewColumnToolName( + Gtk::TreeViewColumn(M("PREFERENCES_TOOLPANEL_TOOL"))), + favoritesViewPtr(Gtk::make_managed()) +{ + const std::vector favorites = toolNamesToTools(options.favorites); + + // Tool list. + toolListViewPtr->set_model(toolListModelPtr); + toolListViewPtr->append_column(toolListViewColumnToolName); + toolListViewColumnToolName.pack_start(toolListCellRendererToolName); + toolListViewColumnToolName.set_expand(); + toolListViewColumnToolName.set_renderer( + toolListCellRendererToolName, toolListColumns.toolName); + toolListViewPtr->append_column(toolListViewColumnFavorite); + toolListViewColumnFavorite.pack_start(toolListCellRendererFavorite); + toolListViewColumnFavorite.set_expand(false); + toolListViewColumnFavorite.set_renderer( + toolListCellRendererFavorite, toolListColumns.isFavorite); + toolListViewColumnFavorite.add_attribute( + toolListCellRendererFavorite, "visible", toolListColumns.isEditable); + toolListCellRendererFavorite.signal_toggled().connect( + sigc::mem_fun(*this, &ToolLocationPreference::Impl::favoriteToggled)); + initToolListRows(favorites); + toolListViewPtr->expand_all(); + + // Favorites list. + favoritesViewPtr->set_model(favoritesModelPtr); + favoritesViewPtr->append_column(favoritesViewColumnToolName); + favoritesViewPtr->set_reorderable(true); + favoritesViewColumnToolName.pack_start(favoritesCellRendererToolName); + favoritesViewColumnToolName.set_renderer( + favoritesCellRendererToolName, favoritesColumns.toolName); + initFavoritesRows(favorites); +} + +void ToolLocationPreference::Impl::favoriteToggled(const Glib::ustring &row_path) +{ + auto row_iter = toolListModelPtr->get_iter(row_path); + const bool is_favorite = !row_iter->get_value(toolListColumns.isFavorite); + const Tool tool = row_iter->get_value(toolListColumns.tool); + + // Update favorite column in the tool list. + row_iter->set_value(toolListColumns.isFavorite, is_favorite); + + // Update the favorites list. + if (is_favorite) { + // Add to favorites list. + auto new_favorite_row_iter = favoritesModelPtr->append(); + new_favorite_row_iter->set_value( + favoritesColumns.toolName, + M(getToolTitleKey(tool))); + new_favorite_row_iter->set_value(favoritesColumns.tool, tool); + } else { + // Remove from favorites list. + const auto favorites_rows = favoritesModelPtr->children(); + auto row = favorites_rows.begin(); + while ( + row != favorites_rows.end() && + row->get_value(favoritesColumns.tool) != tool) { + row++; + } + if (row != favorites_rows.end()) { + favoritesModelPtr->erase(row); + } + } +} + +Tool ToolLocationPreference::Impl::getToolFromName(const std::string &name) const +{ + if (toolNamesReverseMap.empty()) { + // Create the name to tool mapping. + + const auto panels = ToolPanelCoordinator::getDefaultToolLayout(); + std::vector unprocessed_tool_trees; + + // Get the root tools from each panel. + for (const auto &panel_tools : panels) { + for (const auto &tool : panel_tools.second) { + unprocessed_tool_trees.push_back(&tool); + } + } + + // Process all the tools, including their children. + while (unprocessed_tool_trees.size() > 0) { + const ToolPanelCoordinator::ToolTree *tool_tree = + unprocessed_tool_trees.back(); + unprocessed_tool_trees.pop_back(); + toolNamesReverseMap[getToolName(tool_tree->id)] = tool_tree->id; + for (const auto &child_tree : tool_tree->children) { + unprocessed_tool_trees.push_back(&child_tree); + } + } + } + + return toolNamesReverseMap.at(name); +} + +void ToolLocationPreference::Impl::initFavoritesRows( + const std::vector &favorites) +{ + for (const auto tool : favorites) { + auto favorite_row_iter = favoritesModelPtr->append(); + favorite_row_iter->set_value( + favoritesColumns.toolName, + M(getToolTitleKey(tool))); + favorite_row_iter->set_value(favoritesColumns.tool, tool); + } +} + +void ToolLocationPreference::Impl::addToolListRowGroup( + const std::vector &tools, + const Gtk::TreeIter &parentRowIter, + const std::unordered_set &favorites) +{ + for (const ToolPanelCoordinator::ToolTree &tool : tools) { + auto tool_row_iter = toolListModelPtr->append(parentRowIter->children()); + tool_row_iter->set_value( + toolListColumns.toolName, + M(getToolTitleKey(tool.id))); + tool_row_iter->set_value(toolListColumns.tool, tool.id); + tool_row_iter->set_value( + toolListColumns.isFavorite, + favorites.count(tool.id) > 0); + tool_row_iter->set_value( + toolListColumns.isEditable, + ToolPanelCoordinator::isFavoritable(tool.id)); + addToolListRowGroup(tool.children, tool_row_iter, favorites); + } +}; + +void ToolLocationPreference::Impl::initToolListRows(const std::vector &favorites) +{ + const auto panel_tools = ToolPanelCoordinator::getDefaultToolLayout(); + std::unordered_set favorites_set; + + for (const auto &tool : favorites) { + favorites_set.insert(tool); + } + + for (const auto panel : { + ToolPanelCoordinator::Panel::EXPOSURE, + ToolPanelCoordinator::Panel::DETAILS, + ToolPanelCoordinator::Panel::COLOR, + ToolPanelCoordinator::Panel::ADVANCED, + ToolPanelCoordinator::Panel::LOCALLAB, + ToolPanelCoordinator::Panel::TRANSFORM_PANEL, + ToolPanelCoordinator::Panel::RAW, + }) { + auto tool_group_iter = toolListModelPtr->append(); + tool_group_iter->set_value( + toolListColumns.toolName, + M(getToolPanelTitleKey(panel))); + addToolListRowGroup(panel_tools.at(panel), tool_group_iter, favorites_set); + } +} + +std::vector ToolLocationPreference::Impl::toolNamesToTools( + const std::vector &tool_names) const +{ + std::vector tool_set; + + for (auto &&tool_name : tool_names) { + Tool tool; + try { + tool = getToolFromName(tool_name); + } catch (const std::exception &e) { + continue; + } + tool_set.push_back(tool); + } + + return tool_set; +} + +void ToolLocationPreference::Impl::updateOptions() +{ + const auto favorites_rows = favoritesModelPtr->children(); + options.favorites.resize(favorites_rows.size()); + for (unsigned i = 0; i < favorites_rows.size(); i++) { + const Tool tool = favorites_rows[i].get_value(favoritesColumns.tool); + options.favorites[i] = getToolName(tool); + } +} + +ToolLocationPreference::ToolLocationPreference(Options &options) : + impl(new Impl(options)) +{ + // Layout grid. + Gtk::Grid *layout_grid = Gtk::make_managed(); + layout_grid->set_column_spacing(4); + layout_grid->set_row_spacing(4); + add(*layout_grid); + + // Tool list. + Gtk::Frame *tool_list_frame = Gtk::make_managed( + M("PREFERENCES_TOOLPANEL_AVAILABLETOOLS")); + Gtk::ScrolledWindow *tool_list_scrolled_window = + Gtk::make_managed(); + tool_list_scrolled_window->property_hscrollbar_policy() = + Gtk::PolicyType::POLICY_NEVER; + layout_grid->attach_next_to(*tool_list_frame, Gtk::PositionType::POS_RIGHT); + tool_list_frame->add(*tool_list_scrolled_window); + tool_list_scrolled_window->add(*impl->toolListViewPtr); + impl->toolListViewPtr->set_hscroll_policy(Gtk::ScrollablePolicy::SCROLL_MINIMUM); + setExpandAlignProperties( + tool_list_frame, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); + + // Favorites list. + Gtk::Frame *favorites_frame = Gtk::make_managed( + M("PREFERENCES_TOOLPANEL_FAVORITESPANEL")); + Gtk::ScrolledWindow *favorites_list_scrolled_window = + Gtk::make_managed(); + favorites_list_scrolled_window->property_hscrollbar_policy() = + Gtk::PolicyType::POLICY_NEVER; + layout_grid->attach_next_to(*favorites_frame, Gtk::PositionType::POS_RIGHT); + favorites_frame->add(*favorites_list_scrolled_window); + favorites_list_scrolled_window->add(*impl->favoritesViewPtr); + setExpandAlignProperties( + favorites_frame, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); + + this->show_all(); +} + +void ToolLocationPreference::updateOptions() +{ + impl->updateOptions(); +} diff --git a/rtgui/toollocationpref.h b/rtgui/toollocationpref.h new file mode 100644 index 000000000..815df6839 --- /dev/null +++ b/rtgui/toollocationpref.h @@ -0,0 +1,34 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 Lawrence Lee + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#pragma once + +#include + +class Options; + +class ToolLocationPreference : public Gtk::Box +{ +private: + struct Impl; + std::unique_ptr impl; + +public: + explicit ToolLocationPreference(Options &options); + void updateOptions(); +}; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 00fcb208d..586d4755f 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -32,6 +32,241 @@ using namespace rtengine::procparams; +using Tool = ToolPanelCoordinator::Tool; +using ToolTree = struct ToolPanelCoordinator::ToolTree; + +const std::vector EXPOSURE_PANEL_TOOLS = { + { + .id = Tool::TONE_CURVE, + }, + { + .id = Tool::SHADOWS_HIGHLIGHTS, + }, + { + .id = Tool::EPD, + }, + { + .id = Tool::FATTAL, + }, + { + .id = Tool::PC_VIGNETTE, + }, + { + .id = Tool::GRADIENT, + }, + { + .id = Tool::L_CURVE, + }, +}; + +const std::vector DETAILS_PANEL_TOOLS = { + { + .id = Tool::SPOT, + }, + { + .id = Tool::SHARPENING_TOOL, + }, + { + .id = Tool::LOCAL_CONTRAST, + }, + { + .id = Tool::SHARPEN_EDGE, + }, + { + .id = Tool::SHARPEN_MICRO, + }, + { + .id = Tool::IMPULSE_DENOISE, + }, + { + .id = Tool::DIR_PYR_DENOISE, + }, + { + .id = Tool::DEFRINGE_TOOL, + }, + { + .id = Tool::DIR_PYR_EQUALIZER, + }, + { + .id = Tool::DEHAZE, + }, +}; + +const std::vector COLOR_PANEL_TOOLS = { + { + .id = Tool::WHITE_BALANCE, + }, + { + .id = Tool::VIBRANCE, + }, + { + .id = Tool::CH_MIXER, + }, + { + .id = Tool::BLACK_WHITE, + }, + { + .id = Tool::HSV_EQUALIZER, + }, + { + .id = Tool::FILM_SIMULATION, + }, + { + .id = Tool::FILM_NEGATIVE, + }, + { + .id = Tool::SOFT_LIGHT, + }, + { + .id = Tool::RGB_CURVES, + }, + { + .id = Tool::COLOR_TONING, + }, + { + .id = Tool::ICM, + }, +}; + +const std::vector ADVANCED_PANEL_TOOLS = { + { + .id = Tool::RETINEX_TOOL, + }, + { + .id = Tool::COLOR_APPEARANCE, + }, + { + .id = Tool::WAVELET, + }, +}; + +const std::vector LOCALLAB_PANEL_TOOLS = { + { + .id = Tool::LOCALLAB, + }, +}; + +const std::vector TRANSFORM_PANEL_TOOLS = { + { + .id = Tool::CROP_TOOL, + }, + { + .id = Tool::RESIZE_TOOL, + .children = { + { + .id = Tool::PR_SHARPENING, + }, + }, + }, + { + .id = Tool::LENS_GEOM, + .children = { + { + .id = Tool::ROTATE, + }, + { + .id = Tool::PERSPECTIVE, + }, + { + .id = Tool::LENS_PROF, + }, + { + .id = Tool::DISTORTION, + }, + { + .id = Tool::CA_CORRECTION, + }, + { + .id = Tool::VIGNETTING, + }, + }, + }, +}; + +const std::vector RAW_PANEL_TOOLS = { + { + .id = Tool::SENSOR_BAYER, + .children = { + { + { + .id = Tool::BAYER_PROCESS, + }, + { + .id = Tool::BAYER_RAW_EXPOSURE, + }, + { + .id = Tool::BAYER_PREPROCESS, + }, + { + .id = Tool::RAW_CA_CORRECTION, + }, + }, + }, + }, + { + .id = Tool::SENSOR_XTRANS, + .children = { + { + { + .id = Tool::XTRANS_PROCESS, + }, + { + .id = Tool::XTRANS_RAW_EXPOSURE, + }, + }, + }, + }, + { + .id = Tool::RAW_EXPOSURE, + }, + { + .id = Tool::PREPROCESS_WB, + }, + { + .id = Tool::PREPROCESS, + }, + { + .id = Tool::DARKFRAME_TOOL, + }, + { + .id = Tool::FLATFIELD_TOOL, + }, + { + .id = Tool::PD_SHARPENING, + }, +}; + +const std::unordered_map> PANEL_TOOLS = { + { + ToolPanelCoordinator::Panel::EXPOSURE, + EXPOSURE_PANEL_TOOLS + }, + { + ToolPanelCoordinator::Panel::DETAILS, + DETAILS_PANEL_TOOLS + }, + { + ToolPanelCoordinator::Panel::COLOR, + COLOR_PANEL_TOOLS + }, + { + ToolPanelCoordinator::Panel::ADVANCED, + ADVANCED_PANEL_TOOLS + }, + { + ToolPanelCoordinator::Panel::LOCALLAB, + LOCALLAB_PANEL_TOOLS + }, + { + ToolPanelCoordinator::Panel::TRANSFORM_PANEL, + TRANSFORM_PANEL_TOOLS + }, + { + ToolPanelCoordinator::Panel::RAW, + RAW_PANEL_TOOLS + }, +}; + ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favoritePanelSW(nullptr), hasChanged (false), editDataProvider (nullptr), photoLoadedOnce(false) { @@ -288,6 +523,21 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit prevPage = toolPanelNotebook->get_nth_page(0); } +const std::unordered_map> ToolPanelCoordinator::getDefaultToolLayout() +{ + return PANEL_TOOLS; +} + +bool ToolPanelCoordinator::isFavoritable(Tool tool) +{ + switch (tool) { + case Tool::PR_SHARPENING: + return false; + default: + return true; + } +} + void ToolPanelCoordinator::notebookPageChanged(Gtk::Widget* page, guint page_num) { // Locallab spot curves are set visible if at least one photo has been loaded (to avoid diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 13686d6e3..c4215ee2a 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -223,12 +223,90 @@ private: Gtk::Widget* prevPage; public: + enum class Panel { + FAVORITE, + EXPOSURE, + DETAILS, + COLOR, + ADVANCED, + LOCALLAB, + TRANSFORM_PANEL, + RAW, + }; + + enum class Tool { + TONE_CURVE, + SHADOWS_HIGHLIGHTS, + IMPULSE_DENOISE, + DEFRINGE_TOOL, + SPOT, + DIR_PYR_DENOISE, + EPD, + SHARPENING_TOOL, + LOCAL_CONTRAST, + SHARPEN_EDGE, + SHARPEN_MICRO, + L_CURVE, + RGB_CURVES, + COLOR_TONING, + LENS_GEOM, + LENS_PROF, + DISTORTION, + ROTATE, + VIBRANCE, + COLOR_APPEARANCE, + WHITE_BALANCE, + VIGNETTING, + RETINEX_TOOL, + GRADIENT, + LOCALLAB, + PC_VIGNETTE, + PERSPECTIVE, + CA_CORRECTION, + CH_MIXER, + BLACK_WHITE, + RESIZE_TOOL, + PR_SHARPENING, + CROP_TOOL, + ICM, + WAVELET, + DIR_PYR_EQUALIZER, + HSV_EQUALIZER, + FILM_SIMULATION, + SOFT_LIGHT, + DEHAZE, + SENSOR_BAYER, + SENSOR_XTRANS, + BAYER_PROCESS, + XTRANS_PROCESS, + BAYER_PREPROCESS, + PREPROCESS, + DARKFRAME_TOOL, + FLATFIELD_TOOL, + RAW_CA_CORRECTION, + RAW_EXPOSURE, + PREPROCESS_WB, + BAYER_RAW_EXPOSURE, + XTRANS_RAW_EXPOSURE, + FATTAL, + FILM_NEGATIVE, + PD_SHARPENING, + }; + + struct ToolTree { + Tool id; + std::vector children; + }; + CoarsePanel* coarse; Gtk::Notebook* toolPanelNotebook; ToolPanelCoordinator(bool batch = false); ~ToolPanelCoordinator () override; + static const std::unordered_map> getDefaultToolLayout(); + static bool isFavoritable(Tool tool); + bool getChangedState() { return hasChanged; From 23214ae5cd99905fef97e192561886b0210288bb Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Mon, 22 Nov 2021 21:38:14 -0800 Subject: [PATCH 023/134] Clean up code Fix compile warning, remove GTK functions not present in version 3.16, and make code more concise. --- rtgui/preferences.cc | 2 +- rtgui/toollocationpref.cc | 26 ++++++++++++-------------- rtgui/toolpanelcoord.cc | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 556201732..de3553aee 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -498,7 +498,7 @@ void Preferences::behSetRadioToggled(const Glib::ustring& path) Gtk::Widget *Preferences::getFavoritesPanel() { if (!toolLocationPreference) { - toolLocationPreference = Gtk::make_managed(moptions); + toolLocationPreference = Gtk::manage(new ToolLocationPreference(moptions)); } return toolLocationPreference; } diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index 719a72a66..ccbc9310a 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -364,17 +364,16 @@ ToolLocationPreference::Impl::Impl(Options &options) : Gtk::TreeViewColumn(M("PREFERENCES_TOOLPANEL_FAVORITE"))), toolListViewColumnToolName( Gtk::TreeViewColumn(M("PREFERENCES_TOOLPANEL_TOOL"))), - toolListViewPtr(Gtk::make_managed()), + toolListViewPtr(Gtk::manage(new Gtk::TreeView(toolListModelPtr))), favoritesModelPtr(Gtk::ListStore::create(favoritesColumns)), favoritesViewColumnToolName( Gtk::TreeViewColumn(M("PREFERENCES_TOOLPANEL_TOOL"))), - favoritesViewPtr(Gtk::make_managed()) + favoritesViewPtr(Gtk::manage(new Gtk::TreeView(favoritesModelPtr))) { const std::vector favorites = toolNamesToTools(options.favorites); // Tool list. - toolListViewPtr->set_model(toolListModelPtr); toolListViewPtr->append_column(toolListViewColumnToolName); toolListViewColumnToolName.pack_start(toolListCellRendererToolName); toolListViewColumnToolName.set_expand(); @@ -386,14 +385,13 @@ ToolLocationPreference::Impl::Impl(Options &options) : toolListViewColumnFavorite.set_renderer( toolListCellRendererFavorite, toolListColumns.isFavorite); toolListViewColumnFavorite.add_attribute( - toolListCellRendererFavorite, "visible", toolListColumns.isEditable); + toolListCellRendererFavorite.property_visible(), toolListColumns.isEditable); toolListCellRendererFavorite.signal_toggled().connect( sigc::mem_fun(*this, &ToolLocationPreference::Impl::favoriteToggled)); initToolListRows(favorites); toolListViewPtr->expand_all(); // Favorites list. - favoritesViewPtr->set_model(favoritesModelPtr); favoritesViewPtr->append_column(favoritesViewColumnToolName); favoritesViewPtr->set_reorderable(true); favoritesViewColumnToolName.pack_start(favoritesCellRendererToolName); @@ -555,19 +553,19 @@ ToolLocationPreference::ToolLocationPreference(Options &options) : impl(new Impl(options)) { // Layout grid. - Gtk::Grid *layout_grid = Gtk::make_managed(); + Gtk::Grid *layout_grid = Gtk::manage(new Gtk::Grid()); layout_grid->set_column_spacing(4); layout_grid->set_row_spacing(4); add(*layout_grid); // Tool list. - Gtk::Frame *tool_list_frame = Gtk::make_managed( - M("PREFERENCES_TOOLPANEL_AVAILABLETOOLS")); + Gtk::Frame *tool_list_frame = Gtk::manage(new Gtk::Frame( + M("PREFERENCES_TOOLPANEL_AVAILABLETOOLS"))); Gtk::ScrolledWindow *tool_list_scrolled_window = - Gtk::make_managed(); + Gtk::manage(new Gtk::ScrolledWindow()); tool_list_scrolled_window->property_hscrollbar_policy() = Gtk::PolicyType::POLICY_NEVER; - layout_grid->attach_next_to(*tool_list_frame, Gtk::PositionType::POS_RIGHT); + layout_grid->attach_next_to(*tool_list_frame, Gtk::PositionType::POS_RIGHT, 1, 1); tool_list_frame->add(*tool_list_scrolled_window); tool_list_scrolled_window->add(*impl->toolListViewPtr); impl->toolListViewPtr->set_hscroll_policy(Gtk::ScrollablePolicy::SCROLL_MINIMUM); @@ -575,13 +573,13 @@ ToolLocationPreference::ToolLocationPreference(Options &options) : tool_list_frame, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); // Favorites list. - Gtk::Frame *favorites_frame = Gtk::make_managed( - M("PREFERENCES_TOOLPANEL_FAVORITESPANEL")); + Gtk::Frame *favorites_frame = Gtk::manage(new Gtk::Frame( + M("PREFERENCES_TOOLPANEL_FAVORITESPANEL"))); Gtk::ScrolledWindow *favorites_list_scrolled_window = - Gtk::make_managed(); + Gtk::manage(new Gtk::ScrolledWindow()); favorites_list_scrolled_window->property_hscrollbar_policy() = Gtk::PolicyType::POLICY_NEVER; - layout_grid->attach_next_to(*favorites_frame, Gtk::PositionType::POS_RIGHT); + layout_grid->attach_next_to(*favorites_frame, Gtk::PositionType::POS_RIGHT, 1, 1); favorites_frame->add(*favorites_list_scrolled_window); favorites_list_scrolled_window->add(*impl->favoritesViewPtr); setExpandAlignProperties( diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 586d4755f..23b297d20 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -33,7 +33,7 @@ using namespace rtengine::procparams; using Tool = ToolPanelCoordinator::Tool; -using ToolTree = struct ToolPanelCoordinator::ToolTree; +using ToolTree = ToolPanelCoordinator::ToolTree; const std::vector EXPOSURE_PANEL_TOOLS = { { From ac19ea45076498c388526d2bc9b1b182487f3d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Wed, 24 Nov 2021 15:32:04 +0100 Subject: [PATCH 024/134] Fix `enum class` key in hashed containers --- rtgui/guiutils.h | 12 ++++++++++++ rtgui/toollocationpref.cc | 7 ++++--- rtgui/toolpanelcoord.cc | 10 +++++----- rtgui/toolpanelcoord.h | 4 +++- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 126cf672b..21e775c36 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -20,6 +20,7 @@ #include #include +#include #include @@ -74,6 +75,17 @@ private: MyMutex mutex; }; +struct ScopedEnumHash { + template::value && !std::is_convertible::value, int>::type = 0> + size_t operator ()(T val) const noexcept + { + using type = typename std::underlying_type::type; + + return std::hash{}(static_cast(val)); + } +}; + + // TODO: The documentation says gdk_threads_enter and gdk_threads_leave should be replaced // by g_main_context_invoke(), g_idle_add() and related functions, but this will require more extensive changes. // We silence those warnings until then so that we notice the others. diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index ccbc9310a..c0bb6bea3 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -24,6 +24,7 @@ #include "toolpanelcoord.h" using Tool = ToolPanelCoordinator::Tool; +using Favorites = std::unordered_set; std::string getToolName(Tool tool) { @@ -200,7 +201,7 @@ struct ToolLocationPreference::Impl { void addToolListRowGroup( const std::vector &tools, const Gtk::TreeIter &parentRowIter, - const std::unordered_set &favorites); + const Favorites &favorites); void favoriteToggled(const Glib::ustring &row_path); Tool getToolFromName(const std::string &name) const; void initFavoritesRows(const std::vector &favorites); @@ -477,7 +478,7 @@ void ToolLocationPreference::Impl::initFavoritesRows( void ToolLocationPreference::Impl::addToolListRowGroup( const std::vector &tools, const Gtk::TreeIter &parentRowIter, - const std::unordered_set &favorites) + const Favorites &favorites) { for (const ToolPanelCoordinator::ToolTree &tool : tools) { auto tool_row_iter = toolListModelPtr->append(parentRowIter->children()); @@ -498,7 +499,7 @@ void ToolLocationPreference::Impl::addToolListRowGroup( void ToolLocationPreference::Impl::initToolListRows(const std::vector &favorites) { const auto panel_tools = ToolPanelCoordinator::getDefaultToolLayout(); - std::unordered_set favorites_set; + Favorites favorites_set; for (const auto &tool : favorites) { favorites_set.insert(tool); diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 23b297d20..fa2203958 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -236,7 +236,7 @@ const std::vector RAW_PANEL_TOOLS = { }, }; -const std::unordered_map> PANEL_TOOLS = { +const ToolPanelCoordinator::ToolLayout PANEL_TOOLS = { { ToolPanelCoordinator::Panel::EXPOSURE, EXPOSURE_PANEL_TOOLS @@ -378,7 +378,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit addfavoritePanel (detailsPanel, dehaze); addfavoritePanel (advancedPanel, wavelet); addfavoritePanel(locallabPanel, locallab); - + addfavoritePanel (transformPanel, crop); addfavoritePanel (transformPanel, resize); addPanel (resize->getPackBox(), prsharpening, 2); @@ -424,7 +424,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit transformPanelSW = Gtk::manage (new MyScrolledWindow ()); rawPanelSW = Gtk::manage (new MyScrolledWindow ()); advancedPanelSW = Gtk::manage (new MyScrolledWindow ()); - locallabPanelSW = Gtk::manage(new MyScrolledWindow()); + locallabPanelSW = Gtk::manage(new MyScrolledWindow()); // load panel endings for (int i = 0; i < 8; i++) { @@ -455,7 +455,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit locallabPanelSW->add(*locallabPanel); locallabPanel->pack_start(*vbPanelEnd[7], Gtk::PACK_SHRINK, 4); - + transformPanelSW->add (*transformPanel); transformPanel->pack_start (*vbPanelEnd[4], Gtk::PACK_SHRINK, 4); @@ -523,7 +523,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit prevPage = toolPanelNotebook->get_nth_page(0); } -const std::unordered_map> ToolPanelCoordinator::getDefaultToolLayout() +const ToolPanelCoordinator::ToolLayout& ToolPanelCoordinator::getDefaultToolLayout() { return PANEL_TOOLS; } diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index c4215ee2a..94e5a8717 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -298,13 +298,15 @@ public: std::vector children; }; + using ToolLayout = std::unordered_map, ScopedEnumHash>; + CoarsePanel* coarse; Gtk::Notebook* toolPanelNotebook; ToolPanelCoordinator(bool batch = false); ~ToolPanelCoordinator () override; - static const std::unordered_map> getDefaultToolLayout(); + static const ToolLayout& getDefaultToolLayout(); static bool isFavoritable(Tool tool); bool getChangedState() From c6a45ae765c842ab75aa9f936c35756ce1cc97de Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Thu, 25 Nov 2021 14:58:42 -0800 Subject: [PATCH 025/134] Move helper functions into anonymous namespace Move some functions in toollocationpref.cc. --- rtgui/toollocationpref.cc | 143 ++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 69 deletions(-) diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index c0bb6bea3..3e874627c 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -26,6 +26,9 @@ using Tool = ToolPanelCoordinator::Tool; using Favorites = std::unordered_set; +namespace +{ + std::string getToolName(Tool tool) { switch (tool) { @@ -145,75 +148,6 @@ std::string getToolName(Tool tool) return ""; }; -class FavoritesColumns : public Gtk::TreeModelColumnRecord -{ -public: - Gtk::TreeModelColumn toolName; - Gtk::TreeModelColumn tool; - - FavoritesColumns() - { - add(toolName); - add(tool); - } -}; - -class ToolListColumns : public Gtk::TreeModelColumnRecord -{ -public: - Gtk::TreeModelColumn toolName; - Gtk::TreeModelColumn tool; - Gtk::TreeModelColumn isFavorite; - Gtk::TreeModelColumn isEditable; - - ToolListColumns() - { - add(toolName); - add(tool); - add(isFavorite); - add(isEditable); - } -}; - -struct ToolLocationPreference::Impl { - static std::unordered_map toolNamesReverseMap; - - Options &options; - - // Tool list. - ToolListColumns toolListColumns; - Glib::RefPtr toolListModelPtr; - Gtk::CellRendererToggle toolListCellRendererFavorite; - Gtk::CellRendererText toolListCellRendererToolName; - Gtk::TreeViewColumn toolListViewColumnFavorite; - Gtk::TreeViewColumn toolListViewColumnToolName; - Gtk::TreeView *toolListViewPtr; - - // Favorites list. - FavoritesColumns favoritesColumns; - Glib::RefPtr favoritesModelPtr; - Gtk::CellRendererText favoritesCellRendererToolName; - Gtk::TreeViewColumn favoritesViewColumnToolName; - Gtk::TreeView *favoritesViewPtr; - - explicit Impl(Options &options); - - void addToolListRowGroup( - const std::vector &tools, - const Gtk::TreeIter &parentRowIter, - const Favorites &favorites); - void favoriteToggled(const Glib::ustring &row_path); - Tool getToolFromName(const std::string &name) const; - void initFavoritesRows(const std::vector &favorites); - void initToolListRows(const std::vector &favorites); - std::vector toolNamesToTools( - const std::vector &tool_names) const; - void updateOptions(); -}; - -std::unordered_map - ToolLocationPreference::Impl::toolNamesReverseMap; - Glib::ustring getToolPanelTitleKey(ToolPanelCoordinator::Panel panel) { switch (panel) { @@ -357,6 +291,77 @@ Glib::ustring getToolTitleKey(Tool tool) return ""; } +} + +class FavoritesColumns : public Gtk::TreeModelColumnRecord +{ +public: + Gtk::TreeModelColumn toolName; + Gtk::TreeModelColumn tool; + + FavoritesColumns() + { + add(toolName); + add(tool); + } +}; + +class ToolListColumns : public Gtk::TreeModelColumnRecord +{ +public: + Gtk::TreeModelColumn toolName; + Gtk::TreeModelColumn tool; + Gtk::TreeModelColumn isFavorite; + Gtk::TreeModelColumn isEditable; + + ToolListColumns() + { + add(toolName); + add(tool); + add(isFavorite); + add(isEditable); + } +}; + +struct ToolLocationPreference::Impl { + static std::unordered_map toolNamesReverseMap; + + Options &options; + + // Tool list. + ToolListColumns toolListColumns; + Glib::RefPtr toolListModelPtr; + Gtk::CellRendererToggle toolListCellRendererFavorite; + Gtk::CellRendererText toolListCellRendererToolName; + Gtk::TreeViewColumn toolListViewColumnFavorite; + Gtk::TreeViewColumn toolListViewColumnToolName; + Gtk::TreeView *toolListViewPtr; + + // Favorites list. + FavoritesColumns favoritesColumns; + Glib::RefPtr favoritesModelPtr; + Gtk::CellRendererText favoritesCellRendererToolName; + Gtk::TreeViewColumn favoritesViewColumnToolName; + Gtk::TreeView *favoritesViewPtr; + + explicit Impl(Options &options); + + void addToolListRowGroup( + const std::vector &tools, + const Gtk::TreeIter &parentRowIter, + const Favorites &favorites); + void favoriteToggled(const Glib::ustring &row_path); + Tool getToolFromName(const std::string &name) const; + void initFavoritesRows(const std::vector &favorites); + void initToolListRows(const std::vector &favorites); + std::vector toolNamesToTools( + const std::vector &tool_names) const; + void updateOptions(); +}; + +std::unordered_map + ToolLocationPreference::Impl::toolNamesReverseMap; + ToolLocationPreference::Impl::Impl(Options &options) : options(options), From fde15eaebb85a16f5c068ff46e54d8f9d5b48d6e Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Thu, 25 Nov 2021 15:35:02 -0800 Subject: [PATCH 026/134] Improve look of favorites preferences Set a fixed width for the lists, embed the preferences in a horizontally-scrollable window, and open the preferences window on the general tab. --- rtgui/preferences.cc | 8 +++++++- rtgui/preferences.h | 1 + rtgui/toollocationpref.cc | 9 ++------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index de3553aee..39726c791 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -67,6 +67,7 @@ Preferences::Preferences(RTWindow *rtwindow) , newFont(false) , newCPFont(false) , toolLocationPreference(nullptr) + , swFavorites(nullptr) { moptions.copyFrom(&options); @@ -500,7 +501,12 @@ Gtk::Widget *Preferences::getFavoritesPanel() if (!toolLocationPreference) { toolLocationPreference = Gtk::manage(new ToolLocationPreference(moptions)); } - return toolLocationPreference; + if (!swFavorites) { + swFavorites = Gtk::manage(new Gtk::ScrolledWindow()); + swFavorites->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_NEVER); + swFavorites->add(*toolLocationPreference); + } + return swFavorites; } Gtk::Widget *Preferences::getDynamicProfilePanel() diff --git a/rtgui/preferences.h b/rtgui/preferences.h index 18d7a0581..33ca44eca 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -272,6 +272,7 @@ class Preferences final : Gtk::ScrolledWindow *swGeneral; Gtk::ScrolledWindow *swImageProcessing; + Gtk::ScrolledWindow *swFavorites; Gtk::ScrolledWindow *swDynamicProfile; Gtk::ScrolledWindow *swFileBrowser; Gtk::ScrolledWindow *swColorMan; diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index 3e874627c..d0a8cdf34 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -569,12 +569,10 @@ ToolLocationPreference::ToolLocationPreference(Options &options) : M("PREFERENCES_TOOLPANEL_AVAILABLETOOLS"))); Gtk::ScrolledWindow *tool_list_scrolled_window = Gtk::manage(new Gtk::ScrolledWindow()); - tool_list_scrolled_window->property_hscrollbar_policy() = - Gtk::PolicyType::POLICY_NEVER; + tool_list_scrolled_window->set_min_content_width(550); layout_grid->attach_next_to(*tool_list_frame, Gtk::PositionType::POS_RIGHT, 1, 1); tool_list_frame->add(*tool_list_scrolled_window); tool_list_scrolled_window->add(*impl->toolListViewPtr); - impl->toolListViewPtr->set_hscroll_policy(Gtk::ScrollablePolicy::SCROLL_MINIMUM); setExpandAlignProperties( tool_list_frame, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); @@ -583,15 +581,12 @@ ToolLocationPreference::ToolLocationPreference(Options &options) : M("PREFERENCES_TOOLPANEL_FAVORITESPANEL"))); Gtk::ScrolledWindow *favorites_list_scrolled_window = Gtk::manage(new Gtk::ScrolledWindow()); - favorites_list_scrolled_window->property_hscrollbar_policy() = - Gtk::PolicyType::POLICY_NEVER; + favorites_list_scrolled_window->set_min_content_width(400); layout_grid->attach_next_to(*favorites_frame, Gtk::PositionType::POS_RIGHT, 1, 1); favorites_frame->add(*favorites_list_scrolled_window); favorites_list_scrolled_window->add(*impl->favoritesViewPtr); setExpandAlignProperties( favorites_frame, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); - - this->show_all(); } void ToolLocationPreference::updateOptions() From 4fe39a82a5e024777e7b6d314158b1dbb8182ed1 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 26 Nov 2021 15:46:24 -0800 Subject: [PATCH 027/134] Add buttons for reordering favorites --- rtgui/toollocationpref.cc | 194 +++++++++++++++++++++++++++++++++++++- 1 file changed, 191 insertions(+), 3 deletions(-) diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index d0a8cdf34..2330759a4 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -20,6 +20,7 @@ #include "guiutils.h" #include "options.h" +#include "rtimage.h" #include "toollocationpref.h" #include "toolpanelcoord.h" @@ -291,7 +292,28 @@ Glib::ustring getToolTitleKey(Tool tool) return ""; } -} +class ListEditButtons : public Gtk::Box +{ +private: + Gtk::TreeView &list; + Glib::RefPtr listStore; + Gtk::Button buttonUp; + Gtk::Button buttonDown; + Gtk::Button buttonRemove; + + sigc::signal> signalRowsPreErase; + + void onButtonDownPressed(); + void onButtonRemovePressed(); + void onButtonUpPressed(); + void onListSelectionChanged(); + void updateButtonSensitivity(); + +public: + explicit ListEditButtons(Gtk::TreeView &list, Glib::RefPtr listStore); + + sigc::signal> getSignalRowsPreErase(); +}; class FavoritesColumns : public Gtk::TreeModelColumnRecord { @@ -323,6 +345,148 @@ public: } }; +ListEditButtons::ListEditButtons(Gtk::TreeView &list, Glib::RefPtr listStore) : + Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL), + list(list), + listStore(listStore) +{ + assert(list.get_model() == listStore); + + // Set button images. + RTImage *image_button_up = Gtk::manage(new RTImage("arrow-up-small.png")); + RTImage *image_button_down = Gtk::manage(new RTImage("arrow-down-small.png")); + RTImage *image_button_remove = Gtk::manage(new RTImage("remove-small.png")); + buttonUp.set_image(*image_button_up); + buttonDown.set_image(*image_button_down); + buttonRemove.set_image(*image_button_remove); + + // Connect signals for changing button sensitivity. + const auto on_list_sel_changed_fun = sigc::mem_fun( + *this, &ListEditButtons::onListSelectionChanged); + const auto on_row_deleted_fun = sigc::hide(on_list_sel_changed_fun); + const auto on_row_inserted_fun = sigc::hide(on_row_deleted_fun); + list.get_selection()->signal_changed().connect(on_list_sel_changed_fun); + listStore->signal_row_deleted().connect(on_row_deleted_fun); + listStore->signal_row_inserted().connect(on_row_inserted_fun); + + // Connect signals for buttons. + buttonUp.signal_pressed().connect(sigc::mem_fun( + *this, &ListEditButtons::onButtonUpPressed)); + buttonDown.signal_pressed().connect(sigc::mem_fun( + *this, &ListEditButtons::onButtonDownPressed)); + buttonRemove.signal_pressed().connect(sigc::mem_fun( + *this, &ListEditButtons::onButtonRemovePressed)); + + updateButtonSensitivity(); + + add(buttonUp); + add(buttonDown); + add(buttonRemove); +} + +void ListEditButtons::onButtonDownPressed() +{ + const auto list_children = listStore->children(); + const std::vector selected = + list.get_selection()->get_selected_rows(); + + if (selected.size() != 1) { // Only one can be selected. + return; + } + + auto selected_row_iter = listStore->get_iter(selected[0]); + auto next_row_iter = selected_row_iter; + next_row_iter++; + + if (next_row_iter == list_children.end()) { // Can't be last row. + return; + } + + listStore->iter_swap(selected_row_iter, next_row_iter); + updateButtonSensitivity(); +} + +void ListEditButtons::onButtonRemovePressed() +{ + const std::vector selected_paths = + list.get_selection()->get_selected_rows(); + std::vector selected; + + // Get row references, which are valid until the row is removed. + for (const auto & row_path : selected_paths) { + selected.push_back(Gtk::TreeModel::RowReference(listStore, row_path)); + } + + signalRowsPreErase.emit(selected_paths); + + for (const auto & row_ref : selected) { + const auto row_path = row_ref.get_path(); + if (row_path) { + listStore->erase(listStore->get_iter(row_path)); + } + } + + updateButtonSensitivity(); +} + +void ListEditButtons::onButtonUpPressed() +{ + const auto list_children = listStore->children(); + const std::vector selected = + list.get_selection()->get_selected_rows(); + + if (selected.size() != 1) { // Only one can be selected. + return; + } + + auto selected_row_iter = listStore->get_iter(selected[0]); + + if (selected_row_iter == list_children.begin()) { // Can't be first row. + return; + } + + auto prev_row_iter = selected_row_iter; + prev_row_iter--; + listStore->iter_swap(selected_row_iter, prev_row_iter); + updateButtonSensitivity(); +} + +void ListEditButtons::onListSelectionChanged() +{ + updateButtonSensitivity(); +} + +void ListEditButtons::updateButtonSensitivity() +{ + assert(list.get_model() == listStore); + + const std::vector selected = + list.get_selection()->get_selected_rows(); + + // Update sensitivity of the move up/down buttons. + if (selected.size() != 1) { + // Items can only be moved if one row is selected. + buttonDown.set_sensitive(false); + buttonUp.set_sensitive(false); + } else { + auto selected_row_iter = list.get_model()->get_iter(selected[0]); + const auto list_children = listStore->children(); + buttonUp.set_sensitive(!selected_row_iter->equal(list_children.begin())); + buttonDown.set_sensitive(!(++selected_row_iter)->equal(list_children.end())); + } + + // Update sensitivity of the remove button. + buttonRemove.set_sensitive(selected.size() > 0); +} + +sigc::signal> +ListEditButtons::getSignalRowsPreErase() +{ + return signalRowsPreErase; +} + +} + struct ToolLocationPreference::Impl { static std::unordered_map toolNamesReverseMap; @@ -336,6 +500,7 @@ struct ToolLocationPreference::Impl { Gtk::TreeViewColumn toolListViewColumnFavorite; Gtk::TreeViewColumn toolListViewColumnToolName; Gtk::TreeView *toolListViewPtr; + std::unordered_map toolListToolToRowIterMap; // Favorites list. FavoritesColumns favoritesColumns; @@ -343,6 +508,7 @@ struct ToolLocationPreference::Impl { Gtk::CellRendererText favoritesCellRendererToolName; Gtk::TreeViewColumn favoritesViewColumnToolName; Gtk::TreeView *favoritesViewPtr; + ListEditButtons favoritesListEditButtons; explicit Impl(Options &options); @@ -354,6 +520,7 @@ struct ToolLocationPreference::Impl { Tool getToolFromName(const std::string &name) const; void initFavoritesRows(const std::vector &favorites); void initToolListRows(const std::vector &favorites); + void onFavoritesRowsPreRemove(const std::vector paths); std::vector toolNamesToTools( const std::vector &tool_names) const; void updateOptions(); @@ -375,7 +542,8 @@ ToolLocationPreference::Impl::Impl(Options &options) : favoritesModelPtr(Gtk::ListStore::create(favoritesColumns)), favoritesViewColumnToolName( Gtk::TreeViewColumn(M("PREFERENCES_TOOLPANEL_TOOL"))), - favoritesViewPtr(Gtk::manage(new Gtk::TreeView(favoritesModelPtr))) + favoritesViewPtr(Gtk::manage(new Gtk::TreeView(favoritesModelPtr))), + favoritesListEditButtons(*favoritesViewPtr, favoritesModelPtr) { const std::vector favorites = toolNamesToTools(options.favorites); @@ -403,6 +571,10 @@ ToolLocationPreference::Impl::Impl(Options &options) : favoritesViewColumnToolName.pack_start(favoritesCellRendererToolName); favoritesViewColumnToolName.set_renderer( favoritesCellRendererToolName, favoritesColumns.toolName); + favoritesListEditButtons.getSignalRowsPreErase().connect(sigc::mem_fun( + *this, &ToolLocationPreference::Impl::onFavoritesRowsPreRemove)); + favoritesViewPtr->get_selection()->set_mode( + Gtk::SelectionMode::SELECTION_MULTIPLE); initFavoritesRows(favorites); } @@ -497,6 +669,7 @@ void ToolLocationPreference::Impl::addToolListRowGroup( tool_row_iter->set_value( toolListColumns.isEditable, ToolPanelCoordinator::isFavoritable(tool.id)); + toolListToolToRowIterMap[tool.id] = tool_row_iter; addToolListRowGroup(tool.children, tool_row_iter, favorites); } }; @@ -527,6 +700,18 @@ void ToolLocationPreference::Impl::initToolListRows(const std::vector &fav } } +void ToolLocationPreference::Impl::onFavoritesRowsPreRemove( + const std::vector paths) +{ + // Unset the favorite column in the tools list for tools about to be removed + // from the favorites list. + for (const auto &path : paths) { + const auto &row_iter = toolListToolToRowIterMap.at( + favoritesModelPtr->get_iter(path)->get_value(favoritesColumns.tool)); + row_iter->set_value(toolListColumns.isFavorite, false); + } +} + std::vector ToolLocationPreference::Impl::toolNamesToTools( const std::vector &tool_names) const { @@ -579,11 +764,14 @@ ToolLocationPreference::ToolLocationPreference(Options &options) : // Favorites list. Gtk::Frame *favorites_frame = Gtk::manage(new Gtk::Frame( M("PREFERENCES_TOOLPANEL_FAVORITESPANEL"))); + Gtk::Box *favorites_box = Gtk::manage(new Gtk::Box()); Gtk::ScrolledWindow *favorites_list_scrolled_window = Gtk::manage(new Gtk::ScrolledWindow()); favorites_list_scrolled_window->set_min_content_width(400); layout_grid->attach_next_to(*favorites_frame, Gtk::PositionType::POS_RIGHT, 1, 1); - favorites_frame->add(*favorites_list_scrolled_window); + favorites_box->pack_start(*favorites_list_scrolled_window, false, false); + favorites_box->pack_start(impl->favoritesListEditButtons, false, false); + favorites_frame->add(*favorites_box); favorites_list_scrolled_window->add(*impl->favoritesViewPtr); setExpandAlignProperties( favorites_frame, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); From 16a9e3932fb8379537bb1d435631faf0d4334bb2 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 26 Nov 2021 16:39:50 -0800 Subject: [PATCH 028/134] Fix compilation error Add hasher to unordered_map with an enum class key. --- rtgui/toollocationpref.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index 2330759a4..0dda56806 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -500,7 +500,8 @@ struct ToolLocationPreference::Impl { Gtk::TreeViewColumn toolListViewColumnFavorite; Gtk::TreeViewColumn toolListViewColumnToolName; Gtk::TreeView *toolListViewPtr; - std::unordered_map toolListToolToRowIterMap; + std::unordered_map + toolListToolToRowIterMap; // Favorites list. FavoritesColumns favoritesColumns; From 9a67dd726e4c85d3a468466b62de3fa37b42f5ee Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 26 Nov 2021 21:01:37 -0800 Subject: [PATCH 029/134] Comment code for tool location preferences --- rtgui/toollocationpref.cc | 106 ++++++++++++++++++++++++++++++++++++++ rtgui/toollocationpref.h | 11 ++++ 2 files changed, 117 insertions(+) diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index 0dda56806..32cd73e97 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -30,6 +30,12 @@ using Favorites = std::unordered_set; namespace { +/** + * Gets the tool name for the tool's ToolPanel as a string. + * + * @param tool The name as a raw string, or an empty string if the tool is + * unknown. + */ std::string getToolName(Tool tool) { switch (tool) { @@ -149,6 +155,9 @@ std::string getToolName(Tool tool) return ""; }; +/** + * Returns the language key for the panel's title. + */ Glib::ustring getToolPanelTitleKey(ToolPanelCoordinator::Panel panel) { switch (panel) { @@ -172,6 +181,9 @@ Glib::ustring getToolPanelTitleKey(ToolPanelCoordinator::Panel panel) return ""; } +/** + * Returns the language key for the tool's title. + */ Glib::ustring getToolTitleKey(Tool tool) { using Tool = Tool; @@ -292,6 +304,13 @@ Glib::ustring getToolTitleKey(Tool tool) return ""; } +/** + * A widget with buttons (packed vertically) for modifying a list store with a + * tree view. + * + * Includes buttons for moving single rows up or down and a button for removing + * selected rows. + */ class ListEditButtons : public Gtk::Box { private: @@ -310,15 +329,34 @@ private: void updateButtonSensitivity(); public: + /** + * Constructs an edit buttons widget for modifying the provided list store. + * + * @param list The tree view for which selections are made in. The tree + * view's model MUST be the list store. + * @param listStore The list store that the widget will modify. + */ explicit ListEditButtons(Gtk::TreeView &list, Glib::RefPtr listStore); + /** + * Returns the signal that gets emitted right before this widget removes + * rows from its list store. + * + * The signal contains a vector of tree model paths of the rows that will be + * erased. + */ sigc::signal> getSignalRowsPreErase(); }; +/** + * Model columns for the favorites list. + */ class FavoritesColumns : public Gtk::TreeModelColumnRecord { public: + /** The tool's display name. */ Gtk::TreeModelColumn toolName; + /** The tool. */ Gtk::TreeModelColumn tool; FavoritesColumns() @@ -328,12 +366,19 @@ public: } }; +/** + * Model columns for the available tools list. + */ class ToolListColumns : public Gtk::TreeModelColumnRecord { public: + /** The tool's display name. */ Gtk::TreeModelColumn toolName; + /** The tool. */ Gtk::TreeModelColumn tool; + /** Is the tool added to favorites. */ Gtk::TreeModelColumn isFavorite; + /** Can the tool be added to favorites. */ Gtk::TreeModelColumn isEditable; ToolListColumns() @@ -394,6 +439,7 @@ void ListEditButtons::onButtonDownPressed() return; } + // Get the selected row and next row. auto selected_row_iter = listStore->get_iter(selected[0]); auto next_row_iter = selected_row_iter; next_row_iter++; @@ -402,6 +448,7 @@ void ListEditButtons::onButtonDownPressed() return; } + // Move the selected row down and update the buttons. listStore->iter_swap(selected_row_iter, next_row_iter); updateButtonSensitivity(); } @@ -419,6 +466,7 @@ void ListEditButtons::onButtonRemovePressed() signalRowsPreErase.emit(selected_paths); + // Remove the selected rows. for (const auto & row_ref : selected) { const auto row_path = row_ref.get_path(); if (row_path) { @@ -445,6 +493,7 @@ void ListEditButtons::onButtonUpPressed() return; } + // Swap selected row with the previous row. auto prev_row_iter = selected_row_iter; prev_row_iter--; listStore->iter_swap(selected_row_iter, prev_row_iter); @@ -469,6 +518,8 @@ void ListEditButtons::updateButtonSensitivity() buttonDown.set_sensitive(false); buttonUp.set_sensitive(false); } else { + // Up button cannot be used on the first row. Down button cannot be used + // on the last row. auto selected_row_iter = list.get_model()->get_iter(selected[0]); const auto list_children = listStore->children(); buttonUp.set_sensitive(!selected_row_iter->equal(list_children.begin())); @@ -511,19 +562,68 @@ struct ToolLocationPreference::Impl { Gtk::TreeView *favoritesViewPtr; ListEditButtons favoritesListEditButtons; + /** + * Constructs an implementation that gets values from and updates the + * provided options object. + */ explicit Impl(Options &options); + /** + * Adds the tools in the tool tree as a child in the provided row. + * + * @param tools The tool tree. + * @param parentRowIter An iterator to the row under which to add the tools. + * @param favorites The tools which are currently marked as favorites. + */ void addToolListRowGroup( const std::vector &tools, const Gtk::TreeIter &parentRowIter, const Favorites &favorites); + /** + * Toggles the tool list favorite column and updates the favorites list. + * + * @param row_path Path to the tool list model row. + */ void favoriteToggled(const Glib::ustring &row_path); + /** + * Gets the tool with the provided tool name. + * + * @param name The tool name as a raw string. + * @return The tool. + */ Tool getToolFromName(const std::string &name) const; + /** + * Initializes the favorites list. + * + * @param favorites Tools that are currently marked as favorites. + */ void initFavoritesRows(const std::vector &favorites); + /** + * Initializes the available tools list. + * + * @param favorites Tools that are currently marked as favorites. + */ void initToolListRows(const std::vector &favorites); + /** + * Updates the favorites column of the available tools list when tools are + * about to be removed from the favorites list. + * + * @param paths Paths in the favorites list pointing to the rows that are + * about to be removed. + */ void onFavoritesRowsPreRemove(const std::vector paths); + /** + * Converts tool names to their corresponding tools. + * + * @param tool_names The tool names that need to be converted. + * @return The tools. + */ std::vector toolNamesToTools( const std::vector &tool_names) const; + /** + * Updates the options object associated with this object with the current + * favorites preferences. + */ void updateOptions(); }; @@ -533,6 +633,7 @@ std::unordered_map ToolLocationPreference::Impl::Impl(Options &options) : options(options), + // Tool list. toolListModelPtr(Gtk::TreeStore::create(toolListColumns)), toolListViewColumnFavorite( Gtk::TreeViewColumn(M("PREFERENCES_TOOLPANEL_FAVORITE"))), @@ -540,6 +641,7 @@ ToolLocationPreference::Impl::Impl(Options &options) : Gtk::TreeViewColumn(M("PREFERENCES_TOOLPANEL_TOOL"))), toolListViewPtr(Gtk::manage(new Gtk::TreeView(toolListModelPtr))), + // Favorites list. favoritesModelPtr(Gtk::ListStore::create(favoritesColumns)), favoritesViewColumnToolName( Gtk::TreeViewColumn(M("PREFERENCES_TOOLPANEL_TOOL"))), @@ -644,6 +746,7 @@ Tool ToolLocationPreference::Impl::getToolFromName(const std::string &name) cons void ToolLocationPreference::Impl::initFavoritesRows( const std::vector &favorites) { + // Add the favorites to the favorites list store. for (const auto tool : favorites) { auto favorite_row_iter = favoritesModelPtr->append(); favorite_row_iter->set_value( @@ -658,6 +761,7 @@ void ToolLocationPreference::Impl::addToolListRowGroup( const Gtk::TreeIter &parentRowIter, const Favorites &favorites) { + // Recursively add the tool and its children to the tool list tree store. for (const ToolPanelCoordinator::ToolTree &tool : tools) { auto tool_row_iter = toolListModelPtr->append(parentRowIter->children()); tool_row_iter->set_value( @@ -680,10 +784,12 @@ void ToolLocationPreference::Impl::initToolListRows(const std::vector &fav const auto panel_tools = ToolPanelCoordinator::getDefaultToolLayout(); Favorites favorites_set; + // Convert the favorites vector into a set for fast lookup. for (const auto &tool : favorites) { favorites_set.insert(tool); } + // Add each panel and their children to the tool list. for (const auto panel : { ToolPanelCoordinator::Panel::EXPOSURE, ToolPanelCoordinator::Panel::DETAILS, diff --git a/rtgui/toollocationpref.h b/rtgui/toollocationpref.h index 815df6839..c7bee8695 100644 --- a/rtgui/toollocationpref.h +++ b/rtgui/toollocationpref.h @@ -22,6 +22,9 @@ class Options; +/** + * Widget for configuring the location of tools in the tool panel tabs. + */ class ToolLocationPreference : public Gtk::Box { private: @@ -29,6 +32,14 @@ private: std::unique_ptr impl; public: + /** + * Constructs a tool location preference widget that gets values from and + * updates the provided options object. + */ explicit ToolLocationPreference(Options &options); + /** + * Updates the options object associated with this object with the current + * favorites preferences. + */ void updateOptions(); }; From 8bd7712cce1dba8cd6cf0d876008a35646141942 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 26 Nov 2021 21:34:19 -0800 Subject: [PATCH 030/134] Add error handling to tool location preferences --- rtgui/toollocationpref.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index 32cd73e97..a6c7bf6b4 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include #include #include "guiutils.h" @@ -152,6 +153,7 @@ std::string getToolName(Tool tool) case Tool::PD_SHARPENING: return "capturesharpening"; }; + assert(false); return ""; }; @@ -178,6 +180,7 @@ Glib::ustring getToolPanelTitleKey(ToolPanelCoordinator::Panel panel) case ToolPanelCoordinator::Panel::RAW: return "MAIN_TAB_RAW"; } + assert(false); return ""; } @@ -301,6 +304,7 @@ Glib::ustring getToolTitleKey(Tool tool) case Tool::PD_SHARPENING: return "TP_PDSHARPENING_LABEL"; }; + assert(false); return ""; } @@ -471,6 +475,8 @@ void ListEditButtons::onButtonRemovePressed() const auto row_path = row_ref.get_path(); if (row_path) { listStore->erase(listStore->get_iter(row_path)); + } else if (rtengine::settings->verbose) { + std::cout << "Unable to remove row because it does not exist anymore." << std::endl; } } @@ -829,6 +835,10 @@ std::vector ToolLocationPreference::Impl::toolNamesToTools( try { tool = getToolFromName(tool_name); } catch (const std::exception &e) { + if (rtengine::settings->verbose) { + std::cerr << "Unrecognized tool name \"" << tool_name << "\"." << std::endl; + } + assert(false); continue; } tool_set.push_back(tool); From 778b26d5bd26cce1f5bb8f6815f426ccd316cbed Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 5 Dec 2021 17:09:23 -0800 Subject: [PATCH 031/134] Make tool locations dynamic Update tool locations after changing favorite tools preferences. --- rtdata/themes/RawTherapee-GTK3-20_.css | 2 +- rtgui/editorpanel.cc | 7 + rtgui/editorpanel.h | 1 + rtgui/preferences.cc | 3 + rtgui/rtwindow.cc | 8 + rtgui/rtwindow.h | 1 + rtgui/toollocationpref.cc | 167 +------ rtgui/toolpanel.cc | 9 +- rtgui/toolpanel.h | 11 + rtgui/toolpanelcoord.cc | 608 ++++++++++++++++++++----- rtgui/toolpanelcoord.h | 43 +- 11 files changed, 586 insertions(+), 274 deletions(-) diff --git a/rtdata/themes/RawTherapee-GTK3-20_.css b/rtdata/themes/RawTherapee-GTK3-20_.css index 57c6db148..c576e0ddf 100644 --- a/rtdata/themes/RawTherapee-GTK3-20_.css +++ b/rtdata/themes/RawTherapee-GTK3-20_.css @@ -758,7 +758,7 @@ button.radio#histButton:hover { #MyExpander:first-child { border-top: none; } -#MyExpander:nth-last-child(2), +#MyExpander:nth-last-child(1), #MyExpander #MyExpander:nth-last-child(1) { border-bottom: 0.0833333333333333em solid rgba(0,0,0,0.3); } diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 78a07ddd6..888fc9518 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2486,6 +2486,13 @@ void EditorPanel::updateHistogramPosition (int oldPosition, int newPosition) } +void EditorPanel::updateToolPanelToolLocations( + const std::vector &favorites) +{ + if (tpc) { + tpc->updateToolLocations(favorites); + } +} void EditorPanel::defaultMonitorProfileChanged (const Glib::ustring &profile_name, bool auto_monitor_profile) { diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 7675face5..0ffe44ace 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -185,6 +185,7 @@ public: void updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC); void updateTPVScrollbar (bool hide); void updateHistogramPosition (int oldPosition, int newPosition); + void updateToolPanelToolLocations(const std::vector &favorites); void defaultMonitorProfileChanged (const Glib::ustring &profile_name, bool auto_monitor_profile); diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 39726c791..e67d16015 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -2572,6 +2572,9 @@ void Preferences::workflowUpdate() parent->updateProfiles (moptions.rtSettings.printerProfile, rtengine::RenderingIntent(moptions.rtSettings.printerIntent), moptions.rtSettings.printerBPC); } + if (moptions.favorites != options.favorites) { + parent->updateToolPanelToolLocations(moptions.favorites); + } } void Preferences::addExtPressed() diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index 1b90d631b..15715a2fd 100755 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -1110,6 +1110,14 @@ void RTWindow::updateHistogramPosition (int oldPosition, int newPosition) } } +void RTWindow::updateToolPanelToolLocations( + const std::vector &favorites) +{ + if (epanel) { + epanel->updateToolPanelToolLocations(favorites); + } +} + bool RTWindow::splashClosed (GdkEventAny* event) { delete splash; diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h index 0c1cd2572..d35755185 100755 --- a/rtgui/rtwindow.h +++ b/rtgui/rtwindow.h @@ -124,6 +124,7 @@ public: void updateFBQueryTB (bool singleRow); void updateFBToolBarVisibility (bool showFilmStripToolBar); void updateShowtooltipVisibility (bool showtooltip); + void updateToolPanelToolLocations(const std::vector &favorites); bool getIsFullscreen() { return is_fullscreen; diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index a6c7bf6b4..561be4601 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -31,132 +31,6 @@ using Favorites = std::unordered_set; namespace { -/** - * Gets the tool name for the tool's ToolPanel as a string. - * - * @param tool The name as a raw string, or an empty string if the tool is - * unknown. - */ -std::string getToolName(Tool tool) -{ - switch (tool) { - case Tool::TONE_CURVE: - return "tonecurve"; - case Tool::SHADOWS_HIGHLIGHTS: - return "shadowshighlights"; - case Tool::IMPULSE_DENOISE: - return "impulsedenoise"; - case Tool::DEFRINGE_TOOL: - return "defringe"; - case Tool::SPOT: - return "spot"; - case Tool::DIR_PYR_DENOISE: - return "dirpyrdenoise"; - case Tool::EPD: - return "epd"; - case Tool::SHARPENING_TOOL: - return "sharpening"; - case Tool::LOCAL_CONTRAST: - return "localcontrast"; - case Tool::SHARPEN_EDGE: - return "sharpenedge"; - case Tool::SHARPEN_MICRO: - return "sharpenmicro"; - case Tool::L_CURVE: - return "labcurves"; - case Tool::RGB_CURVES: - return "rgbcurves"; - case Tool::COLOR_TONING: - return "colortoning"; - case Tool::LENS_GEOM: - return "lensgeom"; - case Tool::LENS_PROF: - return "lensprof"; - case Tool::DISTORTION: - return "distortion"; - case Tool::ROTATE: - return "rotate"; - case Tool::VIBRANCE: - return "vibrance"; - case Tool::COLOR_APPEARANCE: - return "colorappearance"; - case Tool::WHITE_BALANCE: - return "whitebalance"; - case Tool::VIGNETTING: - return "vignetting"; - case Tool::RETINEX_TOOL: - return "retinex"; - case Tool::GRADIENT: - return "gradient"; - case Tool::LOCALLAB: - return "locallab"; - case Tool::PC_VIGNETTE: - return "pcvignette"; - case Tool::PERSPECTIVE: - return "perspective"; - case Tool::CA_CORRECTION: - return "cacorrection"; - case Tool::CH_MIXER: - return "chmixer"; - case Tool::BLACK_WHITE: - return "blackwhite"; - case Tool::RESIZE_TOOL: - return "resize"; - case Tool::PR_SHARPENING: - return "prsharpening"; - case Tool::CROP_TOOL: - return "crop"; - case Tool::ICM: - return "icm"; - case Tool::WAVELET: - return "wavelet"; - case Tool::DIR_PYR_EQUALIZER: - return "dirpyrdenoise"; - case Tool::HSV_EQUALIZER: - return "hsvequalizer"; - case Tool::FILM_SIMULATION: - return "filmsimulation"; - case Tool::SOFT_LIGHT: - return "softlight"; - case Tool::DEHAZE: - return "dehaze"; - case Tool::SENSOR_BAYER: - return "sensorbayer"; - case Tool::SENSOR_XTRANS: - return "sensorxtrans"; - case Tool::BAYER_PROCESS: - return "bayerprocess"; - case Tool::XTRANS_PROCESS: - return "xtransprocess"; - case Tool::BAYER_PREPROCESS: - return "bayerpreprocess"; - case Tool::PREPROCESS: - return "preprocess"; - case Tool::DARKFRAME_TOOL: - return "darkframe"; - case Tool::FLATFIELD_TOOL: - return "flatfield"; - case Tool::RAW_CA_CORRECTION: - return "rawcacorrection"; - case Tool::RAW_EXPOSURE: - return "rawexposure"; - case Tool::PREPROCESS_WB: - return "preprocesswb"; - case Tool::BAYER_RAW_EXPOSURE: - return "bayerrawexposure"; - case Tool::XTRANS_RAW_EXPOSURE: - return "xtransrawexposure"; - case Tool::FATTAL: - return "fattal"; - case Tool::FILM_NEGATIVE: - return "filmnegative"; - case Tool::PD_SHARPENING: - return "capturesharpening"; - }; - assert(false); - return ""; -}; - /** * Returns the language key for the panel's title. */ @@ -591,13 +465,6 @@ struct ToolLocationPreference::Impl { * @param row_path Path to the tool list model row. */ void favoriteToggled(const Glib::ustring &row_path); - /** - * Gets the tool with the provided tool name. - * - * @param name The tool name as a raw string. - * @return The tool. - */ - Tool getToolFromName(const std::string &name) const; /** * Initializes the favorites list. * @@ -719,36 +586,6 @@ void ToolLocationPreference::Impl::favoriteToggled(const Glib::ustring &row_path } } -Tool ToolLocationPreference::Impl::getToolFromName(const std::string &name) const -{ - if (toolNamesReverseMap.empty()) { - // Create the name to tool mapping. - - const auto panels = ToolPanelCoordinator::getDefaultToolLayout(); - std::vector unprocessed_tool_trees; - - // Get the root tools from each panel. - for (const auto &panel_tools : panels) { - for (const auto &tool : panel_tools.second) { - unprocessed_tool_trees.push_back(&tool); - } - } - - // Process all the tools, including their children. - while (unprocessed_tool_trees.size() > 0) { - const ToolPanelCoordinator::ToolTree *tool_tree = - unprocessed_tool_trees.back(); - unprocessed_tool_trees.pop_back(); - toolNamesReverseMap[getToolName(tool_tree->id)] = tool_tree->id; - for (const auto &child_tree : tool_tree->children) { - unprocessed_tool_trees.push_back(&child_tree); - } - } - } - - return toolNamesReverseMap.at(name); -} - void ToolLocationPreference::Impl::initFavoritesRows( const std::vector &favorites) { @@ -833,7 +670,7 @@ std::vector ToolLocationPreference::Impl::toolNamesToTools( for (auto &&tool_name : tool_names) { Tool tool; try { - tool = getToolFromName(tool_name); + tool = ToolPanelCoordinator::getToolFromName(tool_name); } catch (const std::exception &e) { if (rtengine::settings->verbose) { std::cerr << "Unrecognized tool name \"" << tool_name << "\"." << std::endl; @@ -853,7 +690,7 @@ void ToolLocationPreference::Impl::updateOptions() options.favorites.resize(favorites_rows.size()); for (unsigned i = 0; i < favorites_rows.size(); i++) { const Tool tool = favorites_rows[i].get_value(favoritesColumns.tool); - options.favorites[i] = getToolName(tool); + options.favorites[i] = ToolPanelCoordinator::getToolName(tool); } } diff --git a/rtgui/toolpanel.cc b/rtgui/toolpanel.cc index cfc53639b..bf191133d 100644 --- a/rtgui/toolpanel.cc +++ b/rtgui/toolpanel.cc @@ -73,7 +73,14 @@ FoldableToolPanel::FoldableToolPanel(Gtk::Box* content, Glib::ustring toolName, exp->signal_button_release_event().connect_notify( sigc::mem_fun(this, &FoldableToolPanel::foldThemAll) ); enaConn = signal_enabled_toggled().connect( sigc::mem_fun(*this, &FoldableToolPanel::enabled_toggled) ); - exp->add (*content); + Gtk::Box *expanderContents = Gtk::manage( + new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + subToolsContainer = Gtk::manage( + new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + expanderContents->pack_start(*content, false, false, 0); + expanderContents->pack_start(*subToolsContainer, false, false, 0); + + exp->add(*expanderContents, false); exp->show (); } diff --git a/rtgui/toolpanel.h b/rtgui/toolpanel.h index 8fdb4540d..ce14dc64f 100644 --- a/rtgui/toolpanel.h +++ b/rtgui/toolpanel.h @@ -98,6 +98,10 @@ public: { return nullptr; } + virtual Gtk::Box *getSubToolsContainer() const + { + return nullptr; + } virtual void setExpanded (bool expanded) {} virtual bool getExpanded () { @@ -164,6 +168,7 @@ class FoldableToolPanel : protected: Gtk::Box* parentContainer; MyExpander* exp; + Gtk::Box *subToolsContainer; bool lastEnabled; sigc::connection enaConn; void foldThemAll (GdkEventButton* event); @@ -177,6 +182,12 @@ public: { return exp; } + + Gtk::Box *getSubToolsContainer() const final + { + return subToolsContainer; + } + void setExpanded (bool expanded) final { if (exp) { diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index fa2203958..1b81fb014 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -267,6 +267,8 @@ const ToolPanelCoordinator::ToolLayout PANEL_TOOLS = { }, }; +std::unordered_map ToolPanelCoordinator::toolNamesReverseMap; + ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favoritePanelSW(nullptr), hasChanged (false), editDataProvider (nullptr), photoLoadedOnce(false) { @@ -345,71 +347,33 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit // Valeurs par dfaut: // Best -> low ISO // Medium -> High ISO - favorites.resize(options.favorites.size(), nullptr); - addfavoritePanel (colorPanel, whitebalance); - addfavoritePanel (exposurePanel, toneCurve); - addfavoritePanel (colorPanel, vibrance); - addfavoritePanel (colorPanel, chmixer); - addfavoritePanel (colorPanel, blackwhite); - addfavoritePanel (exposurePanel, shadowshighlights); - addfavoritePanel (detailsPanel, spot); - addfavoritePanel (detailsPanel, sharpening); - addfavoritePanel (detailsPanel, localContrast); - addfavoritePanel (detailsPanel, sharpenEdge); - addfavoritePanel (detailsPanel, sharpenMicro); - addfavoritePanel (colorPanel, hsvequalizer); - addfavoritePanel (colorPanel, filmSimulation); - addfavoritePanel (colorPanel, filmNegative); - addfavoritePanel (colorPanel, softlight); - addfavoritePanel (colorPanel, rgbcurves); - addfavoritePanel (colorPanel, colortoning); - addfavoritePanel (exposurePanel, epd); - addfavoritePanel (exposurePanel, fattal); - addfavoritePanel (advancedPanel, retinex); - addfavoritePanel (exposurePanel, pcvignette); - addfavoritePanel (exposurePanel, gradient); - addfavoritePanel (exposurePanel, lcurve); - addfavoritePanel (advancedPanel, colorappearance); - addfavoritePanel (detailsPanel, impulsedenoise); - addfavoritePanel (detailsPanel, dirpyrdenoise); - addfavoritePanel (detailsPanel, defringe); - addfavoritePanel (detailsPanel, dirpyrequalizer); - addfavoritePanel (detailsPanel, dehaze); - addfavoritePanel (advancedPanel, wavelet); - addfavoritePanel(locallabPanel, locallab); + for (const auto &panel_tool_layout : getDefaultToolLayout()) { + const auto &panel_tools = panel_tool_layout.second; + std::vector unprocessed_tools; - addfavoritePanel (transformPanel, crop); - addfavoritePanel (transformPanel, resize); - addPanel (resize->getPackBox(), prsharpening, 2); - addfavoritePanel (transformPanel, lensgeom); - addfavoritePanel (lensgeom->getPackBox(), rotate, 2); - addfavoritePanel (lensgeom->getPackBox(), perspective, 2); - addfavoritePanel (lensgeom->getPackBox(), lensProf, 2); - addfavoritePanel (lensgeom->getPackBox(), distortion, 2); - addfavoritePanel (lensgeom->getPackBox(), cacorrection, 2); - addfavoritePanel (lensgeom->getPackBox(), vignetting, 2); - addfavoritePanel (colorPanel, icm); - addfavoritePanel (rawPanel, sensorbayer); - addfavoritePanel (sensorbayer->getPackBox(), bayerprocess, 2); - addfavoritePanel (sensorbayer->getPackBox(), bayerrawexposure, 2); - addfavoritePanel (sensorbayer->getPackBox(), bayerpreprocess, 2); - addfavoritePanel (sensorbayer->getPackBox(), rawcacorrection, 2); - addfavoritePanel (rawPanel, sensorxtrans); - addfavoritePanel (sensorxtrans->getPackBox(), xtransprocess, 2); - addfavoritePanel (sensorxtrans->getPackBox(), xtransrawexposure, 2); - addfavoritePanel (rawPanel, rawexposure); - addfavoritePanel (rawPanel, preprocessWB); - addfavoritePanel (rawPanel, preprocess); - addfavoritePanel (rawPanel, darkframe); - addfavoritePanel (rawPanel, flatfield); - addfavoritePanel (rawPanel, pdSharpening); + // Start with the root tools for every panel. + for (const auto &tool_tree : panel_tools) { + unprocessed_tools.push_back(&tool_tree); + } - int favoriteCount = 0; - for(auto it = favorites.begin(); it != favorites.end(); ++it) { - if (*it) { - addPanel(favoritePanel, *it); - ++favoriteCount; + // Process each tool. + while (!unprocessed_tools.empty()) { + // Pop from stack of unprocessed. + const ToolTree *cur_tool = unprocessed_tools.back(); + unprocessed_tools.pop_back(); + // Add tool to list of expanders and tool panels. + FoldableToolPanel *tool_panel = getFoldableToolPanel(*cur_tool); + expList.push_back(tool_panel->getExpander()); + toolPanels.push_back(tool_panel); + expanderToToolPanelMap[tool_panel->getExpander()] = tool_panel; + toolToDefaultToolTreeMap[cur_tool->id] = cur_tool; + // Show all now, since they won't be attached to a parent. + tool_panel->getExpander()->show_all(); + // Add children to unprocessed. + for (const auto &child_tool : cur_tool->children) { + unprocessed_tools.push_back(&child_tool); + } } } @@ -418,6 +382,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit toolPanelNotebook = new Gtk::Notebook(); toolPanelNotebook->set_name("ToolPanelNotebook"); + favoritePanelSW.reset(new MyScrolledWindow()); exposurePanelSW = Gtk::manage (new MyScrolledWindow ()); detailsPanelSW = Gtk::manage (new MyScrolledWindow ()); colorPanelSW = Gtk::manage (new MyScrolledWindow ()); @@ -434,35 +399,58 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit vbPanelEnd[i]->pack_start(*imgPanelEnd[i], Gtk::PACK_SHRINK); vbPanelEnd[i]->show_all(); } - if(favoriteCount > 0) { - favoritePanelSW = Gtk::manage(new MyScrolledWindow()); - favoritePanelSW->add(*favoritePanel); - favoritePanel->pack_start(*vbPanelEnd[0], Gtk::PACK_SHRINK, 4); - } updateVScrollbars(options.hideTPVScrollbar); - exposurePanelSW->add (*exposurePanel); - exposurePanel->pack_start (*vbPanelEnd[1], Gtk::PACK_SHRINK, 4); + Gtk::Box *favoritePanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *exposurePanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *detailsPanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *colorPanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *advancedPanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *locallabPanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *transformPanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + Gtk::Box *rawPanelContainer = + Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); - detailsPanelSW->add (*detailsPanel); - detailsPanel->pack_start (*vbPanelEnd[2], Gtk::PACK_SHRINK, 4); + favoritePanelSW->add(*favoritePanelContainer); + favoritePanelContainer->pack_start(*favoritePanel, Gtk::PACK_SHRINK, 0); + favoritePanelContainer->pack_start(*vbPanelEnd[0], Gtk::PACK_SHRINK, 4); - colorPanelSW->add (*colorPanel); - colorPanel->pack_start (*vbPanelEnd[3], Gtk::PACK_SHRINK, 4); + exposurePanelSW->add (*exposurePanelContainer); + exposurePanelContainer->pack_start(*exposurePanel, Gtk::PACK_SHRINK, 0); + exposurePanelContainer->pack_start (*vbPanelEnd[1], Gtk::PACK_SHRINK, 4); - advancedPanelSW->add (*advancedPanel); - advancedPanel->pack_start (*vbPanelEnd[6], Gtk::PACK_SHRINK, 0); + detailsPanelSW->add (*detailsPanelContainer); + detailsPanelContainer->pack_start(*detailsPanel, Gtk::PACK_SHRINK, 0); + detailsPanelContainer->pack_start (*vbPanelEnd[2], Gtk::PACK_SHRINK, 4); - locallabPanelSW->add(*locallabPanel); - locallabPanel->pack_start(*vbPanelEnd[7], Gtk::PACK_SHRINK, 4); + colorPanelSW->add (*colorPanelContainer); + colorPanelContainer->pack_start(*colorPanel, Gtk::PACK_SHRINK, 0); + colorPanelContainer->pack_start (*vbPanelEnd[3], Gtk::PACK_SHRINK, 4); - transformPanelSW->add (*transformPanel); - transformPanel->pack_start (*vbPanelEnd[4], Gtk::PACK_SHRINK, 4); + advancedPanelSW->add (*advancedPanelContainer); + advancedPanelContainer->pack_start(*advancedPanel, Gtk::PACK_SHRINK, 0); + advancedPanelContainer->pack_start (*vbPanelEnd[6], Gtk::PACK_SHRINK, 0); - rawPanelSW->add (*rawPanel); - rawPanel->pack_start (*vbPanelEnd[5], Gtk::PACK_SHRINK, 0); + locallabPanelSW->add(*locallabPanelContainer); + locallabPanelContainer->pack_start(*locallabPanel, Gtk::PACK_SHRINK, 0); + locallabPanelContainer->pack_start(*vbPanelEnd[7], Gtk::PACK_SHRINK, 4); - toiF = Gtk::manage (new TextOrIcon ("star.png", M ("MAIN_TAB_FAVORITES"), M ("MAIN_TAB_FAVORITES_TOOLTIP"))); + transformPanelSW->add (*transformPanelContainer); + transformPanelContainer->pack_start(*transformPanel, Gtk::PACK_SHRINK, 0); + transformPanelContainer->pack_start (*vbPanelEnd[4], Gtk::PACK_SHRINK, 4); + + rawPanelSW->add (*rawPanelContainer); + rawPanelContainer->pack_start(*rawPanel, Gtk::PACK_SHRINK, 0); + rawPanelContainer->pack_start (*vbPanelEnd[5], Gtk::PACK_SHRINK, 0); + + toiF.reset(new TextOrIcon ("star.png", M ("MAIN_TAB_FAVORITES"), M ("MAIN_TAB_FAVORITES_TOOLTIP"))); toiE = Gtk::manage (new TextOrIcon ("exposure.png", M ("MAIN_TAB_EXPOSURE"), M ("MAIN_TAB_EXPOSURE_TOOLTIP"))); toiD = Gtk::manage (new TextOrIcon ("detail.png", M ("MAIN_TAB_DETAIL"), M ("MAIN_TAB_DETAIL_TOOLTIP"))); toiC = Gtk::manage (new TextOrIcon ("color-circles.png", M ("MAIN_TAB_COLOR"), M ("MAIN_TAB_COLOR_TOOLTIP"))); @@ -472,9 +460,6 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit toiT = Gtk::manage (new TextOrIcon ("transform.png", M ("MAIN_TAB_TRANSFORM"), M ("MAIN_TAB_TRANSFORM_TOOLTIP"))); toiR = Gtk::manage (new TextOrIcon ("bayer.png", M ("MAIN_TAB_RAW"), M ("MAIN_TAB_RAW_TOOLTIP"))); toiM = Gtk::manage (new TextOrIcon ("metadata.png", M ("MAIN_TAB_METADATA"), M ("MAIN_TAB_METADATA_TOOLTIP"))); - if (favoritePanelSW) { - toolPanelNotebook->append_page (*favoritePanelSW, *toiF); - } toolPanelNotebook->append_page (*exposurePanelSW, *toiE); toolPanelNotebook->append_page (*detailsPanelSW, *toiD); toolPanelNotebook->append_page (*colorPanelSW, *toiC); @@ -491,6 +476,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit toolPanelNotebook->set_scrollable(); toolPanelNotebook->show_all(); + updateToolLocations(options.favorites); notebookconn = toolPanelNotebook->signal_switch_page().connect( sigc::mem_fun(*this, &ToolPanelCoordinator::notebookPageChanged)); @@ -528,6 +514,156 @@ const ToolPanelCoordinator::ToolLayout& ToolPanelCoordinator::getDefaultToolLayo return PANEL_TOOLS; } +Tool ToolPanelCoordinator::getToolFromName(const std::string &name) +{ + if (toolNamesReverseMap.empty()) { + // Create the name to tool mapping. + + const auto panels = ToolPanelCoordinator::getDefaultToolLayout(); + std::vector unprocessed_tool_trees; + + // Get the root tools from each panel. + for (const auto &panel_tools : panels) { + for (const auto &tool : panel_tools.second) { + unprocessed_tool_trees.push_back(&tool); + } + } + + // Process all the tools, including their children. + while (unprocessed_tool_trees.size() > 0) { + const ToolPanelCoordinator::ToolTree *tool_tree = + unprocessed_tool_trees.back(); + unprocessed_tool_trees.pop_back(); + toolNamesReverseMap[getToolName(tool_tree->id)] = tool_tree->id; + for (const auto &child_tree : tool_tree->children) { + unprocessed_tool_trees.push_back(&child_tree); + } + } + } + + return toolNamesReverseMap.at(name); +} + +std::string ToolPanelCoordinator::getToolName(Tool tool) +{ + switch (tool) { + case Tool::TONE_CURVE: + return "tonecurve"; + case Tool::SHADOWS_HIGHLIGHTS: + return "shadowshighlights"; + case Tool::IMPULSE_DENOISE: + return "impulsedenoise"; + case Tool::DEFRINGE_TOOL: + return "defringe"; + case Tool::SPOT: + return "spot"; + case Tool::DIR_PYR_DENOISE: + return "dirpyrdenoise"; + case Tool::EPD: + return "epd"; + case Tool::SHARPENING_TOOL: + return "sharpening"; + case Tool::LOCAL_CONTRAST: + return "localcontrast"; + case Tool::SHARPEN_EDGE: + return "sharpenedge"; + case Tool::SHARPEN_MICRO: + return "sharpenmicro"; + case Tool::L_CURVE: + return "labcurves"; + case Tool::RGB_CURVES: + return "rgbcurves"; + case Tool::COLOR_TONING: + return "colortoning"; + case Tool::LENS_GEOM: + return "lensgeom"; + case Tool::LENS_PROF: + return "lensprof"; + case Tool::DISTORTION: + return "distortion"; + case Tool::ROTATE: + return "rotate"; + case Tool::VIBRANCE: + return "vibrance"; + case Tool::COLOR_APPEARANCE: + return "colorappearance"; + case Tool::WHITE_BALANCE: + return "whitebalance"; + case Tool::VIGNETTING: + return "vignetting"; + case Tool::RETINEX_TOOL: + return "retinex"; + case Tool::GRADIENT: + return "gradient"; + case Tool::LOCALLAB: + return "locallab"; + case Tool::PC_VIGNETTE: + return "pcvignette"; + case Tool::PERSPECTIVE: + return "perspective"; + case Tool::CA_CORRECTION: + return "cacorrection"; + case Tool::CH_MIXER: + return "chmixer"; + case Tool::BLACK_WHITE: + return "blackwhite"; + case Tool::RESIZE_TOOL: + return "resize"; + case Tool::PR_SHARPENING: + return "prsharpening"; + case Tool::CROP_TOOL: + return "crop"; + case Tool::ICM: + return "icm"; + case Tool::WAVELET: + return "wavelet"; + case Tool::DIR_PYR_EQUALIZER: + return "dirpyrdenoise"; + case Tool::HSV_EQUALIZER: + return "hsvequalizer"; + case Tool::FILM_SIMULATION: + return "filmsimulation"; + case Tool::SOFT_LIGHT: + return "softlight"; + case Tool::DEHAZE: + return "dehaze"; + case Tool::SENSOR_BAYER: + return "sensorbayer"; + case Tool::SENSOR_XTRANS: + return "sensorxtrans"; + case Tool::BAYER_PROCESS: + return "bayerprocess"; + case Tool::XTRANS_PROCESS: + return "xtransprocess"; + case Tool::BAYER_PREPROCESS: + return "bayerpreprocess"; + case Tool::PREPROCESS: + return "preprocess"; + case Tool::DARKFRAME_TOOL: + return "darkframe"; + case Tool::FLATFIELD_TOOL: + return "flatfield"; + case Tool::RAW_CA_CORRECTION: + return "rawcacorrection"; + case Tool::RAW_EXPOSURE: + return "rawexposure"; + case Tool::PREPROCESS_WB: + return "preprocesswb"; + case Tool::BAYER_RAW_EXPOSURE: + return "bayerrawexposure"; + case Tool::XTRANS_RAW_EXPOSURE: + return "xtransrawexposure"; + case Tool::FATTAL: + return "fattal"; + case Tool::FILM_NEGATIVE: + return "filmnegative"; + case Tool::PD_SHARPENING: + return "capturesharpening"; + }; + assert(false); + return ""; +}; + bool ToolPanelCoordinator::isFavoritable(Tool tool) { switch (tool) { @@ -540,6 +676,8 @@ bool ToolPanelCoordinator::isFavoritable(Tool tool) void ToolPanelCoordinator::notebookPageChanged(Gtk::Widget* page, guint page_num) { + updatePanelTools(page, options.favorites); + // Locallab spot curves are set visible if at least one photo has been loaded (to avoid // segfault) and locallab panel is active if (photoLoadedOnce) { @@ -557,26 +695,140 @@ void ToolPanelCoordinator::notebookPageChanged(Gtk::Widget* page, guint page_num } } +void ToolPanelCoordinator::updateFavoritesPanel( + const std::vector &favoritesNames) +{ + std::unordered_set favorites_set; + std::vector> favorites_tool_tree; + + for (const auto &tool_name : favoritesNames) { + Tool tool = getToolFromName(tool_name.raw()); + favorites_set.insert(tool); + favorites_tool_tree.push_back( + std::ref(*(toolToDefaultToolTreeMap.at(tool)))); + } + + updateToolPanel(favoritePanel, favorites_tool_tree, 1, favorites_set); +} + +void ToolPanelCoordinator::updatePanelTools( + Gtk::Widget *page, const std::vector &favorites) +{ + if (page == favoritePanelSW.get()) { + updateFavoritesPanel(favorites); + return; + } + + ToolVBox *panel = nullptr; + const std::vector *default_panel_tools = nullptr; + if (page == exposurePanelSW) { + panel = exposurePanel; + default_panel_tools = &EXPOSURE_PANEL_TOOLS; + } else if (page == detailsPanelSW) { + panel = detailsPanel; + default_panel_tools = &DETAILS_PANEL_TOOLS; + } else if (page == colorPanelSW) { + panel = colorPanel; + default_panel_tools = &COLOR_PANEL_TOOLS; + } else if (page == transformPanelSW) { + panel = transformPanel; + default_panel_tools = &TRANSFORM_PANEL_TOOLS; + } else if (page == rawPanelSW) { + panel = rawPanel; + default_panel_tools = &RAW_PANEL_TOOLS; + } else if (page == advancedPanelSW) { + panel = advancedPanel; + default_panel_tools = &ADVANCED_PANEL_TOOLS; + } else if (page == locallabPanelSW) { + panel = locallabPanel; + default_panel_tools = &LOCALLAB_PANEL_TOOLS; + } else { + return; + } + assert(panel && default_panel_tools); + + std::unordered_set favoriteTools; + for (const auto &tool_name : favorites) { + favoriteTools.insert(getToolFromName(tool_name.raw())); + } + + updateToolPanel(panel, *default_panel_tools, 1, favoriteTools); +} + +template +typename std::enable_if::value, void>::type +ToolPanelCoordinator::updateToolPanel( + Gtk::Box *panelBox, + const std::vector &children, + int level, + std::unordered_set favorites) +{ + const bool is_favorite_panel = panelBox == favoritePanel; + const std::vector old_tool_panels = panelBox->get_children(); + auto old_widgets_iter = old_tool_panels.begin(); + auto new_tool_trees_iter = children.begin(); + + // Indicates if this tool should not be added. Favorite tools are skipped + // unless the parent panel box is the favorites panel. + const auto should_skip_tool = + [is_favorite_panel, &favorites](const ToolTree &tool_tree) { + return !is_favorite_panel && favorites.count(tool_tree.id); + }; + + // Keep tools that are already correct. + while ( + old_widgets_iter != old_tool_panels.end() && + new_tool_trees_iter != children.end()) { + if (should_skip_tool(*new_tool_trees_iter)) { + ++new_tool_trees_iter; + continue; + } + if (*old_widgets_iter != + getFoldableToolPanel(*new_tool_trees_iter)->getExpander()) { + break; + } + ++old_widgets_iter; + } + + // Remove incorrect tools. + for (auto iter = old_tool_panels.end(); iter != old_widgets_iter;) { + --iter; + FoldableToolPanel *old_tool_panel = expanderToToolPanelMap.at(*iter); + assert(*iter == old_tool_panel->getExpander()); + panelBox->remove(**iter); + old_tool_panel->setParent(nullptr); + } + + // Add correct tools. + for (; new_tool_trees_iter != children.end(); new_tool_trees_iter++) { + if (should_skip_tool(*new_tool_trees_iter)) { + continue; + } + FoldableToolPanel *tool_panel = + getFoldableToolPanel(*new_tool_trees_iter); + if (tool_panel->getParent()) { + tool_panel->getParent()->remove(*tool_panel->getExpander()); + } + addPanel(panelBox, tool_panel, level); + } + + // Update the child tools. + for (const ToolTree &tool_tree : children) { + const FoldableToolPanel *tool_panel = getFoldableToolPanel(tool_tree); + updateToolPanel( + tool_panel->getSubToolsContainer(), + tool_tree.children, + level + 1, + favorites); + } +} + void ToolPanelCoordinator::addPanel(Gtk::Box* where, FoldableToolPanel* panel, int level) { panel->setParent(where); panel->setLevel(level); - - expList.push_back(panel->getExpander()); where->pack_start(*panel->getExpander(), false, false); - toolPanels.push_back(panel); -} -void ToolPanelCoordinator::addfavoritePanel (Gtk::Box* where, FoldableToolPanel* panel, int level) -{ - auto name = panel->getToolName(); - auto it = std::find(options.favorites.begin(), options.favorites.end(), name); - if (it != options.favorites.end()) { - int index = std::distance(options.favorites.begin(), it); - favorites[index] = panel; - } else { - addPanel(where, panel, level); - } } ToolPanelCoordinator::~ToolPanelCoordinator () @@ -1366,6 +1618,30 @@ void ToolPanelCoordinator::foldAllButOne(Gtk::Box* parent, FoldableToolPanel* op } } +void ToolPanelCoordinator::updateToolLocations(const std::vector &favorites) +{ + const int fav_page_num = toolPanelNotebook->page_num(*favoritePanelSW); + + // Add or remove favorites tab if necessary. + if (favorites.empty() && fav_page_num != -1) { + toolPanelNotebook->remove_page(fav_page_num); + } else if (!favorites.empty() && fav_page_num == -1) { + toolPanelNotebook->prepend_page(*favoritePanelSW, *toiF); + } + + // Update favorite tool panels list. + favoritesToolPanels.clear(); + for (const auto &favorite_name : favorites) { + favoritesToolPanels.push_back( + getFoldableToolPanel(getToolFromName(favorite_name))); + } + + int cur_page_num = toolPanelNotebook->get_current_page(); + Gtk::Widget *const cur_page = toolPanelNotebook->get_nth_page(cur_page_num); + + updatePanelTools(cur_page, favorites); +} + bool ToolPanelCoordinator::handleShortcutKey(GdkEventKey* event) { @@ -1376,7 +1652,7 @@ bool ToolPanelCoordinator::handleShortcutKey(GdkEventKey* event) if (alt) { switch (event->keyval) { case GDK_KEY_u: - if (favoritePanelSW) { + if (toolPanelNotebook->page_num(*favoritePanelSW) >= 0) { toolPanelNotebook->set_current_page (toolPanelNotebook->page_num (*favoritePanelSW)); } return true; @@ -1422,9 +1698,7 @@ void ToolPanelCoordinator::updateVScrollbars(bool hide) { GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected Gtk::PolicyType policy = hide ? Gtk::POLICY_NEVER : Gtk::POLICY_AUTOMATIC; - if (favoritePanelSW) { - favoritePanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy); - } + favoritePanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy); exposurePanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy); detailsPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy); colorPanelSW->set_policy (Gtk::POLICY_AUTOMATIC, policy); @@ -1456,7 +1730,7 @@ void ToolPanelCoordinator::toolSelected(ToolMode tool) notebookconn.block(true); // "signal_switch_page" event is blocked to avoid unsubscribing Locallab (allows a correct behavior when switching to another tool using toolbar) auto checkFavorite = [this](FoldableToolPanel* tool) { - for (auto fav : favorites) { + for (auto fav : favoritesToolPanels) { if (fav == tool) { return true; } @@ -1512,6 +1786,8 @@ void ToolPanelCoordinator::toolSelected(ToolMode tool) break; } + updateToolLocations(options.favorites); + notebookconn.block(false); } @@ -1541,3 +1817,127 @@ bool ToolPanelCoordinator::getFilmNegativeSpot(rtengine::Coord spot, int spotSiz { return ipc && ipc->getFilmNegativeSpot(spot.x, spot.y, spotSize, refInput, refOutput); } + +FoldableToolPanel *ToolPanelCoordinator::getFoldableToolPanel(Tool tool) const +{ + switch (tool) { + case Tool::TONE_CURVE: + return toneCurve; + case Tool::SHADOWS_HIGHLIGHTS: + return shadowshighlights; + case Tool::IMPULSE_DENOISE: + return impulsedenoise; + case Tool::DEFRINGE_TOOL: + return defringe; + case Tool::SPOT: + return spot; + case Tool::DIR_PYR_DENOISE: + return dirpyrdenoise; + case Tool::EPD: + return epd; + case Tool::SHARPENING_TOOL: + return sharpening; + case Tool::LOCAL_CONTRAST: + return localContrast; + case Tool::SHARPEN_EDGE: + return sharpenEdge; + case Tool::SHARPEN_MICRO: + return sharpenMicro; + case Tool::L_CURVE: + return lcurve; + case Tool::RGB_CURVES: + return rgbcurves; + case Tool::COLOR_TONING: + return colortoning; + case Tool::LENS_GEOM: + return lensgeom; + case Tool::LENS_PROF: + return lensProf; + case Tool::DISTORTION: + return distortion; + case Tool::ROTATE: + return rotate; + case Tool::VIBRANCE: + return vibrance; + case Tool::COLOR_APPEARANCE: + return colorappearance; + case Tool::WHITE_BALANCE: + return whitebalance; + case Tool::VIGNETTING: + return vignetting; + case Tool::RETINEX_TOOL: + return retinex; + case Tool::GRADIENT: + return gradient; + case Tool::LOCALLAB: + return locallab; + case Tool::PC_VIGNETTE: + return pcvignette; + case Tool::PERSPECTIVE: + return perspective; + case Tool::CA_CORRECTION: + return cacorrection; + case Tool::CH_MIXER: + return chmixer; + case Tool::BLACK_WHITE: + return blackwhite; + case Tool::RESIZE_TOOL: + return resize; + case Tool::PR_SHARPENING: + return prsharpening; + case Tool::CROP_TOOL: + return crop; + case Tool::ICM: + return icm; + case Tool::WAVELET: + return wavelet; + case Tool::DIR_PYR_EQUALIZER: + return dirpyrequalizer; + case Tool::HSV_EQUALIZER: + return hsvequalizer; + case Tool::FILM_SIMULATION: + return filmSimulation; + case Tool::SOFT_LIGHT: + return softlight; + case Tool::DEHAZE: + return dehaze; + case Tool::SENSOR_BAYER: + return sensorbayer; + case Tool::SENSOR_XTRANS: + return sensorxtrans; + case Tool::BAYER_PROCESS: + return bayerprocess; + case Tool::XTRANS_PROCESS: + return xtransprocess; + case Tool::BAYER_PREPROCESS: + return bayerpreprocess; + case Tool::PREPROCESS: + return preprocess; + case Tool::DARKFRAME_TOOL: + return darkframe; + case Tool::FLATFIELD_TOOL: + return flatfield; + case Tool::RAW_CA_CORRECTION: + return rawcacorrection; + case Tool::RAW_EXPOSURE: + return rawexposure; + case Tool::PREPROCESS_WB: + return preprocessWB; + case Tool::BAYER_RAW_EXPOSURE: + return bayerrawexposure; + case Tool::XTRANS_RAW_EXPOSURE: + return xtransrawexposure; + case Tool::FATTAL: + return fattal; + case Tool::FILM_NEGATIVE: + return filmNegative; + case Tool::PD_SHARPENING: + return pdSharpening; + }; + return nullptr; +} + +FoldableToolPanel *ToolPanelCoordinator::getFoldableToolPanel(const ToolTree &toolTree) const +{ + return getFoldableToolPanel(toolTree.id); +} diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 94e5a8717..3182d3e16 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -18,6 +18,7 @@ */ #pragma once +#include #include #include @@ -169,11 +170,13 @@ protected: FilmNegative* filmNegative; PdSharpening* pdSharpening; std::vector paramcListeners; + std::unordered_map + expanderToToolPanelMap; rtengine::StagedImageProcessor* ipc; std::vector toolPanels; - std::vector favorites; + std::vector favoritesToolPanels; ToolVBox* favoritePanel; ToolVBox* exposurePanel; ToolVBox* detailsPanel; @@ -184,7 +187,7 @@ protected: ToolVBox* locallabPanel; ToolBar* toolBar; - TextOrIcon* toiF; + std::unique_ptr toiF; TextOrIcon* toiE; TextOrIcon* toiD; TextOrIcon* toiC; @@ -197,7 +200,7 @@ protected: Gtk::Image* imgPanelEnd[8]; Gtk::Box* vbPanelEnd[8]; - Gtk::ScrolledWindow* favoritePanelSW; + std::unique_ptr favoritePanelSW; Gtk::ScrolledWindow* exposurePanelSW; Gtk::ScrolledWindow* detailsPanelSW; Gtk::ScrolledWindow* colorPanelSW; @@ -215,6 +218,8 @@ protected: void updateVScrollbars(bool hide); void addfavoritePanel (Gtk::Box* where, FoldableToolPanel* panel, int level = 1); void notebookPageChanged(Gtk::Widget* page, guint page_num); + void updatePanelTools( + Gtk::Widget *page, const std::vector &favorites); private: EditDataProvider *editDataProvider; @@ -307,6 +312,20 @@ public: ~ToolPanelCoordinator () override; static const ToolLayout& getDefaultToolLayout(); + /** + * Gets the tool with the provided tool name. + * + * @param name The tool name as a raw string. + * @return The tool. + */ + static Tool getToolFromName(const std::string &name); + /** + * Gets the tool name for the tool's ToolPanel as a string. + * + * @param tool The name as a raw string, or an empty string if the tool is + * unknown. + */ + static std::string getToolName(Tool tool); static bool isFavoritable(Tool tool); bool getChangedState() @@ -326,6 +345,7 @@ public: const LUTu& histLRETI ); void foldAllButOne(Gtk::Box* parent, FoldableToolPanel* openedSection); + void updateToolLocations(const std::vector &favorites); // multiple listeners can be added that are notified on changes (typical: profile panel and the history) void addPParamsChangeListener(PParamsChangeListener* pp) @@ -433,6 +453,23 @@ public: void setEditProvider(EditDataProvider *provider); +protected: + static std::unordered_map toolNamesReverseMap; + + std::unordered_map + toolToDefaultToolTreeMap; + + FoldableToolPanel *getFoldableToolPanel(Tool tool) const; + FoldableToolPanel *getFoldableToolPanel(const ToolTree &tool) const; + void updateFavoritesPanel(const std::vector &favorites); + template + typename std::enable_if::value, void>::type + updateToolPanel( + Gtk::Box *panelBox, + const std::vector &children, + int level, + std::unordered_set favorites); + private: IdleRegister idle_register; }; From acda4da22633983b9c72b1fdb046f3aecb87cdd8 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 5 Dec 2021 18:07:10 -0800 Subject: [PATCH 032/134] Fix favorites panel not being added Favorites panel would not show after adding tools to the favorites panel if the program started with no favorites. --- rtgui/toolpanelcoord.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 1b81fb014..985fb5461 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -421,6 +421,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit favoritePanelSW->add(*favoritePanelContainer); favoritePanelContainer->pack_start(*favoritePanel, Gtk::PACK_SHRINK, 0); favoritePanelContainer->pack_start(*vbPanelEnd[0], Gtk::PACK_SHRINK, 4); + favoritePanelSW->show_all(); exposurePanelSW->add (*exposurePanelContainer); exposurePanelContainer->pack_start(*exposurePanel, Gtk::PACK_SHRINK, 0); @@ -460,6 +461,10 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit toiT = Gtk::manage (new TextOrIcon ("transform.png", M ("MAIN_TAB_TRANSFORM"), M ("MAIN_TAB_TRANSFORM_TOOLTIP"))); toiR = Gtk::manage (new TextOrIcon ("bayer.png", M ("MAIN_TAB_RAW"), M ("MAIN_TAB_RAW_TOOLTIP"))); toiM = Gtk::manage (new TextOrIcon ("metadata.png", M ("MAIN_TAB_METADATA"), M ("MAIN_TAB_METADATA_TOOLTIP"))); + toiF->show_all(); + if (options.favorites.size()) { + toolPanelNotebook->append_page(*favoritePanelSW, *toiF); + } toolPanelNotebook->append_page (*exposurePanelSW, *toiE); toolPanelNotebook->append_page (*detailsPanelSW, *toiD); toolPanelNotebook->append_page (*colorPanelSW, *toiC); From f8a1deb371737971d61e494a23b5d37708517564 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Thu, 9 Dec 2021 21:27:39 -0800 Subject: [PATCH 033/134] Add option to clone favorite tools If cloning is enabled, favorite tools will appear in the favorites panel and in the original location. --- rtdata/languages/default | 1 + rtgui/editorpanel.cc | 4 ++-- rtgui/editorpanel.h | 3 ++- rtgui/options.cc | 6 ++++++ rtgui/options.h | 1 + rtgui/preferences.cc | 6 ++++-- rtgui/rtwindow.cc | 4 ++-- rtgui/rtwindow.h | 3 ++- rtgui/toollocationpref.cc | 16 ++++++++++++++++ rtgui/toolpanelcoord.cc | 39 ++++++++++++++++++++++++--------------- rtgui/toolpanelcoord.h | 13 +++++++++---- 11 files changed, 69 insertions(+), 27 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 525fa2d09..bd65781a8 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1901,6 +1901,7 @@ PREFERENCES_THUMBNAIL_INSPECTOR_MODE;Image to show PREFERENCES_THUMBNAIL_INSPECTOR_RAW;Neutral raw rendering PREFERENCES_THUMBNAIL_INSPECTOR_RAW_IF_NO_JPEG_FULLSIZE;Embedded JPEG if fullsize, neutral raw otherwise PREFERENCES_TOOLPANEL_AVAILABLETOOLS;Available Tools +PREFERENCES_TOOLPANEL_CLONE_FAVORITES;Keep favorite tools in original locations PREFERENCES_TOOLPANEL_FAVORITE;Favorite PREFERENCES_TOOLPANEL_FAVORITESPANEL;Favorites Panel PREFERENCES_TOOLPANEL_TOOL;Tool diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 888fc9518..64fa50a6a 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2487,10 +2487,10 @@ void EditorPanel::updateHistogramPosition (int oldPosition, int newPosition) } void EditorPanel::updateToolPanelToolLocations( - const std::vector &favorites) + const std::vector &favorites, bool cloneFavoriteTools) { if (tpc) { - tpc->updateToolLocations(favorites); + tpc->updateToolLocations(favorites, cloneFavoriteTools); } } diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index 0ffe44ace..bb0ecbc89 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -185,7 +185,8 @@ public: void updateProfiles (const Glib::ustring &printerProfile, rtengine::RenderingIntent printerIntent, bool printerBPC); void updateTPVScrollbar (bool hide); void updateHistogramPosition (int oldPosition, int newPosition); - void updateToolPanelToolLocations(const std::vector &favorites); + void updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools); void defaultMonitorProfileChanged (const Glib::ustring &profile_name, bool auto_monitor_profile); diff --git a/rtgui/options.cc b/rtgui/options.cc index 70b0fa010..b5463949a 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -424,6 +424,7 @@ void Options::setDefaults() //crvOpen.clear (); parseExtensions.clear(); favorites.clear(); + cloneFavoriteTools = true; parseExtensionsEnabled.clear(); parsedExtensions.clear(); parsedExtensionsSet.clear(); @@ -1220,6 +1221,10 @@ void Options::readFromFile(Glib::ustring fname) favorites = keyFile.get_string_list("GUI", "Favorites"); } + if (keyFile.has_key("GUI", "FavoritesCloneTools")) { + cloneFavoriteTools = keyFile.get_boolean("GUI", "FavoritesCloneTools"); + } + if (keyFile.has_key("GUI", "WindowWidth")) { windowWidth = keyFile.get_integer("GUI", "WindowWidth"); } @@ -2261,6 +2266,7 @@ void Options::saveToFile(Glib::ustring fname) Glib::ArrayHandle ahfavorites = favorites; keyFile.set_string_list("GUI", "Favorites", ahfavorites); + keyFile.set_boolean("GUI", "FavoritesCloneTools", cloneFavoriteTools); keyFile.set_integer("GUI", "WindowWidth", windowWidth); keyFile.set_integer("GUI", "WindowHeight", windowHeight); keyFile.set_integer("GUI", "WindowX", windowX); diff --git a/rtgui/options.h b/rtgui/options.h index bc5e41c91..6f21d1d76 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -428,6 +428,7 @@ public: bool fastexport_use_fast_pipeline; std::vector favorites; + bool cloneFavoriteTools; // Dialog settings Glib::ustring lastIccDir; Glib::ustring lastDarkframeDir; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index e67d16015..493f84f5a 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -2572,8 +2572,10 @@ void Preferences::workflowUpdate() parent->updateProfiles (moptions.rtSettings.printerProfile, rtengine::RenderingIntent(moptions.rtSettings.printerIntent), moptions.rtSettings.printerBPC); } - if (moptions.favorites != options.favorites) { - parent->updateToolPanelToolLocations(moptions.favorites); + if (moptions.cloneFavoriteTools != options.cloneFavoriteTools || + moptions.favorites != options.favorites) { + parent->updateToolPanelToolLocations( + moptions.favorites, moptions.cloneFavoriteTools); } } diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index 15715a2fd..f3eb658e5 100755 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -1111,10 +1111,10 @@ void RTWindow::updateHistogramPosition (int oldPosition, int newPosition) } void RTWindow::updateToolPanelToolLocations( - const std::vector &favorites) + const std::vector &favorites, bool cloneFavoriteTools) { if (epanel) { - epanel->updateToolPanelToolLocations(favorites); + epanel->updateToolPanelToolLocations(favorites, cloneFavoriteTools); } } diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h index d35755185..0ef5abb1f 100755 --- a/rtgui/rtwindow.h +++ b/rtgui/rtwindow.h @@ -124,7 +124,8 @@ public: void updateFBQueryTB (bool singleRow); void updateFBToolBarVisibility (bool showFilmStripToolBar); void updateShowtooltipVisibility (bool showtooltip); - void updateToolPanelToolLocations(const std::vector &favorites); + void updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools); bool getIsFullscreen() { return is_fullscreen; diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index 561be4601..849ff29b6 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -423,6 +423,9 @@ struct ToolLocationPreference::Impl { Options &options; + // General options. + Gtk::CheckButton *cloneFavoriteToolsToggleWidget; + // Tool list. ToolListColumns toolListColumns; Glib::RefPtr toolListModelPtr; @@ -506,6 +509,10 @@ std::unordered_map ToolLocationPreference::Impl::Impl(Options &options) : options(options), + // General options. + cloneFavoriteToolsToggleWidget(Gtk::manage( + new Gtk::CheckButton(M("PREFERENCES_TOOLPANEL_CLONE_FAVORITES")))), + // Tool list. toolListModelPtr(Gtk::TreeStore::create(toolListColumns)), toolListViewColumnFavorite( @@ -523,6 +530,9 @@ ToolLocationPreference::Impl::Impl(Options &options) : { const std::vector favorites = toolNamesToTools(options.favorites); + // General options. + cloneFavoriteToolsToggleWidget->set_active(options.cloneFavoriteTools); + // Tool list. toolListViewPtr->append_column(toolListViewColumnToolName); toolListViewColumnToolName.pack_start(toolListCellRendererToolName); @@ -686,6 +696,8 @@ std::vector ToolLocationPreference::Impl::toolNamesToTools( void ToolLocationPreference::Impl::updateOptions() { + options.cloneFavoriteTools = cloneFavoriteToolsToggleWidget->get_active(); + const auto favorites_rows = favoritesModelPtr->children(); options.favorites.resize(favorites_rows.size()); for (unsigned i = 0; i < favorites_rows.size(); i++) { @@ -729,6 +741,10 @@ ToolLocationPreference::ToolLocationPreference(Options &options) : favorites_list_scrolled_window->add(*impl->favoritesViewPtr); setExpandAlignProperties( favorites_frame, false, true, Gtk::ALIGN_START, Gtk::ALIGN_FILL); + + // General options. + layout_grid->attach_next_to( + *impl->cloneFavoriteToolsToggleWidget, Gtk::PositionType::POS_BOTTOM, 2, 1); } void ToolLocationPreference::updateOptions() diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 985fb5461..4991e68d8 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -481,7 +481,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit toolPanelNotebook->set_scrollable(); toolPanelNotebook->show_all(); - updateToolLocations(options.favorites); + updateToolLocations(options.favorites, options.cloneFavoriteTools); notebookconn = toolPanelNotebook->signal_switch_page().connect( sigc::mem_fun(*this, &ToolPanelCoordinator::notebookPageChanged)); @@ -681,7 +681,7 @@ bool ToolPanelCoordinator::isFavoritable(Tool tool) void ToolPanelCoordinator::notebookPageChanged(Gtk::Widget* page, guint page_num) { - updatePanelTools(page, options.favorites); + updatePanelTools(page, options.favorites, options.cloneFavoriteTools); // Locallab spot curves are set visible if at least one photo has been loaded (to avoid // segfault) and locallab panel is active @@ -701,7 +701,8 @@ void ToolPanelCoordinator::notebookPageChanged(Gtk::Widget* page, guint page_num } void ToolPanelCoordinator::updateFavoritesPanel( - const std::vector &favoritesNames) + const std::vector &favoritesNames, + bool cloneFavoriteTools) { std::unordered_set favorites_set; std::vector> favorites_tool_tree; @@ -713,14 +714,17 @@ void ToolPanelCoordinator::updateFavoritesPanel( std::ref(*(toolToDefaultToolTreeMap.at(tool)))); } - updateToolPanel(favoritePanel, favorites_tool_tree, 1, favorites_set); + updateToolPanel( + favoritePanel, favorites_tool_tree, 1, favorites_set, cloneFavoriteTools); } void ToolPanelCoordinator::updatePanelTools( - Gtk::Widget *page, const std::vector &favorites) + Gtk::Widget *page, + const std::vector &favorites, + bool cloneFavoriteTools) { if (page == favoritePanelSW.get()) { - updateFavoritesPanel(favorites); + updateFavoritesPanel(favorites, cloneFavoriteTools); return; } @@ -757,7 +761,7 @@ void ToolPanelCoordinator::updatePanelTools( favoriteTools.insert(getToolFromName(tool_name.raw())); } - updateToolPanel(panel, *default_panel_tools, 1, favoriteTools); + updateToolPanel(panel, *default_panel_tools, 1, favoriteTools, cloneFavoriteTools); } template @@ -766,18 +770,21 @@ ToolPanelCoordinator::updateToolPanel( Gtk::Box *panelBox, const std::vector &children, int level, - std::unordered_set favorites) + std::unordered_set favorites, + bool cloneFavoriteTools) { const bool is_favorite_panel = panelBox == favoritePanel; + const bool skip_favorites = !cloneFavoriteTools && !is_favorite_panel; const std::vector old_tool_panels = panelBox->get_children(); auto old_widgets_iter = old_tool_panels.begin(); auto new_tool_trees_iter = children.begin(); // Indicates if this tool should not be added. Favorite tools are skipped - // unless the parent panel box is the favorites panel. + // if they are sub-tools within the favorites panel, or if tool cloning is + // off and they are not within the favorites panel. const auto should_skip_tool = - [is_favorite_panel, &favorites](const ToolTree &tool_tree) { - return !is_favorite_panel && favorites.count(tool_tree.id); + [skip_favorites, &favorites](const ToolTree &tool_tree) { + return skip_favorites && favorites.count(tool_tree.id); }; // Keep tools that are already correct. @@ -824,7 +831,8 @@ ToolPanelCoordinator::updateToolPanel( tool_panel->getSubToolsContainer(), tool_tree.children, level + 1, - favorites); + favorites, + cloneFavoriteTools && !is_favorite_panel); } } @@ -1623,7 +1631,8 @@ void ToolPanelCoordinator::foldAllButOne(Gtk::Box* parent, FoldableToolPanel* op } } -void ToolPanelCoordinator::updateToolLocations(const std::vector &favorites) +void ToolPanelCoordinator::updateToolLocations( + const std::vector &favorites, bool cloneFavoriteTools) { const int fav_page_num = toolPanelNotebook->page_num(*favoritePanelSW); @@ -1644,7 +1653,7 @@ void ToolPanelCoordinator::updateToolLocations(const std::vector int cur_page_num = toolPanelNotebook->get_current_page(); Gtk::Widget *const cur_page = toolPanelNotebook->get_nth_page(cur_page_num); - updatePanelTools(cur_page, favorites); + updatePanelTools(cur_page, favorites, cloneFavoriteTools); } bool ToolPanelCoordinator::handleShortcutKey(GdkEventKey* event) @@ -1791,7 +1800,7 @@ void ToolPanelCoordinator::toolSelected(ToolMode tool) break; } - updateToolLocations(options.favorites); + updateToolLocations(options.favorites, options.cloneFavoriteTools); notebookconn.block(false); } diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 3182d3e16..8c0f6beaf 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -219,7 +219,9 @@ protected: void addfavoritePanel (Gtk::Box* where, FoldableToolPanel* panel, int level = 1); void notebookPageChanged(Gtk::Widget* page, guint page_num); void updatePanelTools( - Gtk::Widget *page, const std::vector &favorites); + Gtk::Widget *page, + const std::vector &favorites, + bool cloneFavoriteTools); private: EditDataProvider *editDataProvider; @@ -345,7 +347,8 @@ public: const LUTu& histLRETI ); void foldAllButOne(Gtk::Box* parent, FoldableToolPanel* openedSection); - void updateToolLocations(const std::vector &favorites); + void updateToolLocations( + const std::vector &favorites, bool cloneFavoriteTools); // multiple listeners can be added that are notified on changes (typical: profile panel and the history) void addPParamsChangeListener(PParamsChangeListener* pp) @@ -461,14 +464,16 @@ protected: FoldableToolPanel *getFoldableToolPanel(Tool tool) const; FoldableToolPanel *getFoldableToolPanel(const ToolTree &tool) const; - void updateFavoritesPanel(const std::vector &favorites); + void updateFavoritesPanel( + const std::vector &favorites, bool cloneFavoriteTools); template typename std::enable_if::value, void>::type updateToolPanel( Gtk::Box *panelBox, const std::vector &children, int level, - std::unordered_set favorites); + std::unordered_set favorites, + bool cloneFavoriteTools); private: IdleRegister idle_register; From 80944d6c9b83f242a0d7f113ab08e073d6a7e03f Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 10 Dec 2021 22:24:18 -0800 Subject: [PATCH 034/134] Change look of favorites preferences Set column widths based on DPI and font size in pseudo-HiDPI mode. Move favorites buttons to left side of list. --- rtgui/toollocationpref.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index 849ff29b6..d4021f03b 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -22,6 +22,7 @@ #include "guiutils.h" #include "options.h" #include "rtimage.h" +#include "rtscalable.h" #include "toollocationpref.h" #include "toolpanelcoord.h" @@ -720,7 +721,8 @@ ToolLocationPreference::ToolLocationPreference(Options &options) : M("PREFERENCES_TOOLPANEL_AVAILABLETOOLS"))); Gtk::ScrolledWindow *tool_list_scrolled_window = Gtk::manage(new Gtk::ScrolledWindow()); - tool_list_scrolled_window->set_min_content_width(550); + tool_list_scrolled_window->set_min_content_width( + 400 * (RTScalable::getTweakedDPI() / RTScalable::baseDPI)); layout_grid->attach_next_to(*tool_list_frame, Gtk::PositionType::POS_RIGHT, 1, 1); tool_list_frame->add(*tool_list_scrolled_window); tool_list_scrolled_window->add(*impl->toolListViewPtr); @@ -733,10 +735,11 @@ ToolLocationPreference::ToolLocationPreference(Options &options) : Gtk::Box *favorites_box = Gtk::manage(new Gtk::Box()); Gtk::ScrolledWindow *favorites_list_scrolled_window = Gtk::manage(new Gtk::ScrolledWindow()); - favorites_list_scrolled_window->set_min_content_width(400); + favorites_list_scrolled_window->set_min_content_width( + 300 * (RTScalable::getTweakedDPI() / RTScalable::baseDPI)); layout_grid->attach_next_to(*favorites_frame, Gtk::PositionType::POS_RIGHT, 1, 1); - favorites_box->pack_start(*favorites_list_scrolled_window, false, false); favorites_box->pack_start(impl->favoritesListEditButtons, false, false); + favorites_box->pack_start(*favorites_list_scrolled_window, false, false); favorites_frame->add(*favorites_box); favorites_list_scrolled_window->add(*impl->favoritesViewPtr); setExpandAlignProperties( From 546c99d276b3855c293d2d4638b91a2c500af3bb Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 11 Dec 2021 15:35:52 -0800 Subject: [PATCH 035/134] Clean up favorites preferences code --- rtgui/toollocationpref.cc | 54 +++++++++++++++++---------------- rtgui/toolpanelcoord.cc | 64 ++++++++++++++++++++++++++++++++------- rtgui/toolpanelcoord.h | 7 +++-- 3 files changed, 85 insertions(+), 40 deletions(-) diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index d4021f03b..f489c4f63 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -199,7 +199,7 @@ private: Gtk::Button buttonDown; Gtk::Button buttonRemove; - sigc::signal> signalRowsPreErase; + sigc::signal &> signalRowsPreErase; void onButtonDownPressed(); void onButtonRemovePressed(); @@ -224,7 +224,7 @@ public: * The signal contains a vector of tree model paths of the rows that will be * erased. */ - sigc::signal> getSignalRowsPreErase(); + sigc::signal &> getSignalRowsPreErase() const; }; /** @@ -319,7 +319,7 @@ void ListEditButtons::onButtonDownPressed() } // Get the selected row and next row. - auto selected_row_iter = listStore->get_iter(selected[0]); + const auto selected_row_iter = listStore->get_iter(selected[0]); auto next_row_iter = selected_row_iter; next_row_iter++; @@ -336,17 +336,21 @@ void ListEditButtons::onButtonRemovePressed() { const std::vector selected_paths = list.get_selection()->get_selected_rows(); - std::vector selected; + std::vector selected(selected_paths.size()); // Get row references, which are valid until the row is removed. - for (const auto & row_path : selected_paths) { - selected.push_back(Gtk::TreeModel::RowReference(listStore, row_path)); - } + std::transform( + selected_paths.begin(), + selected_paths.end(), + selected.begin(), + [this](const Gtk::TreeModel::Path &row_path) { + return Gtk::TreeModel::RowReference(listStore, row_path); + }); signalRowsPreErase.emit(selected_paths); // Remove the selected rows. - for (const auto & row_ref : selected) { + for (const auto &row_ref : selected) { const auto row_path = row_ref.get_path(); if (row_path) { listStore->erase(listStore->get_iter(row_path)); @@ -368,7 +372,7 @@ void ListEditButtons::onButtonUpPressed() return; } - auto selected_row_iter = listStore->get_iter(selected[0]); + const auto selected_row_iter = listStore->get_iter(selected[0]); if (selected_row_iter == list_children.begin()) { // Can't be first row. return; @@ -411,8 +415,8 @@ void ListEditButtons::updateButtonSensitivity() buttonRemove.set_sensitive(selected.size() > 0); } -sigc::signal> -ListEditButtons::getSignalRowsPreErase() +sigc::signal &> +ListEditButtons::getSignalRowsPreErase() const { return signalRowsPreErase; } @@ -420,8 +424,6 @@ ListEditButtons::getSignalRowsPreErase() } struct ToolLocationPreference::Impl { - static std::unordered_map toolNamesReverseMap; - Options &options; // General options. @@ -488,7 +490,7 @@ struct ToolLocationPreference::Impl { * @param paths Paths in the favorites list pointing to the rows that are * about to be removed. */ - void onFavoritesRowsPreRemove(const std::vector paths); + void onFavoritesRowsPreRemove(const std::vector &paths); /** * Converts tool names to their corresponding tools. * @@ -504,9 +506,6 @@ struct ToolLocationPreference::Impl { void updateOptions(); }; -std::unordered_map - ToolLocationPreference::Impl::toolNamesReverseMap; - ToolLocationPreference::Impl::Impl(Options &options) : options(options), @@ -577,7 +576,7 @@ void ToolLocationPreference::Impl::favoriteToggled(const Glib::ustring &row_path // Update the favorites list. if (is_favorite) { // Add to favorites list. - auto new_favorite_row_iter = favoritesModelPtr->append(); + const auto new_favorite_row_iter = favoritesModelPtr->append(); new_favorite_row_iter->set_value( favoritesColumns.toolName, M(getToolTitleKey(tool))); @@ -602,7 +601,7 @@ void ToolLocationPreference::Impl::initFavoritesRows( { // Add the favorites to the favorites list store. for (const auto tool : favorites) { - auto favorite_row_iter = favoritesModelPtr->append(); + const auto favorite_row_iter = favoritesModelPtr->append(); favorite_row_iter->set_value( favoritesColumns.toolName, M(getToolTitleKey(tool))); @@ -617,7 +616,8 @@ void ToolLocationPreference::Impl::addToolListRowGroup( { // Recursively add the tool and its children to the tool list tree store. for (const ToolPanelCoordinator::ToolTree &tool : tools) { - auto tool_row_iter = toolListModelPtr->append(parentRowIter->children()); + const auto tool_row_iter = + toolListModelPtr->append(parentRowIter->children()); tool_row_iter->set_value( toolListColumns.toolName, M(getToolTitleKey(tool.id))); @@ -653,7 +653,7 @@ void ToolLocationPreference::Impl::initToolListRows(const std::vector &fav ToolPanelCoordinator::Panel::TRANSFORM_PANEL, ToolPanelCoordinator::Panel::RAW, }) { - auto tool_group_iter = toolListModelPtr->append(); + const auto tool_group_iter = toolListModelPtr->append(); tool_group_iter->set_value( toolListColumns.toolName, M(getToolPanelTitleKey(panel))); @@ -662,7 +662,7 @@ void ToolLocationPreference::Impl::initToolListRows(const std::vector &fav } void ToolLocationPreference::Impl::onFavoritesRowsPreRemove( - const std::vector paths) + const std::vector &paths) { // Unset the favorite column in the tools list for tools about to be removed // from the favorites list. @@ -678,13 +678,15 @@ std::vector ToolLocationPreference::Impl::toolNamesToTools( { std::vector tool_set; - for (auto &&tool_name : tool_names) { + for (const auto &tool_name : tool_names) { Tool tool; try { tool = ToolPanelCoordinator::getToolFromName(tool_name); - } catch (const std::exception &e) { + } catch (const std::out_of_range &e) { if (rtengine::settings->verbose) { - std::cerr << "Unrecognized tool name \"" << tool_name << "\"." << std::endl; + std::cerr + << "Unrecognized tool name \"" << tool_name << "\"." + << std::endl; } assert(false); continue; @@ -701,7 +703,7 @@ void ToolLocationPreference::Impl::updateOptions() const auto favorites_rows = favoritesModelPtr->children(); options.favorites.resize(favorites_rows.size()); - for (unsigned i = 0; i < favorites_rows.size(); i++) { + for (Gtk::TreeNodeChildren::size_type i = 0; i < favorites_rows.size(); i++) { const Tool tool = favorites_rows[i].get_value(favoritesColumns.tool); options.favorites[i] = ToolPanelCoordinator::getToolName(tool); } diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 4991e68d8..f89c76b8d 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ +#include + #include "multilangmgr.h" #include "toolpanelcoord.h" #include "metadatapanel.h" @@ -350,12 +352,14 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit for (const auto &panel_tool_layout : getDefaultToolLayout()) { const auto &panel_tools = panel_tool_layout.second; - std::vector unprocessed_tools; + std::vector unprocessed_tools(panel_tools.size()); // Start with the root tools for every panel. - for (const auto &tool_tree : panel_tools) { - unprocessed_tools.push_back(&tool_tree); - } + std::transform( + panel_tools.begin(), + panel_tools.end(), + unprocessed_tools.begin(), + [](const ToolTree &tool_tree) { return &tool_tree; }); // Process each tool. while (!unprocessed_tools.empty()) { @@ -363,7 +367,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit const ToolTree *cur_tool = unprocessed_tools.back(); unprocessed_tools.pop_back(); // Add tool to list of expanders and tool panels. - FoldableToolPanel *tool_panel = getFoldableToolPanel(*cur_tool); + FoldableToolPanel *const tool_panel = getFoldableToolPanel(*cur_tool); expList.push_back(tool_panel->getExpander()); toolPanels.push_back(tool_panel); expanderToToolPanelMap[tool_panel->getExpander()] = tool_panel; @@ -514,7 +518,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit prevPage = toolPanelNotebook->get_nth_page(0); } -const ToolPanelCoordinator::ToolLayout& ToolPanelCoordinator::getDefaultToolLayout() +const ToolPanelCoordinator::ToolLayout &ToolPanelCoordinator::getDefaultToolLayout() { return PANEL_TOOLS; } @@ -708,10 +712,22 @@ void ToolPanelCoordinator::updateFavoritesPanel( std::vector> favorites_tool_tree; for (const auto &tool_name : favoritesNames) { - Tool tool = getToolFromName(tool_name.raw()); + Tool tool; + try { + tool = getToolFromName(tool_name.raw()); + } catch (const std::out_of_range &e) { + if (rtengine::settings->verbose) { + std::cerr + << "Unrecognized favorite tool \"" << tool_name << "\"" + << std::endl; + } + continue; + } + if (isFavoritable(tool)) { favorites_set.insert(tool); favorites_tool_tree.push_back( std::ref(*(toolToDefaultToolTreeMap.at(tool)))); + } } updateToolPanel( @@ -758,7 +774,20 @@ void ToolPanelCoordinator::updatePanelTools( std::unordered_set favoriteTools; for (const auto &tool_name : favorites) { - favoriteTools.insert(getToolFromName(tool_name.raw())); + Tool tool; + try { + tool = getToolFromName(tool_name.raw()); + } catch (const std::out_of_range &e) { + if (rtengine::settings->verbose) { + std::cerr + << "Unrecognized favorite tool \"" << tool_name << "\"" + << std::endl; + } + continue; + } + if (isFavoritable(tool)) { + favoriteTools.insert(tool); + } } updateToolPanel(panel, *default_panel_tools, 1, favoriteTools, cloneFavoriteTools); @@ -770,7 +799,7 @@ ToolPanelCoordinator::updateToolPanel( Gtk::Box *panelBox, const std::vector &children, int level, - std::unordered_set favorites, + const std::unordered_set &favorites, bool cloneFavoriteTools) { const bool is_favorite_panel = panelBox == favoritePanel; @@ -1646,8 +1675,20 @@ void ToolPanelCoordinator::updateToolLocations( // Update favorite tool panels list. favoritesToolPanels.clear(); for (const auto &favorite_name : favorites) { - favoritesToolPanels.push_back( - getFoldableToolPanel(getToolFromName(favorite_name))); + Tool tool; + try { + tool = getToolFromName(favorite_name.raw()); + } catch (const std::out_of_range &e) { + if (rtengine::settings->verbose) { + std::cerr + << "Unrecognized favorite tool \"" << favorite_name << "\"" + << std::endl; + } + continue; + } + if (isFavoritable(tool)) { + favoritesToolPanels.push_back(getFoldableToolPanel(tool)); + } } int cur_page_num = toolPanelNotebook->get_current_page(); @@ -1948,6 +1989,7 @@ FoldableToolPanel *ToolPanelCoordinator::getFoldableToolPanel(Tool tool) const case Tool::PD_SHARPENING: return pdSharpening; }; + assert(false); return nullptr; } diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 8c0f6beaf..cd354738e 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -305,7 +305,7 @@ public: std::vector children; }; - using ToolLayout = std::unordered_map, ScopedEnumHash>; + using ToolLayout = std::unordered_map &, ScopedEnumHash>; CoarsePanel* coarse; Gtk::Notebook* toolPanelNotebook; @@ -313,12 +313,13 @@ public: ToolPanelCoordinator(bool batch = false); ~ToolPanelCoordinator () override; - static const ToolLayout& getDefaultToolLayout(); + static const ToolLayout &getDefaultToolLayout(); /** * Gets the tool with the provided tool name. * * @param name The tool name as a raw string. * @return The tool. + * @throws std::out_of_range If the name is not recognized. */ static Tool getToolFromName(const std::string &name); /** @@ -472,7 +473,7 @@ protected: Gtk::Box *panelBox, const std::vector &children, int level, - std::unordered_set favorites, + const std::unordered_set &favorites, bool cloneFavoriteTools); private: From 40678f67b021de85db7c5d742fc7be2195912576 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 11 Dec 2021 21:21:54 -0800 Subject: [PATCH 036/134] Refactor tool name code --- rtgui/bayerpreprocess.cc | 4 +- rtgui/bayerpreprocess.h | 1 + rtgui/bayerprocess.cc | 3 +- rtgui/bayerprocess.h | 1 + rtgui/bayerrawexposure.cc | 4 +- rtgui/bayerrawexposure.h | 2 + rtgui/blackwhite.cc | 3 +- rtgui/blackwhite.h | 1 + rtgui/cacorrection.cc | 4 +- rtgui/cacorrection.h | 1 + rtgui/chmixer.cc | 4 +- rtgui/chmixer.h | 1 + rtgui/colorappearance.cc | 4 +- rtgui/colorappearance.h | 2 + rtgui/colortoning.cc | 3 +- rtgui/colortoning.h | 2 + rtgui/crop.cc | 4 +- rtgui/crop.h | 2 + rtgui/darkframe.cc | 4 +- rtgui/darkframe.h | 1 + rtgui/defringe.cc | 4 +- rtgui/defringe.h | 1 + rtgui/dehaze.cc | 4 +- rtgui/dehaze.h | 1 + rtgui/dirpyrdenoise.cc | 4 +- rtgui/dirpyrdenoise.h | 2 + rtgui/dirpyrequalizer.cc | 4 +- rtgui/dirpyrequalizer.h | 1 + rtgui/distortion.cc | 4 +- rtgui/distortion.h | 1 + rtgui/epd.cc | 4 +- rtgui/epd.h | 1 + rtgui/fattaltonemap.cc | 4 +- rtgui/fattaltonemap.h | 1 + rtgui/filmnegative.cc | 4 +- rtgui/filmnegative.h | 2 + rtgui/filmsimulation.cc | 4 +- rtgui/filmsimulation.h | 2 + rtgui/flatfield.cc | 4 +- rtgui/flatfield.h | 1 + rtgui/gradient.cc | 4 +- rtgui/gradient.h | 1 + rtgui/hsvequalizer.cc | 4 +- rtgui/hsvequalizer.h | 1 + rtgui/icmpanel.cc | 4 +- rtgui/icmpanel.h | 2 + rtgui/impulsedenoise.cc | 4 +- rtgui/impulsedenoise.h | 1 + rtgui/labcurve.cc | 4 +- rtgui/labcurve.h | 1 + rtgui/lensgeom.cc | 4 +- rtgui/lensgeom.h | 1 + rtgui/lensprofile.cc | 4 +- rtgui/lensprofile.h | 2 + rtgui/localcontrast.cc | 4 +- rtgui/localcontrast.h | 1 + rtgui/locallab.cc | 4 +- rtgui/locallab.h | 2 + rtgui/pcvignette.cc | 4 +- rtgui/pcvignette.h | 1 + rtgui/pdsharpening.cc | 4 +- rtgui/pdsharpening.h | 1 + rtgui/perspective.cc | 4 +- rtgui/perspective.h | 1 + rtgui/preprocess.cc | 4 +- rtgui/preprocess.h | 1 + rtgui/preprocesswb.cc | 4 +- rtgui/preprocesswb.h | 1 + rtgui/prsharpening.cc | 4 +- rtgui/prsharpening.h | 1 + rtgui/rawcacorrection.cc | 4 +- rtgui/rawcacorrection.h | 1 + rtgui/rawexposure.cc | 4 +- rtgui/rawexposure.h | 1 + rtgui/resize.cc | 4 +- rtgui/resize.h | 2 + rtgui/retinex.cc | 4 +- rtgui/retinex.h | 2 + rtgui/rgbcurves.cc | 4 +- rtgui/rgbcurves.h | 1 + rtgui/rotate.cc | 4 +- rtgui/rotate.h | 1 + rtgui/sensorbayer.cc | 4 +- rtgui/sensorbayer.h | 1 + rtgui/sensorxtrans.cc | 4 +- rtgui/sensorxtrans.h | 1 + rtgui/shadowshighlights.cc | 4 +- rtgui/shadowshighlights.h | 1 + rtgui/sharpenedge.cc | 3 +- rtgui/sharpenedge.h | 1 + rtgui/sharpening.cc | 4 +- rtgui/sharpening.h | 1 + rtgui/sharpenmicro.cc | 3 +- rtgui/sharpenmicro.h | 1 + rtgui/softlight.cc | 4 +- rtgui/softlight.h | 1 + rtgui/spot.cc | 4 +- rtgui/spot.h | 1 + rtgui/tonecurve.cc | 4 +- rtgui/tonecurve.h | 2 + rtgui/toollocationpref.cc | 2 +- rtgui/toolpanelcoord.cc | 112 ++++++++++++++++++------------------- rtgui/vibrance.cc | 4 +- rtgui/vibrance.h | 1 + rtgui/vignetting.cc | 4 +- rtgui/vignetting.h | 1 + rtgui/wavelet.cc | 4 +- rtgui/wavelet.h | 2 + rtgui/whitebalance.cc | 4 +- rtgui/whitebalance.h | 1 + rtgui/xtransprocess.cc | 4 +- rtgui/xtransprocess.h | 1 + rtgui/xtransrawexposure.cc | 4 +- rtgui/xtransrawexposure.h | 1 + 114 files changed, 290 insertions(+), 113 deletions(-) diff --git a/rtgui/bayerpreprocess.cc b/rtgui/bayerpreprocess.cc index 793496b5f..e8b965736 100644 --- a/rtgui/bayerpreprocess.cc +++ b/rtgui/bayerpreprocess.cc @@ -28,7 +28,9 @@ using namespace rtengine; using namespace rtengine::procparams; -BayerPreProcess::BayerPreProcess() : FoldableToolPanel(this, "bayerpreprocess", M("TP_PREPROCESS_LABEL"), options.prevdemo != PD_Sidecar) +const Glib::ustring BayerPreProcess::TOOL_NAME = "bayerpreprocess"; + +BayerPreProcess::BayerPreProcess() : FoldableToolPanel(this, TOOL_NAME, M("TP_PREPROCESS_LABEL"), options.prevdemo != PD_Sidecar) { auto m = ProcEventMapper::getInstance(); EvLineDenoiseDirection = m->newEvent(DARKFRAME, "HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION"); diff --git a/rtgui/bayerpreprocess.h b/rtgui/bayerpreprocess.h index 16b469626..8b5f8d981 100644 --- a/rtgui/bayerpreprocess.h +++ b/rtgui/bayerpreprocess.h @@ -37,6 +37,7 @@ protected: rtengine::ProcEvent EvPDAFLinesFilter; public: + static const Glib::ustring TOOL_NAME; BayerPreProcess (); diff --git a/rtgui/bayerprocess.cc b/rtgui/bayerprocess.cc index 4d1657a47..e7e038e52 100644 --- a/rtgui/bayerprocess.cc +++ b/rtgui/bayerprocess.cc @@ -28,9 +28,10 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring BayerProcess::TOOL_NAME = "bayerprocess"; BayerProcess::BayerProcess () : - FoldableToolPanel(this, "bayerprocess", M("TP_RAW_LABEL"), options.prevdemo != PD_Sidecar), + FoldableToolPanel(this, TOOL_NAME, M("TP_RAW_LABEL"), options.prevdemo != PD_Sidecar), oldMethod(-1) { diff --git a/rtgui/bayerprocess.h b/rtgui/bayerprocess.h index b9c63e9b2..00a5c8aac 100644 --- a/rtgui/bayerprocess.h +++ b/rtgui/bayerprocess.h @@ -76,6 +76,7 @@ protected: rtengine::ProcEvent EvDemosaicPixelshiftDemosaicMethod; rtengine::ProcEvent EvPixelshiftAverage; public: + static const Glib::ustring TOOL_NAME; BayerProcess (); ~BayerProcess () override; diff --git a/rtgui/bayerrawexposure.cc b/rtgui/bayerrawexposure.cc index 157abc2cf..834384a91 100644 --- a/rtgui/bayerrawexposure.cc +++ b/rtgui/bayerrawexposure.cc @@ -26,7 +26,9 @@ using namespace rtengine; using namespace rtengine::procparams; -BayerRAWExposure::BayerRAWExposure () : FoldableToolPanel(this, "bayerrawexposure", M("TP_EXPOS_BLACKPOINT_LABEL"), options.prevdemo != PD_Sidecar) +const Glib::ustring BayerRAWExposure::TOOL_NAME = "bayerrawexposure"; + +BayerRAWExposure::BayerRAWExposure () : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOS_BLACKPOINT_LABEL"), options.prevdemo != PD_Sidecar) { PexBlack1 = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_1"), -2048, 2048, 1.0, 0)); //black level PexBlack1->setAdjusterListener (this); diff --git a/rtgui/bayerrawexposure.h b/rtgui/bayerrawexposure.h index eb18aa0e3..53c5817f8 100644 --- a/rtgui/bayerrawexposure.h +++ b/rtgui/bayerrawexposure.h @@ -31,6 +31,8 @@ class BayerRAWExposure final : public FoldableToolPanel { public: + static const Glib::ustring TOOL_NAME; + BayerRAWExposure (); void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; diff --git a/rtgui/blackwhite.cc b/rtgui/blackwhite.cc index e713f1450..c92e68896 100644 --- a/rtgui/blackwhite.cc +++ b/rtgui/blackwhite.cc @@ -34,8 +34,9 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring BlackWhite::TOOL_NAME = "blackwhite"; -BlackWhite::BlackWhite (): FoldableToolPanel(this, "blackwhite", M("TP_BWMIX_LABEL"), false, true) +BlackWhite::BlackWhite (): FoldableToolPanel(this, TOOL_NAME, M("TP_BWMIX_LABEL"), false, true) { CurveListener::setMulti(true); diff --git a/rtgui/blackwhite.h b/rtgui/blackwhite.h index 505d842db..fe41ccda0 100644 --- a/rtgui/blackwhite.h +++ b/rtgui/blackwhite.h @@ -40,6 +40,7 @@ class BlackWhite final : public ColorProvider { public: + static const Glib::ustring TOOL_NAME; BlackWhite (); ~BlackWhite () override; diff --git a/rtgui/cacorrection.cc b/rtgui/cacorrection.cc index 971c0a284..52ed782df 100644 --- a/rtgui/cacorrection.cc +++ b/rtgui/cacorrection.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -CACorrection::CACorrection () : FoldableToolPanel(this, "cacorrection", M("TP_CACORRECTION_LABEL")) +const Glib::ustring CACorrection::TOOL_NAME = "cacorrection"; + +CACorrection::CACorrection () : FoldableToolPanel(this, TOOL_NAME, M("TP_CACORRECTION_LABEL")) { Gtk::Image* icaredL = Gtk::manage (new RTImage ("circle-red-cyan-small.png")); diff --git a/rtgui/cacorrection.h b/rtgui/cacorrection.h index 12d6396eb..7afccb4de 100644 --- a/rtgui/cacorrection.h +++ b/rtgui/cacorrection.h @@ -34,6 +34,7 @@ protected: Adjuster* blue; public: + static const Glib::ustring TOOL_NAME; CACorrection (); diff --git a/rtgui/chmixer.cc b/rtgui/chmixer.cc index 619d7be3e..e54ddfc5d 100644 --- a/rtgui/chmixer.cc +++ b/rtgui/chmixer.cc @@ -25,7 +25,9 @@ using namespace rtengine; using namespace rtengine::procparams; -ChMixer::ChMixer (): FoldableToolPanel(this, "chmixer", M("TP_CHMIXER_LABEL"), false, true) +const Glib::ustring ChMixer::TOOL_NAME = "chmixer"; + +ChMixer::ChMixer (): FoldableToolPanel(this, TOOL_NAME, M("TP_CHMIXER_LABEL"), false, true) { imgIcon[0] = Gtk::manage (new RTImage ("circle-red-small.png")); diff --git a/rtgui/chmixer.h b/rtgui/chmixer.h index d80b89cf7..831449c30 100644 --- a/rtgui/chmixer.h +++ b/rtgui/chmixer.h @@ -36,6 +36,7 @@ protected: Gtk::Image *imgIcon[9]; public: + static const Glib::ustring TOOL_NAME; ChMixer (); diff --git a/rtgui/colorappearance.cc b/rtgui/colorappearance.cc index f579da6e6..6a3346f18 100644 --- a/rtgui/colorappearance.cc +++ b/rtgui/colorappearance.cc @@ -44,6 +44,8 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring ColorAppearance::TOOL_NAME = "colorappearance"; + static double wbSlider2Temp (double sval) { @@ -212,7 +214,7 @@ static double wbTemp2Slider (double temp) } -ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance", M ("TP_COLORAPP_LABEL"), false, true) +ColorAppearance::ColorAppearance () : FoldableToolPanel (this, TOOL_NAME, M ("TP_COLORAPP_LABEL"), false, true) { CurveListener::setMulti (true); std::vector milestones; diff --git a/rtgui/colorappearance.h b/rtgui/colorappearance.h index ce1971e85..caa481c34 100644 --- a/rtgui/colorappearance.h +++ b/rtgui/colorappearance.h @@ -39,6 +39,8 @@ class ColorAppearance final : public ColorProvider { public: + static const Glib::ustring TOOL_NAME; + ColorAppearance (); ~ColorAppearance () override; diff --git a/rtgui/colortoning.cc b/rtgui/colortoning.cc index 0140c5b62..5e97084c9 100644 --- a/rtgui/colortoning.cc +++ b/rtgui/colortoning.cc @@ -14,6 +14,7 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring ColorToning::TOOL_NAME = "colortoning"; namespace { @@ -33,7 +34,7 @@ inline float round_ab(float v) } // namespace -ColorToning::ColorToning () : FoldableToolPanel(this, "colortoning", M("TP_COLORTONING_LABEL"), false, true) +ColorToning::ColorToning () : FoldableToolPanel(this, TOOL_NAME, M("TP_COLORTONING_LABEL"), false, true) { nextbw = 0; CurveListener::setMulti(true); diff --git a/rtgui/colortoning.h b/rtgui/colortoning.h index be3a83c2d..e763a069c 100644 --- a/rtgui/colortoning.h +++ b/rtgui/colortoning.h @@ -30,6 +30,8 @@ class ColorToning final : public AdjusterListener { public: + static const Glib::ustring TOOL_NAME; + ColorToning (); ~ColorToning() override; void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; diff --git a/rtgui/crop.cc b/rtgui/crop.cc index 853cec255..21a32b653 100644 --- a/rtgui/crop.cc +++ b/rtgui/crop.cc @@ -29,6 +29,8 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring Crop::TOOL_NAME = "crop"; + namespace { @@ -124,7 +126,7 @@ private: }; Crop::Crop(): - FoldableToolPanel(this, "crop", M("TP_CROP_LABEL"), false, true), + FoldableToolPanel(this, TOOL_NAME, M("TP_CROP_LABEL"), false, true), crop_ratios(new CropRatios), opt(0), wDirty(true), diff --git a/rtgui/crop.h b/rtgui/crop.h index c6636b917..83eb6bbbb 100644 --- a/rtgui/crop.h +++ b/rtgui/crop.h @@ -41,6 +41,8 @@ class Crop final : public rtengine::SizeListener { public: + static const Glib::ustring TOOL_NAME; + Crop(); ~Crop() override; diff --git a/rtgui/darkframe.cc b/rtgui/darkframe.cc index b6b1201a7..9cb45ae98 100644 --- a/rtgui/darkframe.cc +++ b/rtgui/darkframe.cc @@ -30,7 +30,9 @@ using namespace rtengine; using namespace rtengine::procparams; -DarkFrame::DarkFrame () : FoldableToolPanel(this, "darkframe", M("TP_DARKFRAME_LABEL")), dfChanged(false), lastDFauto(false), dfp(nullptr), israw(true) +const Glib::ustring DarkFrame::TOOL_NAME = "darkframe"; + +DarkFrame::DarkFrame () : FoldableToolPanel(this, TOOL_NAME, M("TP_DARKFRAME_LABEL")), dfChanged(false), lastDFauto(false), dfp(nullptr), israw(true) { hbdf = Gtk::manage(new Gtk::Box()); hbdf->set_spacing(4); diff --git a/rtgui/darkframe.h b/rtgui/darkframe.h index 58e8b4842..fea8299a4 100644 --- a/rtgui/darkframe.h +++ b/rtgui/darkframe.h @@ -62,6 +62,7 @@ protected: bool israw; public: + static const Glib::ustring TOOL_NAME; DarkFrame (); diff --git a/rtgui/defringe.cc b/rtgui/defringe.cc index 7aae8377a..72388ac8c 100644 --- a/rtgui/defringe.cc +++ b/rtgui/defringe.cc @@ -30,7 +30,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Defringe::Defringe () : FoldableToolPanel(this, "defringe", M("TP_DEFRINGE_LABEL"), true, true) +const Glib::ustring Defringe::TOOL_NAME = "defringe"; + +Defringe::Defringe () : FoldableToolPanel(this, TOOL_NAME, M("TP_DEFRINGE_LABEL"), true, true) { std::vector bottomMilestones; diff --git a/rtgui/defringe.h b/rtgui/defringe.h index ebf1eecd8..d939ff926 100644 --- a/rtgui/defringe.h +++ b/rtgui/defringe.h @@ -46,6 +46,7 @@ protected: bool edges; public: + static const Glib::ustring TOOL_NAME; Defringe (); ~Defringe () override; diff --git a/rtgui/dehaze.cc b/rtgui/dehaze.cc index 76d309afc..b77b76945 100644 --- a/rtgui/dehaze.cc +++ b/rtgui/dehaze.cc @@ -29,7 +29,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Dehaze::Dehaze(): FoldableToolPanel(this, "dehaze", M("TP_DEHAZE_LABEL"), false, true) +const Glib::ustring Dehaze::TOOL_NAME = "dehaze"; + +Dehaze::Dehaze(): FoldableToolPanel(this, TOOL_NAME, M("TP_DEHAZE_LABEL"), false, true) { auto m = ProcEventMapper::getInstance(); EvDehazeEnabled = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_ENABLED"); diff --git a/rtgui/dehaze.h b/rtgui/dehaze.h index 155efa522..1da50d7dd 100644 --- a/rtgui/dehaze.h +++ b/rtgui/dehaze.h @@ -39,6 +39,7 @@ private: rtengine::ProcEvent EvDehazeSaturation; public: + static const Glib::ustring TOOL_NAME; Dehaze(); diff --git a/rtgui/dirpyrdenoise.cc b/rtgui/dirpyrdenoise.cc index 3bf7c21f4..f2b780eba 100644 --- a/rtgui/dirpyrdenoise.cc +++ b/rtgui/dirpyrdenoise.cc @@ -33,7 +33,9 @@ using namespace rtengine; using namespace rtengine::procparams; -DirPyrDenoise::DirPyrDenoise () : FoldableToolPanel(this, "dirpyrdenoise", M("TP_DIRPYRDENOISE_LABEL"), true, true), lastmedian(false) +const Glib::ustring DirPyrDenoise::TOOL_NAME = "dirpyrdenoise"; + +DirPyrDenoise::DirPyrDenoise () : FoldableToolPanel(this, TOOL_NAME, M("TP_DIRPYRDENOISE_LABEL"), true, true), lastmedian(false) { std::vector milestones; CurveListener::setMulti(true); diff --git a/rtgui/dirpyrdenoise.h b/rtgui/dirpyrdenoise.h index 71c9b1894..dadd96988 100644 --- a/rtgui/dirpyrdenoise.h +++ b/rtgui/dirpyrdenoise.h @@ -40,6 +40,8 @@ class DirPyrDenoise final : public ColorProvider { public: + static const Glib::ustring TOOL_NAME; + DirPyrDenoise (); ~DirPyrDenoise () override; diff --git a/rtgui/dirpyrequalizer.cc b/rtgui/dirpyrequalizer.cc index 9393d7c42..46966ea45 100644 --- a/rtgui/dirpyrequalizer.cc +++ b/rtgui/dirpyrequalizer.cc @@ -24,7 +24,9 @@ using namespace rtengine; using namespace rtengine::procparams; -DirPyrEqualizer::DirPyrEqualizer () : FoldableToolPanel(this, "dirpyrequalizer", M("TP_DIRPYREQUALIZER_LABEL"), true, true) +const Glib::ustring DirPyrEqualizer::TOOL_NAME = "dirpyrequalizer"; + +DirPyrEqualizer::DirPyrEqualizer () : FoldableToolPanel(this, TOOL_NAME, M("TP_DIRPYREQUALIZER_LABEL"), true, true) { std::vector milestones; diff --git a/rtgui/dirpyrequalizer.h b/rtgui/dirpyrequalizer.h index bb03e1a53..39b201b9b 100644 --- a/rtgui/dirpyrequalizer.h +++ b/rtgui/dirpyrequalizer.h @@ -56,6 +56,7 @@ protected: bool lastgamutlab; public: + static const Glib::ustring TOOL_NAME; DirPyrEqualizer (); ~DirPyrEqualizer () override; diff --git a/rtgui/distortion.cc b/rtgui/distortion.cc index 165ccee06..84566ab80 100644 --- a/rtgui/distortion.cc +++ b/rtgui/distortion.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Distortion::Distortion (): FoldableToolPanel(this, "distortion", M("TP_DISTORTION_LABEL")) +const Glib::ustring Distortion::TOOL_NAME = "distortion"; + +Distortion::Distortion (): FoldableToolPanel(this, TOOL_NAME, M("TP_DISTORTION_LABEL")) { rlistener = nullptr; diff --git a/rtgui/distortion.h b/rtgui/distortion.h index 7ef33d73a..98044bacf 100644 --- a/rtgui/distortion.h +++ b/rtgui/distortion.h @@ -37,6 +37,7 @@ protected: LensGeomListener * rlistener; public: + static const Glib::ustring TOOL_NAME; Distortion (); diff --git a/rtgui/epd.cc b/rtgui/epd.cc index d032cf28d..073c5ecdd 100644 --- a/rtgui/epd.cc +++ b/rtgui/epd.cc @@ -26,7 +26,9 @@ using namespace rtengine; using namespace rtengine::procparams; -EdgePreservingDecompositionUI::EdgePreservingDecompositionUI () : FoldableToolPanel(this, "epd", M("TP_EPD_LABEL"), true, true) +const Glib::ustring EdgePreservingDecompositionUI::TOOL_NAME = "epd"; + +EdgePreservingDecompositionUI::EdgePreservingDecompositionUI () : FoldableToolPanel(this, TOOL_NAME, M("TP_EPD_LABEL"), true, true) { strength = Gtk::manage(new Adjuster (M("TP_EPD_STRENGTH"), -1.0, 2.0, 0.01, 0.5)); diff --git a/rtgui/epd.h b/rtgui/epd.h index 6a5160623..1d866d690 100644 --- a/rtgui/epd.h +++ b/rtgui/epd.h @@ -36,6 +36,7 @@ protected: Adjuster *reweightingIterates; public: + static const Glib::ustring TOOL_NAME; EdgePreservingDecompositionUI(); diff --git a/rtgui/fattaltonemap.cc b/rtgui/fattaltonemap.cc index 89a1e9e30..d4ed90612 100644 --- a/rtgui/fattaltonemap.cc +++ b/rtgui/fattaltonemap.cc @@ -31,7 +31,9 @@ using namespace rtengine; using namespace rtengine::procparams; -FattalToneMapping::FattalToneMapping(): FoldableToolPanel(this, "fattal", M("TP_TM_FATTAL_LABEL"), true, true) +const Glib::ustring FattalToneMapping::TOOL_NAME = "fattal"; + +FattalToneMapping::FattalToneMapping(): FoldableToolPanel(this, TOOL_NAME, M("TP_TM_FATTAL_LABEL"), true, true) { auto m = ProcEventMapper::getInstance(); EvTMFattalAnchor = m->newEvent(HDR, "HISTORY_MSG_TM_FATTAL_ANCHOR"); diff --git a/rtgui/fattaltonemap.h b/rtgui/fattaltonemap.h index 3d36ec7d2..f5c19f15c 100644 --- a/rtgui/fattaltonemap.h +++ b/rtgui/fattaltonemap.h @@ -33,6 +33,7 @@ protected: rtengine::ProcEvent EvTMFattalAnchor; public: + static const Glib::ustring TOOL_NAME; FattalToneMapping(); diff --git a/rtgui/filmnegative.cc b/rtgui/filmnegative.cc index 068575a96..292fa98ae 100644 --- a/rtgui/filmnegative.cc +++ b/rtgui/filmnegative.cc @@ -28,6 +28,8 @@ #include "../rtengine/procparams.h" #include "../rtengine/color.h" +const Glib::ustring FilmNegative::TOOL_NAME = "filmnegative"; + namespace { @@ -184,7 +186,7 @@ void rgb2temp(const RGB &refOut, double &outLev, double &temp, double &green) } FilmNegative::FilmNegative() : - FoldableToolPanel(this, "filmnegative", M("TP_FILMNEGATIVE_LABEL"), false, true), + FoldableToolPanel(this, TOOL_NAME, M("TP_FILMNEGATIVE_LABEL"), false, true), EditSubscriber(ET_OBJECTS), NEUTRAL_TEMP(rtengine::ColorTemp(1., 1., 1., 1.)), evFilmNegativeExponents(ProcEventMapper::getInstance()->newEvent(ALLNORAW, "HISTORY_MSG_FILMNEGATIVE_VALUES")), diff --git a/rtgui/filmnegative.h b/rtgui/filmnegative.h index 21a7dce5c..722625fa2 100644 --- a/rtgui/filmnegative.h +++ b/rtgui/filmnegative.h @@ -52,6 +52,8 @@ class FilmNegative final : public rtengine::FilmNegListener { public: + static const Glib::ustring TOOL_NAME; + FilmNegative(); ~FilmNegative() override; diff --git a/rtgui/filmsimulation.cc b/rtgui/filmsimulation.cc index 6b40bb586..55a8e0ffe 100644 --- a/rtgui/filmsimulation.cc +++ b/rtgui/filmsimulation.cc @@ -12,6 +12,8 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring FilmSimulation::TOOL_NAME = "filmsimulation"; + namespace { @@ -61,7 +63,7 @@ bool notifySlowParseDir (const std::chrono::system_clock::time_point& startedAt) } FilmSimulation::FilmSimulation() - : FoldableToolPanel( this, "filmsimulation", M("TP_FILMSIMULATION_LABEL"), false, true ) + : FoldableToolPanel( this, TOOL_NAME, M("TP_FILMSIMULATION_LABEL"), false, true ) { m_clutComboBox = Gtk::manage( new ClutComboBox(options.clutsDir) ); int foundClutsCount = m_clutComboBox->foundClutsCount(); diff --git a/rtgui/filmsimulation.h b/rtgui/filmsimulation.h index cfe7016bb..ed30b866e 100644 --- a/rtgui/filmsimulation.h +++ b/rtgui/filmsimulation.h @@ -56,6 +56,8 @@ private: class FilmSimulation : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel { public: + static const Glib::ustring TOOL_NAME; + FilmSimulation(); void adjusterChanged(Adjuster* a, double newval) override; diff --git a/rtgui/flatfield.cc b/rtgui/flatfield.cc index 71fa0aab6..7e4086c07 100644 --- a/rtgui/flatfield.cc +++ b/rtgui/flatfield.cc @@ -30,7 +30,9 @@ using namespace rtengine; using namespace rtengine::procparams; -FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_LABEL")) +const Glib::ustring FlatField::TOOL_NAME = "flatfield"; + +FlatField::FlatField () : FoldableToolPanel(this, TOOL_NAME, M("TP_FLATFIELD_LABEL")) { hbff = Gtk::manage(new Gtk::Box()); flatFieldFile = Gtk::manage(new MyFileChooserButton(M("TP_FLATFIELD_LABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); diff --git a/rtgui/flatfield.h b/rtgui/flatfield.h index 0d6f167e1..9b20b3e6f 100644 --- a/rtgui/flatfield.h +++ b/rtgui/flatfield.h @@ -67,6 +67,7 @@ protected: IdleRegister idle_register; public: + static const Glib::ustring TOOL_NAME; FlatField (); ~FlatField () override; diff --git a/rtgui/gradient.cc b/rtgui/gradient.cc index 1274da9ab..26be51975 100644 --- a/rtgui/gradient.cc +++ b/rtgui/gradient.cc @@ -25,7 +25,9 @@ enum GeometryIndex { } -Gradient::Gradient () : FoldableToolPanel(this, "gradient", M("TP_GRADIENT_LABEL"), false, true), EditSubscriber(ET_OBJECTS), lastObject(-1), draggedPointOldAngle(-1000.) +const Glib::ustring Gradient::TOOL_NAME = "gradient"; + +Gradient::Gradient () : FoldableToolPanel(this, TOOL_NAME, M("TP_GRADIENT_LABEL"), false, true), EditSubscriber(ET_OBJECTS), lastObject(-1), draggedPointOldAngle(-1000.) { editHBox = Gtk::manage (new Gtk::Box()); diff --git a/rtgui/gradient.h b/rtgui/gradient.h index dc0371932..d7754007c 100644 --- a/rtgui/gradient.h +++ b/rtgui/gradient.h @@ -38,6 +38,7 @@ protected: void releaseEdit(); public: + static const Glib::ustring TOOL_NAME; Gradient (); ~Gradient () override; diff --git a/rtgui/hsvequalizer.cc b/rtgui/hsvequalizer.cc index 817ba1f4d..ddb1d2fb5 100644 --- a/rtgui/hsvequalizer.cc +++ b/rtgui/hsvequalizer.cc @@ -28,9 +28,11 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring HSVEqualizer::TOOL_NAME = "hsvequalizer"; + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -HSVEqualizer::HSVEqualizer () : FoldableToolPanel(this, "hsvequalizer", M("TP_HSVEQUALIZER_LABEL"), false, true) +HSVEqualizer::HSVEqualizer () : FoldableToolPanel(this, TOOL_NAME, M("TP_HSVEQUALIZER_LABEL"), false, true) { std::vector bottomMilestones; diff --git a/rtgui/hsvequalizer.h b/rtgui/hsvequalizer.h index 77c1ee1b0..1f80cd9e4 100644 --- a/rtgui/hsvequalizer.h +++ b/rtgui/hsvequalizer.h @@ -44,6 +44,7 @@ protected: FlatCurveEditor* vshape; public: + static const Glib::ustring TOOL_NAME; HSVEqualizer (); ~HSVEqualizer () override; diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index 45d0f6622..254882736 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -35,7 +35,9 @@ using namespace rtengine; using namespace rtengine::procparams; -ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iunchanged(nullptr), icmplistener(nullptr) +const Glib::ustring ICMPanel::TOOL_NAME = "icm"; + +ICMPanel::ICMPanel() : FoldableToolPanel(this, TOOL_NAME, M("TP_ICM_LABEL")), iunchanged(nullptr), icmplistener(nullptr) { auto m = ProcEventMapper::getInstance(); EvICMprimariMethod = m->newEvent(GAMMA, "HISTORY_MSG_ICM_OUTPUT_PRIMARIES"); diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 063da28d1..422b674ff 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -177,6 +177,8 @@ private: float nextwy; public: + static const Glib::ustring TOOL_NAME; + ICMPanel(); ~ICMPanel() override; diff --git a/rtgui/impulsedenoise.cc b/rtgui/impulsedenoise.cc index cc2e10899..1df662aad 100644 --- a/rtgui/impulsedenoise.cc +++ b/rtgui/impulsedenoise.cc @@ -28,7 +28,9 @@ using namespace rtengine; using namespace rtengine::procparams; -ImpulseDenoise::ImpulseDenoise () : FoldableToolPanel(this, "impulsedenoise", M("TP_IMPULSEDENOISE_LABEL"), true, true) +const Glib::ustring ImpulseDenoise::TOOL_NAME = "impulsedenoise"; + +ImpulseDenoise::ImpulseDenoise () : FoldableToolPanel(this, TOOL_NAME, M("TP_IMPULSEDENOISE_LABEL"), true, true) { thresh = Gtk::manage (new Adjuster (M("TP_IMPULSEDENOISE_THRESH"), 0, 100, 1, 50)); diff --git a/rtgui/impulsedenoise.h b/rtgui/impulsedenoise.h index b8acafcfc..c4c297927 100644 --- a/rtgui/impulsedenoise.h +++ b/rtgui/impulsedenoise.h @@ -34,6 +34,7 @@ protected: //Adjuster* edge; public: + static const Glib::ustring TOOL_NAME; ImpulseDenoise (); diff --git a/rtgui/labcurve.cc b/rtgui/labcurve.cc index dca1dfd45..1d49cd6ff 100644 --- a/rtgui/labcurve.cc +++ b/rtgui/labcurve.cc @@ -32,7 +32,9 @@ using namespace rtengine; using namespace rtengine::procparams; -LCurve::LCurve () : FoldableToolPanel(this, "labcurves", M("TP_LABCURVE_LABEL"), false, true) +const Glib::ustring LCurve::TOOL_NAME = "labcurves"; + +LCurve::LCurve () : FoldableToolPanel(this, TOOL_NAME, M("TP_LABCURVE_LABEL"), false, true) { brightness = Gtk::manage (new Adjuster (M("TP_LABCURVE_BRIGHTNESS"), -100., 100., 1., 0.)); contrast = Gtk::manage (new Adjuster (M("TP_LABCURVE_CONTRAST"), -100., 100., 1., 0.)); diff --git a/rtgui/labcurve.h b/rtgui/labcurve.h index dfb79ae7a..b9039baca 100644 --- a/rtgui/labcurve.h +++ b/rtgui/labcurve.h @@ -69,6 +69,7 @@ protected: //%%%%%%%%%%%%%%%% public: + static const Glib::ustring TOOL_NAME; LCurve (); ~LCurve () override; diff --git a/rtgui/lensgeom.cc b/rtgui/lensgeom.cc index 8bdbf6dd4..6b9d70fb0 100644 --- a/rtgui/lensgeom.cc +++ b/rtgui/lensgeom.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -LensGeometry::LensGeometry () : FoldableToolPanel(this, "lensgeom", M("TP_LENSGEOM_LABEL")), rlistener(nullptr), lastFill(false) +const Glib::ustring LensGeometry::TOOL_NAME = "lensgeom"; + +LensGeometry::LensGeometry () : FoldableToolPanel(this, TOOL_NAME, M("TP_LENSGEOM_LABEL")), rlistener(nullptr), lastFill(false) { auto m = ProcEventMapper::getInstance(); diff --git a/rtgui/lensgeom.h b/rtgui/lensgeom.h index 73c28b006..e8f85faac 100644 --- a/rtgui/lensgeom.h +++ b/rtgui/lensgeom.h @@ -39,6 +39,7 @@ protected: rtengine::ProcEvent EvTransMethod; public: + static const Glib::ustring TOOL_NAME; LensGeometry (); ~LensGeometry () override; diff --git a/rtgui/lensprofile.cc b/rtgui/lensprofile.cc index 73fb0399b..65c962b7b 100644 --- a/rtgui/lensprofile.cc +++ b/rtgui/lensprofile.cc @@ -36,8 +36,10 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring LensProfilePanel::TOOL_NAME = "lensprof"; + LensProfilePanel::LensProfilePanel() : - FoldableToolPanel(this, "lensprof", M("TP_LENSPROFILE_LABEL")), + FoldableToolPanel(this, TOOL_NAME, M("TP_LENSPROFILE_LABEL")), lcModeChanged(false), lcpFileChanged(false), useDistChanged(false), diff --git a/rtgui/lensprofile.h b/rtgui/lensprofile.h index 7b5b7343c..42746f41e 100644 --- a/rtgui/lensprofile.h +++ b/rtgui/lensprofile.h @@ -28,6 +28,8 @@ class LensProfilePanel final : public FoldableToolPanel { public: + static const Glib::ustring TOOL_NAME; + LensProfilePanel(); void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; diff --git a/rtgui/localcontrast.cc b/rtgui/localcontrast.cc index 6b668a1eb..a56f9cb15 100644 --- a/rtgui/localcontrast.cc +++ b/rtgui/localcontrast.cc @@ -29,7 +29,9 @@ using namespace rtengine; using namespace rtengine::procparams; -LocalContrast::LocalContrast(): FoldableToolPanel(this, "localcontrast", M("TP_LOCALCONTRAST_LABEL"), false, true) +const Glib::ustring LocalContrast::TOOL_NAME = "localcontrast"; + +LocalContrast::LocalContrast(): FoldableToolPanel(this, TOOL_NAME, M("TP_LOCALCONTRAST_LABEL"), false, true) { auto m = ProcEventMapper::getInstance(); /* EvLocalContrastEnabled = m->newEvent(RGBCURVE, "HISTORY_MSG_LOCALCONTRAST_ENABLED"); diff --git a/rtgui/localcontrast.h b/rtgui/localcontrast.h index d1d25fb3d..fa769c35e 100644 --- a/rtgui/localcontrast.h +++ b/rtgui/localcontrast.h @@ -38,6 +38,7 @@ private: rtengine::ProcEvent EvLocalContrastLightness; public: + static const Glib::ustring TOOL_NAME; LocalContrast(); diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc index 880125085..db9fc6e1a 100644 --- a/rtgui/locallab.cc +++ b/rtgui/locallab.cc @@ -29,6 +29,8 @@ using namespace procparams; extern Options options; +const Glib::ustring Locallab::TOOL_NAME = "locallab"; + /* ==== LocallabToolList ==== */ LocallabToolList::LocallabToolList(): // Tool list GUI elements @@ -142,7 +144,7 @@ void LocallabToolList::toolRowSelected() /* ==== Locallab ==== */ Locallab::Locallab(): - FoldableToolPanel(this, "locallab", M("TP_LOCALLAB_LABEL"), false, true), + FoldableToolPanel(this, TOOL_NAME, M("TP_LOCALLAB_LABEL"), false, true), // Spot control panel widget expsettings(Gtk::manage(new ControlSpotPanel())), diff --git a/rtgui/locallab.h b/rtgui/locallab.h index d86d8c5c1..c615d49ae 100644 --- a/rtgui/locallab.h +++ b/rtgui/locallab.h @@ -131,6 +131,8 @@ private: Glib::ustring spotName; public: + static const Glib::ustring TOOL_NAME; + Locallab(); // FoldableToolPanel management functions diff --git a/rtgui/pcvignette.cc b/rtgui/pcvignette.cc index 9c141d618..1ed7446b1 100644 --- a/rtgui/pcvignette.cc +++ b/rtgui/pcvignette.cc @@ -8,7 +8,9 @@ using namespace rtengine; using namespace rtengine::procparams; -PCVignette::PCVignette () : FoldableToolPanel(this, "pcvignette", M("TP_PCVIGNETTE_LABEL"), false, true) +const Glib::ustring PCVignette::TOOL_NAME = "pcvignette"; + +PCVignette::PCVignette () : FoldableToolPanel(this, TOOL_NAME, M("TP_PCVIGNETTE_LABEL"), false, true) { strength = Gtk::manage (new Adjuster (M("TP_PCVIGNETTE_STRENGTH"), -6, 6, 0.01, 0)); strength->set_tooltip_text (M("TP_PCVIGNETTE_STRENGTH_TOOLTIP")); diff --git a/rtgui/pcvignette.h b/rtgui/pcvignette.h index 87915703f..825654630 100644 --- a/rtgui/pcvignette.h +++ b/rtgui/pcvignette.h @@ -20,6 +20,7 @@ protected: Adjuster* roundness; public: + static const Glib::ustring TOOL_NAME; PCVignette (); diff --git a/rtgui/pdsharpening.cc b/rtgui/pdsharpening.cc index 45d5b545c..57133048c 100644 --- a/rtgui/pdsharpening.cc +++ b/rtgui/pdsharpening.cc @@ -31,8 +31,10 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring PdSharpening::TOOL_NAME = "capturesharpening"; + PdSharpening::PdSharpening() : - FoldableToolPanel(this, "capturesharpening", M("TP_PDSHARPENING_LABEL"), false, true), + FoldableToolPanel(this, TOOL_NAME, M("TP_PDSHARPENING_LABEL"), false, true), lastAutoContrast(true), lastAutoRadius(true) { diff --git a/rtgui/pdsharpening.h b/rtgui/pdsharpening.h index eb0576ceb..c4902e4b6 100644 --- a/rtgui/pdsharpening.h +++ b/rtgui/pdsharpening.h @@ -50,6 +50,7 @@ protected: IdleRegister idle_register; public: + static const Glib::ustring TOOL_NAME; PdSharpening (); ~PdSharpening () override; diff --git a/rtgui/perspective.cc b/rtgui/perspective.cc index d06243524..be151e9bc 100644 --- a/rtgui/perspective.cc +++ b/rtgui/perspective.cc @@ -27,6 +27,8 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring PerspCorrection::TOOL_NAME = "perspective"; + namespace { @@ -84,7 +86,7 @@ std::vector valuesToControlLines( } -PerspCorrection::PerspCorrection () : FoldableToolPanel(this, "perspective", M("TP_PERSPECTIVE_LABEL")) +PerspCorrection::PerspCorrection () : FoldableToolPanel(this, TOOL_NAME, M("TP_PERSPECTIVE_LABEL")) { auto mapper = ProcEventMapper::getInstance(); diff --git a/rtgui/perspective.h b/rtgui/perspective.h index 404b02010..6ca2381e3 100644 --- a/rtgui/perspective.h +++ b/rtgui/perspective.h @@ -104,6 +104,7 @@ public: static constexpr std::size_t MIN_HORIZ_LINES = 2; /** Minimum number of vertical lines for vertical/full correction. */ static constexpr std::size_t MIN_VERT_LINES = 2; + static const Glib::ustring TOOL_NAME; PerspCorrection (); diff --git a/rtgui/preprocess.cc b/rtgui/preprocess.cc index b9326e3ad..4d7df213c 100644 --- a/rtgui/preprocess.cc +++ b/rtgui/preprocess.cc @@ -28,7 +28,9 @@ using namespace rtengine; using namespace rtengine::procparams; -PreProcess::PreProcess () : FoldableToolPanel(this, "preprocess", M("TP_PREPROCESS_LABEL"), options.prevdemo != PD_Sidecar) +const Glib::ustring PreProcess::TOOL_NAME = "preprocess"; + +PreProcess::PreProcess () : FoldableToolPanel(this, TOOL_NAME, M("TP_PREPROCESS_LABEL"), options.prevdemo != PD_Sidecar) { Gtk::Box* hotdeadPixel = Gtk::manage( new Gtk::Box () ); diff --git a/rtgui/preprocess.h b/rtgui/preprocess.h index d10ff5223..047413bdb 100644 --- a/rtgui/preprocess.h +++ b/rtgui/preprocess.h @@ -38,6 +38,7 @@ protected: sigc::connection dpixelconn; Adjuster* hdThreshold; public: + static const Glib::ustring TOOL_NAME; PreProcess (); diff --git a/rtgui/preprocesswb.cc b/rtgui/preprocesswb.cc index dddd7fdc2..9251f9440 100644 --- a/rtgui/preprocesswb.cc +++ b/rtgui/preprocesswb.cc @@ -29,8 +29,10 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring PreprocessWB::TOOL_NAME = "preprocesswb"; + PreprocessWB::PreprocessWB() : - FoldableToolPanel(this, "preprocesswb", M("TP_PREPROCWB_LABEL")), + FoldableToolPanel(this, TOOL_NAME, M("TP_PREPROCWB_LABEL")), evPreprocessWBMode(ProcEventMapper::getInstance()->newEvent(FIRST, "HISTORY_MSG_PREPROCWB_MODE")), mode(Gtk::manage(new MyComboBoxText())) { diff --git a/rtgui/preprocesswb.h b/rtgui/preprocesswb.h index 343d2e9e9..08e1dc468 100644 --- a/rtgui/preprocesswb.h +++ b/rtgui/preprocesswb.h @@ -34,6 +34,7 @@ private: MyComboBoxText* mode; public: + static const Glib::ustring TOOL_NAME; PreprocessWB(); diff --git a/rtgui/prsharpening.cc b/rtgui/prsharpening.cc index c79fff1a1..d3c936fa2 100644 --- a/rtgui/prsharpening.cc +++ b/rtgui/prsharpening.cc @@ -23,7 +23,9 @@ using namespace rtengine; using namespace rtengine::procparams; -PrSharpening::PrSharpening () : FoldableToolPanel(this, "prsharpening", M("TP_PRSHARPENING_LABEL"), false, true) +const Glib::ustring PrSharpening::TOOL_NAME = "prsharpening"; + +PrSharpening::PrSharpening () : FoldableToolPanel(this, TOOL_NAME, M("TP_PRSHARPENING_LABEL"), false, true) { auto m = ProcEventMapper::getInstance(); diff --git a/rtgui/prsharpening.h b/rtgui/prsharpening.h index 4128bc4c5..ea22234f8 100644 --- a/rtgui/prsharpening.h +++ b/rtgui/prsharpening.h @@ -59,6 +59,7 @@ protected: sigc::connection hcConn; rtengine::ProcEvent EvPrShrContrast; public: + static const Glib::ustring TOOL_NAME; PrSharpening (); ~PrSharpening () override; diff --git a/rtgui/rawcacorrection.cc b/rtgui/rawcacorrection.cc index 58c7995f9..473ca2ed3 100644 --- a/rtgui/rawcacorrection.cc +++ b/rtgui/rawcacorrection.cc @@ -28,7 +28,9 @@ using namespace rtengine; using namespace rtengine::procparams; -RAWCACorr::RAWCACorr () : FoldableToolPanel(this, "rawcacorrection", M("TP_RAWCACORR_LABEL")) +const Glib::ustring RAWCACorr::TOOL_NAME = "rawcacorrection"; + +RAWCACorr::RAWCACorr () : FoldableToolPanel(this, TOOL_NAME, M("TP_RAWCACORR_LABEL")) { auto m = ProcEventMapper::getInstance(); EvPreProcessCAAutoiterations = m->newEvent(DARKFRAME, "HISTORY_MSG_RAWCACORR_AUTOIT"); diff --git a/rtgui/rawcacorrection.h b/rtgui/rawcacorrection.h index 3c95602a7..88b65528e 100644 --- a/rtgui/rawcacorrection.h +++ b/rtgui/rawcacorrection.h @@ -43,6 +43,7 @@ protected: rtengine::ProcEvent EvPreProcessCAColourshiftHistory; public: + static const Glib::ustring TOOL_NAME; RAWCACorr (); diff --git a/rtgui/rawexposure.cc b/rtgui/rawexposure.cc index 7b5ecabc9..778283b75 100644 --- a/rtgui/rawexposure.cc +++ b/rtgui/rawexposure.cc @@ -28,7 +28,9 @@ using namespace rtengine; using namespace rtengine::procparams; -RAWExposure::RAWExposure () : FoldableToolPanel(this, "rawexposure", M("TP_EXPOS_WHITEPOINT_LABEL")) +const Glib::ustring RAWExposure::TOOL_NAME = "rawexposure"; + +RAWExposure::RAWExposure () : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOS_WHITEPOINT_LABEL")) { PexPos = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_LINEAR"), 0.1, 16.0, 0.01, 1)); PexPos->setAdjusterListener (this); diff --git a/rtgui/rawexposure.h b/rtgui/rawexposure.h index 33c897113..ca839d230 100644 --- a/rtgui/rawexposure.h +++ b/rtgui/rawexposure.h @@ -33,6 +33,7 @@ protected: Adjuster* PexPos; public: + static const Glib::ustring TOOL_NAME; RAWExposure (); diff --git a/rtgui/resize.cc b/rtgui/resize.cc index 0bbb65845..258ccf791 100644 --- a/rtgui/resize.cc +++ b/rtgui/resize.cc @@ -29,7 +29,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Resize::Resize () : FoldableToolPanel(this, "resize", M("TP_RESIZE_LABEL"), false, true), maxw(100000), maxh(100000) +const Glib::ustring Resize::TOOL_NAME = "resize"; + +Resize::Resize () : FoldableToolPanel(this, TOOL_NAME, M("TP_RESIZE_LABEL"), false, true), maxw(100000), maxh(100000) { auto m = ProcEventMapper::getInstance(); EvResizeAllowUpscaling = m->newEvent(RESIZE, "HISTORY_MSG_RESIZE_ALLOWUPSCALING"); diff --git a/rtgui/resize.h b/rtgui/resize.h index d13bf8aa4..71fefb503 100644 --- a/rtgui/resize.h +++ b/rtgui/resize.h @@ -32,6 +32,8 @@ class Resize final : public rtengine::SizeListener { public: + static const Glib::ustring TOOL_NAME; + Resize (); ~Resize () override; diff --git a/rtgui/retinex.cc b/rtgui/retinex.cc index a9d7cc376..3aac6f203 100644 --- a/rtgui/retinex.cc +++ b/rtgui/retinex.cc @@ -14,7 +14,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Retinex::Retinex () : FoldableToolPanel (this, "retinex", M ("TP_RETINEX_LABEL"), false, true), lastmedianmap (false) +const Glib::ustring Retinex::TOOL_NAME = "retinex"; + +Retinex::Retinex () : FoldableToolPanel (this, TOOL_NAME, M ("TP_RETINEX_LABEL"), false, true), lastmedianmap (false) { CurveListener::setMulti (true); std::vector milestones; diff --git a/rtgui/retinex.h b/rtgui/retinex.h index bf480c9cc..bdcbcc466 100644 --- a/rtgui/retinex.h +++ b/rtgui/retinex.h @@ -109,6 +109,8 @@ protected: sigc::connection medianmapConn; public: + static const Glib::ustring TOOL_NAME; + Retinex(); ~Retinex() override; diff --git a/rtgui/rgbcurves.cc b/rtgui/rgbcurves.cc index 5e7616e70..0dd6805fe 100644 --- a/rtgui/rgbcurves.cc +++ b/rtgui/rgbcurves.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -RGBCurves::RGBCurves () : FoldableToolPanel(this, "rgbcurves", M("TP_RGBCURVES_LABEL"), false, true), lastLumamode(false) +const Glib::ustring RGBCurves::TOOL_NAME = "rgbcurves"; + +RGBCurves::RGBCurves () : FoldableToolPanel(this, TOOL_NAME, M("TP_RGBCURVES_LABEL"), false, true), lastLumamode(false) { lumamode = Gtk::manage (new Gtk::CheckButton (M("TP_RGBCURVES_LUMAMODE"))); diff --git a/rtgui/rgbcurves.h b/rtgui/rgbcurves.h index edc80eb41..d7e3c3853 100644 --- a/rtgui/rgbcurves.h +++ b/rtgui/rgbcurves.h @@ -45,6 +45,7 @@ protected: sigc::connection lumamodeConn; public: + static const Glib::ustring TOOL_NAME; RGBCurves (); ~RGBCurves () override; diff --git a/rtgui/rotate.cc b/rtgui/rotate.cc index 06c53cd4e..944c54e6d 100644 --- a/rtgui/rotate.cc +++ b/rtgui/rotate.cc @@ -29,7 +29,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Rotate::Rotate () : FoldableToolPanel(this, "rotate", M("TP_ROTATE_LABEL")) +const Glib::ustring Rotate::TOOL_NAME = "rotate"; + +Rotate::Rotate () : FoldableToolPanel(this, TOOL_NAME, M("TP_ROTATE_LABEL")) { rlistener = nullptr; diff --git a/rtgui/rotate.h b/rtgui/rotate.h index 41e10eb4d..26db33ffd 100644 --- a/rtgui/rotate.h +++ b/rtgui/rotate.h @@ -36,6 +36,7 @@ protected: LensGeomListener* rlistener; public: + static const Glib::ustring TOOL_NAME; Rotate (); diff --git a/rtgui/sensorbayer.cc b/rtgui/sensorbayer.cc index 39ed5cb91..002cdf1de 100644 --- a/rtgui/sensorbayer.cc +++ b/rtgui/sensorbayer.cc @@ -20,7 +20,9 @@ #include "guiutils.h" #include "rtimage.h" -SensorBayer::SensorBayer () : FoldableToolPanel(this, "sensorbayer", M("TP_RAW_SENSOR_BAYER_LABEL")) +const Glib::ustring SensorBayer::TOOL_NAME = "sensorbayer"; + +SensorBayer::SensorBayer () : FoldableToolPanel(this, TOOL_NAME, M("TP_RAW_SENSOR_BAYER_LABEL")) { packBox = Gtk::manage (new ToolParamBlock ()); diff --git a/rtgui/sensorbayer.h b/rtgui/sensorbayer.h index 2401bf760..0e65b8b38 100644 --- a/rtgui/sensorbayer.h +++ b/rtgui/sensorbayer.h @@ -31,6 +31,7 @@ protected: ToolParamBlock* packBox; public: + static const Glib::ustring TOOL_NAME; SensorBayer (); diff --git a/rtgui/sensorxtrans.cc b/rtgui/sensorxtrans.cc index f13e6607f..c4a5bf76d 100644 --- a/rtgui/sensorxtrans.cc +++ b/rtgui/sensorxtrans.cc @@ -20,7 +20,9 @@ #include "guiutils.h" #include "rtimage.h" -SensorXTrans::SensorXTrans () : FoldableToolPanel(this, "sensorxtrans", M("TP_RAW_SENSOR_XTRANS_LABEL")) +const Glib::ustring SensorXTrans::TOOL_NAME = "sensorxtrans"; + +SensorXTrans::SensorXTrans () : FoldableToolPanel(this, TOOL_NAME, M("TP_RAW_SENSOR_XTRANS_LABEL")) { packBox = Gtk::manage (new ToolParamBlock ()); diff --git a/rtgui/sensorxtrans.h b/rtgui/sensorxtrans.h index eee014f6c..12c851db3 100644 --- a/rtgui/sensorxtrans.h +++ b/rtgui/sensorxtrans.h @@ -31,6 +31,7 @@ protected: ToolParamBlock* packBox; public: + static const Glib::ustring TOOL_NAME; SensorXTrans (); diff --git a/rtgui/shadowshighlights.cc b/rtgui/shadowshighlights.cc index a168527d6..3c821d863 100644 --- a/rtgui/shadowshighlights.cc +++ b/rtgui/shadowshighlights.cc @@ -25,7 +25,9 @@ using namespace rtengine; using namespace rtengine::procparams; -ShadowsHighlights::ShadowsHighlights () : FoldableToolPanel(this, "shadowshighlights", M("TP_SHADOWSHLIGHTS_LABEL"), false, true) +const Glib::ustring ShadowsHighlights::TOOL_NAME = "shadowshighlights"; + +ShadowsHighlights::ShadowsHighlights () : FoldableToolPanel(this, TOOL_NAME, M("TP_SHADOWSHLIGHTS_LABEL"), false, true) { auto m = ProcEventMapper::getInstance(); EvSHColorspace = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_SH_COLORSPACE"); diff --git a/rtgui/shadowshighlights.h b/rtgui/shadowshighlights.h index 7bb0bb01c..fd8b30a6a 100644 --- a/rtgui/shadowshighlights.h +++ b/rtgui/shadowshighlights.h @@ -40,6 +40,7 @@ protected: rtengine::ProcEvent EvSHColorspace; public: + static const Glib::ustring TOOL_NAME; ShadowsHighlights (); diff --git a/rtgui/sharpenedge.cc b/rtgui/sharpenedge.cc index e00d919c3..247a8a5d7 100644 --- a/rtgui/sharpenedge.cc +++ b/rtgui/sharpenedge.cc @@ -28,8 +28,9 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring SharpenEdge::TOOL_NAME = "sharpenedge"; -SharpenEdge::SharpenEdge () : FoldableToolPanel(this, "sharpenedge", M("TP_SHARPENEDGE_LABEL"), true, true) +SharpenEdge::SharpenEdge () : FoldableToolPanel(this, TOOL_NAME, M("TP_SHARPENEDGE_LABEL"), true, true) { passes = Gtk::manage(new Adjuster (M("TP_SHARPENEDGE_PASSES"), 1, 4, 1, 2)); diff --git a/rtgui/sharpenedge.h b/rtgui/sharpenedge.h index a813d86e1..bfb48b408 100644 --- a/rtgui/sharpenedge.h +++ b/rtgui/sharpenedge.h @@ -44,6 +44,7 @@ protected: bool lastchanthree; public: + static const Glib::ustring TOOL_NAME; SharpenEdge (); diff --git a/rtgui/sharpening.cc b/rtgui/sharpening.cc index 687358349..ba39ac97c 100644 --- a/rtgui/sharpening.cc +++ b/rtgui/sharpening.cc @@ -23,7 +23,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Sharpening::Sharpening () : FoldableToolPanel(this, "sharpening", M("TP_SHARPENING_LABEL"), true, true) +const Glib::ustring Sharpening::TOOL_NAME = "sharpening"; + +Sharpening::Sharpening () : FoldableToolPanel(this, TOOL_NAME, M("TP_SHARPENING_LABEL"), true, true) { auto m = ProcEventMapper::getInstance(); EvSharpenContrast = m->newEvent(SHARPENING, "HISTORY_MSG_SHARPENING_CONTRAST"); diff --git a/rtgui/sharpening.h b/rtgui/sharpening.h index aa65b3662..e30db3dd2 100644 --- a/rtgui/sharpening.h +++ b/rtgui/sharpening.h @@ -62,6 +62,7 @@ protected: rtengine::ProcEvent EvSharpenContrast; rtengine::ProcEvent EvSharpenBlur; public: + static const Glib::ustring TOOL_NAME; Sharpening (); ~Sharpening () override; diff --git a/rtgui/sharpenmicro.cc b/rtgui/sharpenmicro.cc index 78228d27c..527d146d7 100644 --- a/rtgui/sharpenmicro.cc +++ b/rtgui/sharpenmicro.cc @@ -29,8 +29,9 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring SharpenMicro::TOOL_NAME = "sharpenmicro"; -SharpenMicro::SharpenMicro () : FoldableToolPanel(this, "sharpenmicro", M("TP_SHARPENMICRO_LABEL"), true, true) +SharpenMicro::SharpenMicro () : FoldableToolPanel(this, TOOL_NAME, M("TP_SHARPENMICRO_LABEL"), true, true) { auto m = ProcEventMapper::getInstance(); diff --git a/rtgui/sharpenmicro.h b/rtgui/sharpenmicro.h index 23224dd60..876117e68 100644 --- a/rtgui/sharpenmicro.h +++ b/rtgui/sharpenmicro.h @@ -47,6 +47,7 @@ protected: bool lastmatrix; public: + static const Glib::ustring TOOL_NAME; SharpenMicro (); diff --git a/rtgui/softlight.cc b/rtgui/softlight.cc index 84461f169..3a7f84985 100644 --- a/rtgui/softlight.cc +++ b/rtgui/softlight.cc @@ -29,7 +29,9 @@ using namespace rtengine; using namespace rtengine::procparams; -SoftLight::SoftLight(): FoldableToolPanel(this, "softlight", M("TP_SOFTLIGHT_LABEL"), false, true) +const Glib::ustring SoftLight::TOOL_NAME = "softlight"; + +SoftLight::SoftLight(): FoldableToolPanel(this, TOOL_NAME, M("TP_SOFTLIGHT_LABEL"), false, true) { auto m = ProcEventMapper::getInstance(); EvSoftLightEnabled = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_SOFTLIGHT_ENABLED"); diff --git a/rtgui/softlight.h b/rtgui/softlight.h index 710da4e34..3b9ff5399 100644 --- a/rtgui/softlight.h +++ b/rtgui/softlight.h @@ -32,6 +32,7 @@ private: rtengine::ProcEvent EvSoftLightStrength; public: + static const Glib::ustring TOOL_NAME; SoftLight(); diff --git a/rtgui/spot.cc b/rtgui/spot.cc index 6e9143dbe..ffc380534 100644 --- a/rtgui/spot.cc +++ b/rtgui/spot.cc @@ -52,8 +52,10 @@ enum GeometryIndex { } +const Glib::ustring Spot::TOOL_NAME = "spot"; + Spot::Spot() : - FoldableToolPanel(this, "spot", M ("TP_SPOT_LABEL"), true, true), + FoldableToolPanel(this, TOOL_NAME, M ("TP_SPOT_LABEL"), true, true), EditSubscriber(ET_OBJECTS), draggedSide(DraggedSide::NONE), lastObject(-1), diff --git a/rtgui/spot.h b/rtgui/spot.h index 85cefa4c2..6320e068e 100644 --- a/rtgui/spot.h +++ b/rtgui/spot.h @@ -97,6 +97,7 @@ protected: Geometry* getVisibleGeometryFromMO (int MOID); public: + static const Glib::ustring TOOL_NAME; Spot (); ~Spot (); diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index 8a33575ca..677f73683 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -33,7 +33,9 @@ using namespace rtengine; using namespace rtengine::procparams; -ToneCurve::ToneCurve() : FoldableToolPanel(this, "tonecurve", M("TP_EXPOSURE_LABEL")) +const Glib::ustring ToneCurve::TOOL_NAME = "tonecurve"; + +ToneCurve::ToneCurve() : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOSURE_LABEL")) { auto m = ProcEventMapper::getInstance(); EvHistMatching = m->newEvent(AUTOEXP, "HISTORY_MSG_HISTMATCHING"); diff --git a/rtgui/tonecurve.h b/rtgui/tonecurve.h index 6dd77951d..7ba2178ac 100644 --- a/rtgui/tonecurve.h +++ b/rtgui/tonecurve.h @@ -97,6 +97,8 @@ protected: void setHistmatching(bool enabled); public: + static const Glib::ustring TOOL_NAME; + ToneCurve (); ~ToneCurve () override; diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index f489c4f63..cf2386257 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -137,7 +137,7 @@ Glib::ustring getToolTitleKey(Tool tool) case Tool::WAVELET: return "TP_WAVELET_LABEL"; case Tool::DIR_PYR_EQUALIZER: - return "TP_DIRPYRDENOISE_LABEL"; + return "TP_DIRPYREQUALIZER_LABEL"; case Tool::HSV_EQUALIZER: return "TP_HSVEQUALIZER_LABEL"; case Tool::FILM_SIMULATION: diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index f89c76b8d..7d98d0dc1 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -557,117 +557,117 @@ std::string ToolPanelCoordinator::getToolName(Tool tool) { switch (tool) { case Tool::TONE_CURVE: - return "tonecurve"; + return ToneCurve::TOOL_NAME; case Tool::SHADOWS_HIGHLIGHTS: - return "shadowshighlights"; + return ShadowsHighlights::TOOL_NAME; case Tool::IMPULSE_DENOISE: - return "impulsedenoise"; + return ImpulseDenoise::TOOL_NAME; case Tool::DEFRINGE_TOOL: - return "defringe"; + return Defringe::TOOL_NAME; case Tool::SPOT: - return "spot"; + return Spot::TOOL_NAME; case Tool::DIR_PYR_DENOISE: - return "dirpyrdenoise"; + return DirPyrDenoise::TOOL_NAME; case Tool::EPD: - return "epd"; + return EdgePreservingDecompositionUI::TOOL_NAME; case Tool::SHARPENING_TOOL: - return "sharpening"; + return Sharpening::TOOL_NAME; case Tool::LOCAL_CONTRAST: - return "localcontrast"; + return LocalContrast::TOOL_NAME; case Tool::SHARPEN_EDGE: - return "sharpenedge"; + return SharpenEdge::TOOL_NAME; case Tool::SHARPEN_MICRO: - return "sharpenmicro"; + return SharpenMicro::TOOL_NAME; case Tool::L_CURVE: - return "labcurves"; + return LCurve::TOOL_NAME; case Tool::RGB_CURVES: - return "rgbcurves"; + return RGBCurves::TOOL_NAME; case Tool::COLOR_TONING: - return "colortoning"; + return ColorToning::TOOL_NAME; case Tool::LENS_GEOM: - return "lensgeom"; + return LensGeometry::TOOL_NAME; case Tool::LENS_PROF: - return "lensprof"; + return LensProfilePanel::TOOL_NAME; case Tool::DISTORTION: - return "distortion"; + return Distortion::TOOL_NAME; case Tool::ROTATE: - return "rotate"; + return Rotate::TOOL_NAME; case Tool::VIBRANCE: - return "vibrance"; + return Vibrance::TOOL_NAME; case Tool::COLOR_APPEARANCE: - return "colorappearance"; + return ColorAppearance::TOOL_NAME; case Tool::WHITE_BALANCE: - return "whitebalance"; + return WhiteBalance::TOOL_NAME; case Tool::VIGNETTING: - return "vignetting"; + return Vignetting::TOOL_NAME; case Tool::RETINEX_TOOL: - return "retinex"; + return Retinex::TOOL_NAME; case Tool::GRADIENT: - return "gradient"; + return Gradient::TOOL_NAME; case Tool::LOCALLAB: - return "locallab"; + return Locallab::TOOL_NAME; case Tool::PC_VIGNETTE: - return "pcvignette"; + return PCVignette::TOOL_NAME; case Tool::PERSPECTIVE: - return "perspective"; + return PerspCorrection::TOOL_NAME; case Tool::CA_CORRECTION: - return "cacorrection"; + return CACorrection::TOOL_NAME; case Tool::CH_MIXER: - return "chmixer"; + return ChMixer::TOOL_NAME; case Tool::BLACK_WHITE: - return "blackwhite"; + return BlackWhite::TOOL_NAME; case Tool::RESIZE_TOOL: - return "resize"; + return Resize::TOOL_NAME; case Tool::PR_SHARPENING: - return "prsharpening"; + return PrSharpening::TOOL_NAME; case Tool::CROP_TOOL: - return "crop"; + return Crop::TOOL_NAME; case Tool::ICM: - return "icm"; + return ICMPanel::TOOL_NAME; case Tool::WAVELET: - return "wavelet"; + return Wavelet::TOOL_NAME; case Tool::DIR_PYR_EQUALIZER: - return "dirpyrdenoise"; + return DirPyrEqualizer::TOOL_NAME; case Tool::HSV_EQUALIZER: - return "hsvequalizer"; + return HSVEqualizer::TOOL_NAME; case Tool::FILM_SIMULATION: - return "filmsimulation"; + return FilmSimulation::TOOL_NAME; case Tool::SOFT_LIGHT: - return "softlight"; + return SoftLight::TOOL_NAME; case Tool::DEHAZE: - return "dehaze"; + return Dehaze::TOOL_NAME; case Tool::SENSOR_BAYER: - return "sensorbayer"; + return SensorBayer::TOOL_NAME; case Tool::SENSOR_XTRANS: - return "sensorxtrans"; + return SensorXTrans::TOOL_NAME; case Tool::BAYER_PROCESS: - return "bayerprocess"; + return BayerProcess::TOOL_NAME; case Tool::XTRANS_PROCESS: - return "xtransprocess"; + return XTransProcess::TOOL_NAME; case Tool::BAYER_PREPROCESS: - return "bayerpreprocess"; + return BayerPreProcess::TOOL_NAME; case Tool::PREPROCESS: - return "preprocess"; + return PreProcess::TOOL_NAME; case Tool::DARKFRAME_TOOL: - return "darkframe"; + return DarkFrame::TOOL_NAME; case Tool::FLATFIELD_TOOL: - return "flatfield"; + return FlatField::TOOL_NAME; case Tool::RAW_CA_CORRECTION: - return "rawcacorrection"; + return RAWCACorr::TOOL_NAME; case Tool::RAW_EXPOSURE: - return "rawexposure"; + return RAWExposure::TOOL_NAME; case Tool::PREPROCESS_WB: - return "preprocesswb"; + return PreprocessWB::TOOL_NAME; case Tool::BAYER_RAW_EXPOSURE: - return "bayerrawexposure"; + return BayerRAWExposure::TOOL_NAME; case Tool::XTRANS_RAW_EXPOSURE: - return "xtransrawexposure"; + return XTransRAWExposure::TOOL_NAME; case Tool::FATTAL: - return "fattal"; + return FattalToneMapping::TOOL_NAME; case Tool::FILM_NEGATIVE: - return "filmnegative"; + return FilmNegative::TOOL_NAME; case Tool::PD_SHARPENING: - return "capturesharpening"; + return PdSharpening::TOOL_NAME; }; assert(false); return ""; diff --git a/rtgui/vibrance.cc b/rtgui/vibrance.cc index 4a9fab3d3..f2eb8fc4e 100644 --- a/rtgui/vibrance.cc +++ b/rtgui/vibrance.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Vibrance::Vibrance () : FoldableToolPanel(this, "vibrance", M("TP_VIBRANCE_LABEL"), false, true) +const Glib::ustring Vibrance::TOOL_NAME = "vibrance"; + +Vibrance::Vibrance () : FoldableToolPanel(this, TOOL_NAME, M("TP_VIBRANCE_LABEL"), false, true) { std::vector milestones; diff --git a/rtgui/vibrance.h b/rtgui/vibrance.h index 12acc7948..ee3d029ee 100644 --- a/rtgui/vibrance.h +++ b/rtgui/vibrance.h @@ -57,6 +57,7 @@ protected: sigc::connection pastsattogconn; public: + static const Glib::ustring TOOL_NAME; Vibrance (); ~Vibrance () override; diff --git a/rtgui/vignetting.cc b/rtgui/vignetting.cc index 04a350b99..c2652de42 100644 --- a/rtgui/vignetting.cc +++ b/rtgui/vignetting.cc @@ -23,7 +23,9 @@ using namespace rtengine; using namespace rtengine::procparams; -Vignetting::Vignetting () : FoldableToolPanel(this, "vignetting", M("TP_VIGNETTING_LABEL")) +const Glib::ustring Vignetting::TOOL_NAME = "vignetting"; + +Vignetting::Vignetting () : FoldableToolPanel(this, TOOL_NAME, M("TP_VIGNETTING_LABEL")) { amount = Gtk::manage (new Adjuster (M("TP_VIGNETTING_AMOUNT"), -100, 100, 1, 0)); diff --git a/rtgui/vignetting.h b/rtgui/vignetting.h index be7765094..bcb7f9d19 100644 --- a/rtgui/vignetting.h +++ b/rtgui/vignetting.h @@ -37,6 +37,7 @@ protected: Adjuster* centerY; public: + static const Glib::ustring TOOL_NAME; Vignetting (); diff --git a/rtgui/wavelet.cc b/rtgui/wavelet.cc index f14dd8c8c..e9ee19335 100644 --- a/rtgui/wavelet.cc +++ b/rtgui/wavelet.cc @@ -34,6 +34,8 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring Wavelet::TOOL_NAME = "wavelet"; + namespace { @@ -62,7 +64,7 @@ std::vector makeWholeHueRange() } Wavelet::Wavelet() : - FoldableToolPanel(this, "wavelet", M("TP_WAVELET_LABEL"), true, true), + FoldableToolPanel(this, TOOL_NAME, M("TP_WAVELET_LABEL"), true, true), curveEditorG(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_CONTEDIT"))), curveEditorC(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_CONTRASTEDIT"))), CCWcurveEditorG(new CurveEditorGroup(options.lastWaveletCurvesDir, M("TP_WAVELET_CCURVE"))), diff --git a/rtgui/wavelet.h b/rtgui/wavelet.h index bdbf7bbc3..eee9af91c 100644 --- a/rtgui/wavelet.h +++ b/rtgui/wavelet.h @@ -45,6 +45,8 @@ class Wavelet final : public FoldableToolPanel { public: + static const Glib::ustring TOOL_NAME; + Wavelet(); ~Wavelet() override; bool wavComputed_(); diff --git a/rtgui/whitebalance.cc b/rtgui/whitebalance.cc index fbcf40faf..f6a26e335 100644 --- a/rtgui/whitebalance.cc +++ b/rtgui/whitebalance.cc @@ -34,6 +34,8 @@ using namespace rtengine; using namespace rtengine::procparams; +const Glib::ustring WhiteBalance::TOOL_NAME = "whitebalance"; + Glib::RefPtr WhiteBalance::wbPixbufs[toUnderlying(WBEntry::Type::CUSTOM) + 1]; void WhiteBalance::init () @@ -142,7 +144,7 @@ static double wbTemp2Slider(double temp) return sval; } -WhiteBalance::WhiteBalance () : FoldableToolPanel(this, "whitebalance", M("TP_WBALANCE_LABEL"), true, true), wbp(nullptr), wblistener(nullptr) +WhiteBalance::WhiteBalance () : FoldableToolPanel(this, TOOL_NAME, M("TP_WBALANCE_LABEL"), true, true), wbp(nullptr), wblistener(nullptr) { Gtk::Grid* methodgrid = Gtk::manage(new Gtk::Grid()); diff --git a/rtgui/whitebalance.h b/rtgui/whitebalance.h index 1ed99a2aa..f172590c8 100644 --- a/rtgui/whitebalance.h +++ b/rtgui/whitebalance.h @@ -98,6 +98,7 @@ protected: std::pair findWBEntry (const Glib::ustring& label, enum WB_LabelType lblType = WBLT_GUI); public: + static const Glib::ustring TOOL_NAME; WhiteBalance (); ~WhiteBalance () override; diff --git a/rtgui/xtransprocess.cc b/rtgui/xtransprocess.cc index 89fd0f8a4..d6850da63 100644 --- a/rtgui/xtransprocess.cc +++ b/rtgui/xtransprocess.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP_RAW_LABEL"), options.prevdemo != PD_Sidecar) +const Glib::ustring XTransProcess::TOOL_NAME = "xtransprocess"; + +XTransProcess::XTransProcess () : FoldableToolPanel(this, TOOL_NAME, M("TP_RAW_LABEL"), options.prevdemo != PD_Sidecar) { auto m = ProcEventMapper::getInstance(); EvDemosaicBorder = m->newEvent(DEMOSAIC, "HISTORY_MSG_RAW_BORDER"); diff --git a/rtgui/xtransprocess.h b/rtgui/xtransprocess.h index 4725f4a6d..6639a3796 100644 --- a/rtgui/xtransprocess.h +++ b/rtgui/xtransprocess.h @@ -52,6 +52,7 @@ protected: rtengine::ProcEvent EvDemosaicContrast; public: + static const Glib::ustring TOOL_NAME; XTransProcess (); ~XTransProcess () override; diff --git a/rtgui/xtransrawexposure.cc b/rtgui/xtransrawexposure.cc index e1b56b9f0..2e26b8f63 100644 --- a/rtgui/xtransrawexposure.cc +++ b/rtgui/xtransrawexposure.cc @@ -27,7 +27,9 @@ using namespace rtengine; using namespace rtengine::procparams; -XTransRAWExposure::XTransRAWExposure () : FoldableToolPanel(this, "xtransrawexposure", M("TP_EXPOS_BLACKPOINT_LABEL")) +const Glib::ustring XTransRAWExposure::TOOL_NAME = "xtransrawexposure"; + +XTransRAWExposure::XTransRAWExposure () : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOS_BLACKPOINT_LABEL")) { PexBlackRed = Gtk::manage(new Adjuster (M("TP_RAWEXPOS_BLACK_RED"), -2048, 2048, 1.0, 0)); //black level PexBlackRed->setAdjusterListener (this); diff --git a/rtgui/xtransrawexposure.h b/rtgui/xtransrawexposure.h index a8daf6972..c332bc510 100644 --- a/rtgui/xtransrawexposure.h +++ b/rtgui/xtransrawexposure.h @@ -37,6 +37,7 @@ protected: private: // Gtk::CheckButton* PextwoGreen; public: + static const Glib::ustring TOOL_NAME; XTransRAWExposure (); From 697af1fcb3d2c4d742fa03a60c7902d888853b10 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 12 Dec 2021 16:27:43 -0800 Subject: [PATCH 037/134] Fix tool location updater optimization --- rtgui/toolpanelcoord.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 7d98d0dc1..df28ca21f 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -828,6 +828,7 @@ ToolPanelCoordinator::updateToolPanel( getFoldableToolPanel(*new_tool_trees_iter)->getExpander()) { break; } + ++new_tool_trees_iter; ++old_widgets_iter; } From 901f4e4f6340b84b5c68d43dfb37028e1818bc25 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 12 Dec 2021 17:09:01 -0800 Subject: [PATCH 038/134] Fix memory leak --- rtgui/toolpanelcoord.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index df28ca21f..592c4c97e 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -884,6 +884,17 @@ ToolPanelCoordinator::~ToolPanelCoordinator () // which is responsible of segfault if listener isn't deactivated before notebookconn.block(true); + // Foldable tool panels manage (Gtk::manage) their expanders. Each expander + // will only be automatically deleted if attached to a parent and the parent + // is deleted. This is a hack in lieu of a potentially tedious refactoring + // of FoldableToolPanel. + std::unique_ptr hidden_tool_panel_parent(new Gtk::Box()); + for (const auto expander : expList) { + if (!expander->get_parent()) { + hidden_tool_panel_parent->add(*expander); + } + } + delete toolPanelNotebook; delete toolBar; } From d29b451aa643022f54ffebf14fadfe7a514c03e7 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 12 Dec 2021 17:09:53 -0800 Subject: [PATCH 039/134] Hide local adjustments from batch process favorite --- rtgui/toolpanelcoord.cc | 7 ++++--- rtgui/toolpanelcoord.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 592c4c97e..360aca7a0 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -271,7 +271,7 @@ const ToolPanelCoordinator::ToolLayout PANEL_TOOLS = { std::unordered_map ToolPanelCoordinator::toolNamesReverseMap; -ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favoritePanelSW(nullptr), hasChanged (false), editDataProvider (nullptr), photoLoadedOnce(false) +ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favoritePanelSW(nullptr), hasChanged (false), batch(batch), editDataProvider (nullptr), photoLoadedOnce(false) { favoritePanel = Gtk::manage (new ToolVBox ()); @@ -812,8 +812,9 @@ ToolPanelCoordinator::updateToolPanel( // if they are sub-tools within the favorites panel, or if tool cloning is // off and they are not within the favorites panel. const auto should_skip_tool = - [skip_favorites, &favorites](const ToolTree &tool_tree) { - return skip_favorites && favorites.count(tool_tree.id); + [this, skip_favorites, &favorites](const ToolTree &tool_tree) { + return (skip_favorites && favorites.count(tool_tree.id)) || + (batch && tool_tree.id == Tool::LOCALLAB); }; // Keep tools that are already correct. diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index cd354738e..fda89ef37 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -212,6 +212,7 @@ protected: std::vector expList; bool hasChanged; + bool batch; void addPanel(Gtk::Box* where, FoldableToolPanel* panel, int level = 1); void foldThemAll(GdkEventButton* event); From 012103b4e2d8aa0dba38dc5ccdd4ea668e20198c Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 12 Dec 2021 17:50:12 -0800 Subject: [PATCH 040/134] Fix update of tool locations after changing pref Only the editor panel in single editor mode was being updated. This commit makes them update in multiple editor mode and also updates the batch editor. --- rtgui/editwindow.cc | 8 ++++++++ rtgui/editwindow.h | 2 ++ rtgui/filepanel.cc | 8 ++++++++ rtgui/filepanel.h | 2 ++ rtgui/rtwindow.cc | 13 +++++++++++++ 5 files changed, 33 insertions(+) diff --git a/rtgui/editwindow.cc b/rtgui/editwindow.cc index d0e53d730..4ba1b369a 100644 --- a/rtgui/editwindow.cc +++ b/rtgui/editwindow.cc @@ -485,3 +485,11 @@ void EditWindow::set_title_decorated(Glib::ustring fname) set_title("RawTherapee " + M("EDITWINDOW_TITLE") + subtitle); } + +void EditWindow::updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools) +{ + for (const auto& panel : epanels) { + panel.second->updateToolPanelToolLocations(favorites, cloneFavoriteTools); + } +} diff --git a/rtgui/editwindow.h b/rtgui/editwindow.h index b8eeaee82..b9304c5af 100644 --- a/rtgui/editwindow.h +++ b/rtgui/editwindow.h @@ -64,6 +64,8 @@ public: bool selectEditorPanel(const std::string &name); bool closeOpenEditors(); bool isProcessing(); + void updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools); void toFront(); bool keyPressed (GdkEventKey* event); diff --git a/rtgui/filepanel.cc b/rtgui/filepanel.cc index 682dd1746..63ebd5632 100644 --- a/rtgui/filepanel.cc +++ b/rtgui/filepanel.cc @@ -436,3 +436,11 @@ void FilePanel::updateTPVScrollbar (bool hide) { tpc->updateTPVScrollbar (hide); } + +void FilePanel::updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools) +{ + if (tpc) { + tpc->updateToolLocations(favorites, cloneFavoriteTools); + } +} diff --git a/rtgui/filepanel.h b/rtgui/filepanel.h index ba5dfa7c9..4a006f002 100644 --- a/rtgui/filepanel.h +++ b/rtgui/filepanel.h @@ -83,6 +83,8 @@ public: bool handleShortcutKey (GdkEventKey* event); bool handleShortcutKeyRelease(GdkEventKey *event); void updateTPVScrollbar (bool hide); + void updateToolPanelToolLocations( + const std::vector &favorites, bool cloneFavoriteTools); private: void on_NB_switch_page(Gtk::Widget* page, guint page_num); diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc index f3eb658e5..8dfb18b12 100755 --- a/rtgui/rtwindow.cc +++ b/rtgui/rtwindow.cc @@ -1113,9 +1113,22 @@ void RTWindow::updateHistogramPosition (int oldPosition, int newPosition) void RTWindow::updateToolPanelToolLocations( const std::vector &favorites, bool cloneFavoriteTools) { + if (fpanel) { + fpanel->updateToolPanelToolLocations(favorites, cloneFavoriteTools); + } + if (epanel) { epanel->updateToolPanelToolLocations(favorites, cloneFavoriteTools); } + + for (const auto &panel : epanels) { + panel.second->updateToolPanelToolLocations(favorites, cloneFavoriteTools); + } + + if (options.multiDisplayMode > 0) { + EditWindow::getInstance(this) + ->updateToolPanelToolLocations(favorites, cloneFavoriteTools); + } } bool RTWindow::splashClosed (GdkEventAny* event) From a7010d25cd88ce15b558d3c20fb61868798e555d Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 19 Dec 2021 14:51:47 -0800 Subject: [PATCH 041/134] Fix theme margins Fix spacing that was changed due to the restructuring of foldable tool panels. --- .../themes/RawTherapee - Legacy-GTK3-20_.css | 31 ++++++++++++++--- rtdata/themes/RawTherapee-GTK3-20_.css | 27 +++++++++++++++ rtdata/themes/TooWaBlue-GTK3-20_.css | 3 ++ rtgui/lensgeom.cc | 3 -- rtgui/lensgeom.h | 6 ---- rtgui/resize.cc | 10 +++--- rtgui/resize.h | 6 ---- rtgui/sensorbayer.cc | 3 -- rtgui/sensorbayer.h | 8 ----- rtgui/sensorxtrans.cc | 3 -- rtgui/sensorxtrans.h | 8 ----- rtgui/toolpanel.cc | 6 ++-- rtgui/toolpanel.h | 6 ++-- rtgui/toolpanelcoord.cc | 33 ++++++++++--------- 14 files changed, 85 insertions(+), 68 deletions(-) diff --git a/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css b/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css index dd7be3bfd..07a0bd65d 100644 --- a/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css +++ b/rtdata/themes/RawTherapee - Legacy-GTK3-20_.css @@ -760,6 +760,23 @@ button.radio#histButton:hover { margin-right: 0.25em; } +/* ExpanderContents is just a logical container. Don't add additional spacing. */ +#ExpanderBox > .ExpanderContents > * { + margin: 0; + min-height: 0; + padding: 0; +} + +/* For sub-tools containers that go below another widget, add some margin + * between them if the container has children. */ +#MyExpander .SubToolsContainer:not(:first-child) > :first-child { + margin-top: 0.1666666666666666em; +} + +#MyExpander .SubToolsContainer { + min-height: 0; +} + /* Tool background */ #ExpanderBox > box, #ExpanderBox > grid { background-color: #363636; @@ -808,9 +825,11 @@ button.radio#histButton:hover { } #LocallabToolPanel > box > checkbutton, #LocallabToolPanel > box > box, #LocallabToolPanel > grid > checkbutton, #LocallabToolPanel > box > grid, #LocallabToolPanel > grid > grid, #LocallabToolPanel frame > box > grid, #LocallabToolPanel frame > grid > grid, #LocallabToolPanel frame > grid > box, -#ExpanderBox > box > checkbutton, #ExpanderBox > box > box, #ExpanderBox > grid > checkbutton, #ExpanderBox > box > grid, #ExpanderBox > grid > grid, #ExpanderBox frame > box > grid, #ExpanderBox frame > grid > grid, #ExpanderBox frame > grid > box, -#ExpanderBox2 > box > checkbutton, #ExpanderBox2 > box > box, #ExpanderBox2 > grid > checkbutton, #ExpanderBox2 > box > grid, #ExpanderBox2 > grid > grid, #ExpanderBox2 frame > box > grid, #ExpanderBox2 frame > grid > grid, #ExpanderBox2 frame > grid > box, -#ExpanderBox3 > box > checkbutton, #ExpanderBox3 > box > box, #ExpanderBox3 > grid > checkbutton, #ExpanderBox3 > box > grid, #ExpanderBox3 > grid > grid, #ExpanderBox3 frame > box > grid, #ExpanderBox3 frame > grid > grid, #ExpanderBox3 frame > grid > box { +#ExpanderBox > .ExpanderContents > box:not(.SubToolsContainer) > checkbutton, #ExpanderBox > .ExpanderContents > box:not(.SubToolsContainer) > box, #ExpanderBox > .ExpanderContents > grid > checkbutton, #ExpanderBox > .ExpanderContents > box:not(.SubToolsContainer) > grid, #ExpanderBox > .ExpanderContents > grid > grid, #ExpanderBox frame > box > grid, #ExpanderBox frame > grid > grid, #ExpanderBox frame > grid > box, +#ExpanderBox2 > .ExpanderContents > box:not(.SubToolsContainer) > checkbutton, #ExpanderBox2 > .ExpanderContents > box:not(.SubToolsContainer) > box, #ExpanderBox2 > .ExpanderContents > grid > checkbutton, #ExpanderBox2 > .ExpanderContents > box:not(.SubToolsContainer) > grid, #ExpanderBox2 > .ExpanderContents > grid > grid, #ExpanderBox2 frame > box > grid, #ExpanderBox2 frame > grid > grid, #ExpanderBox2 frame > grid > box, +#ExpanderBox2 > box:not(.ExpanderContents) > checkbutton, #ExpanderBox2 > box:not(.ExpanderContents) > box, #ExpanderBox2 > grid > checkbutton, #ExpanderBox2 > box:not(.ExpanderContents) > grid, #ExpanderBox2 > grid > grid, #ExpanderBox2 frame > box > grid, #ExpanderBox2 frame > grid > grid, #ExpanderBox2 frame > grid > box, +#ExpanderBox3 > .ExpanderContents > box:not(.SubToolsContainer) > checkbutton, #ExpanderBox3 > .ExpanderContents > box:not(.SubToolsContainer) > box, #ExpanderBox3 > .ExpanderContents > grid > checkbutton, #ExpanderBox3 > .ExpanderContents > box:not(.SubToolsContainer) > grid, #ExpanderBox3 > .ExpanderContents > grid > grid, #ExpanderBox3 frame > box > grid, #ExpanderBox3 frame > grid > grid, #ExpanderBox3 frame > grid > box, +#ExpanderBox3 > box:not(.ExpanderContents) > checkbutton, #ExpanderBox3 > box:not(.ExpanderContents) > box, #ExpanderBox3 > grid > checkbutton, #ExpanderBox3 > box:not(.ExpanderContents) > grid, #ExpanderBox3 > grid > grid, #ExpanderBox3 frame > box > grid, #ExpanderBox3 frame > grid > grid, #ExpanderBox3 frame > grid > box { margin-top: 0.1666666666666666em; } @@ -1099,6 +1118,10 @@ dialog frame > label:not(.dummy) { min-width: 25em; } +#ToolPanelNotebook .PanelEnding { + margin-top: 4px; +} + #ToolPanelNotebook header { background-color: #383838; border-color: #262626; @@ -1395,4 +1418,4 @@ progressbar progress { .grid-spacing > * { margin: 0.1666666666666666em; -} \ No newline at end of file +} diff --git a/rtdata/themes/RawTherapee-GTK3-20_.css b/rtdata/themes/RawTherapee-GTK3-20_.css index c576e0ddf..2e314510a 100644 --- a/rtdata/themes/RawTherapee-GTK3-20_.css +++ b/rtdata/themes/RawTherapee-GTK3-20_.css @@ -766,6 +766,29 @@ button.radio#histButton:hover { border-bottom: none; } +/* ExpanderContents is just a logical container. Don't add additional spacing. */ +#ExpanderBox > .ExpanderContents > * { + margin: 0; + min-height: 0; + padding: 0; +} + +/* For sub-tools containers that go below another widget, add some margin + * between them if the container has children. */ +#MyExpander .SubToolsContainer:not(:first-child) > :first-child { + margin-top: 0.3333333333333333em; +} + +#MyExpander .SubToolsContainer { + min-height: 0; +} + +.SubToolsContainer > #MyExpander, +.ToolParamBlock > #MyExpander, +.ExpanderContents, +#MyExpander .ToolParamBlock { + margin: 0; +} /* Tool background */ #ExpanderBox > box, @@ -1046,6 +1069,10 @@ dialog frame > label:not(.dummy) { padding: 0; } +#ToolPanelNotebook .PanelEnding { + margin-top: 4px; +} + #ToolPanelNotebook header tabs { padding: 0.0833333333333333em; background-color: #2A2A2A; diff --git a/rtdata/themes/TooWaBlue-GTK3-20_.css b/rtdata/themes/TooWaBlue-GTK3-20_.css index 4e7e192ad..2e9c6ccde 100644 --- a/rtdata/themes/TooWaBlue-GTK3-20_.css +++ b/rtdata/themes/TooWaBlue-GTK3-20_.css @@ -963,6 +963,9 @@ window.csd:not(.fullscreen) #MainNotebook > header.top { #ToolPanelNotebook { background-color: @bg-dark-grey; } +#ToolPanelNotebook .PanelEnding { + margin-top: 4px; +} #ToolPanelNotebook > header { border-bottom: 0.083333333333333333em solid @view-grid-border; margin-left: 0.083333333333333333em; diff --git a/rtgui/lensgeom.cc b/rtgui/lensgeom.cc index 6b9d70fb0..e8febf8e2 100644 --- a/rtgui/lensgeom.cc +++ b/rtgui/lensgeom.cc @@ -52,9 +52,6 @@ LensGeometry::LensGeometry () : FoldableToolPanel(this, TOOL_NAME, M("TP_LENSGEO autoCrop->get_style_context()->add_class("independent"); pack_start (*autoCrop, Gtk::PACK_SHRINK, 2); - packBox = Gtk::manage (new ToolParamBlock ()); - pack_start (*packBox); - method->connect(method->signal_changed().connect(sigc::mem_fun(*this, &LensGeometry::methodChanged))); autoCrop->signal_pressed().connect(sigc::mem_fun(*this, &LensGeometry::autoCropPressed)); fillConn = fill->signal_toggled().connect(sigc::mem_fun(*this, &LensGeometry::fillPressed)); diff --git a/rtgui/lensgeom.h b/rtgui/lensgeom.h index e8f85faac..fa260e177 100644 --- a/rtgui/lensgeom.h +++ b/rtgui/lensgeom.h @@ -35,7 +35,6 @@ protected: Gtk::CheckButton* fill; bool lastFill; sigc::connection fillConn; - ToolParamBlock* packBox; rtengine::ProcEvent EvTransMethod; public: @@ -44,11 +43,6 @@ public: LensGeometry (); ~LensGeometry () override; - Gtk::Box* getPackBox () - { - return packBox; - } - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; void setBatchMode (bool batchMode) override; diff --git a/rtgui/resize.cc b/rtgui/resize.cc index 258ccf791..de9f6b4d1 100644 --- a/rtgui/resize.cc +++ b/rtgui/resize.cc @@ -172,10 +172,8 @@ Resize::Resize () : FoldableToolPanel(this, TOOL_NAME, M("TP_RESIZE_LABEL"), fal method->signal_changed().connect ( sigc::mem_fun(*this, &Resize::methodChanged) ); sconn = spec->signal_changed().connect ( sigc::mem_fun(*this, &Resize::specChanged) ); - packBox = Gtk::manage (new ToolParamBlock ()); - pack_end (*packBox); - packBox->hide(); - packBox->set_tooltip_markup (M("TP_PRSHARPENING_TOOLTIP")); + getSubToolsContainer()->hide(); + getSubToolsContainer()->set_tooltip_markup (M("TP_PRSHARPENING_TOOLTIP")); show_all(); } @@ -398,9 +396,9 @@ void Resize::methodChanged () // Post-resize Sharpening assumes the image is in Lab space, and currently Lanczos is the only method which uses that space, and Lanczos is on row 0. if (method->get_active_row_number() == 0) { - packBox->set_sensitive(true); + getSubToolsContainer()->set_sensitive(true); } else { - packBox->set_sensitive(false); + getSubToolsContainer()->set_sensitive(false); } } diff --git a/rtgui/resize.h b/rtgui/resize.h index 71fefb503..674bbb34f 100644 --- a/rtgui/resize.h +++ b/rtgui/resize.h @@ -37,11 +37,6 @@ public: Resize (); ~Resize () override; - Gtk::Box* getPackBox () - { - return packBox; - } - void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override; void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override; void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override; @@ -89,7 +84,6 @@ private: int cropw, croph; sigc::connection sconn, aconn, wconn, hconn, leconn, seconn; bool wDirty, hDirty, leDirty, seDirty; - ToolParamBlock* packBox; IdleRegister idle_register; static constexpr int MAX_SCALE = 16; // 16 to match the main preview max scale of 1600% diff --git a/rtgui/sensorbayer.cc b/rtgui/sensorbayer.cc index 002cdf1de..70537f666 100644 --- a/rtgui/sensorbayer.cc +++ b/rtgui/sensorbayer.cc @@ -25,8 +25,5 @@ const Glib::ustring SensorBayer::TOOL_NAME = "sensorbayer"; SensorBayer::SensorBayer () : FoldableToolPanel(this, TOOL_NAME, M("TP_RAW_SENSOR_BAYER_LABEL")) { - packBox = Gtk::manage (new ToolParamBlock ()); - pack_start (*packBox); - show_all (); } diff --git a/rtgui/sensorbayer.h b/rtgui/sensorbayer.h index 0e65b8b38..d3d867ace 100644 --- a/rtgui/sensorbayer.h +++ b/rtgui/sensorbayer.h @@ -27,16 +27,8 @@ class SensorBayer final : public FoldableToolPanel { -protected: - ToolParamBlock* packBox; - public: static const Glib::ustring TOOL_NAME; SensorBayer (); - - Gtk::Box* getPackBox () - { - return packBox; - } }; diff --git a/rtgui/sensorxtrans.cc b/rtgui/sensorxtrans.cc index c4a5bf76d..45e5d57e4 100644 --- a/rtgui/sensorxtrans.cc +++ b/rtgui/sensorxtrans.cc @@ -25,8 +25,5 @@ const Glib::ustring SensorXTrans::TOOL_NAME = "sensorxtrans"; SensorXTrans::SensorXTrans () : FoldableToolPanel(this, TOOL_NAME, M("TP_RAW_SENSOR_XTRANS_LABEL")) { - packBox = Gtk::manage (new ToolParamBlock ()); - pack_start (*packBox); - show_all (); } diff --git a/rtgui/sensorxtrans.h b/rtgui/sensorxtrans.h index 12c851db3..2e5c10483 100644 --- a/rtgui/sensorxtrans.h +++ b/rtgui/sensorxtrans.h @@ -27,16 +27,8 @@ class SensorXTrans final: public FoldableToolPanel { -protected: - ToolParamBlock* packBox; - public: static const Glib::ustring TOOL_NAME; SensorXTrans (); - - Gtk::Box* getPackBox () - { - return packBox; - } }; diff --git a/rtgui/toolpanel.cc b/rtgui/toolpanel.cc index bf191133d..6db30bb14 100644 --- a/rtgui/toolpanel.cc +++ b/rtgui/toolpanel.cc @@ -38,6 +38,7 @@ ToolVBox::ToolVBox() { ToolParamBlock::ToolParamBlock() { set_orientation(Gtk::ORIENTATION_VERTICAL); + get_style_context()->add_class("ToolParamBlock"); //GTK318 #if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION < 20 set_spacing(2); // Vertical space between parameters in a single tool @@ -75,8 +76,9 @@ FoldableToolPanel::FoldableToolPanel(Gtk::Box* content, Glib::ustring toolName, Gtk::Box *expanderContents = Gtk::manage( new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); - subToolsContainer = Gtk::manage( - new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); + subToolsContainer = Gtk::manage(new ToolParamBlock()); + subToolsContainer->get_style_context()->add_class("SubToolsContainer"); + expanderContents->get_style_context()->add_class("ExpanderContents"); expanderContents->pack_start(*content, false, false, 0); expanderContents->pack_start(*subToolsContainer, false, false, 0); diff --git a/rtgui/toolpanel.h b/rtgui/toolpanel.h index ce14dc64f..5ec59c9c2 100644 --- a/rtgui/toolpanel.h +++ b/rtgui/toolpanel.h @@ -98,7 +98,7 @@ public: { return nullptr; } - virtual Gtk::Box *getSubToolsContainer() const + virtual ToolParamBlock *getSubToolsContainer() const { return nullptr; } @@ -168,7 +168,7 @@ class FoldableToolPanel : protected: Gtk::Box* parentContainer; MyExpander* exp; - Gtk::Box *subToolsContainer; + ToolParamBlock *subToolsContainer; bool lastEnabled; sigc::connection enaConn; void foldThemAll (GdkEventButton* event); @@ -183,7 +183,7 @@ public: return exp; } - Gtk::Box *getSubToolsContainer() const final + ToolParamBlock *getSubToolsContainer() const final { return subToolsContainer; } diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 360aca7a0..cd04583c9 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -400,6 +400,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit vbPanelEnd[i] = Gtk::manage (new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); imgPanelEnd[i] = Gtk::manage (new RTImage ("ornament1.png")); imgPanelEnd[i]->show(); + vbPanelEnd[i]->get_style_context()->add_class("PanelEnding"); vbPanelEnd[i]->pack_start(*imgPanelEnd[i], Gtk::PACK_SHRINK); vbPanelEnd[i]->show_all(); } @@ -423,37 +424,37 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit Gtk::manage(new Gtk::Box(Gtk::Orientation::ORIENTATION_VERTICAL)); favoritePanelSW->add(*favoritePanelContainer); - favoritePanelContainer->pack_start(*favoritePanel, Gtk::PACK_SHRINK, 0); - favoritePanelContainer->pack_start(*vbPanelEnd[0], Gtk::PACK_SHRINK, 4); + favoritePanelContainer->pack_start(*favoritePanel, Gtk::PACK_SHRINK); + favoritePanelContainer->pack_start(*vbPanelEnd[0], Gtk::PACK_SHRINK); favoritePanelSW->show_all(); exposurePanelSW->add (*exposurePanelContainer); - exposurePanelContainer->pack_start(*exposurePanel, Gtk::PACK_SHRINK, 0); - exposurePanelContainer->pack_start (*vbPanelEnd[1], Gtk::PACK_SHRINK, 4); + exposurePanelContainer->pack_start(*exposurePanel, Gtk::PACK_SHRINK); + exposurePanelContainer->pack_start (*vbPanelEnd[1], Gtk::PACK_SHRINK); detailsPanelSW->add (*detailsPanelContainer); - detailsPanelContainer->pack_start(*detailsPanel, Gtk::PACK_SHRINK, 0); - detailsPanelContainer->pack_start (*vbPanelEnd[2], Gtk::PACK_SHRINK, 4); + detailsPanelContainer->pack_start(*detailsPanel, Gtk::PACK_SHRINK); + detailsPanelContainer->pack_start (*vbPanelEnd[2], Gtk::PACK_SHRINK); colorPanelSW->add (*colorPanelContainer); - colorPanelContainer->pack_start(*colorPanel, Gtk::PACK_SHRINK, 0); - colorPanelContainer->pack_start (*vbPanelEnd[3], Gtk::PACK_SHRINK, 4); + colorPanelContainer->pack_start(*colorPanel, Gtk::PACK_SHRINK); + colorPanelContainer->pack_start (*vbPanelEnd[3], Gtk::PACK_SHRINK); advancedPanelSW->add (*advancedPanelContainer); - advancedPanelContainer->pack_start(*advancedPanel, Gtk::PACK_SHRINK, 0); - advancedPanelContainer->pack_start (*vbPanelEnd[6], Gtk::PACK_SHRINK, 0); + advancedPanelContainer->pack_start(*advancedPanel, Gtk::PACK_SHRINK); + advancedPanelContainer->pack_start (*vbPanelEnd[6], Gtk::PACK_SHRINK); locallabPanelSW->add(*locallabPanelContainer); - locallabPanelContainer->pack_start(*locallabPanel, Gtk::PACK_SHRINK, 0); - locallabPanelContainer->pack_start(*vbPanelEnd[7], Gtk::PACK_SHRINK, 4); + locallabPanelContainer->pack_start(*locallabPanel, Gtk::PACK_SHRINK); + locallabPanelContainer->pack_start(*vbPanelEnd[7], Gtk::PACK_SHRINK); transformPanelSW->add (*transformPanelContainer); - transformPanelContainer->pack_start(*transformPanel, Gtk::PACK_SHRINK, 0); - transformPanelContainer->pack_start (*vbPanelEnd[4], Gtk::PACK_SHRINK, 4); + transformPanelContainer->pack_start(*transformPanel, Gtk::PACK_SHRINK); + transformPanelContainer->pack_start (*vbPanelEnd[4], Gtk::PACK_SHRINK); rawPanelSW->add (*rawPanelContainer); - rawPanelContainer->pack_start(*rawPanel, Gtk::PACK_SHRINK, 0); - rawPanelContainer->pack_start (*vbPanelEnd[5], Gtk::PACK_SHRINK, 0); + rawPanelContainer->pack_start(*rawPanel, Gtk::PACK_SHRINK); + rawPanelContainer->pack_start (*vbPanelEnd[5], Gtk::PACK_SHRINK); toiF.reset(new TextOrIcon ("star.png", M ("MAIN_TAB_FAVORITES"), M ("MAIN_TAB_FAVORITES_TOOLTIP"))); toiE = Gtk::manage (new TextOrIcon ("exposure.png", M ("MAIN_TAB_EXPOSURE"), M ("MAIN_TAB_EXPOSURE_TOOLTIP"))); From 6a0067d7387365fc094ed66a698b46b771e84c34 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 24 Dec 2021 16:03:58 -0800 Subject: [PATCH 042/134] Disable favorite tool cloning by default Also add tooltip stating that tool cloning may cause a delay while switching between tabs. --- rtdata/languages/default | 1 + rtgui/options.cc | 2 +- rtgui/toollocationpref.cc | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index bd65781a8..d409c4393 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1902,6 +1902,7 @@ PREFERENCES_THUMBNAIL_INSPECTOR_RAW;Neutral raw rendering PREFERENCES_THUMBNAIL_INSPECTOR_RAW_IF_NO_JPEG_FULLSIZE;Embedded JPEG if fullsize, neutral raw otherwise PREFERENCES_TOOLPANEL_AVAILABLETOOLS;Available Tools PREFERENCES_TOOLPANEL_CLONE_FAVORITES;Keep favorite tools in original locations +PREFERENCES_TOOLPANEL_CLONE_FAVORITES_TOOLTIP;If set, favorite tools will appear in both the favorites tab and their original tabs.\n\nNote: Enabling this option may result in a slight delay when switching tabs. PREFERENCES_TOOLPANEL_FAVORITE;Favorite PREFERENCES_TOOLPANEL_FAVORITESPANEL;Favorites Panel PREFERENCES_TOOLPANEL_TOOL;Tool diff --git a/rtgui/options.cc b/rtgui/options.cc index b5463949a..f597d3a1c 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -424,7 +424,7 @@ void Options::setDefaults() //crvOpen.clear (); parseExtensions.clear(); favorites.clear(); - cloneFavoriteTools = true; + cloneFavoriteTools = false; parseExtensionsEnabled.clear(); parsedExtensions.clear(); parsedExtensionsSet.clear(); diff --git a/rtgui/toollocationpref.cc b/rtgui/toollocationpref.cc index cf2386257..cf25dbc34 100644 --- a/rtgui/toollocationpref.cc +++ b/rtgui/toollocationpref.cc @@ -532,6 +532,8 @@ ToolLocationPreference::Impl::Impl(Options &options) : // General options. cloneFavoriteToolsToggleWidget->set_active(options.cloneFavoriteTools); + cloneFavoriteToolsToggleWidget->set_tooltip_text( + M("PREFERENCES_TOOLPANEL_CLONE_FAVORITES_TOOLTIP")); // Tool list. toolListViewPtr->append_column(toolListViewColumnToolName); From 58f0783561d1244edfcd6413b4d8b9d8df98c95e Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 5 Mar 2022 18:26:52 -0800 Subject: [PATCH 043/134] Allow selecting file as external editor --- rtdata/languages/default | 2 + rtgui/externaleditorpreferences.cc | 71 ++++++++++++++++++++++++++++++ rtgui/externaleditorpreferences.h | 19 ++++++++ 3 files changed, 92 insertions(+) diff --git a/rtdata/languages/default b/rtdata/languages/default index 538c25b00..4d80f56a9 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -208,6 +208,7 @@ FILEBROWSER_ZOOMOUTHINT;Decrease thumbnail size.\n\nShortcuts:\n- - Multi FILECHOOSER_FILTER_ANY;All files FILECHOOSER_FILTER_COLPROF;Color profiles (*.icc) FILECHOOSER_FILTER_CURVE;Curve files +FILECHOOSER_FILTER_EXECUTABLE;Executable files FILECHOOSER_FILTER_LCP;Lens correction profiles FILECHOOSER_FILTER_PP;Processing profiles FILECHOOSER_FILTER_SAME;Same format as current photo @@ -1782,6 +1783,7 @@ PREFERENCES_EDITORCMDLINE;Custom command line PREFERENCES_EDITORLAYOUT;Editor layout 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_EXTEDITOR_DIR;Output directory diff --git a/rtgui/externaleditorpreferences.cc b/rtgui/externaleditorpreferences.cc index 61bf8dc3a..c6ee9b93e 100644 --- a/rtgui/externaleditorpreferences.cc +++ b/rtgui/externaleditorpreferences.cc @@ -18,6 +18,11 @@ */ #include +#include +#include +#include +#include + #include "externaleditorpreferences.h" #include "multilangmgr.h" #include "rtimage.h" @@ -54,11 +59,14 @@ ExternalEditorPreferences::ExternalEditorPreferences(): button_add->set_image(*add_image); button_remove->set_image(*remove_image); button_app_chooser = Gtk::make_managed(M("PREFERENCES_EXTERNALEDITOR_CHANGE")); + button_file_chooser = Gtk::manage(new Gtk::Button(M("PREFERENCES_EXTERNALEDITOR_CHANGE_FILE"))); button_app_chooser->signal_pressed().connect(sigc::mem_fun( *this, &ExternalEditorPreferences::openAppChooserDialog)); button_add->signal_pressed().connect(sigc::mem_fun( *this, &ExternalEditorPreferences::addEditor)); + button_file_chooser->signal_pressed().connect(sigc::mem_fun( + *this, &ExternalEditorPreferences::openFileChooserDialog)); button_remove->signal_pressed().connect(sigc::mem_fun( *this, &ExternalEditorPreferences::removeSelectedEditors)); @@ -69,6 +77,7 @@ ExternalEditorPreferences::ExternalEditorPreferences(): // Toolbar. toolbar.set_halign(Gtk::Align::ALIGN_END); toolbar.add(*button_app_chooser); + toolbar.add(*button_file_chooser); toolbar.add(*button_add); toolbar.add(*button_remove); @@ -204,6 +213,38 @@ void ExternalEditorPreferences::onAppChooserDialogResponse( } } +void ExternalEditorPreferences::onFileChooserDialogResponse( + int response_id, Gtk::FileChooserDialog *dialog) +{ + switch (response_id) { + case Gtk::RESPONSE_OK: { + dialog->close(); + + auto selection = list_view->get_selection()->get_selected_rows(); + for (const auto &selected : selection) { + auto row = *list_model->get_iter(selected); + row[model_columns.icon] = Glib::RefPtr(nullptr); + row[model_columns.command] = +#ifdef WIN32 + '"' + dialog->get_filename() + '"'; +#else + Glib::shell_quote(dialog->get_filename()); +#endif + } + + break; + } + + case Gtk::RESPONSE_CANCEL: + case Gtk::RESPONSE_CLOSE: + dialog->close(); + break; + + default: + break; + } +} + void ExternalEditorPreferences::openAppChooserDialog() { if (app_chooser_dialog.get()) { @@ -221,6 +262,35 @@ void ExternalEditorPreferences::openAppChooserDialog() app_chooser_dialog->show(); } +void ExternalEditorPreferences::openFileChooserDialog() +{ + if (file_chooser_dialog.get()) { + file_chooser_dialog->show(); + return; + } + + file_chooser_dialog.reset(new Gtk::FileChooserDialog(M("PREFERENCES_EXTERNALEDITOR_CHANGE_FILE"))); + + const auto exe_filter = Gtk::FileFilter::create(); + exe_filter->set_name(M("FILECHOOSER_FILTER_EXECUTABLE")); + exe_filter->add_custom(Gtk::FILE_FILTER_MIME_TYPE, [](const Gtk::FileFilter::Info &info) { + return Gio::content_type_can_be_executable(info.mime_type); + }); + const auto all_filter = Gtk::FileFilter::create(); + all_filter->set_name(M("FILECHOOSER_FILTER_ANY")); + all_filter->add_pattern("*"); + file_chooser_dialog->add_filter(exe_filter); + file_chooser_dialog->add_filter(all_filter); + + file_chooser_dialog->signal_response().connect(sigc::bind( + sigc::mem_fun(*this, &ExternalEditorPreferences::onFileChooserDialogResponse), + file_chooser_dialog.get())); + file_chooser_dialog->set_modal(); + file_chooser_dialog->add_button(M("GENERAL_CANCEL"), Gtk::RESPONSE_CANCEL); + file_chooser_dialog->add_button(M("GENERAL_OPEN"), Gtk::RESPONSE_OK); + file_chooser_dialog->show(); +} + void ExternalEditorPreferences::removeSelectedEditors() { auto selection = list_view->get_selection()->get_selected_rows(); @@ -265,6 +335,7 @@ void ExternalEditorPreferences::updateToolbarSensitivity() { bool selected = list_view->get_selection()->count_selected_rows(); button_app_chooser->set_sensitive(selected); + button_file_chooser->set_sensitive(selected); button_remove->set_sensitive(selected); } diff --git a/rtgui/externaleditorpreferences.h b/rtgui/externaleditorpreferences.h index 5761d8b63..34658d942 100644 --- a/rtgui/externaleditorpreferences.h +++ b/rtgui/externaleditorpreferences.h @@ -28,6 +28,14 @@ #include "rtappchooserdialog.h" +namespace Gtk +{ + +class FileChooserDialog; + +} + + /** * Widget for editing the external editors options. */ @@ -98,8 +106,10 @@ private: Gtk::Box toolbar; // Contains buttons for editing the list. Gtk::Button *button_app_chooser; Gtk::Button *button_add; + Gtk::Button *button_file_chooser; Gtk::Button *button_remove; std::unique_ptr app_chooser_dialog; + std::unique_ptr file_chooser_dialog; /** * Inserts a new editor entry after the current selection, or at the end if @@ -119,10 +129,19 @@ private: * Closes the dialog and updates the selected entry if an app was chosen. */ void onAppChooserDialogResponse(int responseId, RTAppChooserDialog *dialog); + /** + * Called when the user is done interacting with the file chooser dialog. + * Closes the dialog and updates the selected entry if a file was chosen. + */ + void onFileChooserDialogResponse(int responseId, Gtk::FileChooserDialog *dialog); /** * Shows the app chooser dialog. */ void openAppChooserDialog(); + /** + * Shows the file chooser dialog for picking an executable. + */ + void openFileChooserDialog(); /** * Removes all selected editors. */ From 329341f89f78cd995e6266e97e19e76f08a419b2 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sat, 5 Mar 2022 18:36:28 -0800 Subject: [PATCH 044/134] Replace Gtk::make_managed() with Gtk::manage() Maintain compatibility with gtkmm 3.16. --- rtgui/editorpanel.cc | 2 +- rtgui/externaleditorpreferences.cc | 22 +++++++++++----------- rtgui/popupcommon.cc | 12 ++++++------ rtgui/preferences.cc | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 987852891..a9797a216 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -671,7 +671,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel) queueimg->set_tooltip_markup (M ("MAIN_BUTTON_PUTTOQUEUE_TOOLTIP")); setExpandAlignProperties (queueimg, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); - send_to_external = Gtk::make_managed("", false); + send_to_external = Gtk::manage(new PopUpButton("", false)); send_to_external->set_tooltip_text(M("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP")); setExpandAlignProperties(send_to_external->buttonGroup, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); send_to_external->addEntry("palette-brush.png", M("GENERAL_OTHER")); diff --git a/rtgui/externaleditorpreferences.cc b/rtgui/externaleditorpreferences.cc index c6ee9b93e..58a562725 100644 --- a/rtgui/externaleditorpreferences.cc +++ b/rtgui/externaleditorpreferences.cc @@ -34,7 +34,7 @@ ExternalEditorPreferences::ExternalEditorPreferences(): toolbar(Gtk::Orientation::ORIENTATION_HORIZONTAL) { // List view. - list_view = Gtk::make_managed(); + 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(makeCommandColumn())); @@ -52,13 +52,13 @@ ExternalEditorPreferences::ExternalEditorPreferences(): list_scroll_area.add(*list_view); // Toolbar buttons. - auto add_image = Gtk::make_managed("add-small.png"); - auto remove_image = Gtk::make_managed("remove-small.png"); - button_add = Gtk::make_managed(); - button_remove = Gtk::make_managed(); + auto add_image = Gtk::manage(new RTImage("add-small.png")); + auto remove_image = Gtk::manage(new RTImage("remove-small.png")); + button_add = Gtk::manage(new Gtk::Button()); + button_remove = Gtk::manage(new Gtk::Button()); button_add->set_image(*add_image); button_remove->set_image(*remove_image); - button_app_chooser = Gtk::make_managed(M("PREFERENCES_EXTERNALEDITOR_CHANGE")); + button_app_chooser = Gtk::manage(new Gtk::Button(M("PREFERENCES_EXTERNALEDITOR_CHANGE"))); button_file_chooser = Gtk::manage(new Gtk::Button(M("PREFERENCES_EXTERNALEDITOR_CHANGE_FILE"))); button_app_chooser->signal_pressed().connect(sigc::mem_fun( @@ -159,9 +159,9 @@ void ExternalEditorPreferences::addEditor() Gtk::TreeViewColumn *ExternalEditorPreferences::makeAppColumn() { - auto name_renderer = Gtk::make_managed(); - auto icon_renderer = Gtk::make_managed(); - auto col = Gtk::make_managed(); + auto name_renderer = Gtk::manage(new Gtk::CellRendererText()); + auto icon_renderer = Gtk::manage(new Gtk::CellRendererPixbuf()); + auto col = Gtk::manage(new Gtk::TreeViewColumn()); col->set_title(M("PREFERENCES_EXTERNALEDITOR_COLUMN_NAME")); col->set_resizable(); @@ -180,8 +180,8 @@ Gtk::TreeViewColumn *ExternalEditorPreferences::makeAppColumn() Gtk::TreeViewColumn *ExternalEditorPreferences::makeCommandColumn() { - auto command_renderer = Gtk::make_managed(); - auto col = Gtk::make_managed(); + auto command_renderer = Gtk::manage(new Gtk::CellRendererText()); + auto col = Gtk::manage(new Gtk::TreeViewColumn()); col->set_title(M("PREFERENCES_EXTERNALEDITOR_COLUMN_COMMAND")); col->pack_start(*command_renderer); diff --git a/rtgui/popupcommon.cc b/rtgui/popupcommon.cc index c33ac068e..1dbde833e 100644 --- a/rtgui/popupcommon.cc +++ b/rtgui/popupcommon.cc @@ -50,14 +50,14 @@ PopUpCommon::PopUpCommon (Gtk::Button* thisButton, const Glib::ustring& label) buttonGroup->get_style_context()->add_class("image-combo"); // Create the image for the button - buttonImage = Gtk::make_managed(); + buttonImage = Gtk::manage(new RTImage()); setExpandAlignProperties(buttonImage, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); imageContainer->attach_next_to(*buttonImage, Gtk::POS_RIGHT, 1, 1); buttonImage->set_no_show_all(); // Create the button for showing the pop-up. - arrowButton = Gtk::make_managed(); - Gtk::Image *arrowImage = Gtk::make_managed(); + arrowButton = Gtk::manage(new Gtk::Button()); + Gtk::Image *arrowImage = Gtk::manage(new Gtk::Image()); arrowImage->set_from_icon_name("pan-down-symbolic", Gtk::ICON_SIZE_BUTTON); setExpandAlignProperties(arrowButton, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); arrowButton->add(*arrowImage); //menuSymbol); @@ -82,7 +82,7 @@ bool PopUpCommon::insertEntry(int position, const Glib::ustring& fileName, const { RTImage* image = nullptr; if (!fileName.empty()) { - image = Gtk::make_managed(fileName); + image = Gtk::manage(new RTImage(fileName)); } bool success = insertEntryImpl(position, fileName, Glib::RefPtr(), image, label); if (!success && image) { @@ -93,7 +93,7 @@ bool PopUpCommon::insertEntry(int position, const Glib::ustring& fileName, const bool PopUpCommon::insertEntry(int position, const Glib::RefPtr& gIcon, const Glib::ustring& label) { - RTImage* image = Gtk::make_managed(gIcon, Gtk::ICON_SIZE_BUTTON); + RTImage* image = Gtk::manage(new RTImage(gIcon, Gtk::ICON_SIZE_BUTTON)); bool success = insertEntryImpl(position, "", gIcon, image, label); if (!success) { delete image; @@ -107,7 +107,7 @@ bool PopUpCommon::insertEntryImpl(int position, const Glib::ustring& fileName, c return false; // Create the menu item and image - MyImageMenuItem *newItem = Gtk::make_managed(label, image); + MyImageMenuItem *newItem = Gtk::manage(new MyImageMenuItem(label, image)); imageIcons.insert(imageIcons.begin() + position, gIcon); imageFilenames.insert(imageFilenames.begin() + position, fileName); images.insert(images.begin() + position, newItem->getImage()); diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index a8f5c64a3..734e74e91 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -1249,7 +1249,7 @@ Gtk::Widget* Preferences::getGeneralPanel() #endif #endif - externalEditors = Gtk::make_managed(); + externalEditors = Gtk::manage(new ExternalEditorPreferences()); externalEditors->set_size_request(-1, 200); #ifdef EXT_EDITORS_RADIOS externaleditorGrid->attach_next_to(*externalEditors, *edOther, Gtk::POS_BOTTOM, 2, 1); From 793a77fc4484505645106547ee952dfd2e2d30a8 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 6 Mar 2022 11:52:09 -0800 Subject: [PATCH 045/134] Add missing include --- rtgui/extprog.h | 1 + 1 file changed, 1 insertion(+) diff --git a/rtgui/extprog.h b/rtgui/extprog.h index 86dbc1674..cdcf14e48 100644 --- a/rtgui/extprog.h +++ b/rtgui/extprog.h @@ -20,6 +20,7 @@ #include +#include #include #include "threadutils.h" From ba906af841a47438512ff3f67202b0760b3a6b0e Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Fri, 25 Mar 2022 15:47:40 +0100 Subject: [PATCH 046/134] dcraw: increase linear table parsing to 65536 values The dcraw linear_table method limits the max values to 4096. But 16 bit per channel linear DNGs can provide a LinearizationTable with 65536 entries. This patch changes the dcraw linear_table method to accept 65536 entries. --- rtengine/dcraw.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 39e527598..95df2d21b 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -6292,11 +6292,11 @@ void CLASS parse_mos (int offset) void CLASS linear_table (unsigned len) { int i; - if (len > 0x1000) len = 0x1000; + if (len > 0x10000) len = 0x10000; read_shorts (curve, len); - for (i=len; i < 0x1000; i++) + for (i=len; i < 0x10000; i++) curve[i] = curve[i-1]; - maximum = curve[0xfff]; + maximum = curve[0xffff]; } void CLASS parse_kodak_ifd (int base) From 30f9cc71d968263a41046376d8c97ca91420013d Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Fri, 7 Oct 2022 11:09:19 +0200 Subject: [PATCH 047/134] Writing release notes --- RELEASE_NOTES.txt | 205 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 177 insertions(+), 28 deletions(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index eb8d96379..aa63fb18a 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,21 +1,14 @@ -RAWTHERAPEE 5.8-dev RELEASE NOTES +RAWTHERAPEE 5.9-rc1 RELEASE NOTES -This is a development version of RawTherapee. We update the code almost daily. Every few months, once enough changes have accumulated and the code is stabilized, we make a new official release. Every code change between these releases is known as a "development" version, and this is one of them. +This is Release Candidate 1 of RawTherapee 5.9, release on 2022-10-07. This is not the final release yet. + + + +IN GENERAL Start by reading the "Getting Started" article on RawPedia: https://rawpedia.rawtherapee.com/ -While we only commit tested and relatively stable code and so the development versions should be fairly stable, you should be aware that: -- Development versions only had limited testing, so there may be bugs unknown to us. -- You should report these bugs so that they get fixed for the next stable release. See - https://rawpedia.rawtherapee.com/How_to_write_useful_bug_reports -- The way new tools work in the development versions is likely to change as we tweak and tune them, so your processing profiles may produce different results when used in a future stable version. -- Bugs present in the stable versions get fixed in the development versions, and make it into the next stable version when we make a new official release. That means that in some ways the development versions can be "more stable" than the latest stable release. At the same time, new features may introduce new bugs. This is a trade-off you should be aware of. - - - -NEWS RELEVANT TO PHOTOGRAPHERS - RawTherapee supports most raw formats, including Pentax and Sony Pixel Shift, Canon Dual-Pixel, and those from Foveon and X-Trans sensors. If you're wondering whether it supports your camera's raw format, first download RawTherapee and try for yourself. If a raw format is not supported it will either not open, or the preview in the Editor tab will appear black, white, or have a strong color cast - usually magenta. In that case, read the "Adding Support for New Raw Formats" RawPedia article. @@ -25,16 +18,184 @@ In order to use RawTherapee efficiently you should know that: - To change slider values or drop-down list items with the mouse scroll-wheel, hold the Shift key. This is so that you can safely scroll the panels without accidentally changing a slider or other tool setting. - All curves support the Shift and Ctrl keys while dragging a point. Shift+drag makes the point snap to a meaningful axis (top, bottom, diagonal, other), while Ctrl+drag makes your mouse movement super-fine for precise point positioning. - There are many keyboard shortcuts which make working with RawTherapee much faster and give you greater control. Make sure you familiarize yourself with them on RawPedia's "Keyboard Shortcuts" page! +- All sliders support a fine-tuning mode which you can toggle by pressing the Shift key while dragging a slider. -New features since 5.8: -- TODO + + +NEW FEATURES SINCE 5.8 + +- The Spot Removal tool (Detail tab) was added, for removing dust specks and small objects. +- The Color Appearance & Lighting tool (Advanced tab), formerly known as CIECAM02, now includes CAM16. By taking into account the conditions of the photographed scene and the conditions under which the image is viewed, it allows you to adjust the image in a way which matches human color perception. +- The Local Adjustments tool (Local tab) was added, for performing a wide range of operations on an area of the image determined by its geometry or color. +- The Wavelet Levels tool (Advanced tab) received various improvements. +- The White Balance tool (Color tab) received new automatic white balance methods. +- The Film Negative tool (Color tab) received various improvements including support for non-raw files. TODO new or improved? +- The Preprocess White Balance tool (Raw tab) was added, allowing you to specify whether channels should be balanced automatically or whether the white balance values recorded by the camera should be used instead. +- The Perspective Correction tool (Transform tab) received various improvements, including automatic modes. TODO is auto new? +- The Main Histogram was improved with new modes: waveform, vectorscope and RGB parade. +- Improvements to the Inspect feature (File Browser tab). TODO undocumented, and don't work for me. +- New dual-demosaicing methods in the Demosaicing tool (Raw tab). +- The Haze Removal tool (Detail tab) received a saturation adjuster. +- The RawTherapee theme was improved, including changes to make it easier to see which tools are enabled. +- The Navigator (Editor tab) can now be resized. +- The Resize tool (Transform tab) now allows to resize by the long or short edge. +- The Crop tool (Transform tab) received a "centered square" crop guide, useful when the resulting non-square image will also be used on social media which crop to a square format. +- The Pixel Shift demosaicing method (Raw tab) now allows using an average of all frames for regions with motion. +- Support for Canon CR3 raw files [TODO wasn't basic support added in 5.8? What exactly is new? What is still lacking?] +- Added support for and improvement of (raw formats and color profiles): + - Canon EOS 100D / Rebel SL1 / Kiss X7 (#6187) + - Canon EOS 1DX Mark III + - Canon EOS 2000D / Rebel T7 / Kiss X90 + - Canon EOS 400D DIGITAL + - Canon EOS 5D Mark II + - Canon EOS 5D Mark IV (DCP) + - Canon EOS 90D (DCP) + - Canon EOS M6 Mark II (DCP) + - Canon EOS R (DCP) + - Canon EOS R3, R7 and R10 + - Canon EOS R5 (DCP) + - Canon EOS R6 (DCP) + - Canon EOS RP + - Canon EOS-1D Mark III + - Canon EOS-1Ds + - Canon EOS-1Ds Mark II + - Canon PowerShot G1 X Mark II (DCP) + - Canon PowerShot G9 X Mark II + - Canon PowerShot S120 (DCP) + - Canon PowerShot SX50 HS + - Canon PowerShot SX70 HS + - DJI FC3170 + - FUJIFILM X-A5 (DCP) + - FUJIFILM X-E4 + - Nikon Z fc + - Sony ILCE-7M4 + - Support for compressed CR3, affects Canon EOS M50, R, R5, R6 and 1D X Mark III, etc. + - Canon EOS R3, R7 and R10. + - Samsung Galaxy S7 + - Canon EOS 1DX Mark III + - Canon EOS 5D Mark II + - Canon EOS-1Ds Mark II + - Fujifilm X-T4 + - Nikon D5100 + - FUJIFILM X-H1 (DCP) + - FUJIFILM X-PRO2 + - FUJIFILM X-PRO3 (DCP) + - FUJIFILM X-S10 + - FUJIFILM X-T1 + - FUJIFILM X-T100 + - FUJIFILM X-T2 + - FUJIFILM X-T3 (DCP) + - FUJIFILM X-T30 + - FUJIFILM X-T4 + - FUJIFILM X100V + - Fujifilm GFX 100 + - Fujifilm GFX100S Note that lossy compression is not supported, nor are alternative crop modes (e.g. 4:3) + - Fujifilm X-A20 + - Fujifilm X-T4 + - HASSELBLAD NEX-7 (Lunar) + - Hasselblad L1D-20c (DJI Mavic 2 Pro) + - LEICA C-LUX + - LEICA CAM-DC25 + - LEICA D-LUX 7 + - LEICA M8 + - LEICA V-LUX 5 + - Leica SL2-S + - NIKON COOLPIX P1000 + - NIKON D500 (DCP) + - NIKON D5300 (DCP) + - NIKON D610 (DCP) + - NIKON D7100 (DCP) + - NIKON D7500 (DCP) + - NIKON D800 (DCP) + - NIKON D850 (DCP) + - NIKON Z 6 (DCP) + - NIKON Z 7 (DCP) + - Nikon 1 J4 + - Nikon COOLPIX P950 + - Nikon D2Hs + - Nikon D2Xs + - Nikon D300s + - Nikon D3500 + - Nikon D5100 + - Nikon D6 + - Nikon D70s + - Nikon D780 + - Nikon D810A + - Nikon Z 5 (#5905) + - Nikon Z 50 (#5851) (DCP) + - Nikon Z 6_2 + - Nikon Z 7_2 + - Nikon Z fc + - OLYMPUS E-M10MarkIV + - OLYMPUS E-M1MarkIII + - OLYMPUS E-M1X + - OLYMPUS E-M5MarkII (DCP) + - OLYMPUS E-M5MarkIII + - OLYMPUS E-PL10 + - OLYMPUS E-PL9 + - OLYMPUS STYLUS1 + - OLYMPUS STYLUS1,1s + - OLYMPUS TG-6 + - PENTAX K-50 (DCP) + - PENTAX K10D + - Panasonic DC-FZ1000M2 + - Panasonic DC-FZ80 + - Panasonic DC-FZ81 + - Panasonic DC-FZ82 + - Panasonic DC-FZ83 + - Panasonic DC-G100 + - Panasonic DC-G110 + - Panasonic DC-G90 + - Panasonic DC-G95 + - Panasonic DC-G99 + - Panasonic DC-S1H + - Panasonic DC-S5 (DCP) + - Panasonic DC-TZ95 + - Panasonic DC-ZS80 + - Panasonic DMC-TZ80 + - Panasonic DMC-TZ85 + - Panasonic DMC-ZS60 + - RICOH PENTAX K-1 Mark II + - RICOH PENTAX K-3 MARK III + - SONY ILCE-9 (DCP) + - SONY NEX-7 + - Samsung Galaxy S7 + - Sigma fp + - Sony DCZV1B + - Sony DSC-HX95 + - Sony DSC-HX99 + - Sony DSC-RX0 + - Sony DSC-RX0M2 + - Sony DSC-RX100 + - Sony DSC-RX100M5A + - Sony DSC-RX100M6 + - Sony DSC-RX100M7 + - Sony DSC-RX10M2 + - Sony DSC-RX10M3 + - Sony DSC-RX10M4 + - Sony DSC-RX1R + - Sony ILCE-1 + - Sony ILCE-6100 + - Sony ILCE-6400 (DCP) + - Sony ILCE-6600 (DCP) + - Sony ILCE-7C + - Sony ILCE-7M3 + - Sony ILCE-7M4 + - Sony ILCE-7RM4 (DCP) + - Sony ILCE-7SM3 + - Sony ILCE-9M2 + - Sony NEX-F3 + - Sony SLT-A99V + - Support for compressed CR3, affects Canon EOS M50, R, R5, R6 and 1D X Mark III, etc. NEWS RELEVANT TO PACKAGE MAINTAINERS New since 5.8: -- TODO +- Automated build system moved from Travis CI to GitHub Actions: + https://github.com/Beep6581/RawTherapee/actions +- libcanberra made optional in CMake via USE_LIBCANBERRA, default ON. In general: - To get the source code, either clone from git or use the tarball from https://rawtherapee.com/shared/source/ . Do not use the auto-generated GitHub release tarballs. @@ -74,18 +235,6 @@ https://discuss.pixls.us/c/software/rawtherapee -LIVE CHAT WITH USERS AND DEVELOPERS - -Network: freenode -Server: chat.freenode.net -Channel: #rawtherapee - -You can use freenode webchat to communicate without installing anything: -https://webchat.freenode.net/?randomnick=1&channels=rawtherapee&prompt=1 -More information here: https://rawpedia.rawtherapee.com/IRC - - - REVISION HISTORY The complete changelog is available at: From b08ed74cb84aeec5c93919e03c868e2375ee9fac Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Fri, 7 Oct 2022 12:25:16 +0200 Subject: [PATCH 048/134] Preparing for release 5.9-rc1 --- RELEASE_NOTES.txt | 40 +++-- rtdata/images/svg/splash.svg | 236 ++++++++++++++++++-------- rtdata/images/svg/splash_template.svg | 168 +++++++++--------- 3 files changed, 267 insertions(+), 177 deletions(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index aa63fb18a..de254c0d7 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,6 +1,6 @@ RAWTHERAPEE 5.9-rc1 RELEASE NOTES -This is Release Candidate 1 of RawTherapee 5.9, release on 2022-10-07. This is not the final release yet. +This is Release Candidate 1 of RawTherapee 5.9, released on 2022-10-07. This is not the final release yet. @@ -29,11 +29,11 @@ NEW FEATURES SINCE 5.8 - The Local Adjustments tool (Local tab) was added, for performing a wide range of operations on an area of the image determined by its geometry or color. - The Wavelet Levels tool (Advanced tab) received various improvements. - The White Balance tool (Color tab) received new automatic white balance methods. -- The Film Negative tool (Color tab) received various improvements including support for non-raw files. TODO new or improved? +- The Film Negative tool (Color tab) received various improvements including support for non-raw files. - The Preprocess White Balance tool (Raw tab) was added, allowing you to specify whether channels should be balanced automatically or whether the white balance values recorded by the camera should be used instead. -- The Perspective Correction tool (Transform tab) received various improvements, including automatic modes. TODO is auto new? +- A new Perspective Correction tool (Transform tab) was added which includes an automated perspective correction feature. - The Main Histogram was improved with new modes: waveform, vectorscope and RGB parade. -- Improvements to the Inspect feature (File Browser tab). TODO undocumented, and don't work for me. +- Improvements to the Inspect feature (File Browser tab). - New dual-demosaicing methods in the Demosaicing tool (Raw tab). - The Haze Removal tool (Detail tab) received a saturation adjuster. - The RawTherapee theme was improved, including changes to make it easier to see which tools are enabled. @@ -41,24 +41,27 @@ NEW FEATURES SINCE 5.8 - The Resize tool (Transform tab) now allows to resize by the long or short edge. - The Crop tool (Transform tab) received a "centered square" crop guide, useful when the resulting non-square image will also be used on social media which crop to a square format. - The Pixel Shift demosaicing method (Raw tab) now allows using an average of all frames for regions with motion. -- Support for Canon CR3 raw files [TODO wasn't basic support added in 5.8? What exactly is new? What is still lacking?] -- Added support for and improvement of (raw formats and color profiles): - - Canon EOS 100D / Rebel SL1 / Kiss X7 (#6187) +- Added or improved support for cameras, raw formats and color profiles: + - Canon EOS 100D / Rebel SL1 / Kiss X7 + - Canon EOS 1DX Mark III - Canon EOS 1DX Mark III - Canon EOS 2000D / Rebel T7 / Kiss X90 - Canon EOS 400D DIGITAL - Canon EOS 5D Mark II + - Canon EOS 5D Mark II - Canon EOS 5D Mark IV (DCP) - Canon EOS 90D (DCP) - Canon EOS M6 Mark II (DCP) - Canon EOS R (DCP) - Canon EOS R3, R7 and R10 + - Canon EOS R3, R7 and R10. - Canon EOS R5 (DCP) - Canon EOS R6 (DCP) - Canon EOS RP - Canon EOS-1D Mark III - Canon EOS-1Ds - Canon EOS-1Ds Mark II + - Canon EOS-1Ds Mark II - Canon PowerShot G1 X Mark II (DCP) - Canon PowerShot G9 X Mark II - Canon PowerShot S120 (DCP) @@ -67,16 +70,6 @@ NEW FEATURES SINCE 5.8 - DJI FC3170 - FUJIFILM X-A5 (DCP) - FUJIFILM X-E4 - - Nikon Z fc - - Sony ILCE-7M4 - - Support for compressed CR3, affects Canon EOS M50, R, R5, R6 and 1D X Mark III, etc. - - Canon EOS R3, R7 and R10. - - Samsung Galaxy S7 - - Canon EOS 1DX Mark III - - Canon EOS 5D Mark II - - Canon EOS-1Ds Mark II - - Fujifilm X-T4 - - Nikon D5100 - FUJIFILM X-H1 (DCP) - FUJIFILM X-PRO2 - FUJIFILM X-PRO3 (DCP) @@ -89,11 +82,13 @@ NEW FEATURES SINCE 5.8 - FUJIFILM X-T4 - FUJIFILM X100V - Fujifilm GFX 100 - - Fujifilm GFX100S Note that lossy compression is not supported, nor are alternative crop modes (e.g. 4:3) + - Fujifilm GFX100S though lossy compression and alternative crop modes (e.g. 4:3) are not supported yet - Fujifilm X-A20 - Fujifilm X-T4 + - Fujifilm X-T4 - HASSELBLAD NEX-7 (Lunar) - Hasselblad L1D-20c (DJI Mavic 2 Pro) + - Improved support for the Canon CR3 raw format, added support for compressed files, affects Canon EOS M50, R, R5, R6 and 1D X Mark III, etc. - LEICA C-LUX - LEICA CAM-DC25 - LEICA D-LUX 7 @@ -117,15 +112,17 @@ NEW FEATURES SINCE 5.8 - Nikon D300s - Nikon D3500 - Nikon D5100 + - Nikon D5100 - Nikon D6 - Nikon D70s - Nikon D780 - Nikon D810A - - Nikon Z 5 (#5905) - - Nikon Z 50 (#5851) (DCP) + - Nikon Z 5 + - Nikon Z 50 (DCP) - Nikon Z 6_2 - Nikon Z 7_2 - Nikon Z fc + - Nikon Z fc - OLYMPUS E-M10MarkIV - OLYMPUS E-M1MarkIII - OLYMPUS E-M1X @@ -160,6 +157,7 @@ NEW FEATURES SINCE 5.8 - SONY ILCE-9 (DCP) - SONY NEX-7 - Samsung Galaxy S7 + - Samsung Galaxy S7 - Sigma fp - Sony DCZV1B - Sony DSC-HX95 @@ -181,12 +179,12 @@ NEW FEATURES SINCE 5.8 - Sony ILCE-7C - Sony ILCE-7M3 - Sony ILCE-7M4 + - Sony ILCE-7M4 - Sony ILCE-7RM4 (DCP) - Sony ILCE-7SM3 - Sony ILCE-9M2 - Sony NEX-F3 - Sony SLT-A99V - - Support for compressed CR3, affects Canon EOS M50, R, R5, R6 and 1D X Mark III, etc. diff --git a/rtdata/images/svg/splash.svg b/rtdata/images/svg/splash.svg index 1e7c9f745..4695d9bc6 100644 --- a/rtdata/images/svg/splash.svg +++ b/rtdata/images/svg/splash.svg @@ -7,7 +7,7 @@ viewBox="0 0 160 99.999999" version="1.1" id="svg783" - inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" + inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)" sodipodi:docname="splash.svg" inkscape:export-filename="/tmp/splash.png" inkscape:export-xdpi="96" @@ -151,10 +151,10 @@ style="stop-color:#feab27;stop-opacity:1;" /> + + + + + + + + + + + + + width="157.40977mm" + inkscape:showpageshadow="2" + inkscape:deskcolor="#d1d1d1" /> @@ -1124,41 +1188,6 @@ style="fill:#ffffff;enable-background:new" transform="matrix(0.24804687,0,0,0.2480469,-127.75775,273.1232)" id="g220" /> - - - - - - - - - - - + style="font-size:21.3333px;line-height:1.25;font-family:'Eras BQ';-inkscape-font-specification:'Eras BQ';white-space:pre;shape-inside:url(#rect181038);display:inline" /> + id="g151445-6" + transform="translate(5.1000209,-186.11437)" + style="filter:url(#filter4749-2)"> + + + + + + + + + + + + id="path1849" /> + id="path1851" /> + id="path1853" /> + id="path1855" /> + id="path1857" /> + id="path1859" /> + id="path1861" /> + id="path1863" /> + id="path1865" /> + id="path1867" /> + id="path1869" /> + + + + + + diff --git a/rtdata/images/svg/splash_template.svg b/rtdata/images/svg/splash_template.svg index b6b42d07a..e9f67ff92 100644 --- a/rtdata/images/svg/splash_template.svg +++ b/rtdata/images/svg/splash_template.svg @@ -7,7 +7,7 @@ viewBox="0 0 160 99.999999" version="1.1" id="svg783" - inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" + inkscape:version="1.2.1 (9c6d41e410, 2022-07-14, custom)" sodipodi:docname="splash_template.svg" inkscape:export-filename="/tmp/splash.png" inkscape:export-xdpi="96" @@ -236,10 +236,10 @@ operator="in" /> + width="157.40977mm" + inkscape:showpageshadow="2" + inkscape:deskcolor="#d1d1d1" /> @@ -1120,7 +1122,7 @@ id="tspan40748" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:11.9944px;font-family:'ITC Eras Std';-inkscape-font-specification:'ITC Eras Std Bold';fill:#ffffff;fill-opacity:1;stroke-width:0.537916" x="64.642754" - y="252.72681">8 + y="252.72681">9 PrerequisitesPrerequisites + id="tspan4443"> Obtain and install the font family ITC Eras Std. + id="tspan4447">Obtain and install the font family ITC Eras Std. + id="tspan4451"> DetailsDetails + id="tspan4457"> The color wheel is copied from rt-logo.svg and a glow filter is added + id="tspan4461">The color wheel is copied from rt-logo.svg and a glow filter is added to each segment and the wheel as a whole. + id="tspan4465">to each segment and the wheel as a whole. "Raw": font ITC Eras Ultra-Bold, 60 pt, -3 px letter spacing + id="tspan4469">"Raw": font ITC Eras Ultra-Bold, 60 pt, -3 px letter spacing "Therapee": font ITC Eras Medium, 60 pt, +1,5 pt letter spacing + id="tspan4473">"Therapee": font ITC Eras Medium, 60 pt, +1,5 pt letter spacing Version (big number): ITC Eras Bold, 58 pt, skewed -3° + id="tspan4477">Version (big number): ITC Eras Bold, 58 pt, skewed -3° Version (period + small number): ITC Eras Bold, 34 pt, skewed -3° + id="tspan4481">Version (period + small number): ITC Eras Bold, 34 pt, skewed -3° Release-type: ITC Eras Bold, 16 pt, skewed -3° + id="tspan4485">Release-type: ITC Eras Bold, 16 pt, skewed -3° + id="tspan4489"> PublishingPublishing + id="tspan4495"> 1. To prepare a splash screen for deployment, select all text and 1. To prepare a splash screen for deployment, select all text and choose choose Path > Object to Path. + id="tspan4505">Path > Object to Path. 2. Change release type text to whatever is required, or hide the layer 2. Change release type text to whatever is required, or hide the layer "Release type" entirely. + id="tspan4513">"Release type" entirely. 3. Remove this text field. + id="tspan4517">3. Remove this text field. 44. Save as "splash.svg" into "./rtdata/images/svg". + id="tspan4523">. Save as "splash.svg" into "./rtdata/images/svg". + id="tspan4527"> RawTherapee splash screen design 1.5 (March 2022) + id="tspan4531">RawTherapee splash screen design 1.5 (March 2022) www.rawtherapee.com + id="tspan4535">www.rawtherapee.com Date: Wed, 12 Oct 2022 22:59:29 +0200 Subject: [PATCH 049/134] Apply suggestions from code review Thanks Lawrence37 Co-authored-by: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> --- RELEASE_NOTES.txt | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index de254c0d7..f6036fbcc 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -44,24 +44,20 @@ NEW FEATURES SINCE 5.8 - Added or improved support for cameras, raw formats and color profiles: - Canon EOS 100D / Rebel SL1 / Kiss X7 - Canon EOS 1DX Mark III - - Canon EOS 1DX Mark III - Canon EOS 2000D / Rebel T7 / Kiss X90 - Canon EOS 400D DIGITAL - Canon EOS 5D Mark II - - Canon EOS 5D Mark II - Canon EOS 5D Mark IV (DCP) - Canon EOS 90D (DCP) - Canon EOS M6 Mark II (DCP) - Canon EOS R (DCP) - Canon EOS R3, R7 and R10 - - Canon EOS R3, R7 and R10. - Canon EOS R5 (DCP) - Canon EOS R6 (DCP) - Canon EOS RP - Canon EOS-1D Mark III - Canon EOS-1Ds - Canon EOS-1Ds Mark II - - Canon EOS-1Ds Mark II - Canon PowerShot G1 X Mark II (DCP) - Canon PowerShot G9 X Mark II - Canon PowerShot S120 (DCP) @@ -85,7 +81,6 @@ NEW FEATURES SINCE 5.8 - Fujifilm GFX100S though lossy compression and alternative crop modes (e.g. 4:3) are not supported yet - Fujifilm X-A20 - Fujifilm X-T4 - - Fujifilm X-T4 - HASSELBLAD NEX-7 (Lunar) - Hasselblad L1D-20c (DJI Mavic 2 Pro) - Improved support for the Canon CR3 raw format, added support for compressed files, affects Canon EOS M50, R, R5, R6 and 1D X Mark III, etc. @@ -112,26 +107,24 @@ NEW FEATURES SINCE 5.8 - Nikon D300s - Nikon D3500 - Nikon D5100 - - Nikon D5100 - Nikon D6 - Nikon D70s - Nikon D780 - Nikon D810A - Nikon Z 5 - Nikon Z 50 (DCP) - - Nikon Z 6_2 - - Nikon Z 7_2 + - Nikon Z 6II + - Nikon Z 7II - Nikon Z fc - - Nikon Z fc - - OLYMPUS E-M10MarkIV - - OLYMPUS E-M1MarkIII + - OLYMPUS E-M10 Mark IV + - OLYMPUS E-M1 Mark III - OLYMPUS E-M1X - - OLYMPUS E-M5MarkII (DCP) - - OLYMPUS E-M5MarkIII + - OLYMPUS E-M5 Mark II (DCP) + - OLYMPUS E-M5 Mark III - OLYMPUS E-PL10 - OLYMPUS E-PL9 - - OLYMPUS STYLUS1 - - OLYMPUS STYLUS1,1s + - OLYMPUS Stylus 1 + - OLYMPUS Stylus 1s - OLYMPUS TG-6 - PENTAX K-50 (DCP) - PENTAX K10D @@ -153,11 +146,10 @@ NEW FEATURES SINCE 5.8 - Panasonic DMC-TZ85 - Panasonic DMC-ZS60 - RICOH PENTAX K-1 Mark II - - RICOH PENTAX K-3 MARK III + - RICOH PENTAX K-3 Mark III - SONY ILCE-9 (DCP) - SONY NEX-7 - Samsung Galaxy S7 - - Samsung Galaxy S7 - Sigma fp - Sony DCZV1B - Sony DSC-HX95 @@ -179,7 +171,6 @@ NEW FEATURES SINCE 5.8 - Sony ILCE-7C - Sony ILCE-7M3 - Sony ILCE-7M4 - - Sony ILCE-7M4 - Sony ILCE-7RM4 (DCP) - Sony ILCE-7SM3 - Sony ILCE-9M2 From 190f11b1229eb3995679a9dddb00773a162bc62f Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Wed, 12 Oct 2022 23:01:01 +0200 Subject: [PATCH 050/134] Update release notes regarding white balance #6596 --- RELEASE_NOTES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index f6036fbcc..de50d7d7d 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -28,7 +28,7 @@ NEW FEATURES SINCE 5.8 - The Color Appearance & Lighting tool (Advanced tab), formerly known as CIECAM02, now includes CAM16. By taking into account the conditions of the photographed scene and the conditions under which the image is viewed, it allows you to adjust the image in a way which matches human color perception. - The Local Adjustments tool (Local tab) was added, for performing a wide range of operations on an area of the image determined by its geometry or color. - The Wavelet Levels tool (Advanced tab) received various improvements. -- The White Balance tool (Color tab) received new automatic white balance methods. +- The White Balance tool (Color tab) received a new automatic white balance method named "temperature correlation" (the old one was renamed to "RGB grey"). - The Film Negative tool (Color tab) received various improvements including support for non-raw files. - The Preprocess White Balance tool (Raw tab) was added, allowing you to specify whether channels should be balanced automatically or whether the white balance values recorded by the camera should be used instead. - A new Perspective Correction tool (Transform tab) was added which includes an automated perspective correction feature. From b0725b44e2f2f94708eb248b52d5540ba6794415 Mon Sep 17 00:00:00 2001 From: Martin <78749513+marter001@users.noreply.github.com> Date: Thu, 13 Oct 2022 09:07:15 +0200 Subject: [PATCH 051/134] Update AUTHORS.txt --- AUTHORS.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 471bf3da4..ff859768b 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -69,6 +69,7 @@ Other contributors (profiles, ideas, mockups, testing, forum activity, translati Wim ter Meer Alberto Righetto Kostia (Kildor) Romanov + Henning Sidow Kalle Söderman Wayne Sutton Johan Thor @@ -76,3 +77,4 @@ Other contributors (profiles, ideas, mockups, testing, forum activity, translati TooWaBoo Franz Trischberger Colin Walker + Martin Werner From fa18c9faa3148127cf700deb93deb53135a87fa5 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Fri, 14 Oct 2022 22:05:12 -0700 Subject: [PATCH 052/134] macOS: Adding Barber to Authors --- AUTHORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.txt b/AUTHORS.txt index 471bf3da4..1ed4068bf 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -6,6 +6,7 @@ Project initiator: Development contributors, in last name alphabetical order: Roel Baars + Richard E Barber Martin Burri Pierre Cabrera Javier Celaya From ba2a15a6afabc11b2492c56059148126b2260a42 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Sat, 22 Oct 2022 20:18:04 +0200 Subject: [PATCH 053/134] Espanol (Castellano) translation updated by TechXavAl Closes #6597 --- rtdata/languages/Espanol (Castellano) | 256 +++++++++++++------------- 1 file changed, 124 insertions(+), 132 deletions(-) diff --git a/rtdata/languages/Espanol (Castellano) b/rtdata/languages/Espanol (Castellano) index e18188142..ede64894f 100644 --- a/rtdata/languages/Espanol (Castellano) +++ b/rtdata/languages/Espanol (Castellano) @@ -1,5 +1,5 @@ #01 Español - Castellano -#02 2022-07-22 Francisco Lorés y Javier Bartol, para la versión 5.9 +#02 2022-10-08 Francisco Lorés y Javier Bartol, para la versión 5.9 ABOUT_TAB_BUILD;Versión ABOUT_TAB_CREDITS;Reconocimientos @@ -250,7 +250,7 @@ HISTOGRAM_TOOLTIP_G;Muestra/oculta el canal verde en el histograma. HISTOGRAM_TOOLTIP_L;Muestra/oculta el histograma de luminancia CIELAB. HISTOGRAM_TOOLTIP_MODE;Cambia entre la escala lineal, la logarítmica-lineal y la escala logarítmica (o doble logarítmica) del histograma. HISTOGRAM_TOOLTIP_R;Muestra/oculta el canal rojo en el histograma. -HISTOGRAM_TOOLTIP_SHOW_OPTIONS;Muestra/oculta opciones adicionales. +HISTOGRAM_TOOLTIP_SHOW_OPTIONS;Muestra/oculta opciones adicionales del histograma. HISTOGRAM_TOOLTIP_TRACE_BRIGHTNESS;Ajusta el brillo del vectorscopio. HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM;Histograma HISTOGRAM_TOOLTIP_TYPE_HISTOGRAM_RAW;Histograma raw @@ -416,39 +416,39 @@ HISTORY_MSG_170;Vivacidad - curva HH HISTORY_MSG_171;L*a*b* - curva LC HISTORY_MSG_172;L*a*b* - Restringir curva LC HISTORY_MSG_173;Reducción de ruido - Reconstrucción de detalle -HISTORY_MSG_174;CIECAM02/16 -HISTORY_MSG_175;CIECAM02/16 - Adaptación CAT02 -HISTORY_MSG_176;CIECAM02/16 - Contexto visual -HISTORY_MSG_177;CIECAM02/16 - Luminosidad de la escena -HISTORY_MSG_178;CIECAM02/16 - Luminosidad ambiental -HISTORY_MSG_179;CIECAM02/16 - Modelo de punto blanco -HISTORY_MSG_180;CIECAM02/16 - Claridad (J) -HISTORY_MSG_181;CIECAM02/16 - Cromaticidad (C) -HISTORY_MSG_182;CIECAM02/16 - CAT02 automático -HISTORY_MSG_183;CIECAM02/16 - Contraste (J) -HISTORY_MSG_184;CIECAM02/16 - Contexto de la escena -HISTORY_MSG_185;CIECAM02/16 - Control del rango de colores -HISTORY_MSG_186;CIECAM02/16 - Algoritmo -HISTORY_MSG_187;CIECAM02/16 - Protección de rojos/piel -HISTORY_MSG_188;CIECAM02/16 - Brillo (Q) -HISTORY_MSG_189;CIECAM02/16 - Contraste (Q) -HISTORY_MSG_190;CIECAM02/16 - Saturación (S) -HISTORY_MSG_191;CIECAM02/16 - Colorido (M) -HISTORY_MSG_192;CIECAM02/16 - Matiz (h) -HISTORY_MSG_193;CIECAM02/16 - Curva tonal 1 -HISTORY_MSG_194;CIECAM02/16 - Curva tonal 2 -HISTORY_MSG_195;CIECAM02/16 - Curva tonal 1 -HISTORY_MSG_196;CIECAM02/16 - Curva tonal 2 -HISTORY_MSG_197;CIECAM02/16 - Curva de color -HISTORY_MSG_198;CIECAM02/16 - Curva de color -HISTORY_MSG_199;CIECAM02/16 - Histogramas de salida -HISTORY_MSG_200;CIECAM02/16 - Mapeo tonal +HISTORY_MSG_174;Apariencia de color e Iluminación (AC & I) +HISTORY_MSG_175;AC & I - Condic. escena - Adaptación +HISTORY_MSG_176;AC & I - Condic. visualiz. - Contexto visual +HISTORY_MSG_177;AC & I - Condic. escena - Luminosidad absoluta +HISTORY_MSG_178;AC & I - Condic. visualiz. - Luminosidad absoluta +HISTORY_MSG_179;AC & I - Condic. escena - Modelo de punto blanco +HISTORY_MSG_180;AC & I - Ajustes imagen - Claridad (J) +HISTORY_MSG_181;AC & I - Ajustes imagen - Cromaticidad (C) +HISTORY_MSG_182;AC & I - Condic. escena - Adapt. automática +HISTORY_MSG_183;AC & I - Ajustes imagen - Contraste (J) +HISTORY_MSG_184;AC & I - Condic. escena - Contexto de la escena +HISTORY_MSG_185;AC & I - Control del rango de colores +HISTORY_MSG_186;AC & I - Ajustes imagen - Algoritmo +HISTORY_MSG_187;AC & I - Ajustes imagen - Protección de rojos/piel +HISTORY_MSG_188;AC & I - Ajustes imagen - Brillo (Q) +HISTORY_MSG_189;AC & I - Ajustes imagen - Contraste (Q) +HISTORY_MSG_190;AC & I - Ajustes imagen - Saturación (S) +HISTORY_MSG_191;AC & I - Ajustes imagen - Colorido (M) +HISTORY_MSG_192;AC & I - Ajustes imagen - Matiz (h) +HISTORY_MSG_193;AC & I - Ajustes imagen - Curva tonal 1 +HISTORY_MSG_194;AC & I - Ajustes imagen - Curva tonal 2 +HISTORY_MSG_195;AC & I - Ajustes imagen - Curva tonal 1 +HISTORY_MSG_196;AC & I - Ajustes imagen - Curva tonal 2 +HISTORY_MSG_197;AC & I - Ajustes imagen - Curva de color +HISTORY_MSG_198;AC & I - Ajustes imagen - Modo curva de color +HISTORY_MSG_199;AC & I - Ajustes imagen - Usar salida CAM para histogramas de salida +HISTORY_MSG_200;AC & I - Ajustes imagen - Usar CAM para mapeo tonal HISTORY_MSG_201;Reducción de ruido - Cromaticidad R/V HISTORY_MSG_202;Reducción de ruido - Cromaticidad A/Am HISTORY_MSG_203;Reducción de ruido - Espacio de color HISTORY_MSG_204;Pasos de mejora de LMMSE -HISTORY_MSG_205;CAT02/16 - Filtro de píxel caliente/muerto -HISTORY_MSG_206;CAT02/16 - Luminosidad automática de la escena +HISTORY_MSG_205;AC & I - Filtro de píxel caliente/muerto +HISTORY_MSG_206;AC & I - Luminosidad automática de la escena HISTORY_MSG_207;Quitar borde púrpura - Curva de matiz HISTORY_MSG_208;Balance de blancos - Compensador azul/rojo HISTORY_MSG_210;Filtro graduado - Ángulo @@ -661,7 +661,7 @@ HISTORY_MSG_421;Retinex - Gamma HISTORY_MSG_422;Retinex - Gamma HISTORY_MSG_423;Retinex - Pendiente de gamma HISTORY_MSG_424;Retinex - Umbral luces -HISTORY_MSG_425;Retinex - Base del logaritmo +HISTORY_MSG_425;-- no usado -- HISTORY_MSG_426;Retinex - Ecualizador de matiz HISTORY_MSG_427;Tipo de conversión del rango de colores de salida HISTORY_MSG_428;Tipo de conversión del rango de colores del monitor @@ -682,28 +682,44 @@ HISTORY_MSG_442;Retinex - Escala HISTORY_MSG_443;Compensación punto negro de salida HISTORY_MSG_444;Balance de blancos - Sesgo de temperatura HISTORY_MSG_445;Sub-imagen raw +HISTORY_MSG_446;-- no usado -- +HISTORY_MSG_447;-- no usado -- +HISTORY_MSG_448;-- no usado -- HISTORY_MSG_449;PixelShift - Adaptación ISO +HISTORY_MSG_450;-- no usado -- +HISTORY_MSG_451;-- no usado -- HISTORY_MSG_452;PixelShift - Mostrar movimiento HISTORY_MSG_453;PixelShift - Mostrar sólo la máscara +HISTORY_MSG_454;-- no usado -- +HISTORY_MSG_455;-- no usado -- +HISTORY_MSG_456;-- no usado -- HISTORY_MSG_457;PixelShift - Comprobar rojo/azul +HISTORY_MSG_458;-- no usado -- +HISTORY_MSG_459;-- no usado -- +HISTORY_MSG_460;-- no usado -- +HISTORY_MSG_461;-- no usado -- HISTORY_MSG_462;PixelShift - Comprobar verde +HISTORY_MSG_463;-- no usado -- HISTORY_MSG_464;PixelShift - Difuminar máscara de movimiento HISTORY_MSG_465;PixelShift - Radio de difuminado +HISTORY_MSG_466;-- no usado -- +HISTORY_MSG_467;-- no usado -- HISTORY_MSG_468;PixelShift - Rellenar huecos HISTORY_MSG_469;PixelShift - Mediana +HISTORY_MSG_470;-- no usado -- HISTORY_MSG_471;PixelShift - Corrección de movimiento HISTORY_MSG_472;PixelShift - Suavizar transiciones HISTORY_MSG_474;PixelShift - Ecualizar HISTORY_MSG_475;PixelShift - Ecualizar canal -HISTORY_MSG_476;CAM02 - Temperatura de salida -HISTORY_MSG_477;CAM02 - Verde de salida -HISTORY_MSG_478;CAM02 - Yb de salida -HISTORY_MSG_479;CAM02 - Adaptación CAT02 de salida -HISTORY_MSG_480;CAM02 - Salida automática CAT02 -HISTORY_MSG_481;CAM02 - Temperatura de la escena -HISTORY_MSG_482;CAM02 - Verde de la escena -HISTORY_MSG_483;CAM02 - Yb de la escena -HISTORY_MSG_484;CAM02 - Yb automático de la escena +HISTORY_MSG_476;AC & I - Condic. visualiz. - Temperatura +HISTORY_MSG_477;AC & I - Condic. visualiz. - Tinte +HISTORY_MSG_478;AC & I - Condic. visualiz. - Luminancia media +HISTORY_MSG_479;AC & I - Condic. visualiz. - Adaptación +HISTORY_MSG_480;AC & I - Condic. visualiz. - Adaptac. automática +HISTORY_MSG_481;AC & I - Condic. escena - Temperatura +HISTORY_MSG_482;AC & I - Condic. escena - Tinte +HISTORY_MSG_483;AC & I - Condic. escena - Luminancia media +HISTORY_MSG_484;AC & I - Condic. escena -Lumin. media auto HISTORY_MSG_485;Corrección de objetivo HISTORY_MSG_486;Corrección de objetivo - Cámara HISTORY_MSG_487;Corrección de objetivo - Objetivo @@ -716,23 +732,23 @@ HISTORY_MSG_493;Ajustes L*a*b* HISTORY_MSG_494;Nitidez en captura HISTORY_MSG_496;Local - Punto borrado HISTORY_MSG_497;Local - Punto seleccionado -HISTORY_MSG_498;Local - Nombre de punto -HISTORY_MSG_499;Local - Visibilidad de punto -HISTORY_MSG_500;Local - Forma de punto -HISTORY_MSG_501;Local - Método de punto -HISTORY_MSG_502;Local - Método de forma de punto -HISTORY_MSG_503;Local - locX de punto -HISTORY_MSG_504;Local - locXL de punto -HISTORY_MSG_505;Local - locY de punto -HISTORY_MSG_506;Local - locYT de punto -HISTORY_MSG_507;Local - Centro de punto -HISTORY_MSG_508;Local - Radio circular de punto -HISTORY_MSG_509;Local - Método de calidad de punto -HISTORY_MSG_510;Local - Transición de punto -HISTORY_MSG_511;Local - Umbral de punto -HISTORY_MSG_512;Local - Decaimiento de ΔE de punto -HISTORY_MSG_513;Local - Ámbito de punto -HISTORY_MSG_514;Local - Estructura de punto +HISTORY_MSG_498;Local - Nombre del punto +HISTORY_MSG_499;Local - Visibilidad del punto +HISTORY_MSG_500;Local - Forma del punto +HISTORY_MSG_501;Local - Método del punto +HISTORY_MSG_502;Local - Método de forma del punto +HISTORY_MSG_503;Local - locX del punto +HISTORY_MSG_504;Local - locXL del punto +HISTORY_MSG_505;Local - locY del punto +HISTORY_MSG_506;Local - locYT del punto +HISTORY_MSG_507;Local - Centro del punto +HISTORY_MSG_508;Local - Radio circular del punto +HISTORY_MSG_509;Local - Método de calidad del punto +HISTORY_MSG_510;Local - Transición del punto +HISTORY_MSG_511;Local - Umbral del punto +HISTORY_MSG_512;Local - Decaimiento de ΔE del punto +HISTORY_MSG_513;Local - Ámbito del punto +HISTORY_MSG_514;Local - Estructura del punto HISTORY_MSG_515;Ajustes Locales HISTORY_MSG_516;Local - Color y luz HISTORY_MSG_517;Local - Activar super @@ -798,7 +814,7 @@ HISTORY_MSG_576;Local - CPND Mult HISTORY_MSG_577;Local - CPND Cromaticidad HISTORY_MSG_578;Local - CPND Umbral HISTORY_MSG_579;Local - CPND Ámbito -HISTORY_MSG_580;Local - Reducción ruido +HISTORY_MSG_580;-- no usado -- HISTORY_MSG_581;Local - RD Lumin. fino 1 HISTORY_MSG_582;Local - RD Lumin. grueso HISTORY_MSG_583;Local - RD Lumin. detalle @@ -881,7 +897,7 @@ HISTORY_MSG_660;Local - CPND Claridad HISTORY_MSG_661;Local - CPND Contraste residual HISTORY_MSG_662;Local - Reducc. ruido Lumin. fino 0 HISTORY_MSG_663;Local - Reducc. ruido Lumin. fino 2 -HISTORY_MSG_664;Local - CPND Difuminado +HISTORY_MSG_664;-- no usado -- HISTORY_MSG_665;Local - CPND Mezcla máscara HISTORY_MSG_666;Local - CPND Radio máscara HISTORY_MSG_667;Local - CPND Cromaticidad máscara @@ -1129,7 +1145,7 @@ HISTORY_MSG_920;Local - Ondíc. sigma LC HISTORY_MSG_921;Local - Ondíc. Graduado sigma LC2 HISTORY_MSG_922;Local - Cambios en B/N HISTORY_MSG_923;Local - Modo Complejidad herram. -HISTORY_MSG_924;Local - Modo Complejidad herram. +HISTORY_MSG_924;-- no usado -- HISTORY_MSG_925;Local - Ámbito herram. color HISTORY_MSG_926;Local - Mostrar tipo máscara HISTORY_MSG_927;Local - Sombras @@ -1353,13 +1369,15 @@ HISTORY_MSG_1145;Local - Jz Codific. Log HISTORY_MSG_1146;Local - Jz Codific. Log gris objetivo HISTORY_MSG_1147;Local - Jz Ev Negro Ev Blanco HISTORY_MSG_1148;Local - Jz Sigmoide +HISTORY_MSG_1149;Local - Sigmoide Q +HISTORY_MSG_1150;Local - Codif. log. Q en vez de Sigmoide Q HISTORY_MSG_BLSHAPE;Difuminado por niveles HISTORY_MSG_BLURCWAV;Difuminar cromaticidad HISTORY_MSG_BLURWAV;Difuminar luminancia HISTORY_MSG_BLUWAV;Respuesta de atenuación -HISTORY_MSG_CATCAT;Modo Cat02/16 -HISTORY_MSG_CATCOMPLEX;Complejidad CIECAM -HISTORY_MSG_CATMODEL;Modelo CAM +HISTORY_MSG_CATCAT;AC & I - Ajustes - Modo +HISTORY_MSG_CATCOMPLEX;AC & I - Ajustes - Complejidad +HISTORY_MSG_CATMODEL;AC & I - Ajustes - CAM HISTORY_MSG_CLAMPOOG;Recortar colores fuera de rango HISTORY_MSG_COLORTONING_LABGRID_VALUE;Virado - Corrección de color HISTORY_MSG_COLORTONING_LABREGION_AB;Virado - Corrección de color @@ -1410,7 +1428,7 @@ HISTORY_MSG_ICM_WORKING_ILLUM_METHOD;Método de iluminante HISTORY_MSG_ICM_WORKING_PRIM_METHOD;Método de primarios HISTORY_MSG_ICM_WORKING_SLOPE;Espacio trabajo - Pendiente HISTORY_MSG_ICM_WORKING_TRC_METHOD;Espacio trabajo - Método TRC -HISTORY_MSG_ILLUM;Iluminante +HISTORY_MSG_ILLUM;AC & I - Condic. escena - Iluminante HISTORY_MSG_LOCALCONTRAST_AMOUNT;Contraste local - Cantidad HISTORY_MSG_LOCALCONTRAST_DARKNESS;Contraste local - Oscuridad HISTORY_MSG_LOCALCONTRAST_ENABLED;Contraste local @@ -1517,6 +1535,7 @@ ICCPROFCREATOR_ILL_41;D41 ICCPROFCREATOR_ILL_50;D50 ICCPROFCREATOR_ILL_55;D55 ICCPROFCREATOR_ILL_60;D60 +ICCPROFCREATOR_ILL_63;D63: DCI-P3 Sala de cine ICCPROFCREATOR_ILL_65;D65 ICCPROFCREATOR_ILL_80;D80 ICCPROFCREATOR_ILL_DEF;Predeterminado @@ -1531,6 +1550,7 @@ ICCPROFCREATOR_PRIM_BETA;BetaRGB ICCPROFCREATOR_PRIM_BLUX;Azul X ICCPROFCREATOR_PRIM_BLUY;Azul Y ICCPROFCREATOR_PRIM_BRUCE;BruceRGB +ICCPROFCREATOR_PRIM_DCIP3;DCI-P3 ICCPROFCREATOR_PRIM_GREX;Verde X ICCPROFCREATOR_PRIM_GREY;Verde Y ICCPROFCREATOR_PRIM_PROPH;Prophoto @@ -1586,7 +1606,7 @@ IPTCPANEL_SUPPCATEGORIES;Categorías adicionales IPTCPANEL_SUPPCATEGORIESHINT;Refina aún más el tema de la imagen. IPTCPANEL_TITLE;Título IPTCPANEL_TITLEHINT;Nombre verbal y legible para la imagen. Puede ser el nombre del archivo de imagen. -IPTCPANEL_TRANSREFERENCE;Job ID +IPTCPANEL_TRANSREFERENCE;Identificador del trabajo IPTCPANEL_TRANSREFERENCEHINT;Número o identificador necesario para el control del flujo de trabajo o el seguimiento. MAIN_BUTTON_FULLSCREEN;Pantalla completa MAIN_BUTTON_ICCPROFCREATOR;Creador de perfiles ICC @@ -1690,7 +1710,7 @@ PARTIALPASTE_CACORRECTION;Corrección de aberración cromática PARTIALPASTE_CHANNELMIXER;Mezclador de canales PARTIALPASTE_CHANNELMIXERBW;Blanco y negro PARTIALPASTE_COARSETRANS;Rotación/Volteo grueso -PARTIALPASTE_COLORAPP;CIECAM02/16 +PARTIALPASTE_COLORAPP;Apariencia de color e Iluminación PARTIALPASTE_COLORGROUP;Ajustes de color PARTIALPASTE_COLORTONING;Virado de color PARTIALPASTE_COMMONTRANSFORMPARAMS;Auto-llenado @@ -1762,6 +1782,7 @@ PARTIALPASTE_SHARPENEDGE;Bordes PARTIALPASTE_SHARPENING;Nitidez (USM/RL) PARTIALPASTE_SHARPENMICRO;Microcontraste PARTIALPASTE_SOFTLIGHT;Luz suave +PARTIALPASTE_SPOT;Eliminación de manchas PARTIALPASTE_TM_FATTAL;Compresión de rango dinámico PARTIALPASTE_VIBRANCE;Vivacidad PARTIALPASTE_VIGNETTING;Corrección de viñeteado @@ -1902,7 +1923,7 @@ PREFERENCES_PERFORMANCE_MEASURE_HINT;Anota los tiempos de procesamiento en la co PREFERENCES_PERFORMANCE_THREADS;Hilos de ejecución PREFERENCES_PERFORMANCE_THREADS_LABEL;Número máximo de hilos para Reducción de ruido y Niveles de ondículas (0 = Automático) PREFERENCES_PREVDEMO;Método de desentramado de la vista previa -PREFERENCES_PREVDEMO_FAST;Fast +PREFERENCES_PREVDEMO_FAST;Rápido PREFERENCES_PREVDEMO_LABEL;Método de desentramado usado para la vista previa a ampliaciones <100%: PREFERENCES_PREVDEMO_SIDECAR;Como en PP3 PREFERENCES_PRINTER;Impresora (Prueba de impresión) @@ -2037,12 +2058,12 @@ SAVEDLG_WARNFILENAME;El archivo se nombrará SHCSELECTOR_TOOLTIP;La posición de estos tres deslizadores se reinicia haciendo clic en el botón derecho del ratón. SOFTPROOF_GAMUTCHECK_TOOLTIP;Destaca los píxels con colores fuera de rango con respecto a:\n\n- el perfil de la impresora, si éste está establecido y la prueba de impresión está activada,\n- el perfil de salida, si no se ha establecido un perfil de impresora y la prueba de impresión está activada,\n- el perfil del monitor, si la prueba de impresión está desactivada. SOFTPROOF_TOOLTIP;La prueba de impresión simula la apariencia de la imagen:\n\n- cuando se imprima, si se ha establecido un perfil de impresora en Preferencias > Gestión de color,\n- cuando se visualiza en una pantalla que usa el perfil de salida actual, si no se ha establecido un perfil de impresora. -TC_PRIM_BLUX;Bx -TC_PRIM_BLUY;By -TC_PRIM_GREX;Gx -TC_PRIM_GREY;Gy -TC_PRIM_REDX;Rx -TC_PRIM_REDY;Ry +TC_PRIM_BLUX;Azul X +TC_PRIM_BLUY;Azul Y +TC_PRIM_GREX;Verde X +TC_PRIM_GREY;Verde Y +TC_PRIM_REDX;Rojo X +TC_PRIM_REDY;Rojo Y THRESHOLDSELECTOR_B;Inferior THRESHOLDSELECTOR_BL;Inferior-izquierda THRESHOLDSELECTOR_BR;Inferior-derecha @@ -2140,7 +2161,7 @@ TP_COLORAPP_ALGO_TOOLTIP;Permite escoger entre subconjuntos de parámetros o tod TP_COLORAPP_BADPIXSL;Filtro de píxels calientes/muertos TP_COLORAPP_BADPIXSL_TOOLTIP;Supresión de píxels calientes/muertos (de un color brillante).\n0 = Sin efecto\n1 = Mediana\n2 = Gaussiano.\nAlternativamente, ajusta la imagen para evitar sombras muy oscuras.\n\nEstos artefactos se deben a limitaciones de CIECAM02. TP_COLORAPP_BRIGHT;Brillo (Q) -TP_COLORAPP_BRIGHT_TOOLTIP;El Brillo en CIECAM02/16 es la cantidad de luz percibida que emana de un estímulo, y difiere del brillo de L*a*b* y RGB. +TP_COLORAPP_BRIGHT_TOOLTIP;El Brillo en CIECAM es la cantidad de luz percibida que emana de un estímulo. Difiere del brillo de L*a*b* y RGB. TP_COLORAPP_CAT02ADAPTATION_TOOLTIP;Si se ajusta manualmente, se recomiendan valores por encima de 65. TP_COLORAPP_CATCLASSIC;Clásico TP_COLORAPP_CATMET_TOOLTIP;Clásico: funcionamiento tradicional de CIECAM. Las transformaciones de adaptación cromática se aplican separadamente en «Condiciones de la escena» e iluminante básico por un lado, y en el iluminante básico y «Condiciones de entorno» por otro.\n\nSimétrico: La adaptación cromática se basa en el balance de blancos. Los ajustes «Condiciones de la escena», «Ajustes de imagen» y «Condiciones de entorno» se neutralizan.\n\nMezcla: Como la opción «Clásico», pero en este caso, la adaptación cromática se basa en el balance de blancos. @@ -2149,29 +2170,29 @@ TP_COLORAPP_CATSYMGEN;Automático simétrico TP_COLORAPP_CATSYMSPE;Mezcla TP_COLORAPP_CHROMA;Cromaticidad (C) TP_COLORAPP_CHROMA_M;Colorido (M) -TP_COLORAPP_CHROMA_M_TOOLTIP;El colorido en CIECAM02/16 es la cantidad percibida de matiz en relación al gris, un indicador de que un estímulo parece estar más o menos coloreado. +TP_COLORAPP_CHROMA_M_TOOLTIP;El colorido en CIECAM es la cantidad percibida de matiz en relación al gris, un indicador de que un estímulo parece estar más o menos coloreado. TP_COLORAPP_CHROMA_S;Saturación (S) -TP_COLORAPP_CHROMA_S_TOOLTIP;La Saturación en CIECAM02/16 corresponde al color de un estímulo en relación a su propio brillo. Difiere de la saturación L*a*b* y RGB. -TP_COLORAPP_CHROMA_TOOLTIP;La Cromaticidad en CIECAM02/16 corresponde al color de un estímulo relativo a la claridad de un estímulo que parece blanco bajo idénticas condiciones. Difiere de la cromaticidad L*a*b* y RGB. -TP_COLORAPP_CIECAT_DEGREE;Adaptación CAT02 +TP_COLORAPP_CHROMA_S_TOOLTIP;La Saturación en CIECAM corresponde al color de un estímulo en relación a su propio brillo. Difiere de la saturación L*a*b* y RGB. +TP_COLORAPP_CHROMA_TOOLTIP;La Cromaticidad en CIECAM corresponde al color de un estímulo relativo a la claridad de un estímulo que parece blanco bajo idénticas condiciones. Difiere de la cromaticidad L*a*b* y RGB. +TP_COLORAPP_CIECAT_DEGREE;Adaptación TP_COLORAPP_CONTRAST;Contraste (J) TP_COLORAPP_CONTRAST_Q;Contraste (Q) -TP_COLORAPP_CONTRAST_Q_TOOLTIP;El Contraste (Q) en CIECAM02/16 se basa en el brillo. Difiere del contraste en L*a*b* y RGB. -TP_COLORAPP_CONTRAST_TOOLTIP;El Contraste (J) en CIECAM02/16 se basa en la claridad. Difiere del contraste en L*a*b* y RGB. +TP_COLORAPP_CONTRAST_Q_TOOLTIP;El Contraste (Q) en CIECAM se basa en el brillo. Difiere del contraste en L*a*b* y RGB. +TP_COLORAPP_CONTRAST_TOOLTIP;El Contraste (J) en CIECAM se basa en la claridad. Difiere del contraste en L*a*b* y RGB. TP_COLORAPP_CURVEEDITOR1;Curva tonal 1 -TP_COLORAPP_CURVEEDITOR1_TOOLTIP;Muestra el histograma de L* (L*a*b*) antes de CIECAM02/16.\nSi la casilla «Mostrar histogramas de salida de CIECAM02/16 en curvas» está activada, muestra el histograma de J después de CIECAM02/16.\n\nJ no se muestra en el panel del histograma principal.\n\nPara la salida final, se puede consultar el panel del histograma principal. +TP_COLORAPP_CURVEEDITOR1_TOOLTIP;Muestra el histograma de L* (L*a*b*) antes de CIECAM.\nSi la casilla «Mostrar histogramas de salida de CIECAM en curvas» está activada, muestra el histograma de J después de CIECAM.\n\nJ no se muestra en el panel del histograma principal.\n\nPara la salida final, se puede consultar el panel del histograma principal. TP_COLORAPP_CURVEEDITOR2;Curva tonal 2 TP_COLORAPP_CURVEEDITOR2_TOOLTIP;El mismo uso que la primera curva tonal J(J). TP_COLORAPP_CURVEEDITOR3;Curva de color -TP_COLORAPP_CURVEEDITOR3_TOOLTIP;Ajusta la cromaticidad, la saturación o el colorido.\n\nMuestra el histograma de cromaticidad (L*a*b*) antes de CIECAM02/16.\nSi la casilla «Mostrar histogramas de salida de CIECAM02/16 en curvas» está activada, muestra el histograma de C, S o M después de CIECAM02/16.\n\nC, S y M no se muestran en el panel del histograma principal.\nPara la salida final, se puede consultar el panel del histograma principal. -TP_COLORAPP_DATACIE;Histogramas de salida CIECAM02/16 en curvas -TP_COLORAPP_DATACIE_TOOLTIP;Si está activado, los histogramas en las curvas CIECAM02/16 muestran los valores/rangos aproximados de J, y C, S o M después de los ajustes de CIECAM02/16.\nEsta selección no influye en el histograma principal.\n\nSi está desactivado, los histogramas en las curvas CIECAM02/16 muestran los valores L*a*b* antes de los ajustes de CIECAM02/16. +TP_COLORAPP_CURVEEDITOR3_TOOLTIP;Ajusta la cromaticidad, la saturación o el colorido.\n\nMuestra el histograma de cromaticidad (L*a*b*) antes de CIECAM.\nSi la casilla «Mostrar histogramas de salida de CIECAM en curvas» está activada, muestra el histograma de C, S o M después de CIECAM.\n\nC, S y M no se muestran en el panel del histograma principal.\nPara la salida final, se puede consultar el panel del histograma principal. +TP_COLORAPP_DATACIE;Histogramas de salida CIECAM en las curvas +TP_COLORAPP_DATACIE_TOOLTIP;Si está activado, los histogramas en las curvas CIECAM muestran los valores/rangos aproximados de J, y C, S o M después de los ajustes de CIECAM.\nEsta selección no influye en el histograma principal.\n\nSi está desactivado, los histogramas en las curvas CIECAM muestran los valores L*a*b* antes de los ajustes de CIECAM. TP_COLORAPP_DEGREE_TOOLTIP;CAT02/16 es una adaptación cromática. Convierte los valores de una imagen cuyo punto blanco es el de un iluminante dado (por ejemplo D65) a nuevos valores cuyo punto blanco es el del nuevo iluminante. Consúltese el Modelo de Punto Blanco (por ejemplo, D50 or D55). TP_COLORAPP_DEGREOUT_TOOLTIP;CAT02/16 es una adaptación cromática. Convierte los valores de una imagen cuyo punto blanco es el de un iluminante dado (por ejemplo D50) a nuevos valores cuyo punto blanco es el del nuevo iluminante. Consúltese el Modelo de Punto Blanco (por ejemplo D75). TP_COLORAPP_FREE;Temperatura+verde libres + CAT02/16 + [salida] -TP_COLORAPP_GAMUT;Control de rango de colores (L*a*b*) -TP_COLORAPP_GEN;Ajustes - Preselección -TP_COLORAPP_GEN_TOOLTIP;Este módulo está basado en el modelo de apariencia de color CIECAM, que se diseñó para simular mejor cómo la visión humana percibe los colores bajo diferentes condiciones de iluminación, por ejemplo, contra fondos diferentes.\n\nTiene en cuenta el entorno de cada color y modifica su apariencia para que sea lo más cercana posible a la percepción humana.\n\nTambién adapta la salida a las condiciones de visualización previstas (monitor, TV, proyector, impresora, etc.) de modo que la apariencia cromática se preserve para todos los entornos de escena y visualización. +TP_COLORAPP_GAMUT;Emplear el control de rango de colores en el modo L*a*b* +TP_COLORAPP_GEN;Ajustes +TP_COLORAPP_GEN_TOOLTIP;Este módulo está basado en los modelos de apariencia de color CIECAM, que se diseñaron para simular mejor cómo la visión humana percibe los colores bajo diferentes condiciones de iluminación, por ejemplo, contra fondos diferentes.\n\nTiene en cuenta el entorno de cada color y modifica su apariencia para que sea lo más cercana posible a la percepción humana.\n\nTambién adapta la salida a las condiciones de visualización previstas (monitor, TV, proyector, impresora, etc.) de modo que la apariencia cromática se preserve para todos los entornos de escena y visualización. TP_COLORAPP_HUE;Matiz (h) TP_COLORAPP_HUE_TOOLTIP;Matiz (h) es el grado en que un estímulo puede describirse como similar a un color descrito como rojo, verde, azul y amarillo. TP_COLORAPP_IL41;D41 @@ -2184,12 +2205,12 @@ TP_COLORAPP_ILA;Incandescente StdA 2856K TP_COLORAPP_ILFREE;Libre TP_COLORAPP_ILLUM;Iluminante TP_COLORAPP_ILLUM_TOOLTIP;Selecciona el iluminante más cercano a las condiciones de toma.\nEn general será D50, pero puede cambiar en función de la hora y la latitud. -TP_COLORAPP_LABEL;Apariencia de Color e Iluminación (CIECAM02/16) +TP_COLORAPP_LABEL;Apariencia de Color e Iluminación TP_COLORAPP_LABEL_CAM02;Ajustes de imagen TP_COLORAPP_LABEL_SCENE;Condiciones de la escena TP_COLORAPP_LABEL_VIEWING;Condiciones de visualización TP_COLORAPP_LIGHT;Claridad (J) -TP_COLORAPP_LIGHT_TOOLTIP;La Claridad en CIECAM02/16 es la claridad de un estímulo relativa a la claridad de un estímulo que parece blanco bajo condiciones de visualización similares. Difiere de la claridad en L*a*b* y RGB. +TP_COLORAPP_LIGHT_TOOLTIP;La Claridad en CIECAM es la claridad de un estímulo relativa a la claridad de un estímulo que parece blanco bajo condiciones de visualización similares. Difiere de la claridad en L*a*b* y RGB. TP_COLORAPP_MEANLUMINANCE;Luminancia media (Yb%) TP_COLORAPP_MOD02;CIECAM02 TP_COLORAPP_MOD16;CIECAM16 @@ -2202,14 +2223,13 @@ TP_COLORAPP_NEUTRAL_TOOLTIP;Restablece todos los deslizadores, casillas de verif TP_COLORAPP_RSTPRO;Protección de rojo y tonos de piel TP_COLORAPP_RSTPRO_TOOLTIP;La Protección de rojo y tonos de piel afecta tanto a los deslizadores como a las curvas. TP_COLORAPP_SOURCEF_TOOLTIP;Corresponde a las condiciones de toma y cómo llevar las condiciones y los datos a una zona «normal». «Normal» significa aquí condiciones y datos promedio o estándar, es decir, sin tener en cuenta las correcciones CIECAM. -TP_COLORAPP_SURROUND;Entorno -TP_COLORAPP_SURROUNDSRC;Entorno - Iluminación de escena +TP_COLORAPP_SURROUND;Entorno de visualización +TP_COLORAPP_SURROUNDSRC;Entorno (Iluminación de escena) TP_COLORAPP_SURROUND_AVER;Promedio TP_COLORAPP_SURROUND_DARK;Oscuro TP_COLORAPP_SURROUND_DIM;Luz tenue TP_COLORAPP_SURROUND_EXDARK;Muy oscuro TP_COLORAPP_SURROUND_TOOLTIP;Cambia los tonos y colores teniendo en cuenta las condiciones de visualización del dispositivo de salida.\n\nPromedio: Entorno de luz promedio (estándar). La imagen no cambiará.\n\nLuz tenue: Entorno con luz tenue (TV). La imagen se volverá un poco oscura.\n\nOscuro: Entorno oscuro (proyector). La imagen se volverá más oscura.\n\nMuy oscuro: Entorno muy oscuro. La imagen se volverá muy oscura. -TP_COLORAPP_SURSOURCE;Entorno origen TP_COLORAPP_SURSOURCE_TOOLTIP;Cambia tonos y colores para tener en cuenta las condiciones de la escena.\n\nPromedio: Entorno de luz promedio (estándar). La imagen no cambiará.\n\nTenue: Entorno tenue. La imagen se volverá ligeramente brillante.\n\nOscuro: Entorno oscuro. La imagen se volverá más brillante.\n\nMuy oscuro: Entorno muy oscuro. La imagen se volverá muy brillante. TP_COLORAPP_TCMODE_BRIGHTNESS;Brillo TP_COLORAPP_TCMODE_CHROMA;Cromaticidad @@ -2221,9 +2241,9 @@ TP_COLORAPP_TCMODE_LIGHTNESS;Claridad TP_COLORAPP_TCMODE_SATUR;Saturación TP_COLORAPP_TEMP2_TOOLTIP;O bien modo simétrico, Temp = balance de blancos.\nO bien, se selecciona el iluminante, poniendo siempre Tinte=1.\n\nA Temp=2856 K\nD41 Temp=4100 K\nD50 Temp=5003 K\nD55 Temp=5503 K\nD60 Temp=6000 K\nD65 Temp=6504 K\nD75 Temp=7504 K TP_COLORAPP_TEMP_TOOLTIP;Para seleccionar un iluminante, se ajusta siempre Tinte=1.\n\nTemp A=2856 K\nTemp D50=5003 K\nTemp D55=5503 K\nTemp D65=6504 K\nTemp D75=7504 K -TP_COLORAPP_TONECIE;Mapeo tonal mediante CIECAM02 +TP_COLORAPP_TONECIE;Mapeo tonal mediante CIECAM TP_COLORAPP_TONECIE_TOOLTIP;Si esta opción está desactivada, el mapeo tonal se realiza en el espacio L*a*b*.\nSi está activada, el mapeo tonal se realiza mediante CIECAM02.\nLa herramienta Mapeo tonal debe estar activada para que este ajuste tenga efectos. -TP_COLORAPP_VIEWINGF_TOOLTIP;Tiene en cuenta el medio en el que se visualizará la imagen final (monitor, TV, proyector, impresora, ...), así como su entorno. Este proceso tomará los datos procedentes del proceso «Ajustes de imagen» y los «llevará» al medio de visualización, de tal modo que se tendrán en cuenta las condiciones de visualización. +TP_COLORAPP_VIEWINGF_TOOLTIP;Tiene en cuenta el medio en el que se visualizará la imagen final (monitor, TV, proyector, impresora, etc.), así como su entorno. Este proceso tomará los datos procedentes del proceso «Ajustes de imagen» y los «llevará» al medio de visualización, de tal modo que se tendrán en cuenta las condiciones de visualización. TP_COLORAPP_VIEWING_ABSOLUTELUMINANCE_TOOLTIP;Luminancia absoluta del entorno de visualización\n(normalmente 16 cd/m²). TP_COLORAPP_WBCAM;WB [RT+CAT02] + [salida] TP_COLORAPP_WBRT;WB [RT] + [salida] @@ -2919,6 +2939,7 @@ TP_LOCALLAB_JZHJZFRA;Curva Jz(Hz) TP_LOCALLAB_JZHUECIE;Rotación de matiz TP_LOCALLAB_JZLIGHT;Luminosidad TP_LOCALLAB_JZLOG;Codificación Log Jz +TP_LOCALLAB_JZLOGWBS_TOOLTIP;Los ajustes Ev de Negro y Ev de Blanco pueden ser diferentes, dependiendo de si se usa Codificación logarítmica o Sigmoide.\nEn el caso de Sigmoide, puede ser necesario un cambio (aumento en la mayoría de los casos) de Ev de Blanco, para obtener una mejor representación de las altas luces, el contraste y la saturación. TP_LOCALLAB_JZLOGWB_TOOLTIP;Si Auto está activado, calculará y ajustará los niveles Ev y la «luminancia media Yb%» en el área del punto de edición. Los valores resultantes se usarán en todas las operaciones Jz, incluyendo «Codificación Log Jz».\nTambién calcula la luminancia absoluta en el momento de la toma. TP_LOCALLAB_JZLOGYBOUT_TOOLTIP;Yb es la luminosidad relativa del fondo, expresada como un porcentaje de gris. Un 18% de gris corresponde a una luminosidad del fondo del 50%, expresada en CIE L.\nLos datos se basan en la luminosidad media de la imagen.\nSi se usa con la Codificación logarítmica, la luminosidad media se utilizará para determinar la cantidad de ganancia que se necesita aplicar a la señal antes de la codificación logarítimica. Los valores bajos de luminosidad media darán como resultado un aumento de la ganancia. TP_LOCALLAB_JZMODECAM_TOOLTIP;Jz (sólo en modo «Avanzado»). Sólo funcionará si el dispositivo de salida (monitor) es HDR (luminancia pico mayor que 100 cd/m², idealmente entre 4000 y 10000 cd/m², y luminancia del punto negro inferior a 0.005 cd/m²). Esto supone que: a) el espacio de conexión de perfiles ICC (ICC-PCS) para la pantalla usa Jzazbz (o XYZ), b) trabaja con precisión de números reales (de coma flotante), c) el monitor está calibrado (si es posible, con un rango de colores DCI-P3 o Rec-2020), d) la gamma usual (sRGB o BT709) se substituye por una función Cuantificadora Perceptual (CP). @@ -2979,6 +3000,8 @@ TP_LOCALLAB_LOGAUTOGRAY_TOOLTIP;Calcula automáticamente la «luminancia media» TP_LOCALLAB_LOGAUTO_TOOLTIP;Al pulsar este botón se calculará el «rango dinámico» y la «luminancia media» para las condiciones de la escena si está activada la casilla «Luminancia media automática (Yb%)».\nTambién se calcula la luminancia absoluta en el momento de la toma.\nPara ajustar los valores calculados automáticamente hay que volver a pulsar el botón. TP_LOCALLAB_LOGBASE_TOOLTIP;Valor predeterminado = 2.\nLos valores menores que 2 reducen la acción del algoritmo, haciendo las sombras más oscuras y las luces más brillantes.\nCon valores mayores que 2, las sombras son más grises y las luces son más desteñidas. TP_LOCALLAB_LOGCATAD_TOOLTIP;La adaptación cromática permite interpretar un color en función de su entorno espacio-temporal.\nEs útil cuando el balance de blancos está lejos de la referencia D50.\nAdapta los colores al iluminante del dispositivo de salida. +TP_LOCALLAB_LOGCIE;Codificación logarítmica en lugar de Sigmoide +TP_LOCALLAB_LOGCIE_TOOLTIP;Permite el uso de Ev de Negro, Ev de Blanco, Luminancia media de la escena (Yb%) y Luminancia media de la visualización (Yb%) para el mapeo tonal con Codificación logarítmica Q. TP_LOCALLAB_LOGCOLORFL;Colorido (M) TP_LOCALLAB_LOGCOLORF_TOOLTIP;Cantidad de matiz percibida en relación al gris.\nIndicador de que un estímulo parece más o menos coloreado. TP_LOCALLAB_LOGCONQL;Contraste (Q) @@ -3003,6 +3026,7 @@ TP_LOCALLAB_LOGREPART;Intensidad TP_LOCALLAB_LOGREPART_TOOLTIP;Permite ajustar la intensidad relativa de la imagen codificada logarítmicamente con respecto a la imagen original.\nNo afecta al componente Ciecam. TP_LOCALLAB_LOGSATURL_TOOLTIP;La Saturación (s) en CIECAM16 corresponde al color de un estímulo en relación a su propio brillo.\nActúa principalmente en tonos medios y luces. TP_LOCALLAB_LOGSCENE_TOOLTIP;Corresponde a las condiciones de toma. +TP_LOCALLAB_LOGSURSOUR_TOOLTIP;Cambia los tonos y colores teniendo en cuenta las condiciones de la escena.\n\nPromedio: Condiciones de luz promedio (estándar). La imagen no cambiará.\n\nTenue: Condiciones de luz tenue. La imagen será ligeramente más brillante.\n\nOscuro: Condiciones de oscuridad. La imagen será más brillante. TP_LOCALLAB_LOGVIEWING_TOOLTIP;Corresponde al medio en el que se visualizará la imagen final (monitor, TV, proyector, impresora,..), así como su entorno. TP_LOCALLAB_LOG_TOOLNAME;Codificación logarítmica - 0 TP_LOCALLAB_LUM;Curvas LL - CC @@ -3068,7 +3092,6 @@ TP_LOCALLAB_MASKRESWAV_TOOLTIP;Usado para modular el efecto de los ajustes de Co TP_LOCALLAB_MASKUNUSABLE;Máscara desactivada (Máscara y modificaciones) TP_LOCALLAB_MASKUSABLE;Máscara activada (Máscara y modificaciones) TP_LOCALLAB_MASK_TOOLTIP;Se puede activar varias máscaras para una herramienta, activando otra herramienta y usando solamente la máscara (ajusta los deslizadores de la herramienta a 0 ).\n\nTambién es posible duplicar el punto RT y situarlo cerca del primer punto. Las pequeñas variaciones en las referencias del punto permiten hacer ajustes finos. -TP_LOCALLAB_MED;Medio TP_LOCALLAB_MEDIAN;Mediana baja TP_LOCALLAB_MEDIANITER_TOOLTIP;El número de iteraciones sucesivas llevadas a cabo por el filtro de mediana. TP_LOCALLAB_MEDIAN_TOOLTIP;Se puede elegir un valor de mediana en el rango de 3x3 a 9x9 píxels. Los valores altos aumentan la reducción de ruido y el difuminado. @@ -3480,9 +3503,9 @@ TP_RAWEXPOS_LINEAR;Corrección de punto blanco TP_RAWEXPOS_RGB;Rojo, Verde, Azul TP_RAWEXPOS_TWOGREEN;Vincular verdes TP_RAW_1PASSMEDIUM;1 paso (Markesteijn) -TP_RAW_2PASS;1 paso + fast +TP_RAW_2PASS;1 paso + rápido TP_RAW_3PASSBEST;3 pasos (Markesteijn) -TP_RAW_4PASS;3 pasos + fast +TP_RAW_4PASS;3 pasos + rápido TP_RAW_AHD;AHD TP_RAW_AMAZE;AMaZE TP_RAW_AMAZEBILINEAR;AMaZE+Bilineal @@ -3502,7 +3525,7 @@ TP_RAW_DUALDEMOSAICAUTOCONTRAST_TOOLTIP;Si la casilla está activada (recomendad TP_RAW_DUALDEMOSAICCONTRAST;Umbral de contraste TP_RAW_EAHD;EAHD TP_RAW_FALSECOLOR;Pasos de supresión de falso color -TP_RAW_FAST;Fast +TP_RAW_FAST;Rápido TP_RAW_HD;Umbral TP_RAW_HD_TOOLTIP;Los valores bajos hacen más agresiva la detección de píxels muertos/calientes, pero los falsos positivos pueden dar lugar a artefactos. Si se observa la aparición de cualquier artefacto al activar el filtro de píxel muerto/caliente, debe incrementarse gradualmente el umbral hasta que desaparezcan. TP_RAW_HPHD;HPHD @@ -3549,11 +3572,11 @@ TP_RAW_RCD;RCD TP_RAW_RCDBILINEAR;RCD+Bilineal TP_RAW_RCDVNG4;RCD+VNG4 TP_RAW_SENSOR_BAYER_LABEL;Sensor con matriz Bayer -TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP;El método de 3 pasos da los mejores resultados (recomendado para imágenes de ISO baja).\nEl método de 1 paso es casi indistinguible del de 3 pasos para imágenes de ISO alta y es más rápido.\n+fast genera menos artefactos en zonas planas. +TP_RAW_SENSOR_XTRANS_DMETHOD_TOOLTIP;El método de 3 pasos da los mejores resultados (recomendado para imágenes de ISO baja).\nEl método de 1 paso es casi indistinguible del de 3 pasos para imágenes de ISO alta y es más rápido.\n+rápido genera menos artefactos en zonas planas. TP_RAW_SENSOR_XTRANS_LABEL;Sensor con matriz X-Trans TP_RAW_VNG4;VNG4 TP_RAW_XTRANS;X-Trans -TP_RAW_XTRANSFAST;Fast X-Trans +TP_RAW_XTRANSFAST;X-Trans rápido TP_RESIZE_ALLOW_UPSCALING;Permitir aumento de tamaño TP_RESIZE_APPLIESTO;Se aplica a: TP_RESIZE_CROPPEDAREA;Área recortada @@ -4042,35 +4065,4 @@ ZOOMPANEL_ZOOMFITCROPSCREEN;Encajar recorte en la vista previa\nAtajo de teclado ZOOMPANEL_ZOOMFITSCREEN;Encajar la imagen entera en la vista previa\nAtajo de teclado: Alt-f ZOOMPANEL_ZOOMIN;Acercar\nAtajo de teclado: + ZOOMPANEL_ZOOMOUT;Alejar\nAtajo de teclado: - -xTP_LOCALLAB_LOGSURSOUR_TOOLTIP;Cambia los tonos y colores para tener en cuenta las condiciones de la escena.\n\nPromedio: Entorno de luz promedio (estándar). La imagen no cambiará.\n\nTenue: Entorno tenue. La imagen aumentará su brillo ligeramente. -//HISTORY_MSG_1099;Local - Curva Hz(Hz) -!!!!!!!!!!!!!!!!!!!!!!!!! -! Untranslated keys follow; remove the ! prefix after an entry is translated. -!!!!!!!!!!!!!!!!!!!!!!!!! - -!HISTORY_MSG_446;--unused-- -!HISTORY_MSG_447;--unused-- -!HISTORY_MSG_448;--unused-- -!HISTORY_MSG_450;--unused-- -!HISTORY_MSG_451;--unused-- -!HISTORY_MSG_454;--unused-- -!HISTORY_MSG_455;--unused-- -!HISTORY_MSG_456;--unused-- -!HISTORY_MSG_458;--unused-- -!HISTORY_MSG_459;--unused-- -!HISTORY_MSG_460;--unused-- -!HISTORY_MSG_461;--unused-- -!HISTORY_MSG_463;--unused-- -!HISTORY_MSG_466;--unused-- -!HISTORY_MSG_467;--unused-- -!HISTORY_MSG_470;--unused-- -!HISTORY_MSG_1149;Local - Q Sigmoid -!HISTORY_MSG_1150;Local - Log encoding Q instead Sigmoid Q -!ICCPROFCREATOR_ILL_63;D63 : DCI-P3 Theater -!ICCPROFCREATOR_PRIM_DCIP3;DCI-P3 -!PARTIALPASTE_SPOT;Spot removal -!TP_LOCALLAB_JZLOGWBS_TOOLTIP;Black Ev and White Ev adjustments can be different depending on whether Log encoding or Sigmoid is used.\nFor Sigmoid, a change (increase in most cases) of White Ev may be necessary to obtain a better rendering of highlights, contrast and saturation. -!TP_LOCALLAB_LOGCIE;Log encoding instead of Sigmoid -!TP_LOCALLAB_LOGCIE_TOOLTIP;Allows you tu use Black Ev, White Ev, Scene Mean luminance(Yb%) and Viewing Mean luminance(Yb%) for tone-mapping using Log encoding Q. -!TP_LOCALLAB_LOGSURSOUR_TOOLTIP;Changes tones and colors to take into account the Scene conditions.\n\nAverage: Average light conditions (standard). The image will not change.\n\nDim: Dim conditions. The image will become slightly brighter.\n\nDark: Dark conditions. The image will become more bright. From db1e7659a27a020f9eb00dc4656429d1889e1514 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Sat, 22 Oct 2022 20:19:10 +0200 Subject: [PATCH 054/134] Japanese translation updated by Yz2house Closes #6598 --- rtdata/languages/Japanese | 585 +++++++++++++++++++------------------- 1 file changed, 287 insertions(+), 298 deletions(-) diff --git a/rtdata/languages/Japanese b/rtdata/languages/Japanese index 913ee8112..0f35036db 100644 --- a/rtdata/languages/Japanese +++ b/rtdata/languages/Japanese @@ -1,15 +1,4 @@ -#01 2011-05-15 a3novy -#02 2011-11-13 a3novy -#03 2011-11-20 a3novy -#04 2011-12-03 a3novy -#05 2012-02-11 a3novy -#06 2012-04-04 a3novy -#07 2012-07-12 a3novy -#08 2012-12-22 a3novy -#09 2013-04-01 a3novy -#10 2013-04-19 a3novy -#11 2020-06-24 Yz2house -#12 2022-06-04 Yz2house +#Last update 10-12-2022 ABOUT_TAB_BUILD;バージョン ABOUT_TAB_CREDITS;クレジット @@ -19,9 +8,9 @@ ABOUT_TAB_SPLASH;スプラッシュ ADJUSTER_RESET_TO_DEFAULT;クリック - デフォルト値にリセット\nCtrl+クリック - 初期値にリセット BATCH_PROCESSING;バッチ処理 CURVEEDITOR_AXIS_IN;入力値: -CURVEEDITOR_AXIS_LEFT_TAN;LT: +CURVEEDITOR_AXIS_LEFT_TAN;左正接: CURVEEDITOR_AXIS_OUT;出力値: -CURVEEDITOR_AXIS_RIGHT_TAN;RT: +CURVEEDITOR_AXIS_RIGHT_TAN;右正接: CURVEEDITOR_CATMULLROM;フレキシブル CURVEEDITOR_CURVE;カーブ CURVEEDITOR_CURVES;カーブ @@ -38,7 +27,7 @@ CURVEEDITOR_PARAMETRIC;パラメトリック CURVEEDITOR_SAVEDLGLABEL;カーブの保存... CURVEEDITOR_SHADOWS;シャドウ CURVEEDITOR_TOOLTIPCOPY;クリップボードに現在のカーブをコピー -CURVEEDITOR_TOOLTIPLINEAR;リニアにリセット +CURVEEDITOR_TOOLTIPLINEAR;線形にリセット CURVEEDITOR_TOOLTIPLOAD;ファイルからカーブを読み込む CURVEEDITOR_TOOLTIPPASTE;クリップボードからカーブを貼り付け CURVEEDITOR_TOOLTIPSAVE;現在のカーブを保存 @@ -52,7 +41,7 @@ DYNPROFILEEDITOR_ENTRY_TOOLTIP;整合性が悪い場合は、入力する際に" DYNPROFILEEDITOR_IMGTYPE_ANY;任意 DYNPROFILEEDITOR_IMGTYPE_HDR;HDR DYNPROFILEEDITOR_IMGTYPE_PS;ピクセルシフト -DYNPROFILEEDITOR_IMGTYPE_STD;標準え +DYNPROFILEEDITOR_IMGTYPE_STD;標準 DYNPROFILEEDITOR_MOVE_DOWN;下に移動 DYNPROFILEEDITOR_MOVE_UP;上に移動 DYNPROFILEEDITOR_NEW;新規 @@ -197,7 +186,7 @@ FILEBROWSER_SHOWCOLORLABEL5HINT;パープル・ラベルの画像を表示\nシ FILEBROWSER_SHOWDIRHINT;全ての絞り込みをクリア\nショートカット: d FILEBROWSER_SHOWEDITEDHINT;編集済み画像を表示\nショートカット: 7 FILEBROWSER_SHOWEDITEDNOTHINT;未編集画像を表示\nショートカット: 6 -FILEBROWSER_SHOWEXIFINFO;EXIF情報を表示\nショートカット: i\n\nシングル・エディタ・タブのショートカット: Alt-i +FILEBROWSER_SHOWEXIFINFO;EXIF情報を表示\nショートカット: i\n\nシングル編集タブのショートカット: Alt-i FILEBROWSER_SHOWNOTTRASHHINT;ゴミ箱の中にある画像だけを表示 FILEBROWSER_SHOWORIGINALHINT;元画像だけを表示\n\nファイル名は同じだが拡張子が異なる画像がある場合は、環境設定の中のファイルブラウザタブにある拡張子リストの上位に位置する拡張子を持った画像を元画像とする。 FILEBROWSER_SHOWRANK1HINT;1つ星ランクを表示\nショートカット: 1 @@ -212,8 +201,8 @@ FILEBROWSER_SHOWUNCOLORHINT;カラー・ラベルのない画像を表示\nシ FILEBROWSER_SHOWUNRANKHINT;ランクなし画像を表示\nショートカット: 0 FILEBROWSER_THUMBSIZE;サムネイルのサイズ FILEBROWSER_UNRANK_TOOLTIP;ランクなし\nショートカット: Shift-0 -FILEBROWSER_ZOOMINHINT;サムネイルサイズの拡大\nショートカット: +\n\nシングル・エディタ・タブのショートカット: Alt-+ -FILEBROWSER_ZOOMOUTHINT;サムネイルサイズの縮小\nショートカット: -\n\nシングル・エディタ・タブのショートカット: Alt-- +FILEBROWSER_ZOOMINHINT;サムネイルサイズの拡大\nショートカット: +\n\nシングル編集タブのショートカット: Alt-+ +FILEBROWSER_ZOOMOUTHINT;サムネイルサイズの縮小\nショートカット: -\n\nシングル編集タブのショートカット: Alt-- FILECHOOSER_FILTER_ANY;全てのファイル FILECHOOSER_FILTER_COLPROF;カラープロファイル FILECHOOSER_FILTER_CURVE;カーブファイル @@ -311,14 +300,14 @@ HISTORY_MSG_40;色偏差 HISTORY_MSG_41;トーンカーブ1のモード HISTORY_MSG_42;トーンカーブ 2 HISTORY_MSG_43;トーンカーブ2のモード -HISTORY_MSG_48;DCPトーンカーブ使用 -HISTORY_MSG_49;色ノイズ低減 エッジの感度 +HISTORY_MSG_48;DCP トーンカーブ +HISTORY_MSG_49;DCP 光源 HISTORY_MSG_50;シャドウ/ハイライト -HISTORY_MSG_51;ハイライト -HISTORY_MSG_52;シャドウ -HISTORY_MSG_53;ハイライト トーンの幅 -HISTORY_MSG_54;シャドウ トーンの幅 -HISTORY_MSG_56;シャドウ/ハイライト 半径 +HISTORY_MSG_51;S/H - ハイライト +HISTORY_MSG_52;S/H - シャドウ +HISTORY_MSG_53;S/H - ハイライト トーンの幅 +HISTORY_MSG_54;S/H - シャドウ トーンの幅 +HISTORY_MSG_56;S/H - シャドウ/ハイライト 半径 HISTORY_MSG_57;90度 回転 HISTORY_MSG_58;左右反転 HISTORY_MSG_59;上下反転 @@ -339,9 +328,9 @@ HISTORY_MSG_74;リサイズ スケール HISTORY_MSG_75;リサイズ 方式 HISTORY_MSG_76;Exif メタデータ HISTORY_MSG_77;IPTC メタデータ -HISTORY_MSG_79;リサイズ幅 +HISTORY_MSG_79;リサイズ 幅 HISTORY_MSG_80;リサイズ 高さ -HISTORY_MSG_81;リサイズの有効・無効 +HISTORY_MSG_81;リサイズ HISTORY_MSG_82;プロファイル変更 HISTORY_MSG_84;パースペクティブの補正 HISTORY_MSG_85;レンズ補正 プロファイル @@ -426,39 +415,39 @@ HISTORY_MSG_170;自然な彩度 - カーブ HISTORY_MSG_171;L*a*b* LC カーブ HISTORY_MSG_172;LCの適用をレッドと肌色トーンだけに制限 HISTORY_MSG_173;ノイズ低減 - 細部の復元 -HISTORY_MSG_174;CIE色の見えモデル2002 -HISTORY_MSG_175;CAM02 - CAT02 -HISTORY_MSG_176;CAM02 - 観視環境 -HISTORY_MSG_177;CAM02 - 画像の輝度 -HISTORY_MSG_178;CAM02 - 観視の輝度 -HISTORY_MSG_179;CAM02 - ホワイトポイントモデル -HISTORY_MSG_180;CAM02 - 明度 (J) -HISTORY_MSG_181;CAM02 - 色度 (C) -HISTORY_MSG_182;CAM02 - 自動 CAT02 -HISTORY_MSG_183;CAM02 - コントラスト (J) -HISTORY_MSG_184;CAM02 - 画像の周辺環境 -HISTORY_MSG_185;CAM02 - 色域制御 -HISTORY_MSG_186;CAM02 - アルゴリズム -HISTORY_MSG_187;CAM02 - レッドと肌色トーンを保護 -HISTORY_MSG_188;CAM02 - 明るさ (Q) -HISTORY_MSG_189;CAM02 - コントラスト (Q) -HISTORY_MSG_190;CAM02 - 彩度 (S) -HISTORY_MSG_191;CAM02 - 彩度 (M) -HISTORY_MSG_192;CAM02 - 色相角 -HISTORY_MSG_193;CAM02 - トーンカーブ 1 -HISTORY_MSG_194;CAM02 - トーンカーブ 2 -HISTORY_MSG_195;CAM02 - トーンカーブ 1 -HISTORY_MSG_196;CAM02 - トーンカーブ 2 -HISTORY_MSG_197;CAM02 - カラー・カーブ -HISTORY_MSG_198;CAM02 - カラー・カーブ -HISTORY_MSG_199;CAM02 - 出力のヒストグラムを表示 -HISTORY_MSG_200;CAM02 - トーンマッピング +HISTORY_MSG_174;色の見え&明るさ +HISTORY_MSG_175;CAL - 場面 - 色順応 +HISTORY_MSG_176;CAL - 観視 - 周囲 +HISTORY_MSG_177;CAL - 場面 - 絶対輝度 +HISTORY_MSG_178;CAL - 観視 - 絶対輝度 +HISTORY_MSG_179;CAL - 場面 - ホワイトポイントモデル +HISTORY_MSG_180;CAL - 編集 - 明度(J) +HISTORY_MSG_181;CAL - 編集 - 色度(C) +HISTORY_MSG_182;CAL - 場面 - 自動色順応 +HISTORY_MSG_183;CAL - 編集 - コントラスト(J) +HISTORY_MSG_184;CAL - 場面 - 周囲 +HISTORY_MSG_185;CAL - 色域制御 +HISTORY_MSG_186;CAL - 編集 - アルゴリズム +HISTORY_MSG_187;CAL - 編集 - レッドと肌色トーンを保護 +HISTORY_MSG_188;CAL - 編集 - 明るさ(Q) +HISTORY_MSG_189;CAL - 編集 - コントラスト(Q) +HISTORY_MSG_190;CAL - 編集 - 彩度(S) +HISTORY_MSG_191;CAL - 編集 - 鮮やかさ(M) +HISTORY_MSG_192;CAL - 編集 - 色相(h) +HISTORY_MSG_193;CAL - 編集 - トーンカーブ 1 +HISTORY_MSG_194;CAL - 編集 - トーンカーブ 2 +HISTORY_MSG_195;CAL - 編集 - トーンカーブ1のモード +HISTORY_MSG_196;CAL - 編集 - トーンカーブ2のモード +HISTORY_MSG_197;CAL - 編集 - カラーカーブ +HISTORY_MSG_198;CAL - 編集 - カラーカーブのモード +HISTORY_MSG_199;CAL - 編集 - ヒストグラムにCAMの出力を使う +HISTORY_MSG_200;CAL - 編集 - トーンマッピングにCAMを使う HISTORY_MSG_201;色差 レッド/グリーン HISTORY_MSG_202;色差 ブルー/イエロー HISTORY_MSG_203;ノイズ低減 - 方式 HISTORY_MSG_204;LMMSE 拡張処理 -HISTORY_MSG_205;CAM02 ホット/バッドピクセル -HISTORY_MSG_206;CAT02 - 自動で順応 +HISTORY_MSG_205;CAL ホット/バッドピクセル +HISTORY_MSG_206;CAL - 場面 - 自動で絶対輝度 HISTORY_MSG_207;フリンジ低減 - 色相カーブ HISTORY_MSG_208;ブルー/レッド イコライザ HISTORY_MSG_210;減光フィルター - 角度 @@ -487,7 +476,7 @@ HISTORY_MSG_232;白黒 ‘前の‘カーブのタイプ HISTORY_MSG_233;白黒 ‘後の‘カーブ HISTORY_MSG_234;白黒 ‘後の‘カーブのタイプ HISTORY_MSG_235;白黒 チャンネルミキサー 自動 -HISTORY_MSG_236;--未使用-- +HISTORY_MSG_236;--未使用の文字列-- HISTORY_MSG_237;白黒 チャンネルミキサー HISTORY_MSG_238;減光フィルター フェザー HISTORY_MSG_239;減光フィルター 強さ @@ -500,8 +489,8 @@ HISTORY_MSG_245;ビネットフィルター 中央 HISTORY_MSG_246;L*a*b* CL カーブ HISTORY_MSG_247;L*a*b* LH カーブ HISTORY_MSG_248;L*a*b* HH カーブ -HISTORY_MSG_249;詳細レベルによるコントラスト調整 - しきい値 -HISTORY_MSG_251;白黒 - アルゴリズム +HISTORY_MSG_249;CbDL しきい値 +HISTORY_MSG_251;白黒 アルゴリズム HISTORY_MSG_252;CbDL 肌色の目標/保護 HISTORY_MSG_253;CbDL アーティファクトを軽減 HISTORY_MSG_254;CbDL 肌色の色相 @@ -525,7 +514,7 @@ HISTORY_MSG_271;カラートーン調整 - ハイライトのブルー HISTORY_MSG_272;カラートーン調整 - バランス HISTORY_MSG_273;カラートーン調整 - SMHでカラーバランス HISTORY_MSG_276;カラートーン調整 - 不透明度 -HISTORY_MSG_277;カラートーン調整 - カーブをリセット +HISTORY_MSG_277;--未使用の文字列-- HISTORY_MSG_278;カラートーン調整 - 明度を維持 HISTORY_MSG_279;カラートーン調整 - シャドウ HISTORY_MSG_280;カラートーン調整 - ハイライト @@ -545,7 +534,7 @@ HISTORY_MSG_293;フィルムシミュレーション HISTORY_MSG_294;フィルムシミュレーション - 強さ HISTORY_MSG_295;フィルムシミュレーション - フィルム HISTORY_MSG_296;輝度ノイズ低減のカーブ -HISTORY_MSG_297;ノイズ低減 - 質 +HISTORY_MSG_297;ノイズ低減 - モード HISTORY_MSG_298;デッドピクセルフィルター HISTORY_MSG_299;色ノイズ低減のカーブ HISTORY_MSG_301;輝度ノイズの調整方法 @@ -671,7 +660,7 @@ HISTORY_MSG_421;レティネックス - ガンマ HISTORY_MSG_422;レティネックス - ガンマ HISTORY_MSG_423;レティネックス - 勾配 HISTORY_MSG_424;レティネックス - HLしきい値 -HISTORY_MSG_425;レティネックス - 対数の基数 +HISTORY_MSG_425;--未使用の文字列-- HISTORY_MSG_426;レティネックス - 色相イコライザ HISTORY_MSG_427;出力レンダリングの意図 HISTORY_MSG_428;モニターレンダリングの意図 @@ -692,44 +681,44 @@ HISTORY_MSG_442;レティネックス - スケール HISTORY_MSG_443;出力のブラックポイント補正 HISTORY_MSG_444;WB - 色温度のバイアス HISTORY_MSG_445;Raw サブイメージ -HISTORY_MSG_446;EvPixelShiftMotion -HISTORY_MSG_447;EvPixelShiftMotionCorrection -HISTORY_MSG_448;EvPixelShiftStddevFactorGreen +HISTORY_MSG_446;--未使用の文字列-- +HISTORY_MSG_447;--未使用の文字列-- +HISTORY_MSG_448;--未使用の文字列-- HISTORY_MSG_449;PS - ISOへの適合 -HISTORY_MSG_450;EvPixelShiftNreadIso -HISTORY_MSG_451;EvPixelShiftPrnu -HISTORY_MSG_452;PS - モーションを表示 +HISTORY_MSG_450;--未使用の文字列-- +HISTORY_MSG_451;--未使用の文字列-- +HISTORY_MSG_452;PS - 動体部分を表示 HISTORY_MSG_453;PS - マスクだけを表示 -HISTORY_MSG_454;EvPixelShiftAutomatic -HISTORY_MSG_455;EvPixelShiftNonGreenHorizontal -HISTORY_MSG_456;EvPixelShiftNonGreenVertical +HISTORY_MSG_454;--未使用の文字列-- +HISTORY_MSG_455;--未使用の文字列-- +HISTORY_MSG_456;--未使用の文字列-- HISTORY_MSG_457;PS - レッド/ブルーを確認 -HISTORY_MSG_458;EvPixelShiftStddevFactorRed -HISTORY_MSG_459;EvPixelShiftStddevFactorBlue -HISTORY_MSG_460;EvPixelShiftGreenAmaze -HISTORY_MSG_461;EvPixelShiftNonGreenAmaze +HISTORY_MSG_458;--未使用の文字列-- +HISTORY_MSG_459;--未使用の文字列-- +HISTORY_MSG_460;--未使用の文字列-- +HISTORY_MSG_461;--未使用の文字列-- HISTORY_MSG_462;PS - グリーンを確認 -HISTORY_MSG_463;EvPixelShiftRedBlueWeight -HISTORY_MSG_464;PS - モーションマスクをぼかす +HISTORY_MSG_463;--未使用の文字列-- +HISTORY_MSG_464;PS - 動体マスクをぼかす HISTORY_MSG_465;PS - ぼかしの半径 -HISTORY_MSG_466;EvPixelShiftSum -HISTORY_MSG_467;EvPixelShiftExp0 +HISTORY_MSG_466;--未使用の文字列-- +HISTORY_MSG_467;--未使用の文字列-- HISTORY_MSG_468;PS - 穴を埋める HISTORY_MSG_469;PS - メディアン -HISTORY_MSG_470;EvPixelShiftMedian3 -HISTORY_MSG_471;PS - 振れの補正 +HISTORY_MSG_470;--未使用の文字列-- +HISTORY_MSG_471;PS - 動体補正 HISTORY_MSG_472;PS - 境界を滑らかにする HISTORY_MSG_474;PS - 均等化 HISTORY_MSG_475;PS - 色チャンネルの均等化 -HISTORY_MSG_476;CAM02 - 観視環境の色温度 -HISTORY_MSG_477;CAM02 - 観視環境の色偏差 -HISTORY_MSG_478;CAM02 - 観視環境のYb -HISTORY_MSG_479;CAM02 - 観視環境のCAT02 -HISTORY_MSG_480;CAM02 - 観視環境のCAT02 自動 -HISTORY_MSG_481;CAM02 - 撮影環境の色温度 -HISTORY_MSG_482;CAM02 - 撮影環境の色偏差 -HISTORY_MSG_483;CAM02 - 撮影環境のYb -HISTORY_MSG_484;CAM02 - 撮影環境のYb 自動 +HISTORY_MSG_476;CAL - 観視 - 色温度 +HISTORY_MSG_477;CAL - 観視 - 色偏差 +HISTORY_MSG_478;CAL - 観視 - 平均輝度 +HISTORY_MSG_479;CAL - 観視 - 色順応 +HISTORY_MSG_480;CAL - 観視 - 色順応(自動) +HISTORY_MSG_481;CAL - 場面 - 色温度 +HISTORY_MSG_482;CAL - 場面 - 色偏差 +HISTORY_MSG_483;CAL - 場面 - 平均輝度 +HISTORY_MSG_484;CAL - 場面 - 平均輝度(自動) HISTORY_MSG_485;レンズ補正 HISTORY_MSG_486;レンズ補正 - カメラ HISTORY_MSG_487;レンズ補正 - レンズ @@ -824,7 +813,7 @@ HISTORY_MSG_576;ローカル - CbDL 複数のレベル HISTORY_MSG_577;ローカル - CbDL 色度 HISTORY_MSG_578;ローカル - CbDL しきい値 HISTORY_MSG_579;ローカル - CbDL スコープ -HISTORY_MSG_580;ローカル - ノイズ除去 +HISTORY_MSG_580;--未使用の文字列-- HISTORY_MSG_581;ローカル - ノイズ除去 輝度 番手の低いレベル HISTORY_MSG_582;ローカル - ノイズ除去 輝度 番手の高いレベル HISTORY_MSG_583;ローカル - ノイズ除去 ディテールの回復 @@ -867,9 +856,9 @@ HISTORY_MSG_620;ローカル - 色と明るさ ぼかし HISTORY_MSG_621;ローカル - 露光補正 反対処理 HISTORY_MSG_622;ローカル - 構造の除外 HISTORY_MSG_623;ローカル - 露光補正 色の補間 -HISTORY_MSG_624;ローカル - 色と明るさ 補正グリッド -HISTORY_MSG_625;ローカル - 色と明るさ 補正の強さ -HISTORY_MSG_626;ローカル - 色と明るさ 補正の方式 +HISTORY_MSG_624;ローカル - カラー補正グリッド +HISTORY_MSG_625;ローカル - 補正グリッドの強さ +HISTORY_MSG_626;ローカル - 補正グリッドの方式 HISTORY_MSG_627;ローカル - シャドウ/ハイライト HISTORY_MSG_628;ローカル - シャドウハイライト ハイライト HISTORY_MSG_629;ローカル - シャドウハイライト ハイライトトーンの幅 @@ -907,7 +896,7 @@ HISTORY_MSG_660;ローカル - CbDL 明瞭 HISTORY_MSG_661;ローカル - CbDL 残差のコントラスト HISTORY_MSG_662;ローカル - deNoise 輝度 細かい0 HISTORY_MSG_663;ローカル - deNoise 輝度 細かい2 -HISTORY_MSG_664;ローカル - CbDL ぼかし +HISTORY_MSG_664;--未使用の文字列-- HISTORY_MSG_665;ローカル - CbDL ブレンドのマスク HISTORY_MSG_666;ローカル - CbDL 半径のマスク HISTORY_MSG_667;ローカル - CbDL 色度のマスク @@ -986,16 +975,16 @@ HISTORY_MSG_745;ローカル - Exp Fattal オフセット HISTORY_MSG_746;ローカル - Exp Fattal シグマ HISTORY_MSG_747;ローカル 作成されたスポット HISTORY_MSG_748;ローカル - Exp ノイズ除去 -HISTORY_MSG_749;ローカル - Reti 深度 -HISTORY_MSG_750;ローカル - Reti モード 対数 - 線形 -HISTORY_MSG_751;ローカル - Reti 霞除去 彩度 -HISTORY_MSG_752;ローカル - Reti オフセット -HISTORY_MSG_753;ローカル - Reti 透過マップ -HISTORY_MSG_754;ローカル - Reti クリップ +HISTORY_MSG_749;ローカル - レティネックス 深度 +HISTORY_MSG_750;ローカル - レティネックス モード 対数 - 線形 +HISTORY_MSG_751;ローカル - レティネックス 霞除去 彩度 +HISTORY_MSG_752;ローカル - レティネックス オフセット +HISTORY_MSG_753;ローカル - レティネックス 透過マップ +HISTORY_MSG_754;ローカル - レティネックス クリップ HISTORY_MSG_755;ローカル - TM マスクを使う HISTORY_MSG_756;ローカル - Exp 露光補正マスクのアルゴリズムを使う HISTORY_MSG_757;ローカル - Exp ラプラシアンマスク -HISTORY_MSG_758;ローカル - Reti ラプラシアンマスク +HISTORY_MSG_758;ローカル - レティネックス ラプラシアンマスク HISTORY_MSG_759;ローカル - Exp ラプラシアンマスク HISTORY_MSG_760;ローカル - Color ラプラシアンマスク HISTORY_MSG_761;ローカル - シャドウハイライト ラプラシアンマスク @@ -1011,7 +1000,7 @@ HISTORY_MSG_770;ローカル - Color コントラストカーブのマスク HISTORY_MSG_771;ローカル - Exp コントラストカーブのマスク HISTORY_MSG_772;ローカル - シャドウハイライト コントラストカーブのマスク HISTORY_MSG_773;ローカル - TM コントラストカーブのマスク -HISTORY_MSG_774;ローカル - Reti コントラストカーブのマスク +HISTORY_MSG_774;ローカル - レティネックス コントラストカーブのマスク HISTORY_MSG_775;ローカル - CBDL コントラストカーブのマスク HISTORY_MSG_776;ローカル - Blur Denoise コントラストカーブのマスク HISTORY_MSG_777;ローカル - Blur ローカルコントラストカーブのマスク @@ -1033,7 +1022,7 @@ HISTORY_MSG_792;ローカル - マスク 背景輝度 HISTORY_MSG_793;ローカル - シャドウハイライト TRCのガンマ HISTORY_MSG_794;ローカル - シャドウハイライト TRCのスロープ HISTORY_MSG_795;ローカル - マスク 復元したイメージの保存 -HISTORY_MSG_796;ローカル - 参考値の繰り返し +HISTORY_MSG_796;ローカル - 基準値の繰り返し HISTORY_MSG_797;ローカル - オリジナルとの融合方式 HISTORY_MSG_798;ローカル - 不透明度 HISTORY_MSG_799;ローカル - Color RGB トーンカーブ @@ -1078,9 +1067,9 @@ HISTORY_MSG_838;ローカル - 自然な彩度 階調 Hの強さ HISTORY_MSG_839;ローカル - ソフトウェアの難易度 HISTORY_MSG_840;ローカル - CL カーブ HISTORY_MSG_841;ローカル - LC カーブ -HISTORY_MSG_842;ローカル - ぼかしマスクの半径 -HISTORY_MSG_843;ローカル - ぼかしマスクのコントラストしきい値 -HISTORY_MSG_844;ローカル - ぼかしマスクのFFTW +HISTORY_MSG_842;ローカル - マスクぼかしの半径 +HISTORY_MSG_843;ローカル - マスクぼかしのコントラストしきい値 +HISTORY_MSG_844;ローカル - マスクぼかしのFFTW HISTORY_MSG_845;ローカル - 対数符号化 HISTORY_MSG_846;ローカル - 対数符号化 自動 HISTORY_MSG_847;ローカル - 対数符号化 情報源 @@ -1127,7 +1116,7 @@ HISTORY_MSG_890;ローカル - コントラスト ウェーブレット 階調 HISTORY_MSG_891;ローカル - コントラスト ウェーブレット 階調フィルタ HISTORY_MSG_892;ローカル - 対数符号化 階調の強さ HISTORY_MSG_893;ローカル - 対数符号化 階調の角度 -HISTORY_MSG_894;ローカル - 色と明るさ 色差のプレビュー +HISTORY_MSG_894;ローカル - 色と明るさ ΔEのプレビュー HISTORY_MSG_897;ローカル - コントラスト ウェーブレット ES 強さ HISTORY_MSG_898;ローカル - コントラスト ウェーブレット ES 半径 HISTORY_MSG_899;ローカル - コントラスト ウェーブレット ES ディテール @@ -1155,7 +1144,7 @@ HISTORY_MSG_920;ローカル - ウェーブレット シグマ LC HISTORY_MSG_921;ローカル - ウェーブレット 階調のシグマ LC2 HISTORY_MSG_922;ローカル - 白黒での変更 HISTORY_MSG_923;ローカル - 機能の複雑度モード -HISTORY_MSG_924;ローカル - 機能の複雑度モード +HISTORY_MSG_924;--未使用の文字列-- HISTORY_MSG_925;ローカル - カラー機能のスコープ HISTORY_MSG_926;ローカル - マスクのタイプを表示 HISTORY_MSG_927;ローカル - シャドウマスク @@ -1281,113 +1270,113 @@ HISTORY_MSG_1047;ローカル - シャドウ/ハイライトとトーンイコ HISTORY_MSG_1048;ローカル - ダイナミックレンジと露光補正 強さ HISTORY_MSG_1049;ローカル - トーンマッピング 強さ HISTORY_MSG_1050;ローカル - 対数符号化 色度 -HISTORY_MSG_1051;Local - 残差画像 ウェーブレット ガンマ -HISTORY_MSG_1052;Local - 残差画像 ウェーブレット スロープ -HISTORY_MSG_1053;Local - ノイズ除去 ガンマ -HISTORY_MSG_1054;Local - ウェーブレット ガンマ -HISTORY_MSG_1055;Local - 色と明るさ ガンマ -HISTORY_MSG_1056;Local - ダイナミックレンジ圧縮と露光補正 ガンマ -HISTORY_MSG_1057;Local - CIECAM 有効 -HISTORY_MSG_1058;Local - CIECAM 全体的な強さ -HISTORY_MSG_1059;Local - CIECAM 自動グレー -HISTORY_MSG_1060;Local - CIECAM 元画像のの平均輝度 -HISTORY_MSG_1061;Local - CIECAM 元画像の絶対輝度 -HISTORY_MSG_1062;Local - CIECAM 元画像の周囲環境 -HISTORY_MSG_1063;Local - CIECAM 彩度 -HISTORY_MSG_1064;Local - CIECAM 色度 -HISTORY_MSG_1065;Local - CIECAM 明度 J -HISTORY_MSG_1066;Local - CIECAM 明るさ Q -HISTORY_MSG_1067;Local - CIECAM コントラスト J -HISTORY_MSG_1068;Local - CIECAM しきい値 -HISTORY_MSG_1069;Local - CIECAM コントラスト Q -HISTORY_MSG_1070;Local - CIECAM 鮮やかさ -HISTORY_MSG_1071;Local - CIECAM 絶対輝度 -HISTORY_MSG_1072;Local - CIECAM 平均輝度 -HISTORY_MSG_1073;Local - CIECAM Cat16 -HISTORY_MSG_1074;Local - CIECAM ローカルコントラスト -HISTORY_MSG_1075;Local - CIECAM 観視条件 -HISTORY_MSG_1076;Local - CIECAM スロープ -HISTORY_MSG_1077;Local - CIECAM モード -HISTORY_MSG_1078;Local - レッドと肌色トーンを保護 -HISTORY_MSG_1079;Local - CIECAM シグモイドの強さ J -HISTORY_MSG_1080;Local - CIECAM シグモイドのしきい値 -HISTORY_MSG_1081;Local - CIECAM シグモイドのブレンド -HISTORY_MSG_1082;Local - CIECAM シグモイド Q ブラックEv ホワイトEv -HISTORY_MSG_1083;Local - CIECAM 色相 -HISTORY_MSG_1084;Local - ブラックEvとホワイトEvを使う -HISTORY_MSG_1085;Local - Jz 明度 -HISTORY_MSG_1086;Local - Jz コントラスト -HISTORY_MSG_1087;Local - Jz 色度 -HISTORY_MSG_1088;Local - Jz 色相 -HISTORY_MSG_1089;Local - Jz シグモイドの強さ -HISTORY_MSG_1090;Local - Jz シグモイドのしきい値 -HISTORY_MSG_1091;Local - Jz シグモイドのブレンド -HISTORY_MSG_1092;Local - Jz 順応 -HISTORY_MSG_1093;Local - CAMのモデル -HISTORY_MSG_1094;Local - Jz ハイライト -HISTORY_MSG_1095;Local - Jz ハイライトのしきい値 -HISTORY_MSG_1096;Local - Jz シャドウ -HISTORY_MSG_1097;Local - Jz シャドウのしきい値 -HISTORY_MSG_1098;Local - Jz SHの半径 -HISTORY_MSG_1099;Local - Cz(Hz)カーブ -HISTORY_MSG_1100;Local - 100カンデラのJzの参考値 -HISTORY_MSG_1101;Local - Jz PQ 再配分 -HISTORY_MSG_1102;Local - Jz(Hz)カーブ -HISTORY_MSG_1103;Local - 自然な彩度 ガンマ -HISTORY_MSG_1104;Local - シャープネス ガンマ -HISTORY_MSG_1105;Local - CIECAM トーン調整の方法 -HISTORY_MSG_1106;Local - CIECAM トーンカーブ -HISTORY_MSG_1107;Local - CIECAM 色調整の方法 -HISTORY_MSG_1108;Local - CIECAM カラーカーブ -HISTORY_MSG_1109;Local - Jz(Jz)カーブ -HISTORY_MSG_1110;Local - Cz(Cz)カーブ -HISTORY_MSG_1111;Local - Cz(Jz)カーブ -HISTORY_MSG_1112;Local - 強制的なJz -HISTORY_MSG_1113;Local - HDR PQ -HISTORY_MSG_1114;Local - Cie マスク 有効 -HISTORY_MSG_1115;Local - Cie マスク Cカーブ -HISTORY_MSG_1116;Local - Cie マスク Lカーブ -HISTORY_MSG_1117;Local - Cie マスク Hカーブ -HISTORY_MSG_1118;Local - Cie マスク ブレンド -HISTORY_MSG_1119;Local - Cie マスク 半径 -HISTORY_MSG_1120;Local - Cie マスク 色度 -HISTORY_MSG_1121;Local - Cie マスク コントラストカーブ -HISTORY_MSG_1122;Local - Cie マスク 復元のしきい値 -HISTORY_MSG_1123;Local - Cie マスク 復元 暗い部分 -HISTORY_MSG_1124;Local - Cie マスク 復元 明るい部分 -HISTORY_MSG_1125;Local - Cie マスク 復元の減衰 -HISTORY_MSG_1126;Local - Cie マスク ラプラシアン -HISTORY_MSG_1127;Local - Cie マスク ガンマ -HISTORY_MSG_1128;Local - Cie マスク スロープ -HISTORY_MSG_1129;Local - Cie 相対輝度 -HISTORY_MSG_1130;Local - Cie 彩度 Jz -HISTORY_MSG_1131;Local - マスク 色ノイズ除去  -HISTORY_MSG_1132;Local - Cie ウェーブレット シグマ Jz -HISTORY_MSG_1133;Local - Cie ウェーブレット レベル Jz -HISTORY_MSG_1134;Local - Cie ウェーブレット ローカルコントラスト Jz -HISTORY_MSG_1135;Local - Cie ウェーブレット 明瞭 Jz -HISTORY_MSG_1136;Local - Cie ウェーブレット 明瞭 Cz -HISTORY_MSG_1137;Local - Cie ウェーブレット 明瞭 ソフト -HISTORY_MSG_1138;Local - ローカル - Hz(Hz)カーブ -HISTORY_MSG_1139;Local - Jz ソフト Hカーブ -HISTORY_MSG_1140;Local - Jz 色度のしきい値 -HISTORY_MSG_1141;Local - 色度のカーブ Jz(Hz) -HISTORY_MSG_1142;Local - 強さ ソフト -HISTORY_MSG_1143;Local - Jz ブラックEv -HISTORY_MSG_1144;Local - Jz ホワイトEv -HISTORY_MSG_1145;Local - Jz 対数符号化 -HISTORY_MSG_1146;Local - Jz 対数符号化 目標のグレー -HISTORY_MSG_1147;Local - Jz ブラックEv ホワイトEv -HISTORY_MSG_1148;Local - Jz シグモイド -HISTORY_MSG_1149;Local - Q シグモイド -HISTORY_MSG_1150;Local - シグモイドQの代わりに対数符号化Qを使う +HISTORY_MSG_1051;ローカル - 残差画像 ウェーブレット ガンマ +HISTORY_MSG_1052;ローカル - 残差画像 ウェーブレット スロープ +HISTORY_MSG_1053;ローカル - ノイズ除去 ガンマ +HISTORY_MSG_1054;ローカル - ウェーブレット ガンマ +HISTORY_MSG_1055;ローカル - 色と明るさ ガンマ +HISTORY_MSG_1056;ローカル - ダイナミックレンジ圧縮と露光補正 ガンマ +HISTORY_MSG_1057;ローカル - CIECAM 有効 +HISTORY_MSG_1058;ローカル - CIECAM 全体的な強さ +HISTORY_MSG_1059;ローカル - CIECAM 自動グレー +HISTORY_MSG_1060;ローカル - CIECAM 元画像のの平均輝度 +HISTORY_MSG_1061;ローカル - CIECAM 元画像の絶対輝度 +HISTORY_MSG_1062;ローカル - CIECAM 元画像の周囲環境 +HISTORY_MSG_1063;ローカル - CIECAM 彩度 +HISTORY_MSG_1064;ローカル - CIECAM 色度 +HISTORY_MSG_1065;ローカル - CIECAM 明度 J +HISTORY_MSG_1066;ローカル - CIECAM 明るさ Q +HISTORY_MSG_1067;ローカル - CIECAM コントラスト J +HISTORY_MSG_1068;ローカル - CIECAM しきい値 +HISTORY_MSG_1069;ローカル - CIECAM コントラスト Q +HISTORY_MSG_1070;ローカル - CIECAM 鮮やかさ +HISTORY_MSG_1071;ローカル - CIECAM 絶対輝度 +HISTORY_MSG_1072;ローカル - CIECAM 平均輝度 +HISTORY_MSG_1073;ローカル - CIECAM Cat16 +HISTORY_MSG_1074;ローカル - CIECAM ローカルコントラスト +HISTORY_MSG_1075;ローカル - CIECAM 観視条件 +HISTORY_MSG_1076;ローカル - CIECAM スロープ +HISTORY_MSG_1077;ローカル - CIECAM モード +HISTORY_MSG_1078;ローカル - レッドと肌色トーンを保護 +HISTORY_MSG_1079;ローカル - CIECAM シグモイドの強さ J +HISTORY_MSG_1080;ローカル - CIECAM シグモイドのしきい値 +HISTORY_MSG_1081;ローカル - CIECAM シグモイドのブレンド +HISTORY_MSG_1082;ローカル - CIECAM シグモイド Q ブラックEv ホワイトEv +HISTORY_MSG_1083;ローカル - CIECAM 色相 +HISTORY_MSG_1084;ローカル - ブラックEvとホワイトEvを使う +HISTORY_MSG_1085;ローカル - Jz 明度 +HISTORY_MSG_1086;ローカル - Jz コントラスト +HISTORY_MSG_1087;ローカル - Jz 色度 +HISTORY_MSG_1088;ローカル - Jz 色相 +HISTORY_MSG_1089;ローカル - Jz シグモイドの強さ +HISTORY_MSG_1090;ローカル - Jz シグモイドのしきい値 +HISTORY_MSG_1091;ローカル - Jz シグモイドのブレンド +HISTORY_MSG_1092;ローカル - Jz 順応 +HISTORY_MSG_1093;ローカル - CAMのモデル +HISTORY_MSG_1094;ローカル - Jz ハイライト +HISTORY_MSG_1095;ローカル - Jz ハイライトのしきい値 +HISTORY_MSG_1096;ローカル - Jz シャドウ +HISTORY_MSG_1097;ローカル - Jz シャドウのしきい値 +HISTORY_MSG_1098;ローカル - Jz SHの半径 +HISTORY_MSG_1099;ローカル - Cz(Hz)カーブ +HISTORY_MSG_1100;ローカル - 100カンデラのJzの基準値 +HISTORY_MSG_1101;ローカル - Jz PQ 再配分 +HISTORY_MSG_1102;ローカル - Jz(Hz)カーブ +HISTORY_MSG_1103;ローカル - 自然な彩度 ガンマ +HISTORY_MSG_1104;ローカル - シャープネス ガンマ +HISTORY_MSG_1105;ローカル - CIECAM トーン調整の方法 +HISTORY_MSG_1106;ローカル - CIECAM トーンカーブ +HISTORY_MSG_1107;ローカル - CIECAM 色調整の方法 +HISTORY_MSG_1108;ローカル - CIECAM カラーカーブ +HISTORY_MSG_1109;ローカル - Jz(Jz)カーブ +HISTORY_MSG_1110;ローカル - Cz(Cz)カーブ +HISTORY_MSG_1111;ローカル - Cz(Jz)カーブ +HISTORY_MSG_1112;ローカル - 強制的なJz +HISTORY_MSG_1113;ローカル - HDR PQ +HISTORY_MSG_1114;ローカル - Cie マスク 有効 +HISTORY_MSG_1115;ローカル - Cie マスク Cカーブ +HISTORY_MSG_1116;ローカル - Cie マスク Lカーブ +HISTORY_MSG_1117;ローカル - Cie マスク Hカーブ +HISTORY_MSG_1118;ローカル - Cie マスク ブレンド +HISTORY_MSG_1119;ローカル - Cie マスク 半径 +HISTORY_MSG_1120;ローカル - Cie マスク 色度 +HISTORY_MSG_1121;ローカル - Cie マスク コントラストカーブ +HISTORY_MSG_1122;ローカル - Cie マスク 復元のしきい値 +HISTORY_MSG_1123;ローカル - Cie マスク 復元 暗い部分 +HISTORY_MSG_1124;ローカル - Cie マスク 復元 明るい部分 +HISTORY_MSG_1125;ローカル - Cie マスク 復元の減衰 +HISTORY_MSG_1126;ローカル - Cie マスク ラプラシアン +HISTORY_MSG_1127;ローカル - Cie マスク ガンマ +HISTORY_MSG_1128;ローカル - Cie マスク スロープ +HISTORY_MSG_1129;ローカル - Cie 相対輝度 +HISTORY_MSG_1130;ローカル - Cie 彩度 Jz +HISTORY_MSG_1131;ローカル - マスク 色ノイズ除去  +HISTORY_MSG_1132;ローカル - Cie ウェーブレット シグマ Jz +HISTORY_MSG_1133;ローカル - Cie ウェーブレット レベル Jz +HISTORY_MSG_1134;ローカル - Cie ウェーブレット ローカルコントラスト Jz +HISTORY_MSG_1135;ローカル - Cie ウェーブレット 明瞭 Jz +HISTORY_MSG_1136;ローカル - Cie ウェーブレット 明瞭 Cz +HISTORY_MSG_1137;ローカル - Cie ウェーブレット 明瞭 ソフト +HISTORY_MSG_1138;ローカル - ローカル - Hz(Hz)カーブ +HISTORY_MSG_1139;ローカル - Jz ソフト Hカーブ +HISTORY_MSG_1140;ローカル - Jz 色度のしきい値 +HISTORY_MSG_1141;ローカル - 色度のカーブ Jz(Hz) +HISTORY_MSG_1142;ローカル - 強さ ソフト +HISTORY_MSG_1143;ローカル - Jz ブラックEv +HISTORY_MSG_1144;ローカル - Jz ホワイトEv +HISTORY_MSG_1145;ローカル - Jz 対数符号化 +HISTORY_MSG_1146;ローカル - Jz 対数符号化 目標のグレー +HISTORY_MSG_1147;ローカル - Jz ブラックEv ホワイトEv +HISTORY_MSG_1148;ローカル - Jz シグモイド +HISTORY_MSG_1149;ローカル - Q シグモイド +HISTORY_MSG_1150;ローカル - シグモイドQの代わりに対数符号化Qを使う HISTORY_MSG_BLSHAPE;レベルによるぼかし HISTORY_MSG_BLURCWAV;色度のぼかし HISTORY_MSG_BLURWAV;輝度のぼかし HISTORY_MSG_BLUWAV;減衰応答 -HISTORY_MSG_CATCAT;モード Cat02/16 -HISTORY_MSG_CATCOMPLEX;色の見えモデルの機能水準 -HISTORY_MSG_CATMODEL;色の見えモデルのバージョン +HISTORY_MSG_CATCAT;CAL - モードの設定 +HISTORY_MSG_CATCOMPLEX;CAL - 機能水準の設定 +HISTORY_MSG_CATMODEL;CAL - 色の見えモデルの設定 HISTORY_MSG_CLAMPOOG;色域外の色を切り取る HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - 色の補正 HISTORY_MSG_COLORTONING_LABREGION_AB;CT - 色の補正 @@ -1422,7 +1411,7 @@ HISTORY_MSG_HISTMATCHING;トーンカーブの自動調節 HISTORY_MSG_HLBL;Color 色の波及 - ぼかし HISTORY_MSG_ICL_LABGRIDCIEXY;Cie xy HISTORY_MSG_ICM_AINTENT;アブストラクトプロファイルの意図 -HISTORY_MSG_ICM_BLUX;原色 ブルー X +HISTORY_MSG_ICM_BLUX;原色 ブルー X HISTORY_MSG_ICM_BLUY;原色 ブルー Y HISTORY_MSG_ICM_FBW;白黒 HISTORY_MSG_ICM_GREX;原色 グリーン X @@ -1462,7 +1451,7 @@ HISTORY_MSG_PERSP_PROJ_ANGLE;パースペクティブ - 回復 HISTORY_MSG_PERSP_PROJ_ROTATE;パースペクティブ - PCA 回転 HISTORY_MSG_PERSP_PROJ_SHIFT;パースペクティブ - PCA HISTORY_MSG_PIXELSHIFT_AVERAGE;PS - 平均 -HISTORY_MSG_PIXELSHIFT_DEMOSAIC;PS - ブレに対するデモザイクの方式 +HISTORY_MSG_PIXELSHIFT_DEMOSAIC;PS - 動体に対するデモザイクの方式 HISTORY_MSG_PREPROCESS_LINEDENOISE_DIRECTION;ラインノイズフィルタの方向 HISTORY_MSG_PREPROCESS_PDAFLINESFILTER;PDAFラインフィルタ HISTORY_MSG_PREPROCWB_MODE;ホワイトバランスモードの前処理 @@ -1486,7 +1475,7 @@ HISTORY_MSG_SOFTLIGHT_ENABLED;ソフトライト HISTORY_MSG_SOFTLIGHT_STRENGTH;ソフトライト - 強さ HISTORY_MSG_SPOT;スポット除去 HISTORY_MSG_SPOT_ENTRY;スポット除去 - ポイント変更 -HISTORY_MSG_TEMPOUT;CAM02 自動色温度設定 +HISTORY_MSG_TEMPOUT;CAM02/16 自動色温度設定 HISTORY_MSG_THRESWAV;バランスのしきい値 HISTORY_MSG_TM_FATTAL_ANCHOR;DRC - アンカー HISTORY_MSG_TRANS_METHOD;ジオメトリ - 方式 @@ -1512,7 +1501,7 @@ HISTORY_MSG_WAVLIMDEN;相互作用 レベル5~6 とレベル1~4 HISTORY_MSG_WAVLOWTHR;最小コントラストのしきい値 HISTORY_MSG_WAVMERGEC;色度の融合 HISTORY_MSG_WAVMERGEL;輝度の融合 -HISTORY_MSG_WAVMIXMET;ローカルコントラストの参考値 +HISTORY_MSG_WAVMIXMET;ローカルコントラストの基準値 HISTORY_MSG_WAVOFFSET;オフセット HISTORY_MSG_WAVOLDSH;古いアルゴリズムを使う HISTORY_MSG_WAVQUAMET;ノイズ除去モード @@ -1574,7 +1563,7 @@ ICCPROFCREATOR_PROF_V2;ICC v2 ICCPROFCREATOR_PROF_V4;ICC v4 ICCPROFCREATOR_SAVEDIALOG_TITLE;...でICCプロファイルを保存 ICCPROFCREATOR_SLOPE;勾配 -ICCPROFCREATOR_TRC_PRESET;トーンレスポンスカーブ +ICCPROFCREATOR_TRC_PRESET;トーンリプレーススカーブ INSPECTOR_WINDOW_TITLE;カメラ出し画像 IPTCPANEL_CATEGORY;カテゴリ IPTCPANEL_CATEGORYHINT;画像の意図 @@ -1792,7 +1781,7 @@ PARTIALPASTE_SHARPENEDGE;エッジ PARTIALPASTE_SHARPENING;シャープニング (USM/RL) PARTIALPASTE_SHARPENMICRO;マイクロコントラスト PARTIALPASTE_SOFTLIGHT;ソフトライト -PARTIALPASTE_SPOT;染み除去 +PARTIALPASTE_SPOT;スポット除去 PARTIALPASTE_TM_FATTAL;ダイナミックレンジ圧縮 PARTIALPASTE_VIBRANCE;自然な彩度 PARTIALPASTE_VIGNETTING;周辺光量補正 @@ -1828,7 +1817,7 @@ PREFERENCES_CHUNKSIZE_RAW_CA;Raw 色収差補正 PREFERENCES_CHUNKSIZE_RAW_RCD;RCD デモザイク PREFERENCES_CHUNKSIZE_RAW_XT;Xtrans デモザイク PREFERENCES_CHUNKSIZE_RGB;RGB 処理 -PREFERENCES_CIE;Ciecam +PREFERENCES_CIE;色の見えモデル PREFERENCES_CIEARTIF;アーティファクトを回避 PREFERENCES_CLIPPINGIND;クリッピング警告の表示 PREFERENCES_CLUTSCACHE;HaldCLUT cache @@ -2068,6 +2057,12 @@ SAVEDLG_WARNFILENAME;ファイルに名前が付けられます SHCSELECTOR_TOOLTIP;この3つのスライダーの位置をリセットするには\nマウスの右ボタンをクリック SOFTPROOF_GAMUTCHECK_TOOLTIP;有効にすると、出力プロファイルの色域から外れた色のピクセルをグレーで表示します SOFTPROOF_TOOLTIP;ソフトプルーフィング\n有効にすると、ICMツールの出力プロファイルを使った疑似的なレンダリングを行います。印刷した場合などの画像の印象を掴むのに大変便利です。 +TC_PRIM_BLUX;Bx +TC_PRIM_BLUY;By +TC_PRIM_GREX;Gx +TC_PRIM_GREY;Gy +TC_PRIM_REDX;Rx +TC_PRIM_REDY;Ry THRESHOLDSELECTOR_B;下 THRESHOLDSELECTOR_BL;下-左 THRESHOLDSELECTOR_BR;下-右 @@ -2169,7 +2164,7 @@ TP_COLORAPP_BRIGHT_TOOLTIP;CIECAM02/16の明るさは 色刺激から発せら TP_COLORAPP_CAT02ADAPTATION_TOOLTIP;設定を手動で行う場合、65以上の設定値を推奨 TP_COLORAPP_CATCLASSIC;クラシック TP_COLORAPP_CATMET_TOOLTIP;クラシック - 従来のCIECAMの作用です。色順応変換が、基本的な光源をベースにした'場面条件'と、基本的な光源をベースにした'観視条件'に対し、別々に作用します。\n\nシンメトリック – 色順応がホワイトバランスをベースにして作用します。'場面条件'、'画像の調整'、'観視条件'の設定はニュートラルになります。\n\n混成 – 作用は'クラシック'と同じですが、色順応はホワイトバランスをベースにします。 -TP_COLORAPP_CATMOD;モード Cat02/16 +TP_COLORAPP_CATMOD;モード TP_COLORAPP_CATSYMGEN;自動シンメトリック TP_COLORAPP_CATSYMSPE;混成 TP_COLORAPP_CHROMA;色度 (C) @@ -2177,7 +2172,7 @@ TP_COLORAPP_CHROMA_M;鮮やかさ (M) TP_COLORAPP_CHROMA_M_TOOLTIP;CIECAM02/16の鮮やかさは、グレーと比較して知覚される色の量のことで、その色刺激の映り方に彩が多いか少ないかを意味します。 TP_COLORAPP_CHROMA_S;彩度 (S) TP_COLORAPP_CHROMA_S_TOOLTIP;CIECAM02/16の彩度は、色刺激自体が持つ明るさと比較したその色合いに該当するもので、L*a*b*やRGBの彩度とは異なります。 -TP_COLORAPP_CHROMA_TOOLTIP;CIECAM02の色度は、同一の観視環境の下では白に見える色刺激と比較した、その色刺激の'色合い'に相当するもので、L*a*b*やRGBの色度とは異なります。 +TP_COLORAPP_CHROMA_TOOLTIP;CIECAM02/16の色度は、同一の観視環境の下では白に見える色刺激と比較した、その色刺激の'色合い'に相当するもので、L*a*b*やRGBの色度とは異なります。 TP_COLORAPP_CIECAT_DEGREE;CAT02/16(色順応変換02/16) TP_COLORAPP_CONTRAST;コントラスト (J) TP_COLORAPP_CONTRAST_Q;コントラスト (Q) @@ -2188,9 +2183,9 @@ TP_COLORAPP_CURVEEDITOR1_TOOLTIP;CIECAM02/16調整前のL(L*a*b*)のヒス TP_COLORAPP_CURVEEDITOR2;トーンカーブ2 TP_COLORAPP_CURVEEDITOR2_TOOLTIP;最初のJ(J)カーブトーンカーブも同じ使い方です TP_COLORAPP_CURVEEDITOR3;カラーカーブ -TP_COLORAPP_CURVEEDITOR3_TOOLTIP;色度、彩度、鮮やかさのいずれかを調整します\n\nCIECAM02/16調整前の色度(L*a*b*)のヒストグラムを表示します\nチェックボックスの'カーブにCIECAM02出力のヒストグラム' が有効の場合、CIECAM02調整後のC,sまたはMのヒストグラムを表示します\n\nC, sとMは、メインのヒストグラム・パネルには表示されません\n最終出力は、メインのヒストグラム・パネルを参照してください +TP_COLORAPP_CURVEEDITOR3_TOOLTIP;色度、彩度、鮮やかさのいずれかを調整します\n\nCIECAM02/16調整前の色度(L*a*b*)のヒストグラムを表示します\nチェックボックスの'カーブにCIECAM02/16出力のヒストグラム' が有効の場合、CIECAM02/16調整後のC,sまたはMのヒストグラムを表示します\n\nC, sとMは、メインのヒストグラム・パネルには表示されません\n最終出力は、メインのヒストグラム・パネルを参照してください TP_COLORAPP_DATACIE;カーブでCIECAM02/16出力のヒストグラムを表示 -TP_COLORAPP_DATACIE_TOOLTIP;有効の場合、CIECAM02/16カーブのヒストグラムは、JかQ、CIECAM02調整後のCかs、またはMの値/範囲の近似値を表示します\nこの選択はメイン・ヒストグラムパネルには影響を与えません\n\n無効の場合、CIECAM02カーブのヒストグラムは、CIECAM調整前のL*a*b*値を表示します +TP_COLORAPP_DATACIE_TOOLTIP;有効の場合、CIECAM02/16カーブのヒストグラムは、JかQ、CIECAM02/16調整後のCかs、またはMの値/範囲の近似値を表示します\nこの選択はメイン・ヒストグラムパネルには影響を与えません\n\n無効の場合、CIECAM02/16カーブのヒストグラムは、CIECAM調整前のL*a*b*値を表示します TP_COLORAPP_DEGREE_TOOLTIP;CAT02/16は色順応変換の一つで、一定の光源(例えばD65)のホワイトポイントの値を、別な光源(例えばD50 やD55)のホワイトポイントの値に変換することです(WPモデルを参照)。 TP_COLORAPP_DEGREOUT_TOOLTIP;CAT02/16は色順応変換の一つで、一定の光源(例えばD50)のホワイトポイントの値を、別な光源(例えばD75)のホワイトポイントの値に変換することです(WPモデルを参照)。 TP_COLORAPP_FREE;任意の色温度と色偏差 + CAT02/16 + [出力] @@ -2209,30 +2204,30 @@ TP_COLORAPP_ILA;白熱灯標準A 2856K TP_COLORAPP_ILFREE;フリー TP_COLORAPP_ILLUM;光源 TP_COLORAPP_ILLUM_TOOLTIP;撮影条件に最も近い条件を選択します\n一般的にはD50 ですが、時間と緯度に応じて変えます -TP_COLORAPP_LABEL;色の見えモデル(CIECAM02/16) -TP_COLORAPP_LABEL_CAM02;画像の調整 +TP_COLORAPP_LABEL;色の見え&明るさ +TP_COLORAPP_LABEL_CAM02;画像編集 TP_COLORAPP_LABEL_SCENE;場面条件 TP_COLORAPP_LABEL_VIEWING;観視条件 TP_COLORAPP_LIGHT;明度 (J) -TP_COLORAPP_LIGHT_TOOLTIP;CIECAM02の明度は、同じような環視環境の下で白に見える色刺激の明瞭度と、その色の明瞭度を比較したもので、L*a*b*やRGBの明度とは異なります。 +TP_COLORAPP_LIGHT_TOOLTIP;CIECAM02/16の明度は、同じような環視環境の下で白に見える色刺激の明瞭度と、その色の明瞭度を比較したもので、L*a*b*やRGBの明度とは異なります。 TP_COLORAPP_MEANLUMINANCE;平均輝度 (Yb%) -TP_COLORAPP_MOD02;CIECAM02 -TP_COLORAPP_MOD16;CIECAM16 +TP_COLORAPP_MOD02;CAM02 +TP_COLORAPP_MOD16;CAM16 TP_COLORAPP_MODEL;ホワイトポイント・モデル TP_COLORAPP_MODELCAT;色の見えモデル -TP_COLORAPP_MODELCAT_TOOLTIP;色の見えモデルはCIECAM02或いはCIECAM16のどちらかを選択出来ます\n CIECAM02の方がより正確な場合があります\n CIECAM16の方がアーティファクトの発生が少ないでしょう +TP_COLORAPP_MODELCAT_TOOLTIP;色の見えモデルはCAM02或いはCAM16のどちらかを選択出来ます\n CAM02の方がより正確な場合があります\n CAM16の方がアーティファクトの発生が少ないでしょう TP_COLORAPP_MODEL_TOOLTIP;ホワイトポイントモデル\n\nWB [RT] + [出力]\:周囲環境のホワイトバランスは、カラータブのホワイトバランスが使われます。CIECAM02/16の光源にはD50が使われ, 出力デバイスのホワイトバランスには観視環境のホワイトバランスが使われます\n\nWB [RT+CAT02] + [出力]:カラータブのホワイトバランスがCAT02で使われます。出力デバイスのホワイトバランスには観視環境のホワイトバランスが使われます\n\n任意の色温度と色偏差 + CAT02 + [出力]:色温度と色偏差はユーザーが設定します。出力デバイスのホワイトバランスには観視環境のホワイトバランスが使われます TP_COLORAPP_NEUTRAL;リセット TP_COLORAPP_NEUTRAL_TOOLTIP;全てのスライダーチェックボックスとカーブをデフォルトにリセットします TP_COLORAPP_RSTPRO;レッドと肌色トーンを保護 TP_COLORAPP_RSTPRO_TOOLTIP;レッドと肌色トーンを保護はスライダーとカーブの両方に影響します -TP_COLORAPP_SOURCEF_TOOLTIP;撮影条件に合わせて、その条件とデータを通常の範囲に収めます。ここで言う“通常”とは、平均的或いは標準的な条件とデータのことです。例えば、CIECAM02の補正を計算に入れずに収める。 +TP_COLORAPP_SOURCEF_TOOLTIP;撮影条件に合わせて、その条件とデータを通常の範囲に収めます。ここで言う“通常”とは、平均的或いは標準的な条件とデータのことです。例えば、CIECAM02/16の補正を計算に入れずに収める。 TP_COLORAPP_SURROUND;観視時の周囲環境 TP_COLORAPP_SURROUNDSRC;撮影時の周囲環境 TP_COLORAPP_SURROUND_AVER;平均 TP_COLORAPP_SURROUND_DARK;暗い TP_COLORAPP_SURROUND_DIM;薄暗い -TP_COLORAPP_SURROUND_EXDARK;非常に暗い +TP_COLORAPP_SURROUND_EXDARK;非常に暗い TP_COLORAPP_SURROUND_TOOLTIP;出力デバイスで観視する時の周囲環境を考慮するため、画像の明暗と色を変えます\n\n平均:\n周囲が平均的な明るさ(標準)\n画像は変わりません\n\n薄暗い:\n薄暗い環境、例、TVを見る環境\n画像は若干暗くなります\n\n暗い:\n暗い環境 例、プロジェクターを見る環境\n画像はかなり暗くなります\n\n非常に暗い:\n非常に暗い環境 (例、カットシートを使っている)\n画像はとても暗くなります TP_COLORAPP_SURSOURCE_TOOLTIP;撮影時の周囲環境を考慮するため、画像の明暗と色を変えます。\n平均:周囲が平均的な明るさ(標準)。画像は変化しません。\n\n薄暗い:画像が少し明るくなります。\n\n暗い:画像が更に明るくなります。\n\n非常に暗い:画像は非常に明るくなります。 TP_COLORAPP_TCMODE_BRIGHTNESS;明るさ @@ -2532,8 +2527,8 @@ TP_ICM_NEUTRAL;リセット TP_ICM_NOICM;No ICM: sRGB 出力 TP_ICM_OUTPUTPROFILE;出力プロファイル TP_ICM_OUTPUTPROFILE_TOOLTIP;デフォルトでは、全てのRTv4或いはRTv2プロファイルでTRC - sRGB: ガンマ=2.4 勾配=12.92が適用されています\n\n'ICCプロファイルクリエーター'でv4或いはv2のプロファイルを以下の条件で作成出来ます;\n 原色: Aces AP0, Aces AP1, AdobeRGB, Prophoto, Rec2020, sRGB, Widegamut, BestRGB, BetaRGB, BruceRGB, Custom\n TRC: BT709, sRGB, 線形, 標準ガンマ=2.2, 標準ガンマ=1.8, カスタム\n 光源: D41, D50, D55, D60, D65, D80, stdA 2856K -TP_ICM_PRIMBLU_TOOLTIP;原色 ブルー:\nsRGB x=0.15 y=0.06\nAdobe x=0.15 y=0.06\nWidegamut x=0.157 y=0.018\nRec2020 x=0.131 y=0.046\nACES P1 x=0.128 y= 0.044\nACES P0 x=0.0001 y=-0.077\nProphoto x=0.0366 y=0.0001\nBruceRGB x=0.15 y=0.06\nBeta RGB x=0.1265 y=0.0352\nBestRGB x=0.131 y=0.046 -TP_ICM_PRIMGRE_TOOLTIP;原色 グリーン:\nsRGB x=0.3 y=0.6\nAdobe x=0.21 y=0.71\nWidegamut x=0.115 y=0.826\nRec2020 x=0.17 y=0.797\nACES P1 x=0.165 y= 0.83\nACES P0 x=0.0 y=1.0\nProphoto x=0.1596 y=0.8404\nBruceRGB x=0.28 y=0.65\nBeta RGB x=0.1986 y=0.7551\nBest RGB x=0.2150 0.7750 +TP_ICM_PRIMBLU_TOOLTIP;原色 ブルー:\nsRGB x=0.15 y=0.06\nAdobe x=0.15 y=0.06\nWidegamut x=0.157 y=0.018\nRec2020 x=0.131 y=0.046\nACES P1 x=0.128 y= 0.044\nACES P0 x=0.0001 y=-0.077\nProphoto x=0.0366 y=0.0001\nBruceRGB x=0.15 y=0.06\nBeta RGB x=0.1265 y=0.0352\nBestRGB x=0.131 y=0.046 +TP_ICM_PRIMGRE_TOOLTIP;原色 グリーン:\nsRGB x=0.3 y=0.6\nAdobe x=0.21 y=0.71\nWidegamut x=0.115 y=0.826\nRec2020 x=0.17 y=0.797\nACES P1 x=0.165 y= 0.83\nACES P0 x=0.0 y=1.0\nProphoto x=0.1596 y=0.8404\nBruceRGB x=0.28 y=0.65\nBeta RGB x=0.1986 y=0.7551\nBest RGB x=0.2150 0.7750 TP_ICM_PRIMILLUM_TOOLTIP;画像を元のモード(“作業プロファイル”)から異なるモード(“変換先の原色”)に変えることが出来ます。画像に対し異なるカラーモードを選択すると、画像の色値を恒久的に変えることになります。\n\n‘原色’の変更は非常に複雑で、その使い方は非常に難しいものです。熟達した経験が必要です。\nチャンネルミキサーの原色のように、エキゾチックな色の調整が可能です。\nカスタム(スライダー)を使ってカメラのキャリブレーションを変えることが出来ます。 TP_ICM_PRIMRED_TOOLTIP;原色 レッド:\nsRGB x=0.64 y=0.33\nAdobe x=0.64 y=0.33\nWidegamut x=0.735 y=0.265\nRec2020 x=0.708 y=0.292\nACES P1 x=0.713 y= 0.293\nACES P0 x=0.7347 y=0.2653\nProphoto x=0.7347 y=0.2653\nBruceRGB x=0.64 y=0.33\nBeta RGB x=0.688 y=0.3112\nBestRGB x=0.7347 y=0.2653 TP_ICM_PROFILEINTENT;レンダリングの意図 @@ -2669,8 +2664,8 @@ TP_LOCALLAB_BILATERAL;平滑化フィルタ TP_LOCALLAB_BLACK_EV;ブラックEv TP_LOCALLAB_BLCO;色度だけ TP_LOCALLAB_BLENDMASKCOL;ブレンド -TP_LOCALLAB_BLENDMASKMASK;輝度マスクを強める/弱める -TP_LOCALLAB_BLENDMASKMASKAB;色度マスクを強める/弱める +TP_LOCALLAB_BLENDMASKMASK;マスクの輝度の加減 +TP_LOCALLAB_BLENDMASKMASKAB;マスクの色度の加減 TP_LOCALLAB_BLENDMASKMASK_TOOLTIP;スライダーの値が0の場合は作用しません\n元画像にマスクを追加したり、追加したマスクを削除します TP_LOCALLAB_BLENDMASK_TOOLTIP;ブレンド=0の場合は、形状検出だけが改善します\nブレンドが0より大きい場合は、画像にマスクが追加されます。 ブレンドが0より小さい場合は、画像からマスクが除かれます。 TP_LOCALLAB_BLGUID;ガイド付きフィルタ @@ -2730,7 +2725,7 @@ TP_LOCALLAB_CIEC;色の見えモデルの環境変数を使う TP_LOCALLAB_CIECAMLOG_TOOLTIP;このモジュールはCIE色の見えモデルをベースにしています。このモデルは異なる光源の下で人の目が知覚する色を真似るものです。\n最初の処理は’場面条件’で対数符号化によって実行されます。この際、撮影時の’絶対輝度’が使われます。\n次の処理は単純化した’画像の調整’で3つに絞り込んだ変数(ローカルコントラスト、コントラストJ、彩度S)を使います。\n3つ目の処理は’観視条件’で出力画像を見る条件(モニター、TV、プロジェクター、プリンターなどのこと)を考慮します。この処理により表示媒体に関わらず同じ画像の色やコントラストを維持します。 TP_LOCALLAB_CIECOLORFRA;色 TP_LOCALLAB_CIECONTFRA;コントラスト -TP_LOCALLAB_CIELIGHTCONTFRA;明度とコントラスト +TP_LOCALLAB_CIELIGHTCONTFRA;明るさとコントラスト TP_LOCALLAB_CIELIGHTFRA;明度 TP_LOCALLAB_CIEMODE;処理過程の位置の変更 TP_LOCALLAB_CIEMODE_COM;デフォルト @@ -2741,7 +2736,7 @@ TP_LOCALLAB_CIEMODE_WAV;ウェーブレット TP_LOCALLAB_CIETOOLEXP;カーブ TP_LOCALLAB_CIE_TOOLNAME;色の見えモデル(CAM16とJzCzHz) TP_LOCALLAB_CIRCRADIUS;スポットの中心の大きさ -TP_LOCALLAB_CIRCRAD_TOOLTIP;この円内の情報がRT-スポットの編集の参考値となります。色相、輝度、色度、Sobelの形状検出に使います。\n小さい半径は花の色などの補正に。\n大きな半径は肌などの補正に適しています。 +TP_LOCALLAB_CIRCRAD_TOOLTIP;この円内の情報がRT-スポットの編集の基準値となります。色相、輝度、色度、Sobelの形状検出に使います。\n小さい半径は花の色などの補正に。\n大きな半径は肌などの補正に適しています。 TP_LOCALLAB_CLARICRES;色度を融合 TP_LOCALLAB_CLARIFRA;明瞭とシャープマスク/ブレンド & ソフトイメージ TP_LOCALLAB_CLARIJZ_TOOLTIP;レベル0から4まではシャープマスクが働きます\nレベル5以上では明瞭が働きます @@ -2799,11 +2794,11 @@ TP_LOCALLAB_DENOICHRODET_TOOLTIP;漸進的にフーリエ変換(離散コサ TP_LOCALLAB_DENOICHROF_TOOLTIP;小さいディテールの色ノイズを調整します TP_LOCALLAB_DENOIEQUALCHRO_TOOLTIP;ブルー/イエロー、或いはレッド/グリーンの補色次元で色ノイズを軽減します TP_LOCALLAB_DENOIEQUAL_TOOLTIP;シャドウ、或いはハイライト部分で、ある程度ノイズ低減を実行出来ます -TP_LOCALLAB_DENOILUMDETAIL_TOOLTIP;漸進的にフーリエ変換(離散コサイン変換)を適用することで、輝度のディテールを回復します +TP_LOCALLAB_DENOILUMDETAIL_TOOLTIP;漸進的にフーリエ変換(離散コサイン変換)を適用することで、輝度のディテールを回復します TP_LOCALLAB_DENOIMASK;色ノイズのマスク TP_LOCALLAB_DENOIMASK_TOOLTIP;全ての機能でマスクの色ノイズの程度を加減することが出来ます。\nLC(h)カーブを使う際、アーティファクトを避けたり、色度をコントロールするのに便利です。 TP_LOCALLAB_DENOIQUA_TOOLTIP;’控え目’なモードでは、低周波ノイズは除去されません。’積極的’なモードは低周波ノイズも除去します。\n’控え目’も’積極的’も、ウェーブレットとDCTを使いますが、’輝度のノンローカルミーン’を併用することも出来ます。 -TP_LOCALLAB_DENOITHR_TOOLTIP;均一及び低コントラスト部分のノイズを減らす補助としてエッジ検出を調整します +TP_LOCALLAB_DENOITHR_TOOLTIP;均一及び低コントラスト部分のノイズを減らす補助としてエッジ検出を調整します TP_LOCALLAB_DENOI_EXP;ノイズ除去 TP_LOCALLAB_DENOI_TOOLTIP;このモジュールは単独のノイズ低減機能(処理工程の最後の方に位置)として、或いはメインのディテールタブに付属するノイズ低減(処理工程の最初の方に位置)の追加機能として使うことが出来ます。\n色(ΔE)を基本に、スコープを使って作用に差を付けることが出来ます。\n但し、RT-スポットは最低128x128の大きさの必要です TP_LOCALLAB_DEPTH;深度 @@ -2844,7 +2839,7 @@ TP_LOCALLAB_EXPCHROMA_TOOLTIP;色が褪せるのを避けるため、’露光 TP_LOCALLAB_EXPCOLOR_TOOLTIP;色、明度、コントラストの調整に使います。赤目やセンサーの汚れに起因する不良の補正にも使えます。 TP_LOCALLAB_EXPCOMP;露光量補正 ƒ TP_LOCALLAB_EXPCOMPINV;露光量補正 -TP_LOCALLAB_EXPCOMP_TOOLTIP;ポートレート或いは色の階調が少ない画像の場合、’設定’の’形状検出’を調整します:\n\n’ΔEスコープのしきい値’を増やします\n’ΔEの減衰’を減らします\n’バランス ab-L(ΔE)'を増やします +TP_LOCALLAB_EXPCOMP_TOOLTIP;ポートレート或いは色の階調が少ない画像の場合、’設定’の’形状検出’を調整します:\n\n’ΔEスコープのしきい値’を増やします\n’ΔEの減衰’を減らします\n’バランス ab-L(ΔE)'を増やします TP_LOCALLAB_EXPCONTRASTPYR_TOOLTIP;RawPediaの'ウェーブレットのレベル’を参照して下さい。\nローカル編集のウェーブレットのレベルは異なる部分が幾つかあります:各ディテールのレベルに対する調整機能がより多く、多様性が増します。\n例、ウェーブレットのレベルのトーンマッピングです。 TP_LOCALLAB_EXPCONTRAST_TOOLTIP;あまりに小さいRT-スポットの設定は避けます(少なくとも32x32ピクセル以上)。\n低い’境界値’と高い’境界の減衰’値、及び’スコープ’値を使い、小さいRT-スポットを真似て欠陥部分を補正します。\nアーティファクトを軽減するために、必要に応じて’ソフトな半径’を調整して ’明瞭とシャープマスク’、’ファイルの融合’を使います。 TP_LOCALLAB_EXPCURV;カーブ @@ -2890,7 +2885,7 @@ TP_LOCALLAB_GAMW;ガンマ(ウェーブレットピラミッド) TP_LOCALLAB_GRADANG;階調フィルタの角度 TP_LOCALLAB_GRADANG_TOOLTIP;-180度から+180度の間で角度を調整 TP_LOCALLAB_GRADFRA;階調フィルタのマスク -TP_LOCALLAB_GRADGEN_TOOLTIP;階調フィルタの機能は’色と明るさ’と、’露光’、'シャドウ/ハイライト”、’自然な彩度’に備わっています\n\n自然な彩度、色と明るさには輝度、色調、色相の階調フィルタが使えます\nフェザー処理は設定の中にあります +TP_LOCALLAB_GRADGEN_TOOLTIP;階調フィルタの機能は’色と明るさ’と、’露光’、'シャドウ/ハイライト”、’自然な彩度’に備わっています\n\n自然な彩度、色と明るさには輝度、色調、色相の階調フィルタが使えます\nフェザー処理は設定の中にあります TP_LOCALLAB_GRADLOGFRA;輝度の階調フィルタ TP_LOCALLAB_GRADSTR;階調フィルタ 強さ TP_LOCALLAB_GRADSTRAB_TOOLTIP;色度の階調の強さを調整します @@ -2911,7 +2906,7 @@ TP_LOCALLAB_GUIDBL;ソフトな半径 TP_LOCALLAB_GUIDBL_TOOLTIP;半径を変えられるガイド付きフィルタを適用します。アーティファクトを軽減したり、画像にぼかしを掛けたり出来ます。 TP_LOCALLAB_GUIDEPSBL_TOOLTIP;ガイド付きフィルタの配分機能を変化させます。マイナス値の設定はガウスぼかしに似た効果となります TP_LOCALLAB_GUIDFILTER;ガイド付きフィルタの半径 -TP_LOCALLAB_GUIDFILTER_TOOLTIP;アーティファクトが減ったり、増えたりします +TP_LOCALLAB_GUIDFILTER_TOOLTIP;アーティファクトが減ったり、増えたりします TP_LOCALLAB_GUIDSTRBL_TOOLTIP;ガイド付きフィルタの強さ TP_LOCALLAB_HHMASK_TOOLTIP;例えば肌の微妙な色相調整に使います TP_LOCALLAB_HIGHMASKCOL;ハイライト @@ -2926,10 +2921,10 @@ TP_LOCALLAB_INVERS_TOOLTIP;インバースを選択すると使える機能の TP_LOCALLAB_INVMASK;インバースアルゴリズム TP_LOCALLAB_ISOGR;配分(ISO) TP_LOCALLAB_JAB;ブラックEvとホワイトEvを使う -TP_LOCALLAB_JABADAP_TOOLTIP;均一的知覚の順応\n"絶対輝度"を考慮したJzと彩度の関係を自動的に調整します -TP_LOCALLAB_JZ100;Jz reference 100カンデラでのJzの参考値 -TP_LOCALLAB_JZ100_TOOLTIP;100カンデラ毎平方メートルでのJzの参考値(画像シグナル)を自動で調整します。\n彩度の値と“PU 順応” (均一的な知覚の順応)が変わります。 -TP_LOCALLAB_JZADAP;均一的知覚の順応 +TP_LOCALLAB_JABADAP_TOOLTIP;PU(均一的知覚)の順応\n"絶対輝度"を考慮したJzと彩度の関係を自動的に調整します +TP_LOCALLAB_JZ100;Jzの基準値 100カンデラ +TP_LOCALLAB_JZ100_TOOLTIP;100カンデラ毎平方メートルでのJzの基準値(画像シグナル)を自動で調整します。\n彩度の値と“PU 順応” (均一的な知覚の順応)が変わります。 +TP_LOCALLAB_JZADAP;PU-順応 TP_LOCALLAB_JZCH;色度 TP_LOCALLAB_JZCHROM;色度 TP_LOCALLAB_JZCLARICRES;色度Czを融合 @@ -2942,14 +2937,14 @@ TP_LOCALLAB_JZHFRA;Hzカーブ TP_LOCALLAB_JZHJZFRA;Jz(Hz)カーブ TP_LOCALLAB_JZHUECIE;色相の回転 TP_LOCALLAB_JZLIGHT;明るさ -TP_LOCALLAB_JZLOG;Jz 対数符号化 +TP_LOCALLAB_JZLOG;対数符号化 Jz TP_LOCALLAB_JZLOGWBS_TOOLTIP;対数符号化を使うかシグモイドを使うかでブラックEvとホワイトEvの調整が異なる場合があります\nシグモイドの場合、ハイライト、コントラスト、彩度の良好なレンダリングを得るために、ホワイトEvの調整(多くの場合、増やす方向)が必要になることがあります TP_LOCALLAB_JZLOGWB_TOOLTIP;自動を有効にすると、スポット内のEvレベルと'平均輝度 Yb%'が計算されて調整されます。計算結果は"対数符号化 Jz"を含む、全てのJzの働きに使われます。\nまた、撮影時の絶対輝度が計算されます。 TP_LOCALLAB_JZLOGYBOUT_TOOLTIP;Ybは背景の平均輝度を指し、グレーの割合(%)で表します。グレー18%は背景のCIE Labの輝度値が50%であることと同じです。\nデータは画像の平均輝度に基づいています\n対数符号化が使われている場合は、対数符号化が行われる前に適用するゲインの量を決めるために平均輝度が使われます。平均輝度の値が低い程、ゲインが増えます。 TP_LOCALLAB_JZMODECAM_TOOLTIP;Jzが使えるのは機能水準が'高度'な場合だけです。Jzが機能するのは出力デバイス(モニター)がHDRの場合だけです(最大出力輝度が100カンデラ毎平方メートル以上、理想的には4000から10000カンデラ毎平方メートル、ブラックポイントが0.005カンデラ毎平方メートル以下のモニターです)。ここで想定されるのは、a)モニターのICCのプロファイル接続色空間でJzazbz (或いはXYZ)が使える、b)実数精度で作業出来る、c)モニターがキャリブレートされている(出来れば、DCI-P3、或いはRec-2020の色域で)、d) 通常のガンマ(sRGB、或いはBT709)が知覚量子化の関数で置き換えられる、ことです。 TP_LOCALLAB_JZPQFRA;Jz 再マッピング -TP_LOCALLAB_JZPQFRA_TOOLTIP;Jzのアルゴリズムを以下の様にSDR(標準ダイナミックレンジ)の環境、或いはHDR(ハイダイナミックレンジ)の環境の特性に対して適応させることが出来ます:\n a) 輝度値が0から100カンデラ毎平方メートルの間では、システムがSDRであるように作用する\n b) 輝度値が100から10000カンデラ毎平方メートルの間では、画像とモニターのHDR特性にJzのアルゴリズムを適応させる。\n\n“PQ - 最大輝度P”を10000カンデラ毎平方メートルに設定すると、“Jzの再マッピング”がJzazbzのオリジナルアルゴリズムの特性を示します。 -TP_LOCALLAB_JZPQREMAP;PQ - 最大輝度 +TP_LOCALLAB_JZPQFRA_TOOLTIP;Jzのアルゴリズムを以下の様にSDR(標準ダイナミックレンジ)の環境、或いはHDR(ハイダイナミックレンジ)の環境の特性に対して適応させることが出来ます:\n a) 輝度値が0から100カンデラ毎平方メートルの間では、システムがSDRであるように作用する\n b) 輝度値が100から10000カンデラ毎平方メートルの間では、画像とモニターのHDR特性にJzのアルゴリズムを適応させる。\n\n“PQ - 最大輝度P”を10000カンデラ毎平方メートルに設定すると、“Jzの再マッピング”がJzazbzのオリジナルアルゴリズムの特性を示します。 +TP_LOCALLAB_JZPQREMAP;PQ - 最大輝度 TP_LOCALLAB_JZPQREMAP_TOOLTIP;PQ (知覚量子化) - PQの内部関数を変えることが出来ます。デフォルトでは120カンデラ毎平方メートルが設定されていますが、一般的な10000カンデラ毎平方メートルに変えられます。\n異なる画像、処理、デバイスに適応させるために使います。 TP_LOCALLAB_JZQTOJ;相対輝度 TP_LOCALLAB_JZQTOJ_TOOLTIP;"絶対輝度"の代わりに"相対輝度"が使えるようになります - 明るさが明度で表現されるようになります。\n変更により、明るさとコントラストのスライダー、及びJz(Jz)カーブが影響を受けます。 @@ -2960,7 +2955,7 @@ TP_LOCALLAB_JZSTRSOFTCIE;ガイド付きフィルタの強さ TP_LOCALLAB_JZTARGET_EV;観視の平均輝度(Yb%) TP_LOCALLAB_JZTHRHCIE;Jz(Hz)の色度のしきい値 TP_LOCALLAB_JZWAVEXP;Jz ウェーブレット -TP_LOCALLAB_LABBLURM;ぼかしマスク +TP_LOCALLAB_LABBLURM;マスクのぼかし TP_LOCALLAB_LABEL;ローカル編集 TP_LOCALLAB_LABGRID;カラー補正グリッド TP_LOCALLAB_LABGRIDMERG;背景 @@ -2999,6 +2994,7 @@ TP_LOCALLAB_LOG;対数符号化 TP_LOCALLAB_LOG1FRA;CAM16による画像の調整 TP_LOCALLAB_LOG2FRA;観視条件 TP_LOCALLAB_LOGAUTO;自動 +TP_LOCALLAB_LOGAUTOGRAYJZ_TOOLTIP;場面条件の’平均輝度’を自動で計算します。 TP_LOCALLAB_LOGAUTOGRAY_TOOLTIP;相対的な露光レベルの中の’自動’ボタンを押すと、撮影画像の環境に関する平均輝度が自動的に計算されます。 TP_LOCALLAB_LOGAUTO_TOOLTIP;'自動平均輝度(Yb%)'のオプションが有効になっている時に、このボタンを押すと撮影画像の環境に関する’ダイナミックレンジ’と’平均輝度’が計算されます。\nまた、撮影時の絶対輝度も計算されます。\n再度ボタンを押すと自動的にこれら値が調整されます。 TP_LOCALLAB_LOGBASE_TOOLTIP;デフォルト値は2です\n2以下ではアルゴリズムの働きが弱まり、シャドウ部分が暗く、ハイライト部分が明るくなります\n2より大きい場合は、シャドウ部分が濃いグレーに変わり、ハイライト部分は白っぽくなります @@ -3020,9 +3016,9 @@ TP_LOCALLAB_LOGFRA;場面条件 TP_LOCALLAB_LOGFRAME_TOOLTIP;RT-スポットに関する露出のレベルと’平均輝度 Yb%'(グレーポイントの情報源)を計算し調整します。結果は全てのLab関連処理と殆どのRGB関連処理に使われます。\nまた、場面の絶対輝度も考慮します。 TP_LOCALLAB_LOGIMAGE_TOOLTIP;対応する色の見えモデルの変数(例えば、コントラストJと彩度S、及び機能水準が高度な場合の、コントラストQ、明るさQ、明度J、鮮やかさM)を考慮します。 TP_LOCALLAB_LOGLIGHTL;明度 (J) -TP_LOCALLAB_LOGLIGHTL_TOOLTIP;L*a*b*の明度に近いものですが、知覚される彩色の増加を考慮ています。 +TP_LOCALLAB_LOGLIGHTL_TOOLTIP;L*a*b*の明度に近いものですが、知覚される彩色の増加を考慮ています。 TP_LOCALLAB_LOGLIGHTQ;明るさ (Q) -TP_LOCALLAB_LOGLIGHTQ_TOOLTIP;その色刺激から発せられる知覚された光の量を意味します。\nその色刺激の明るさの多寡の指標です。 +TP_LOCALLAB_LOGLIGHTQ_TOOLTIP;その色刺激から発せられる知覚された光の量を意味します。\nその色刺激の明るさの多寡の指標です。 TP_LOCALLAB_LOGLIN;対数モード TP_LOCALLAB_LOGPFRA;相対的な露光レベル TP_LOCALLAB_LOGREPART;全体の強さ @@ -3034,7 +3030,7 @@ TP_LOCALLAB_LOGVIEWING_TOOLTIP;最終画像を見る周囲環境同様、それ TP_LOCALLAB_LOG_TOOLNAME;対数符号化 TP_LOCALLAB_LUM;LL - CC TP_LOCALLAB_LUMADARKEST;最も暗い部分 -TP_LOCALLAB_LUMASK;背景の色/輝度のマスク +TP_LOCALLAB_LUMASK;マスクの背景色と輝度 TP_LOCALLAB_LUMASK_TOOLTIP;マスクの表示(マスクと修正領域)で、背景のグレーを調節します TP_LOCALLAB_LUMAWHITESEST;最も明るい部分 TP_LOCALLAB_LUMFRA;L*a*b* 標準 @@ -3094,8 +3090,7 @@ TP_LOCALLAB_MASKRESVIB_TOOLTIP;'マスクと修正領域'のL(L)やLC(H)マス TP_LOCALLAB_MASKRESWAV_TOOLTIP;'マスクと修正領域'のL(L)やLC(H)マスクに内包されている輝度の情報をベースに、”ローカルコントラスト ウェーブレット”の設定による効果を和らげるために使います。\n この機能を使うためにはL(L)やLC(H)のマスクを有効にする必要があります。\n 暗いしきい値以下と明るいしきい値以上の'暗い'領域と'明るい'領域は、'ローカルコントラスト ウェーブレット'の設定によって変更される前の値(元の値)に漸進的に復元されます。\n 2つのしきい値の間の部分では、'ローカルコントラスト ウェーブレット'の設定値が100%適用されます。 TP_LOCALLAB_MASKUNUSABLE;'マスクと修正領域'のマスクが無効 TP_LOCALLAB_MASKUSABLE;'マスクと修正領域'のマスクが有効 -TP_LOCALLAB_MASK_TOOLTIP;一つの機能の中で複数のマスクを活用することが出来ます。他の機能を有効にしてそのマスクだけを使います(機能の中のスライダー値は全て0にする)。\n\nまたは、RT-スポットを複製し、初めのスポットの近くに置き、そのRT-スポットのマスクを使います。この場合、調整のための参考値の違いが小さいため、より精緻な調整が可能です。 -TP_LOCALLAB_MED;中間 +TP_LOCALLAB_MASK_TOOLTIP;一つの機能の中で複数のマスクを活用することが出来ます。他の機能を有効にしてそのマスクだけを使います(機能の中のスライダー値は全て0にする)。\n\nまたは、RT-スポットを複製し、初めのスポットの近くに置き、そのRT-スポットのマスクを使います。この場合、調整のための基準値の違いが小さいため、より精緻な調整が可能です。 TP_LOCALLAB_MEDIAN;メディアン 低 TP_LOCALLAB_MEDIANITER_TOOLTIP;メディアンフィルタ適用の繰り返し回数を設定します TP_LOCALLAB_MEDIAN_TOOLTIP;メディアンの値を3x3~9x9ピクセルの範囲で選べます。値を高くするほどノイズ低減とぼかしが強くなります @@ -3138,7 +3133,7 @@ TP_LOCALLAB_MRFIV;背景 TP_LOCALLAB_MRFOU;前のRT-スポット TP_LOCALLAB_MRONE;なし TP_LOCALLAB_MRTHR;オリジナルRT-スポット -TP_LOCALLAB_MULTIPL_TOOLTIP;トーンの幅が広い画像、-18EV~+4EV、を調整します: 最初のスライダーは-18EV~-6EVの非常に暗い部分に作用します。2つ目のスライダーは-6EV~+4EVの部分に作用します +TP_LOCALLAB_MULTIPL_TOOLTIP;トーンの幅が広い画像、-18EV~+4EV、を調整します: 最初のスライダーは-18EV~-6EVの非常に暗い部分に作用します。2つ目のスライダーは-6EV~+4EVの部分に作用します TP_LOCALLAB_NEIGH;半径 TP_LOCALLAB_NLDENOISENLGAM_TOOLTIP;値を低くすると詳細と質感が保たれます。高くするとノイズ除去が強まります。\nガンマが3.0の場合は輝度ノイズの除去には線形が使われます。 TP_LOCALLAB_NLDENOISENLPAT_TOOLTIP;処理対象の大きさに対して適用するノイズ除去の量を調節するスライダーです。 @@ -3192,8 +3187,8 @@ TP_LOCALLAB_RADIUS_TOOLTIP;半径が30より大きい場合は、高速フーリ TP_LOCALLAB_RADMASKCOL;スムーズな半径 TP_LOCALLAB_RECOTHRES02_TOOLTIP;“回復のしきい値”が1より大きい場合は、“マスクと修正領域”に付属するマスクは、その前に画像に対して行われた全ての調整を考慮しますが、現在のツールで行われた調整(例、色と明るさや、ウェーブレット、CAM16、など)は考慮しません。\n“回復のしきい値”が1より小さい場合は、“マスクと修正領域”に付属するマスクは、その前に画像に対して行われた全ての調整を考慮しません。\n\nどちらの場合も、“回復のしきい値”は現在のツール(例、色と明るさや、ウェーブレット、CAM16、など)で調整されたマスクされた画像に作用します。 TP_LOCALLAB_RECT;長方形 -TP_LOCALLAB_RECURS;参考値の繰り返し -TP_LOCALLAB_RECURS_TOOLTIP;各機能の適用後に参考値を強制的に再計算させる機能です\nマスクを使った作業にも便利です +TP_LOCALLAB_RECURS;基準値を繰り返し更新 +TP_LOCALLAB_RECURS_TOOLTIP;各機能の適用後に基準値を強制的に再計算させる機能です\nマスクを使った作業にも便利です TP_LOCALLAB_REN_DIALOG_LAB;新しいコントロールスポットの名前を入力 TP_LOCALLAB_REN_DIALOG_NAME;コントロールスポットの名前変更 TP_LOCALLAB_REPARCOL_TOOLTIP;元画像に関する色と明るさの構成の相対的強さを調整出来るようにします。 @@ -3215,12 +3210,12 @@ TP_LOCALLAB_RETI;霞除去 & レティネックス TP_LOCALLAB_RETIFRA;レティネックス TP_LOCALLAB_RETIFRAME_TOOLTIP;画像処理においてレティネックスは便利な機能です\nぼけた、霧かかった、或いは霞んだ画像を補正出来ます\nこういった画像は輝度に大きな違いがあるのが特徴です\n特殊効果を付けるためにも使えます(トーンマッピング) TP_LOCALLAB_RETIM;独自のレティネックス -TP_LOCALLAB_RETITOOLFRA;高度なレティネックス機能 +TP_LOCALLAB_RETITOOLFRA;レティネックス機能 TP_LOCALLAB_RETI_LIGHTDARK_TOOLTIP;'明度=1'或いは'暗さ=2'の場合は効果がありません\n他の値の場合は、最終工程で'マルチスケールレティネックス'('ローカルコントラスト'の調整に似ています)が適用されます。'強さ'に関わる2つのスライダーでローカルコントラストのアップストリーの処理が調整されます TP_LOCALLAB_RETI_LIMDOFFS_TOOLTIP;効果の最適化を図るため内部の変数を変えます\n'修復されたデータ'は最低値が0、最大値が32768(対数モード)に近いことが望ましいのですが、必ずしも一致させる必要はありません。 TP_LOCALLAB_RETI_LOGLIN_TOOLTIP;対数モードを使うとコントラストが増えますが、ハロが発生することもあります TP_LOCALLAB_RETI_NEIGH_VART_TOOLTIP;半径と分散(バリアンス)のスライダーは霞を調整します。前景或いは背景を目標にします -TP_LOCALLAB_RETI_SCALE_TOOLTIP;スケールが1の時は、レティネックスはローカルコントラストを調整した様な効果になります\nスケールの値を増やすと回帰作用が強化されますが、その分処理時間も増加します +TP_LOCALLAB_RETI_SCALE_TOOLTIP;スケールが1の時は、レティネックスはローカルコントラストを調整した様な効果になります\nスケールの値を増やすと回帰作用が強化されますが、その分処理時間も増加します TP_LOCALLAB_RET_TOOLNAME;霞除去 & レティネックス TP_LOCALLAB_REWEI;再加重平均の繰り返し TP_LOCALLAB_RGB;RGB トーンカーブ @@ -3238,7 +3233,7 @@ TP_LOCALLAB_SCOPEMASK_TOOLTIP;ΔE画像のマスクが有効の場合に使え TP_LOCALLAB_SENSI;スコープ TP_LOCALLAB_SENSIEXCLU;スコープ TP_LOCALLAB_SENSIEXCLU_TOOLTIP;除外される色を調整します -TP_LOCALLAB_SENSIMASK_TOOLTIP;共通なマスクに付属するスコープを調整します\n元画像とマスクの違いに対して作用します\nRT-スポットの中心の輝度、色度、色相参考値を使います\n\nマスク自体のΔEを調整することも出来ます。'設定'の中の”スコープ(ΔE画像のマスク)”を使います。 +TP_LOCALLAB_SENSIMASK_TOOLTIP;共通なマスクに付属するスコープを調整します\n元画像とマスクの違いに対して作用します\nRT-スポットの中心の輝度、色度、色相の基準値を使います\n\nマスク自体のΔEを調整することも出来ます。'設定'の中の”スコープ(ΔE画像のマスク)”を使います。 TP_LOCALLAB_SENSI_TOOLTIP;スコープの作用を加減します:\n小さい値を設定すると、色に対する作用はRT-スポットの中心部付近に限定されます\n高い値を設定すると、広範囲の色に作用が及びます TP_LOCALLAB_SETTINGS;設定 TP_LOCALLAB_SH1;シャドウ/ハイライト @@ -3271,24 +3266,24 @@ TP_LOCALLAB_SHOWFOURIER;フーリエ (DCT) TP_LOCALLAB_SHOWLAPLACE;Δ ラプラシアン (一次) TP_LOCALLAB_SHOWLC;マスクと修正領域 TP_LOCALLAB_SHOWMASK;マスクの表示 -TP_LOCALLAB_SHOWMASKCOL_TOOLTIP;マスクと修正箇所の表示:\n注意:一度に一つの機能のマスクしか見ることが出来きません\n調整及び修正した画像:機能による調整とマスクによる修正の両方を含む画像を表示\n修正された領域をマスクなしで表示:マスクを適用する前の修正領域を表示\n修正された領域をマスクと共に表示:マスクを適用した修正領域を表示\nマスクの表示:カーブやフィルタの効果を含めたマスクの様子を表示します\nスポットの構造を表示:'スポットの構造'スライダー(機能水準が高度の場合)が有効になった時に、構造検出マスクを見ることが出来ます\n注意:形状検出のアルゴリズムが作用する前にマスクが適用されます +TP_LOCALLAB_SHOWMASKCOL_TOOLTIP;マスクと修正箇所の表示:\n注意:一度に一つの機能のマスクしか見ることが出来きません\n調整及び修正した画像:機能による調整とマスクによる修正の両方を含む画像を表示\n修正領域をマスクなしで表示:マスクを適用する前の修正領域を表示\n修正領域をマスクと共に表示:マスクを適用した修正領域を表示\nマスクの表示:カーブやフィルタの効果を含めたマスクの様子を表示します\nスポットの構造を表示:'スポットの構造'スライダー(機能水準が高度の場合)が有効になった時に、構造検出マスクを見ることが出来ます\n注意:形状検出のアルゴリズムが作用する前にマスクが適用されます TP_LOCALLAB_SHOWMASKSOFT_TOOLTIP;フーリエ変換による処理を段階的に見ることが出来ます\nラプラス - しきい値の関数としてラプラス変換の2次微分を計算仕します\nフーリエ - 離散コサイン変換(DCT)でラプラス変換を表示します\nポアソン - ポアソン方程式の解を表示します\n輝度の標準化なし - 輝度の標準化なしで結果を表示します TP_LOCALLAB_SHOWMASKTYP1;ぼかし&ノイズ除去 TP_LOCALLAB_SHOWMASKTYP2;ノイズ除去 TP_LOCALLAB_SHOWMASKTYP3;ぼかし&ノイズ除去 + ノイズ除去 TP_LOCALLAB_SHOWMASKTYP_TOOLTIP;‘マスクと修正領域’と併せて使うことが出来ます。\n‘ぼかしとノイズ’を選択した場合、マスクはノイズ除去には使えません。\n‘ノイズ除去を選択した場合、マスクは’ぼかしとノイズ‘には使えません。\n’ぼかしとノイズ + ノイズ除去‘を選択した場合は、マスクを共有することが出来ます。但し、この場合、’ぼかしとノイズ‘とノイズ除去のスコープスライダーが有効となるので、修正を行う際には’マスクと共に修正領域を表示‘のオプションを使うことを奨めます。 TP_LOCALLAB_SHOWMNONE;調整及び修正した画像 -TP_LOCALLAB_SHOWMODIF;修正された領域をマスクなしで表示 +TP_LOCALLAB_SHOWMODIF;修正領域をマスクなしで表示 TP_LOCALLAB_SHOWMODIF2;マスクの表示 -TP_LOCALLAB_SHOWMODIFMASK;修正された領域をマスクと共に表示 +TP_LOCALLAB_SHOWMODIFMASK;修正領域をマスクと共に表示 TP_LOCALLAB_SHOWNORMAL;輝度の標準化をしない TP_LOCALLAB_SHOWPLUS;マスクと修正領域(ぼかし&ノイズ除去) TP_LOCALLAB_SHOWPOISSON;ポアソン (pde f) TP_LOCALLAB_SHOWR;マスクと修正領域 TP_LOCALLAB_SHOWREF;ΔEのプレビュー TP_LOCALLAB_SHOWS;マスクと修正領域 -TP_LOCALLAB_SHOWSTRUC;スポットの構造を表示(高度) -TP_LOCALLAB_SHOWSTRUCEX;スポットの構造を表示(高度) +TP_LOCALLAB_SHOWSTRUC;スポットの構造を表示 +TP_LOCALLAB_SHOWSTRUCEX;スポットの構造を表示 TP_LOCALLAB_SHOWT;マスクと修正領域 TP_LOCALLAB_SHOWVI;マスクと修正領域 TP_LOCALLAB_SHRESFRA;シャドウ/ハイライト&TRC @@ -3301,7 +3296,7 @@ TP_LOCALLAB_SIGMOIDBL;ブレンド TP_LOCALLAB_SIGMOIDLAMBDA;コントラスト TP_LOCALLAB_SIGMOIDQJ;ブラックEvとホワイトEvを使う TP_LOCALLAB_SIGMOIDTH;しきい値(グレーポイント) -TP_LOCALLAB_SIGMOID_TOOLTIP;'CIECAM'(或いは’Jz)と'シグモイド'関数を使って、トーンマッピングの様な効果を作ることが出来ます。\n3つのスライダーを使います: a) コントラストのスライダーはシグモイドの形状を変えることで強さを変えます。 b) しきい値(グレーポイント)のスライダーは、輝度に応じて作用を変えます。 c)ブレンドは画像の最終的なコントラストや輝度を変えます。 +TP_LOCALLAB_SIGMOID_TOOLTIP;'CIECAM'(或いは’Jz)と'シグモイド'関数を使って、トーンマッピングの様な効果を作ることが出来ます。\n3つのスライダーを使います: a) コントラストのスライダーはシグモイドの形状を変えることで強さを変えます。 b) しきい値(グレーポイント)のスライダーは、輝度に応じて作用を変えます。 c)ブレンドは画像の最終的なコントラストや輝度を変えます。 TP_LOCALLAB_SLOMASKCOL;スロープ TP_LOCALLAB_SLOMASK_TOOLTIP;ガンマとスロープを調整することで、不連続を避けるための“L”の漸進的修正により、アーティファクトの無いマスクの修正が出来ます TP_LOCALLAB_SLOSH;スロープ @@ -3313,10 +3308,10 @@ TP_LOCALLAB_SOFTRADIUSCOL_TOOLTIP;アーティファクトの発生を軽減す TP_LOCALLAB_SOFTRETI;ΔEアーティファクトの軽減 TP_LOCALLAB_SOFT_TOOLNAME;ソフトライト & 独自のレティネックス TP_LOCALLAB_SOURCE_ABS;絶対輝度 -TP_LOCALLAB_SOURCE_GRAY;値 +TP_LOCALLAB_SOURCE_GRAY;平均輝度(Y%) TP_LOCALLAB_SPECCASE;特有の設定 TP_LOCALLAB_SPECIAL;RGBカーブの特殊な利用 -TP_LOCALLAB_SPECIAL_TOOLTIP;チェックボックスに✔を入れると、他の全ての作用が取り除かれます。例えば、“スコープ”, マスク, スライダーなどの作用(境界を除きます) が除かれRGBトーンカーブの効果だけが使われます +TP_LOCALLAB_SPECIAL_TOOLTIP;チェックボックスに✔を入れると、他の全ての作用が取り除かれます。例えば、“スコープ”, マスク, スライダーなどの作用(境界を除きます) が除かれRGBトーンカーブの効果だけが使われます TP_LOCALLAB_SPOTNAME;新しいスポット TP_LOCALLAB_STD;標準 TP_LOCALLAB_STR;強さ @@ -3360,10 +3355,10 @@ TP_LOCALLAB_TOOLMASK_2;ウェーブレット TP_LOCALLAB_TOOLMASK_TOOLTIP;'機能としての構造のマスク'のオプションを有効にして、構造マスク(スライダー)を使う:この場合、構造を表示するマスクは、1回以上2つのカーブ、L(L)或いはLC(H)が変更された後に生成されます\nここで、'構造マスク'は他のマスクの様な機能を果たします:ガンマ、スロープなど\n画像の構造に応じてマスクの作用を変えられます。このオプションは'ΔE画像のマスク'と付随する'スコープ(Δ”画像のマスク)'に敏感に作用します TP_LOCALLAB_TRANSIT;境界の階調調整 TP_LOCALLAB_TRANSITGRAD;XY軸方向の境界の差別 -TP_LOCALLAB_TRANSITGRAD_TOOLTIP;Y軸方向の作用の領域を変えることが出来ます +TP_LOCALLAB_TRANSITGRAD_TOOLTIP;Y軸方向の作用の領域を変えることが出来ます TP_LOCALLAB_TRANSITVALUE;境界値 TP_LOCALLAB_TRANSITWEAK;境界値の減衰(線形~Log) -TP_LOCALLAB_TRANSITWEAK_TOOLTIP;境界値の減衰を調節 : 処理の滑らかさを変える - 1 線形 - 2 パラボリック - 3~25乗\n非常に低い境界値と併せれば、CBDL、ウェーブレット、色と明るさを使った不良部分の補正に使うことが出来ます。 +TP_LOCALLAB_TRANSITWEAK_TOOLTIP;境界値の減衰を調節 : 処理の滑らかさを変える - 1 線形 - 2 パラボリック - 3~25乗\n非常に低い境界値と併せれば、CBDL、ウェーブレット、色と明るさを使った不良部分の補正に使うことが出来ます。 TP_LOCALLAB_TRANSIT_TOOLTIP;RT-スポットの中心円からフレームの間で作用が働く領域と作用が減衰する領域の境界を、中心円からフレームまでの%で調整します TP_LOCALLAB_TRANSMISSIONGAIN;透過のゲイン TP_LOCALLAB_TRANSMISSIONMAP;透過マップ @@ -3434,7 +3429,7 @@ TP_METADATA_MODE;メタデータ コピーモード TP_METADATA_STRIP;メタデータを全て取り除く TP_METADATA_TUNNEL;変更なしでコピー TP_NEUTRAL;リセット -TP_NEUTRAL_TOOLTIP;露光量補正のスライダー値をニュートラルにリセットします。\n自動露光補正の調整値ついても同様にリセットされます +TP_NEUTRAL_TIP;露光量補正のスライダー値をニュートラルにリセットします。\n自動露光補正の調整値ついても同様にリセットされます TP_PCVIGNETTE_FEATHER;フェザー TP_PCVIGNETTE_FEATHER_TOOLTIP;フェザー: 0=四隅だけ、50=中央までの半分、100=中央まで TP_PCVIGNETTE_LABEL;ビネットフィルター @@ -3544,34 +3539,34 @@ TP_RAW_LMMSE_TOOLTIP;ガンマ追加 (step 1) - メディアン追加 (step 2,3, TP_RAW_MONO;Mono TP_RAW_NONE;なし (センサーのパターンを表示) TP_RAW_PIXELSHIFT;ピクセルシフト -TP_RAW_PIXELSHIFTAVERAGE;ブレのある部分の平均を使う +TP_RAW_PIXELSHIFTAVERAGE;動体部分に平均を使う TP_RAW_PIXELSHIFTAVERAGE_TOOLTIP;ブレのある部分の特定のフレームを使う代わりに、全てのフレームの平均を使う\nブレの少ない(オーバーラップ)対象にブレの効果を施す -TP_RAW_PIXELSHIFTBLUR;ブレのマスクのぼかし -TP_RAW_PIXELSHIFTDMETHOD;ブレに対するデモザイクの方式 +TP_RAW_PIXELSHIFTBLUR;動体マスクのぼかし +TP_RAW_PIXELSHIFTDMETHOD;動体に対するデモザイクの方式 TP_RAW_PIXELSHIFTEPERISO;感度 TP_RAW_PIXELSHIFTEPERISO_TOOLTIP;通常のISOに関してはデフォルトの0で十分だと思われます。\n高いISOの場合は、振れの検知を良くするために設定値を上げます。\n少しづつ増加させ、振れのマスクの変化を見ます。 TP_RAW_PIXELSHIFTEQUALBRIGHT;構成画像の明るさを均等にする TP_RAW_PIXELSHIFTEQUALBRIGHTCHANNEL;チャンネルごとに均等化 TP_RAW_PIXELSHIFTEQUALBRIGHTCHANNEL_TOOLTIP;有効:RGBの色チャンネルごとに均等化を行います。\n無効:全ての色チャンネルで同じように均等化を行います。 TP_RAW_PIXELSHIFTEQUALBRIGHT_TOOLTIP;選択した構成画像の明るさを他の構成画像の明るさに適用し均等化します。\n露出オーバーがある画像が発生する場合は、マゼンタ被りが起こるのを避けるために最も明るい画像を選択しないようにるいか、或いは振れの補正を有効にします。 -TP_RAW_PIXELSHIFTGREEN;ブレに関するグリーンチャンネルを確認 -TP_RAW_PIXELSHIFTHOLEFILL;ブレのマスクの穴を埋める -TP_RAW_PIXELSHIFTHOLEFILL_TOOLTIP;ブレのマスクの穴を埋める -TP_RAW_PIXELSHIFTMEDIAN;ブレのある部分にはメディアンを使用 -TP_RAW_PIXELSHIFTMEDIAN_TOOLTIP;ブレのある領域に関しては、選択した画像ではなく全ての構成画像にメディアンを使います。\n全ての構成画像で異なる位置にある被写体は除きます。\n動きの遅い被写体(オーバーラッピング)にはブレの効果が出ます。 +TP_RAW_PIXELSHIFTGREEN;動体のグリーンチャンネルを確認 +TP_RAW_PIXELSHIFTHOLEFILL;動体のマスクのギャップを埋める +TP_RAW_PIXELSHIFTHOLEFILL_TOOLTIP;動体マスクのギャップ埋めて大きい領域全体がデモザイクされるようにします +TP_RAW_PIXELSHIFTMEDIAN;動体部分にメディアンを使用 +TP_RAW_PIXELSHIFTMEDIAN_TOOLTIP;動体部分に関しては、選択した画像ではなく全ての構成画像にメディアンを使います。\n全ての構成画像で異なる位置にある被写体は除きます。\n動きの遅い被写体(オーバーラッピング)にはブレの効果が出ます。 TP_RAW_PIXELSHIFTMM_AUTO;自動 TP_RAW_PIXELSHIFTMM_CUSTOM;カスタム TP_RAW_PIXELSHIFTMM_OFF;オフ -TP_RAW_PIXELSHIFTMOTIONMETHOD;ブレの補正 -TP_RAW_PIXELSHIFTNONGREENCROSS;ブレに関するレッド/ブルーのチャンネルを確認 -TP_RAW_PIXELSHIFTSHOWMOTION;ブレのマスクを含めて表示 -TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY;ブレのマスクだけを表示 -TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY_TOOLTIP;画像全体ではなくブレのマスクだけを表示します。 -TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP;ブレのある画像部分をグリーンマスクを被せて表示します。 +TP_RAW_PIXELSHIFTMOTIONMETHOD;動体補正 +TP_RAW_PIXELSHIFTNONGREENCROSS;動体のレッド/ブルーのチャンネルを確認 +TP_RAW_PIXELSHIFTSHOWMOTION;動体マスクを含めて表示 +TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY;動体マスクだけを表示 +TP_RAW_PIXELSHIFTSHOWMOTIONMASKONLY_TOOLTIP;画像全体ではなく動体マスクだけを表示します。 +TP_RAW_PIXELSHIFTSHOWMOTION_TOOLTIP;動体部分にグリーンのマスクを被せて表示します。 TP_RAW_PIXELSHIFTSIGMA;ぼかしの半径 TP_RAW_PIXELSHIFTSIGMA_TOOLTIP;デフォルトで設定している値1.0で基本的なISO値の画像には十分です。\nISO値の高い画像ではスライダーの値を増やします。5.0から始めるのがいいでしょう。\n設定値を変えながら振れマスクを見極めます。 TP_RAW_PIXELSHIFTSMOOTH;境界部分を滑らかにする -TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;これはブレのある領域とブレがない領域の境を滑らかに補正するものです。\n0に設定すると機能の働きはありません。\n1に設定すると、選択された構成画像にAMaZEかLMMSEが使われた結果が得られます("LMMSEを使う"というオプション次第)、或いは"メディアンを使う"が選択されていれば全ての構成画像にメディアンが使われます。 +TP_RAW_PIXELSHIFTSMOOTH_TOOLTIP;これは動体部分とそうでない部分の境を滑らかに補正するものです。\n0に設定すると機能の働きはありません。\n1に設定すると、選択された構成画像にAMaZEかLMMSEが使われた結果が得られます("LMMSEを使う"というオプション次第)、或いは"メディアンを使う"が選択されていれば全ての構成画像にメディアンが使われます。 TP_RAW_RCD;RCD TP_RAW_RCDBILINEAR;RCD+バイリニア補間 TP_RAW_RCDVNG4;RCD+VNG4 @@ -3847,7 +3842,7 @@ TP_WAVELET_DENCURV;カーブ TP_WAVELET_DENL;補正の構造 TP_WAVELET_DENLH;レベル1~4のガイド付きしきい値 TP_WAVELET_DENLOCAL_TOOLTIP;ローカルコントラストに応じてノイズ除去を行うためにカーブを使います\nノイズが除去される領域は構造が保たれます。 -TP_WAVELET_DENMIX_TOOLTIP;ローカルコントラストの参考値はガイド付きフィルタで使われます。\n画像次第で、ノイズのレベル計測がノイズ除去処理の前か後になるかで結果が変わります。これら4つの選択の中から、元画像と修正(ノイズ除去)画像の間で最も妥協できるものを選びます。 +TP_WAVELET_DENMIX_TOOLTIP;ローカルコントラストの基準値はガイド付きフィルタで使われます。\n画像次第で、ノイズのレベル計測がノイズ除去処理の前か後になるかで結果が変わります。これら4つの選択の中から、元画像と修正(ノイズ除去)画像の間で最も妥協できるものを選びます。 TP_WAVELET_DENOISE;ローカルコントラストをベースにしたガイド付きカーブ TP_WAVELET_DENOISEGUID;色相をベースにしたガイド付きしきい値 TP_WAVELET_DENOISEH;番手の高いレベルのカーブ ローカルコントラスト @@ -3930,7 +3925,7 @@ TP_WAVELET_MEDILEV;エッジ検出 TP_WAVELET_MEDILEV_TOOLTIP;エッジの検出を有効にした際には、次の操作が奨められます:\n- アーティファクト発生を避けるため低いレベルのコントラストを使わない\n- グラデーション感度では高い値を使う\n\n効果を和らげるには、ノイズ低減とリファインの’リファイン’を下げる TP_WAVELET_MERGEC;色調の融合 TP_WAVELET_MERGEL;輝度の融合 -TP_WAVELET_MIXCONTRAST;参考値 +TP_WAVELET_MIXCONTRAST;基準値 TP_WAVELET_MIXDENOISE;ノイズ除去 TP_WAVELET_MIXMIX;混成 50%ノイズ - 50%ノイズ除去 TP_WAVELET_MIXMIX70;混成 30%ノイズ - 70%ノイズ除去 @@ -3986,7 +3981,7 @@ TP_WAVELET_STRENGTH;強さ TP_WAVELET_SUPE;エキストラ TP_WAVELET_THR;シャドウのしきい値 TP_WAVELET_THRDEN_TOOLTIP;ローカルコントラストに応じたノイズ除去の目安に使うため、ステップカーブを作成します。ノイズ除去がコントラストの低い均一な画質部分に適用されます。詳細がある部分(コントラストが高い)は保持されます。 -TP_WAVELET_THREND;ローカルコントラストのしきい値 +TP_WAVELET_THREND;ローカルコントラストのしきい値 TP_WAVELET_THRESHOLD;調整レベル(小さいディテール) TP_WAVELET_THRESHOLD2;調整レベル(大きいディテール) TP_WAVELET_THRESHOLD2_TOOLTIP;設定値より上のレベルだけが、大きなディテールのレベルの輝度範囲で設定された条件で調整されます。 @@ -4074,10 +4069,4 @@ ZOOMPANEL_ZOOMOUT;ズームアウト\nショートカット: - ! Untranslated keys follow; remove the ! prefix after an entry is translated. !!!!!!!!!!!!!!!!!!!!!!!!! -!TC_PRIM_BLUX;Bx -!TC_PRIM_BLUY;By -!TC_PRIM_GREX;Gx -!TC_PRIM_GREY;Gy -!TC_PRIM_REDX;Rx -!TC_PRIM_REDY;Ry -!TP_LOCALLAB_LOGAUTOGRAYJZ_TOOLTIP;Automatically calculates the 'Mean luminance' for the scene conditions. +!TP_NEUTRAL_TOOLTIP;Resets exposure sliders to neutral values.\nApplies to the same controls that Auto Levels applies to, regardless of whether you used Auto Levels or not. From 11168aa6404b6db18c3b6e67ac12b47740369b6c Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Mon, 7 Nov 2022 09:35:59 +0100 Subject: [PATCH 055/134] Fix black level for Panasonic DC-G90/G95/G99 --- rtengine/camconst.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 2b243e04a..a2fa76806 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -2144,7 +2144,8 @@ Camera constants: { // Quality C "make_model": [ "Panasonic DC-G90", "Panasonic DC-G95", "Panasonic DC-G99" ], - "dcraw_matrix": [ 9657, -3963, -748, -3361, 11378, 2258, -568, 1414, 5158 ] // DNG + "dcraw_matrix": [ 9657, -3963, -748, -3361, 11378, 2258, -568, 1414, 5158 ], // DNG + "ranges": { "black": 15 } // see above: RT already reads a value from exif }, { // Quality C From 5fbdbcc758ead4614950429c274a52a2d7c2fa5d Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Tue, 15 Nov 2022 14:30:38 +0100 Subject: [PATCH 056/134] Bump release date to now --- RELEASE_NOTES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index de50d7d7d..6a048975e 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,6 +1,6 @@ RAWTHERAPEE 5.9-rc1 RELEASE NOTES -This is Release Candidate 1 of RawTherapee 5.9, released on 2022-10-07. This is not the final release yet. +This is Release Candidate 1 of RawTherapee 5.9, released on 2022-11-15. This is not the final release yet. From 331b3af0e412fb39f51f789c86430aab7b230b35 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Wed, 16 Nov 2022 13:56:50 +0100 Subject: [PATCH 057/134] Bump release date to now, again --- RELEASE_NOTES.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 6a048975e..0d44aeb59 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,6 +1,6 @@ RAWTHERAPEE 5.9-rc1 RELEASE NOTES -This is Release Candidate 1 of RawTherapee 5.9, released on 2022-11-15. This is not the final release yet. +This is Release Candidate 1 of RawTherapee 5.9, released on 2022-11-16. This is not the final release yet. From 32cc60a658d523f6b10629775c045eab240b8916 Mon Sep 17 00:00:00 2001 From: Beep6581 Date: Wed, 16 Nov 2022 19:41:46 +0100 Subject: [PATCH 058/134] Update appimage.yml --- .github/workflows/appimage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index 4a853a5f6..7382a882e 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -3,6 +3,7 @@ on: push: branches: - dev + - releases tags: - '[0-9]+.*' pull_request: From ecb09ef13eb238f67fd4789a3f98982e2f5f1b94 Mon Sep 17 00:00:00 2001 From: Beep6581 Date: Wed, 16 Nov 2022 19:42:01 +0100 Subject: [PATCH 059/134] Update main.yml --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1663e4051..1f8393e08 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,7 +4,7 @@ on: branches: - dev - patch** - - newlocallab + - releases pull_request: branches: - dev From 7635ac06f3aafed30e4304c5b6658a211c5bff81 Mon Sep 17 00:00:00 2001 From: Beep6581 Date: Wed, 16 Nov 2022 19:42:12 +0100 Subject: [PATCH 060/134] Update windows.yml --- .github/workflows/windows.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index e6c03a014..296037812 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -3,6 +3,7 @@ on: push: branches: - dev + - releases tags: - '[0-9]+.*' pull_request: From 33a4737c89d9b7450532908d5ef6477d47a5f08e Mon Sep 17 00:00:00 2001 From: Beep6581 Date: Wed, 16 Nov 2022 19:43:52 +0100 Subject: [PATCH 061/134] Update appimage.yml Renamed to match others --- .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 7382a882e..cc0d16b8f 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -1,4 +1,4 @@ -name: Build AppImage +name: AppImage Build on: push: branches: From 7057a70babe50f2a0b9679234d94acc8e1c154f2 Mon Sep 17 00:00:00 2001 From: Desmis Date: Mon, 21 Nov 2022 18:28:56 +0100 Subject: [PATCH 062/134] Try to fix bug when using CBDL main and Local Sharpening (#6611) * Work around to fix bug when using CBDL main and Local Sharpening * Optimization int replace by bool sharplablocal * Try to fix bug by using shardamping > 0 in LA --- rtengine/improccoordinator.cc | 9 +++++++++ rtengine/simpleprocess.cc | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 9eb7043d1..8d377d30c 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -731,6 +731,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // Remove transformation if unneeded bool needstransform = ipf.needsTransform(fw, fh, imgsrc->getRotateDegree(), imgsrc->getMetaData()); + if ((needstransform || ((todo & (M_TRANSFORM | M_RGBCURVE)) && params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled && !params->colorappearance.enabled))) { // Forking the image assert(oprevi); @@ -745,6 +746,14 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } + for (int sp = 0; sp < (int)params->locallab.spots.size(); sp++) { + if(params->locallab.spots.at(sp).expsharp && params->dirpyrequalizer.cbdlMethod == "bef") { + if(params->locallab.spots.at(sp).shardamping < 1) { + params->locallab.spots.at(sp).shardamping = 1; + } + } + } + if ((todo & (M_TRANSFORM | M_RGBCURVE)) && params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled && !params->colorappearance.enabled) { const int W = oprevi->getWidth(); const int H = oprevi->getHeight(); diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 6e75635cf..c542cf726 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -924,6 +924,14 @@ private: //ImProcFunctions ipf (¶ms, true); ImProcFunctions &ipf = * (ipf_p.get()); + for (int sp = 0; sp < (int)params.locallab.spots.size(); sp++) { + if(params.locallab.spots.at(sp).expsharp && params.dirpyrequalizer.cbdlMethod == "bef") { + if(params.locallab.spots.at(sp).shardamping < 1) { + params.locallab.spots.at(sp).shardamping = 1; + } + } + } + if (params.dirpyrequalizer.cbdlMethod == "bef" && params.dirpyrequalizer.enabled && !params.colorappearance.enabled) { const int W = baseImg->getWidth(); const int H = baseImg->getHeight(); From ea437dc852405570213080e565703cdd451e2e00 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Tue, 22 Nov 2022 02:08:18 -0800 Subject: [PATCH 063/134] mac: use Big Sur for the autobuild The *Catalina* image is now deprecated --- .github/workflows/main.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1f8393e08..9bf1d1cc1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,13 +8,12 @@ on: pull_request: branches: - dev - - newlocallab release: types: - created jobs: build: - runs-on: macos-10.15 + runs-on: macos-11 steps: - uses: actions/checkout@v2 - name: Install dependencies From 239dec3124bf92fe9e2d951fc7269fec89fa9040 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Tue, 22 Nov 2022 02:54:06 -0800 Subject: [PATCH 064/134] mac: list a dir --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9bf1d1cc1..5d3e989d3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -64,6 +64,7 @@ jobs: -DCMAKE_RANLIB=/usr/bin/ranlib \ -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 \ .. + ls /usr/local/lib zsh -c 'echo "Configured in $(printf "%0.2f" $(($[$(date +%s)-$(cat configstamp)]/$((60.))))) minutes"' - name: Compile RawTherapee run: | From 43c8544b1f0a8a1db1eb52d41ebe54cab5fe162f Mon Sep 17 00:00:00 2001 From: Benitoite Date: Tue, 22 Nov 2022 03:05:13 -0800 Subject: [PATCH 065/134] mac: brew install llvm instead of libomp --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5d3e989d3..83d8aa3a9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,7 +22,7 @@ jobs: mkdir build date +%s > build/stamp brew uninstall --ignore-dependencies libtiff - brew install libtiff gtk+3 gtkmm3 gtk-mac-integration adwaita-icon-theme libsigc++@2 little-cms2 libiptcdata fftw lensfun expat pkgconfig libomp shared-mime-info | tee -a depslog + brew install libtiff gtk+3 gtkmm3 gtk-mac-integration adwaita-icon-theme libsigc++@2 little-cms2 libiptcdata fftw lensfun expat pkgconfig llvm shared-mime-info | tee -a depslog date -u echo "----====Pourage====----" cat depslog | grep Pouring From 1a9b5cfacd137b4ad967317de0512042869d5175 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Tue, 22 Nov 2022 03:17:57 -0800 Subject: [PATCH 066/134] mac: install libomp11 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 83d8aa3a9..95b46f004 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -64,7 +64,7 @@ jobs: -DCMAKE_RANLIB=/usr/bin/ranlib \ -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 \ .. - ls /usr/local/lib + curl -L https://github.com/Homebrew/homebrew-core/raw/679923b4eb48a8dc7ecc1f05d06063cd79b3fc00/Formula/libomp.rb -o libomp.rb && brew install libomp.rb zsh -c 'echo "Configured in $(printf "%0.2f" $(($[$(date +%s)-$(cat configstamp)]/$((60.))))) minutes"' - name: Compile RawTherapee run: | From 255dc1384373ac4bdcf7cb4c7fdbf10578f84c9c Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Thu, 24 Nov 2022 13:09:30 -0800 Subject: [PATCH 067/134] Add Lensfun DB lookup fallback directory Load from the bundled database directory if loading from the configured location fails. --- rtengine/init.cc | 14 ++++++++++++-- rtengine/settings.h | 1 + rtgui/main-cli.cc | 2 ++ rtgui/main.cc | 2 ++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/rtengine/init.cc b/rtengine/init.cc index ff29c3476..4ec3f0ec5 100644 --- a/rtengine/init.cc +++ b/rtengine/init.cc @@ -58,10 +58,20 @@ int init (const Settings* s, const Glib::ustring& baseDir, const Glib::ustring& #pragma omp section #endif { + bool ok; + if (s->lensfunDbDirectory.empty() || Glib::path_is_absolute(s->lensfunDbDirectory)) { - LFDatabase::init(s->lensfunDbDirectory); + ok = LFDatabase::init(s->lensfunDbDirectory); } else { - LFDatabase::init(Glib::build_filename(baseDir, s->lensfunDbDirectory)); + ok = LFDatabase::init(Glib::build_filename(baseDir, s->lensfunDbDirectory)); + } + + if (!ok && !s->lensfunDbBundleDirectory.empty() && s->lensfunDbBundleDirectory != s->lensfunDbDirectory) { + if (Glib::path_is_absolute(s->lensfunDbBundleDirectory)) { + LFDatabase::init(s->lensfunDbBundleDirectory); + } else { + LFDatabase::init(Glib::build_filename(baseDir, s->lensfunDbBundleDirectory)); + } } } #ifdef _OPENMP diff --git a/rtengine/settings.h b/rtengine/settings.h index bc49a2281..1c8c73630 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -83,6 +83,7 @@ public: double level0_cbdl; double level123_cbdl; Glib::ustring lensfunDbDirectory; // The directory containing the lensfun database. If empty, the system defaults will be used, as described in https://lensfun.github.io/manual/latest/dbsearch.html + Glib::ustring lensfunDbBundleDirectory; int cropsleep; double reduchigh; double reduclow; diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc index feef93564..8375ffe8b 100644 --- a/rtgui/main-cli.cc +++ b/rtgui/main-cli.cc @@ -148,12 +148,14 @@ int main (int argc, char **argv) } options.rtSettings.lensfunDbDirectory = LENSFUN_DB_PATH; + options.rtSettings.lensfunDbBundleDirectory = LENSFUN_DB_PATH; #else argv0 = DATA_SEARCH_PATH; creditsPath = CREDITS_SEARCH_PATH; licensePath = LICENCE_SEARCH_PATH; options.rtSettings.lensfunDbDirectory = LENSFUN_DB_PATH; + options.rtSettings.lensfunDbBundleDirectory = LENSFUN_DB_PATH; #endif bool quickstart = dontLoadCache (argc, argv); diff --git a/rtgui/main.cc b/rtgui/main.cc index 9f623a6df..30e2d7da6 100644 --- a/rtgui/main.cc +++ b/rtgui/main.cc @@ -425,12 +425,14 @@ int main (int argc, char **argv) } options.rtSettings.lensfunDbDirectory = LENSFUN_DB_PATH; + options.rtSettings.lensfunDbBundleDirectory = LENSFUN_DB_PATH; #else argv0 = DATA_SEARCH_PATH; creditsPath = CREDITS_SEARCH_PATH; licensePath = LICENCE_SEARCH_PATH; options.rtSettings.lensfunDbDirectory = LENSFUN_DB_PATH; + options.rtSettings.lensfunDbBundleDirectory = LENSFUN_DB_PATH; #endif #ifdef WIN32 From 2978a2a15b80bd083b05c5377840179f82f985ca Mon Sep 17 00:00:00 2001 From: Beep6581 Date: Sun, 27 Nov 2022 18:50:01 +0100 Subject: [PATCH 068/134] Update main.yml Added workflow_dispatch: to allow triggering workflow manually --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 95b46f004..3607e3e56 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,6 +11,7 @@ on: release: types: - created + workflow_dispatch: jobs: build: runs-on: macos-11 From 9b85839884f920de0c7cd3a150f865f3c5e47732 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Sun, 27 Nov 2022 19:04:23 +0100 Subject: [PATCH 069/134] Preparing for release 5.9 --- RELEASE_NOTES.txt | 4 +- com.rawtherapee.RawTherapee.appdata.xml | 1 + rtdata/images/svg/splash.svg | 95 ++++--------------- rtdata/images/svg/splash_template.svg | 119 ++++++++++++++---------- 4 files changed, 90 insertions(+), 129 deletions(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 0d44aeb59..3b647d0ce 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,6 +1,6 @@ -RAWTHERAPEE 5.9-rc1 RELEASE NOTES +RAWTHERAPEE 5.9 RELEASE NOTES -This is Release Candidate 1 of RawTherapee 5.9, released on 2022-11-16. This is not the final release yet. +This is RawTherapee 5.9, released on 2022-11-27. diff --git a/com.rawtherapee.RawTherapee.appdata.xml b/com.rawtherapee.RawTherapee.appdata.xml index f7d588684..7e4c0b3a5 100644 --- a/com.rawtherapee.RawTherapee.appdata.xml +++ b/com.rawtherapee.RawTherapee.appdata.xml @@ -22,6 +22,7 @@ https://rawpedia.rawtherapee.com/Main_Page#Localization rawtherapee.desktop + diff --git a/rtdata/images/svg/splash.svg b/rtdata/images/svg/splash.svg index 4695d9bc6..c85abf034 100644 --- a/rtdata/images/svg/splash.svg +++ b/rtdata/images/svg/splash.svg @@ -945,8 +945,8 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="4.7333958" - inkscape:cx="369.07963" - inkscape:cy="211.15918" + inkscape:cx="369.07964" + inkscape:cy="211.15919" inkscape:document-units="px" inkscape:current-layer="layer2" showgrid="false" @@ -991,7 +991,24 @@ RawTherapee splash screen + + + + + + + + + - - - - - - - - - - - - - - - - - - - diff --git a/rtdata/images/svg/splash_template.svg b/rtdata/images/svg/splash_template.svg index e9f67ff92..8f1e52eb0 100644 --- a/rtdata/images/svg/splash_template.svg +++ b/rtdata/images/svg/splash_template.svg @@ -151,10 +151,10 @@ style="stop-color:#feab27;stop-opacity:1;" /> RawTherapee splash screen + + + + + + + + + PrerequisitesPrerequisites + id="tspan706"> Obtain and install the font family ITC Eras Std. + id="tspan710">Obtain and install the font family ITC Eras Std. + id="tspan714"> DetailsDetails + id="tspan720"> The color wheel is copied from rt-logo.svg and a glow filter is added + id="tspan724">The color wheel is copied from rt-logo.svg and a glow filter is added to each segment and the wheel as a whole. + id="tspan728">to each segment and the wheel as a whole. "Raw": font ITC Eras Ultra-Bold, 60 pt, -3 px letter spacing + id="tspan732">"Raw": font ITC Eras Ultra-Bold, 60 pt, -3 px letter spacing "Therapee": font ITC Eras Medium, 60 pt, +1,5 pt letter spacing + id="tspan736">"Therapee": font ITC Eras Medium, 60 pt, +1,5 pt letter spacing Version (big number): ITC Eras Bold, 58 pt, skewed -3° + id="tspan740">Version (big number): ITC Eras Bold, 58 pt, skewed -3° Version (period + small number): ITC Eras Bold, 34 pt, skewed -3° + id="tspan744">Version (period + small number): ITC Eras Bold, 34 pt, skewed -3° Release-type: ITC Eras Bold, 16 pt, skewed -3° + id="tspan748">Release-type: ITC Eras Bold, 16 pt, skewed -3° + id="tspan752"> PublishingPublishing + id="tspan758"> 1. To prepare a splash screen for deployment, select all text and 1. To prepare a splash screen for deployment, select all text and choose choose Path > Object to Path. + id="tspan768">Path > Object to Path. 2. Change release type text to whatever is required, or hide the layer 2. Change release type text to whatever is required, or hide the layer "Release type" entirely. + id="tspan776">"Release type" entirely. 3. Remove this text field. + id="tspan780">3. Remove this text field. 44. Save as "splash.svg" into "./rtdata/images/svg". + id="tspan786">. Save as "splash.svg" into "./rtdata/images/svg". + id="tspan790"> RawTherapee splash screen design 1.5 (March 2022) + id="tspan794">RawTherapee splash screen design 1.5 (March 2022) www.rawtherapee.com + id="tspan798">www.rawtherapee.com Date: Sun, 27 Nov 2022 20:29:39 +0100 Subject: [PATCH 070/134] Preparing to merge back to dev --- RELEASE_NOTES.txt | 165 +----- rtdata/images/svg/splash.svg | 783 ++++++++++---------------- rtdata/images/svg/splash_template.svg | 131 +++-- 3 files changed, 379 insertions(+), 700 deletions(-) diff --git a/RELEASE_NOTES.txt b/RELEASE_NOTES.txt index 3b647d0ce..510847c8a 100644 --- a/RELEASE_NOTES.txt +++ b/RELEASE_NOTES.txt @@ -1,6 +1,6 @@ -RAWTHERAPEE 5.9 RELEASE NOTES +RAWTHERAPEE 5.9-dev RELEASE NOTES -This is RawTherapee 5.9, released on 2022-11-27. +This is a development version of RawTherapee. We update the code almost daily. Every few months, once enough changes have accumulated and the code is stabilized, we make a new official release. Every code change between these releases is known as a "development" version, and this is one of them. @@ -22,169 +22,18 @@ In order to use RawTherapee efficiently you should know that: -NEW FEATURES SINCE 5.8 +NEW FEATURES SINCE 5.9 -- The Spot Removal tool (Detail tab) was added, for removing dust specks and small objects. -- The Color Appearance & Lighting tool (Advanced tab), formerly known as CIECAM02, now includes CAM16. By taking into account the conditions of the photographed scene and the conditions under which the image is viewed, it allows you to adjust the image in a way which matches human color perception. -- The Local Adjustments tool (Local tab) was added, for performing a wide range of operations on an area of the image determined by its geometry or color. -- The Wavelet Levels tool (Advanced tab) received various improvements. -- The White Balance tool (Color tab) received a new automatic white balance method named "temperature correlation" (the old one was renamed to "RGB grey"). -- The Film Negative tool (Color tab) received various improvements including support for non-raw files. -- The Preprocess White Balance tool (Raw tab) was added, allowing you to specify whether channels should be balanced automatically or whether the white balance values recorded by the camera should be used instead. -- A new Perspective Correction tool (Transform tab) was added which includes an automated perspective correction feature. -- The Main Histogram was improved with new modes: waveform, vectorscope and RGB parade. -- Improvements to the Inspect feature (File Browser tab). -- New dual-demosaicing methods in the Demosaicing tool (Raw tab). -- The Haze Removal tool (Detail tab) received a saturation adjuster. -- The RawTherapee theme was improved, including changes to make it easier to see which tools are enabled. -- The Navigator (Editor tab) can now be resized. -- The Resize tool (Transform tab) now allows to resize by the long or short edge. -- The Crop tool (Transform tab) received a "centered square" crop guide, useful when the resulting non-square image will also be used on social media which crop to a square format. -- The Pixel Shift demosaicing method (Raw tab) now allows using an average of all frames for regions with motion. +- TODO - Added or improved support for cameras, raw formats and color profiles: - - Canon EOS 100D / Rebel SL1 / Kiss X7 - - Canon EOS 1DX Mark III - - Canon EOS 2000D / Rebel T7 / Kiss X90 - - Canon EOS 400D DIGITAL - - Canon EOS 5D Mark II - - Canon EOS 5D Mark IV (DCP) - - Canon EOS 90D (DCP) - - Canon EOS M6 Mark II (DCP) - - Canon EOS R (DCP) - - Canon EOS R3, R7 and R10 - - Canon EOS R5 (DCP) - - Canon EOS R6 (DCP) - - Canon EOS RP - - Canon EOS-1D Mark III - - Canon EOS-1Ds - - Canon EOS-1Ds Mark II - - Canon PowerShot G1 X Mark II (DCP) - - Canon PowerShot G9 X Mark II - - Canon PowerShot S120 (DCP) - - Canon PowerShot SX50 HS - - Canon PowerShot SX70 HS - - DJI FC3170 - - FUJIFILM X-A5 (DCP) - - FUJIFILM X-E4 - - FUJIFILM X-H1 (DCP) - - FUJIFILM X-PRO2 - - FUJIFILM X-PRO3 (DCP) - - FUJIFILM X-S10 - - FUJIFILM X-T1 - - FUJIFILM X-T100 - - FUJIFILM X-T2 - - FUJIFILM X-T3 (DCP) - - FUJIFILM X-T30 - - FUJIFILM X-T4 - - FUJIFILM X100V - - Fujifilm GFX 100 - - Fujifilm GFX100S though lossy compression and alternative crop modes (e.g. 4:3) are not supported yet - - Fujifilm X-A20 - - Fujifilm X-T4 - - HASSELBLAD NEX-7 (Lunar) - - Hasselblad L1D-20c (DJI Mavic 2 Pro) - - Improved support for the Canon CR3 raw format, added support for compressed files, affects Canon EOS M50, R, R5, R6 and 1D X Mark III, etc. - - LEICA C-LUX - - LEICA CAM-DC25 - - LEICA D-LUX 7 - - LEICA M8 - - LEICA V-LUX 5 - - Leica SL2-S - - NIKON COOLPIX P1000 - - NIKON D500 (DCP) - - NIKON D5300 (DCP) - - NIKON D610 (DCP) - - NIKON D7100 (DCP) - - NIKON D7500 (DCP) - - NIKON D800 (DCP) - - NIKON D850 (DCP) - - NIKON Z 6 (DCP) - - NIKON Z 7 (DCP) - - Nikon 1 J4 - - Nikon COOLPIX P950 - - Nikon D2Hs - - Nikon D2Xs - - Nikon D300s - - Nikon D3500 - - Nikon D5100 - - Nikon D6 - - Nikon D70s - - Nikon D780 - - Nikon D810A - - Nikon Z 5 - - Nikon Z 50 (DCP) - - Nikon Z 6II - - Nikon Z 7II - - Nikon Z fc - - OLYMPUS E-M10 Mark IV - - OLYMPUS E-M1 Mark III - - OLYMPUS E-M1X - - OLYMPUS E-M5 Mark II (DCP) - - OLYMPUS E-M5 Mark III - - OLYMPUS E-PL10 - - OLYMPUS E-PL9 - - OLYMPUS Stylus 1 - - OLYMPUS Stylus 1s - - OLYMPUS TG-6 - - PENTAX K-50 (DCP) - - PENTAX K10D - - Panasonic DC-FZ1000M2 - - Panasonic DC-FZ80 - - Panasonic DC-FZ81 - - Panasonic DC-FZ82 - - Panasonic DC-FZ83 - - Panasonic DC-G100 - - Panasonic DC-G110 - - Panasonic DC-G90 - - Panasonic DC-G95 - - Panasonic DC-G99 - - Panasonic DC-S1H - - Panasonic DC-S5 (DCP) - - Panasonic DC-TZ95 - - Panasonic DC-ZS80 - - Panasonic DMC-TZ80 - - Panasonic DMC-TZ85 - - Panasonic DMC-ZS60 - - RICOH PENTAX K-1 Mark II - - RICOH PENTAX K-3 Mark III - - SONY ILCE-9 (DCP) - - SONY NEX-7 - - Samsung Galaxy S7 - - Sigma fp - - Sony DCZV1B - - Sony DSC-HX95 - - Sony DSC-HX99 - - Sony DSC-RX0 - - Sony DSC-RX0M2 - - Sony DSC-RX100 - - Sony DSC-RX100M5A - - Sony DSC-RX100M6 - - Sony DSC-RX100M7 - - Sony DSC-RX10M2 - - Sony DSC-RX10M3 - - Sony DSC-RX10M4 - - Sony DSC-RX1R - - Sony ILCE-1 - - Sony ILCE-6100 - - Sony ILCE-6400 (DCP) - - Sony ILCE-6600 (DCP) - - Sony ILCE-7C - - Sony ILCE-7M3 - - Sony ILCE-7M4 - - Sony ILCE-7RM4 (DCP) - - Sony ILCE-7SM3 - - Sony ILCE-9M2 - - Sony NEX-F3 - - Sony SLT-A99V + - TODO NEWS RELEVANT TO PACKAGE MAINTAINERS -New since 5.8: -- Automated build system moved from Travis CI to GitHub Actions: - https://github.com/Beep6581/RawTherapee/actions -- libcanberra made optional in CMake via USE_LIBCANBERRA, default ON. +New since 5.9: +- TODO In general: - To get the source code, either clone from git or use the tarball from https://rawtherapee.com/shared/source/ . Do not use the auto-generated GitHub release tarballs. diff --git a/rtdata/images/svg/splash.svg b/rtdata/images/svg/splash.svg index c85abf034..a840aac4d 100644 --- a/rtdata/images/svg/splash.svg +++ b/rtdata/images/svg/splash.svg @@ -13,6 +13,7 @@ inkscape:export-xdpi="96" inkscape:export-ydpi="96" enable-background="new" + xml:space="preserve" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xlink="http://www.w3.org/1999/xlink" @@ -20,137 +21,92 @@ xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#" - xmlns:dc="http://purl.org/dc/elements/1.1/"> - RawTherapee splash screen - - RawTherapee splash screen - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - RawTherapee splash screen - - - - - - - - - - - - - RawTherapee splash screen - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="path1890" /> diff --git a/rtdata/images/svg/splash_template.svg b/rtdata/images/svg/splash_template.svg index 8f1e52eb0..f5424e7cc 100644 --- a/rtdata/images/svg/splash_template.svg +++ b/rtdata/images/svg/splash_template.svg @@ -882,9 +882,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="2.6078167" - inkscape:cx="546.43411" - inkscape:cy="219.91576" + inkscape:zoom="2.6083441" + inkscape:cx="546.32363" + inkscape:cy="219.8713" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" @@ -922,7 +922,22 @@ fit-margin-bottom="0" width="157.40977mm" inkscape:showpageshadow="2" - inkscape:deskcolor="#d1d1d1" /> + inkscape:deskcolor="#d1d1d1"> + + + @@ -1157,162 +1172,162 @@ xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333px;line-height:1.25;font-family:'Eras BQ';-inkscape-font-specification:'Eras BQ';letter-spacing:0px;word-spacing:-0.132292px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.0495763px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;filter:url(#filter4749);enable-background:new" x="5.3633847" - y="277.27142" + y="277.12344" id="text45159">GNU GPLv3 + y="277.12344">GNU GPLv3 + style="font-size:21.3333px;line-height:1.25;font-family:'Eras BQ';-inkscape-font-specification:'Eras BQ';white-space:pre;shape-inside:url(#rect181038);display:inline" /> PrerequisitesPrerequisites + id="tspan17771"> Obtain and install the font family ITC Eras Std. + id="tspan17775">Obtain and install the font family ITC Eras Std. + id="tspan17779"> DetailsDetails + id="tspan17785"> The color wheel is copied from rt-logo.svg and a glow filter is added + id="tspan17789">The color wheel is copied from rt-logo.svg and a glow filter is added to each segment and the wheel as a whole. + id="tspan17793">to each segment and the wheel as a whole. "Raw": font ITC Eras Ultra-Bold, 60 pt, -3 px letter spacing + id="tspan17797">"Raw": font ITC Eras Ultra-Bold, 60 pt, -3 px letter spacing "Therapee": font ITC Eras Medium, 60 pt, +1,5 pt letter spacing + id="tspan17801">"Therapee": font ITC Eras Medium, 60 pt, +1,5 pt letter spacing Version (big number): ITC Eras Bold, 58 pt, skewed -3° + id="tspan17805">Version (big number): ITC Eras Bold, 58 pt, skewed -3° Version (period + small number): ITC Eras Bold, 34 pt, skewed -3° + id="tspan17809">Version (period + small number): ITC Eras Bold, 34 pt, skewed -3° Release-type: ITC Eras Bold, 16 pt, skewed -3° + id="tspan17813">Release-type: ITC Eras Bold, 16 pt, skewed -3° + id="tspan17817"> PublishingPublishing + id="tspan17823"> 1. To prepare a splash screen for deployment, select all text and 1. To prepare a splash screen for deployment, select all text and choose choose Path > Object to Path. + id="tspan17833">Path > Object to Path. 2. Change release type text to whatever is required, or hide the layer 2. Change release type text to whatever is required, or hide the layer "Release type" entirely. + id="tspan17841">"Release type" entirely. 3. Remove this text field. + id="tspan17845">3. Remove this text field. 44. Save as "splash.svg" into "./rtdata/images/svg". + id="tspan17851">. Save as "splash.svg" into "./rtdata/images/svg". + id="tspan17855"> RawTherapee splash screen design 1.5 (March 2022) + id="tspan17859">RawTherapee splash screen design 1.5 (March 2022) www.rawtherapee.com + id="tspan17863">www.rawtherapee.com Date: Sun, 27 Nov 2022 20:42:05 +0100 Subject: [PATCH 071/134] Update and rename main.yml to macos.yml Renamed main.yml to macos.yml and updated "on" section to match other workflows. --- .github/workflows/{main.yml => macos.yml} | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) rename .github/workflows/{main.yml => macos.yml} (98%) diff --git a/.github/workflows/main.yml b/.github/workflows/macos.yml similarity index 98% rename from .github/workflows/main.yml rename to .github/workflows/macos.yml index 3607e3e56..90dd1618e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/macos.yml @@ -1,16 +1,14 @@ -name: macOS build +name: macOS Build on: push: branches: - dev - - patch** - releases + tags: + - '[0-9]+.*' pull_request: branches: - dev - release: - types: - - created workflow_dispatch: jobs: build: From 6aa4c870e0d0199e8c058f19f16f950808f6a249 Mon Sep 17 00:00:00 2001 From: Beep6581 Date: Sun, 27 Nov 2022 21:34:20 +0100 Subject: [PATCH 072/134] Update macos.yml Automatically publish macOS builds in tag nightly-github-actions --- .github/workflows/macos.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 90dd1618e..11ae28aa4 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -84,6 +84,12 @@ jobs: echo "ARTIFACT_PATH=${GITHUB_WORKSPACE}/build/${ARTIFACT}" >> $GITHUB_ENV echo "ARTIFACT_FILE=${ARTIFACT}" >> $GITHUB_ENV zsh -c 'echo "Bundled in $(printf "%0.2f" $(($[$(date +%s)-$(cat bundlestamp)]/$((60.))))) minutes"' + printf '%s\n' \ + "REF: ${REF}" \ + "ARTIFACT: ${ARTIFACT}" \ + "ARTIFACT_PATH: ${ARTIFACT_PATH}" \ + "ARTIFACT_FILE: ${ARTIFACT_FILE}" \ + "PUBLISH_NAME: ${PUBLISH_NAME}" exit - uses: actions/upload-artifact@v2 with: @@ -93,3 +99,11 @@ jobs: run: | date -u zsh -c 'echo "Build completed in $(printf "%0.2f" $(($[$(date +%s)-$(cat build/stamp)]/$((60.))))) minutes"' + + - name: Publish artifacts + uses: softprops/action-gh-release@v1 + if: ${{github.ref_type == 'tag' || github.ref_name == 'dev'}} + with: + tag_name: nightly-github-actions + files: | + ${{env.ARTIFACT_PATH}} From 9b79c241d7fe94247a15405b4ba7938830495cc4 Mon Sep 17 00:00:00 2001 From: Desmis Date: Wed, 30 Nov 2022 19:14:40 +0100 Subject: [PATCH 073/134] Improves sharp in LA to avoid long processing if user chooses fullimage (#6616) --- rtengine/iplocallab.cc | 47 +++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 9272c2c69..62f211ae6 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -16793,23 +16793,36 @@ void ImProcFunctions::Lab_Local( if (!lp.invshar && lp.shrad > 0.42 && call < 3 && lp.sharpena && sk == 1) { //interior ellipse for sharpening, call = 1 and 2 only with Dcrop and simpleprocess int bfh = call == 2 ? int (lp.ly + lp.lyT) + del : original->H; //bfw bfh real size of square zone int bfw = call == 2 ? int (lp.lx + lp.lxL) + del : original->W; - JaggedArray loctemp(bfw, bfh); if (call == 2) { //call from simpleprocess - // printf("bfw=%i bfh=%i\n", bfw, bfh); if (bfw < mSPsharp || bfh < mSPsharp) { printf("too small RT-spot - minimum size 39 * 39\n"); return; } - JaggedArray bufsh(bfw, bfh, true); - JaggedArray hbuffer(bfw, bfh); int begy = lp.yc - lp.lyT; int begx = lp.xc - lp.lxL; int yEn = lp.yc + lp.ly; int xEn = lp.xc + lp.lx; + if(lp.fullim == 2) {//limit sharpening to image dimension...no more...to avoid a long treatment + begy = 0; + begx = 0; + yEn = original->H; + xEn = original->W; + lp.lxL = lp.xc; + lp.lyT = lp.yc; + lp.ly = yEn - lp.yc; + lp.lx = xEn - lp.xc; + bfh= yEn; + bfw = xEn; + } + //printf("begy=%i begx=%i yen=%i xen=%i\n", begy, begx, yEn, xEn); + JaggedArray bufsh(bfw, bfh, true); + JaggedArray hbuffer(bfw, bfh); + JaggedArray loctemp2(bfw, bfh); + #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) if (multiThread) #endif @@ -16846,9 +16859,8 @@ void ImProcFunctions::Lab_Local( } - - //sharpen only square area instead of all image - ImProcFunctions::deconvsharpeningloc(bufsh, hbuffer, bfw, bfh, loctemp, params->locallab.spots.at(sp).shardamping, (double)params->locallab.spots.at(sp).sharradius, params->locallab.spots.at(sp).shariter, params->locallab.spots.at(sp).sharamount, params->locallab.spots.at(sp).sharcontrast, (double)params->locallab.spots.at(sp).sharblur, 1); + //sharpen only square area instead of all image, but limited to image dimensions (full image) + ImProcFunctions::deconvsharpeningloc(bufsh, hbuffer, bfw, bfh, loctemp2, params->locallab.spots.at(sp).shardamping, (double)params->locallab.spots.at(sp).sharradius, params->locallab.spots.at(sp).shariter, params->locallab.spots.at(sp).sharamount, params->locallab.spots.at(sp).sharcontrast, (double)params->locallab.spots.at(sp).sharblur, 1); /* float gamma = params->locallab.spots.at(sp).shargam; double pwr = 1.0 / (double) gamma;//default 3.0 - gamma Lab @@ -16864,20 +16876,20 @@ void ImProcFunctions::Lab_Local( #ifdef __SSE2__ for (; x < bfw - 3; x += 4) { STVFU(bufsh[y][x], F2V(32768.f) * gammalog(LVFU(bufsh[y][x]) / F2V(32768.f), F2V(gamma1), F2V(ts1), F2V(g_a[3]), F2V(g_a[4]))); - STVFU(loctemp[y][x], F2V(32768.f) * gammalog(LVFU(loctemp[y][x]) / F2V(32768.f), F2V(gamma1), F2V(ts1), F2V(g_a[3]), F2V(g_a[4]))); + STVFU(loctemp2[y][x], F2V(32768.f) * gammalog(LVFU(loctemp2[y][x]) / F2V(32768.f), F2V(gamma1), F2V(ts1), F2V(g_a[3]), F2V(g_a[4]))); } #endif for (; x < bfw; ++x) { bufsh[y][x] = 32768.f * gammalog(bufsh[y][x] / 32768.f, gamma1, ts1, g_a[3], g_a[4]); - loctemp[y][x] = 32768.f * gammalog(loctemp[y][x] / 32768.f, gamma1, ts1, g_a[3], g_a[4]); + loctemp2[y][x] = 32768.f * gammalog(loctemp2[y][x] / 32768.f, gamma1, ts1, g_a[3], g_a[4]); } } } - - - - + //sharpen simpleprocess + Sharp_Local(call, loctemp2, 0, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); } else { //call from dcrop.cc + JaggedArray loctemp(bfw, bfh); + float gamma1 = params->locallab.spots.at(sp).shargam; rtengine::GammaValues g_a; //gamma parameters double pwr1 = 1.0 / (double) gamma1;//default 3.0 - gamma Lab @@ -16926,13 +16938,11 @@ void ImProcFunctions::Lab_Local( } } } - - + //sharpen dcrop + Sharp_Local(call, loctemp, 0, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); } - //sharpen ellipse and transition - Sharp_Local(call, loctemp, 0, hueref, chromaref, lumaref, lp, original, transformed, cx, cy, sk); - + if (lp.recur) { original->CopyFrom(transformed, multiThread); float avge; @@ -16967,7 +16977,6 @@ void ImProcFunctions::Lab_Local( } - ImProcFunctions::deconvsharpeningloc(original->L, shbuffer, GW, GH, loctemp, params->locallab.spots.at(sp).shardamping, (double)params->locallab.spots.at(sp).sharradius, params->locallab.spots.at(sp).shariter, params->locallab.spots.at(sp).sharamount, params->locallab.spots.at(sp).sharcontrast, (double)params->locallab.spots.at(sp).sharblur, sk); /* float gamma = params->locallab.spots.at(sp).shargam; From 7b51a079cd489a2be78a72a129785e0e44b6b43c Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Fri, 2 Dec 2022 10:03:19 +0100 Subject: [PATCH 074/134] Basic support for Fujifilm X-T5 and X-H2 Closes #6624 --- rtengine/camconst.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index a2fa76806..189d8f3f4 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1543,6 +1543,12 @@ Camera constants: "ranges": { "white": 4040 } }, + { // Quality B + "make_model": [ "FUJIFILM X-T5", "FUJIFILM X-H2" ], + "dcraw_matrix": [ 11809, -5358, -1141, -4248, 12164, 2343, -514, 1097, 5848 ], // RawSpeed / DNG + "raw_crop": [ 0, 5, 7752, 5184 ] + }, + { // Quality C, Leica C-Lux names can differ? "make_model" : [ "LEICA C-LUX", "LEICA CAM-DC25" ], "dcraw_matrix" : [7790, -2736, -755, -3452, 11870, 1769, -628, 1647, 4898] From abbdbe81bce66f48f97f227f566f493ea3725479 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alvaro=20Mu=C3=B1oz?= Date: Fri, 2 Dec 2022 13:23:34 +0100 Subject: [PATCH 075/134] Add CodeQL workflow --- .github/workflows/codeql.yml | 89 ++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 000000000..b90d30e27 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,89 @@ +name: "CodeQL" + +on: + push: + branches: [ 'dev' ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ 'dev' ] + schedule: + - cron: '56 5 * * 1' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + build_type: [release] + language: [ 'cpp', 'python' ] + + steps: + - name: Checkout source + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Install dependencies + run: | + echo "Running apt update." + sudo apt update + echo "Installing dependencies with apt." + DEBIAN_FRONTEND=noninteractive sudo apt install -y cmake libgtk-3-dev libgtkmm-3.0-dev liblensfun-dev librsvg2-dev liblcms2-dev libfftw3-dev libiptcdata0-dev libtiff5-dev libcanberra-gtk3-dev liblensfun-bin + + - name: Configure build + run: | + export REF_NAME_FILTERED="$(echo '${{github.ref_name}}' | sed 's/[^A-z0-9_.-]//g')" + echo "Setting cache suffix." + if [ '${{github.ref_type}}' == 'tag' ]; then + export CACHE_SUFFIX="" + else + export CACHE_SUFFIX="5-$REF_NAME_FILTERED" + fi + export CACHE_SUFFIX="$CACHE_SUFFIX-AppImage" + echo "Cache suffix is '$CACHE_SUFFIX'." + echo "Making build directory." + mkdir build + echo "Changing working directory to the build directory." + cd build + echo "Running CMake configure." + cmake \ + -DCMAKE_BUILD_TYPE='${{matrix.build_type}}' \ + -DCACHE_NAME_SUFFIX="$CACHE_SUFFIX" \ + -DPROC_TARGET_NUMBER="1" \ + -DBUILD_BUNDLE="ON" \ + -DBUNDLE_BASE_INSTALL_DIR="/" \ + -DOPTION_OMP="ON" \ + -DWITH_LTO="OFF" \ + -DWITH_PROF="OFF" \ + -DWITH_SAN="OFF" \ + -DWITH_SYSTEM_KLT="OFF" \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DLENSFUNDBDIR="../share/lensfun/version_1" \ + .. + echo "Recording filtered ref name." + echo "REF_NAME_FILTERED=$REF_NAME_FILTERED" >> $GITHUB_ENV + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Build RawTherapee + working-directory: ./build + run: | + echo "Running make install." + make -j$(nproc) install DESTDIR=AppDir/usr/bin + echo "Moving usr/bin/share to usr/share." + mv AppDir/usr/bin/share AppDir/usr/ + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" From dcd2d3df0efe758ff797483fe115a3909383f6e9 Mon Sep 17 00:00:00 2001 From: Desmis Date: Sun, 11 Dec 2022 13:51:44 +0100 Subject: [PATCH 076/134] Replace Observer 10 by Observer 2 in most cases - see issue 6639 (#6640) * Change observer10 to observer2 * Another forgotten change observer 2 10 * Change colortemp.cc in accordance to options Itcwb_stdobserver10 --- rtengine/CMakeLists.txt | 1 + rtengine/colortemp.cc | 54 ++++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 1f3cf352b..0fab84b55 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -176,6 +176,7 @@ if(LENSFUN_HAS_LOAD_DIRECTORY) set_source_files_properties(rtlensfun.cc PROPERTIES COMPILE_DEFINITIONS RT_LENSFUN_HAS_LOAD_DIRECTORY) endif() + if(WITH_BENCHMARK) add_definitions(-DBENCHMARK) endif() diff --git a/rtengine/colortemp.cc b/rtengine/colortemp.cc index 36d42f063..a4dd8a4d1 100644 --- a/rtengine/colortemp.cc +++ b/rtengine/colortemp.cc @@ -33,7 +33,7 @@ namespace rtengine { -static const double cie_colour_match_jd2[97][3] = {//350nm to 830nm 5 nm J.Desmis 2° Standard Observer. +static double cie_colour_match_jd2[97][3] = {//350nm to 830nm 5 nm J.Desmis 2° Standard Observer. {0.0000000, 0.000000, 0.000000}, {0.0000000, 0.000000, 0.000000}, {0.0001299, 0.0003917, 0.0006061}, {0.0002321, 0.000006965, 0.001086}, {0.0004149, 0.00001239, 0.001946}, {0.0007416, 0.00002202, 0.003846}, {0.001368, 0.000039, 0.006450001}, {0.002236, 0.000064, 0.01054999}, {0.004243, 0.000120, 0.02005001}, @@ -70,7 +70,7 @@ static const double cie_colour_match_jd2[97][3] = {//350nm to 830nm 5 nm J.Des }; -static double cie_colour_match_jd[97][3] = {//350nm to 830nm 5 nm J.Desmis 10° Standard Observer. +static const double cie_colour_match_jd[97][3] = {//350nm to 830nm 5 nm J.Desmis 10° Standard Observer. {0.000000000000, 0.000000000000, 0.000000000000}, {0.000000000000, 0.000000000000, 0.000000000000}, {0.000000122200, 0.000000013398, 0.000000535027}, @@ -3388,7 +3388,7 @@ The next 3 methods are inspired from: this values are often called xBar yBar zBar and are characteristics of a color / illuminant -values cie_colour_match[][3] = 2° Standard Observer x2, y2, z2 +values cie_colour_match2[][3] = 2° Standard Observer x2, y2, z2 E.g. for 380nm: x2=0.001368 y2=0.000039 z2=0.006451 round in J.Walker to 0.0014 0.0000 0.0065 above I have increase precision used by J.Walker and pass to 350nm to 830nm And also add 10° standard observer @@ -3401,9 +3401,9 @@ void ColorTemp::spectrum_to_xyz_daylight(double _m1, double _m2, double &x, doub for (i = 0, lambda = 350.; lambda < 830.1; i++, lambda += 5.) { double Me = daylight_spect(lambda, _m1, _m2); - X += Me * cie_colour_match_jd[i][0]; - Y += Me * cie_colour_match_jd[i][1]; - Z += Me * cie_colour_match_jd[i][2]; + X += Me * cie_colour_match_jd2[i][0]; + Y += Me * cie_colour_match_jd2[i][1]; + Z += Me * cie_colour_match_jd2[i][2]; } XYZ = (X + Y + Z); @@ -3419,9 +3419,9 @@ void ColorTemp::spectrum_to_xyz_blackbody(double _temp, double &x, double &y, do for (i = 0, lambda = 350.; lambda < 830.1; i++, lambda += 5.) { double Me = blackbody_spect(lambda, _temp); - X += Me * cie_colour_match_jd[i][0]; - Y += Me * cie_colour_match_jd[i][1]; - Z += Me * cie_colour_match_jd[i][2]; + X += Me * cie_colour_match_jd2[i][0]; + Y += Me * cie_colour_match_jd2[i][1]; + Z += Me * cie_colour_match_jd2[i][2]; } XYZ = (X + Y + Z); @@ -3447,16 +3447,16 @@ void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, dou this values are often called xBar yBar zBar and are characteristics of a color / illuminant - values cie_colour_match[][3] = 2° Standard Observer x2, y2, z2 + values cie_colour_match_jd2[][3] = 2° Standard Observer x2, y2, z2 E.g. for 380nm: x2=0.001368 y2=0.000039 z2=0.006451 round in J.Walker to 0.0014 0.0000 0.0065 above I have increased the precision used by J.Walker and pass from 350nm to 830nm And also add standard observer 10° */ for (i = 0, lambda = 350.; lambda < 830.1; i++, lambda += 5.) { double Me = get_spectral_color(lambda, spec_intens); - X += Me * cie_colour_match_jd[i][0]; - Y += Me * cie_colour_match_jd[i][1]; - Z += Me * cie_colour_match_jd[i][2]; + X += Me * cie_colour_match_jd2[i][0]; + Y += Me * cie_colour_match_jd2[i][1]; + Z += Me * cie_colour_match_jd2[i][2]; } XYZ = (X + Y + Z); @@ -3478,9 +3478,9 @@ void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const dou Me = get_spectral_color(lambda, spec_color); Mc = get_spectral_color(lambda, spec_intens); - X += Mc * cie_colour_match_jd[i][0] * Me; - Y += Mc * cie_colour_match_jd[i][1] * Me; - Z += Mc * cie_colour_match_jd[i][2] * Me; + X += Mc * cie_colour_match_jd2[i][0] * Me; + Y += Mc * cie_colour_match_jd2[i][1] * Me; + Z += Mc * cie_colour_match_jd2[i][2] * Me; } for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5) { @@ -3488,7 +3488,7 @@ void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const dou double Ms; Ms = get_spectral_color(lambda, spec_intens); - Yo += cie_colour_match_jd[i][1] * Ms; + Yo += cie_colour_match_jd2[i][1] * Ms; } xx = X / Yo; @@ -3505,9 +3505,9 @@ void ColorTemp::spectrum_to_color_xyz_daylight(const double* spec_color, double for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5) { const double Me = spec_color[i]; const double Mc = daylight_spect(lambda, _m1, _m2); - X += Mc * cie_colour_match_jd[i][0] * Me; - Y += Mc * cie_colour_match_jd[i][1] * Me; - Z += Mc * cie_colour_match_jd[i][2] * Me; + X += Mc * cie_colour_match_jd2[i][0] * Me; + Y += Mc * cie_colour_match_jd2[i][1] * Me; + Z += Mc * cie_colour_match_jd2[i][2] * Me; } xx = X / Y; @@ -3524,9 +3524,9 @@ void ColorTemp::spectrum_to_color_xyz_blackbody(const double* spec_color, double for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5) { const double Me = spec_color[i]; const double Mc = blackbody_spect(lambda, _temp); - X += Mc * cie_colour_match_jd[i][0] * Me; - Y += Mc * cie_colour_match_jd[i][1] * Me; - Z += Mc * cie_colour_match_jd[i][2] * Me; + X += Mc * cie_colour_match_jd2[i][0] * Me; + Y += Mc * cie_colour_match_jd2[i][1] * Me; + Z += Mc * cie_colour_match_jd2[i][2] * Me; } xx = X / Y; @@ -3769,11 +3769,11 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float } } - if (settings->itcwb_stdobserver10 == false) { + if (settings->itcwb_stdobserver10 == true) { for (int i = 0; i < 97; i++) { - cie_colour_match_jd[i][0] = cie_colour_match_jd2[i][0]; - cie_colour_match_jd[i][1] = cie_colour_match_jd2[i][1];; - cie_colour_match_jd[i][2] = cie_colour_match_jd2[i][2]; + cie_colour_match_jd2[i][0] = cie_colour_match_jd[i][0]; + cie_colour_match_jd2[i][1] = cie_colour_match_jd[i][1];; + cie_colour_match_jd2[i][2] = cie_colour_match_jd[i][2]; } } From 9332333a12c781ec777ba5a825563dfeb5e1951a Mon Sep 17 00:00:00 2001 From: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> Date: Fri, 16 Dec 2022 23:01:23 -0800 Subject: [PATCH 077/134] Speed up compilation of rtengine/procparams.cc --- rtengine/CMakeLists.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 0fab84b55..c657d6f9d 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -176,6 +176,18 @@ if(LENSFUN_HAS_LOAD_DIRECTORY) set_source_files_properties(rtlensfun.cc PROPERTIES COMPILE_DEFINITIONS RT_LENSFUN_HAS_LOAD_DIRECTORY) endif() +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.0") + # procparams.cc takes a long time to compile with optimizations starting + # with GCC 12.1 due to PTA (see issue #6548) + get_source_file_property(PROCPARAMS_COMPILE_OPTIONS procparams.cc COMPILE_OPTIONS) + if(PROCPARAMS_COMPILE_OPTIONS STREQUAL "NOTFOUND") + set(PROCPARAMS_COMPILE_OPTIONS "") + else() + set(PROCPARAMS_COMPILE_OPTIONS "${PROCPARAMS_COMPILE_OPTIONS};") + endif() + set(PROCPARAMS_COMPILE_OPTIONS "${PROCPARAMS_COMPILE_OPTIONS}-fno-tree-pta") + set_source_files_properties(procparams.cc PROPERTIES COMPILE_OPTIONS ${PROCPARAMS_COMPILE_OPTIONS}) +endif() if(WITH_BENCHMARK) add_definitions(-DBENCHMARK) From f64ddf0d8eb677ca5a13319c147a6028c43399e4 Mon Sep 17 00:00:00 2001 From: Beep6581 Date: Sun, 18 Dec 2022 01:03:59 +0100 Subject: [PATCH 078/134] Updated logo image --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ae9efd9c8..a30a77212 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![RawTherapee logo](https://www.rawtherapee.com/images/logos/rawtherapee_logo_discuss.png) +![RawTherapee logo](https://raw.githubusercontent.com/Beep6581/RawTherapee/dev/rtdata/images/rt-logo-text-white.svg) RawTherapee is a powerful, cross-platform raw photo processing program, released as [libre software](https://en.wikipedia.org/wiki/Free_software) under the [GNU General Public License Version 3](https://opensource.org/licenses/gpl-3.0.html). It is written mostly in C++ using a [GTK+](https://www.gtk.org) front-end. It uses a patched version of [dcraw](https://www.dechifro.org/dcraw/) for reading raw files, with an in-house solution which adds the highest quality support for certain camera models unsupported by dcraw and enhances the accuracy of certain raw files already supported by dcraw. It is notable for the advanced control it gives the user over the demosaicing and development process. From bbe4558dff509604949e1bac58152ff0836b84f3 Mon Sep 17 00:00:00 2001 From: Morgan Hardwood Date: Sun, 18 Dec 2022 03:55:29 +0100 Subject: [PATCH 079/134] Improvement to dcraw linear_table #6448 Merged on behalf of heckflosse https://github.com/Beep6581/RawTherapee/pull/6448#issuecomment-1081779513 --- rtengine/dcraw.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 6ca0e4331..4ab1694b8 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -6319,12 +6319,13 @@ void CLASS parse_mos (int offset) void CLASS linear_table (unsigned len) { - int i; - if (len > 0x10000) len = 0x10000; - read_shorts (curve, len); - for (i=len; i < 0x10000; i++) - curve[i] = curve[i-1]; - maximum = curve[0xffff]; + const unsigned maxLen = std::min(0x10000ull, 1ull << tiff_bps); + len = std::min(len, maxLen); + read_shorts(curve, len); + maximum = curve[len - 1]; + for (std::size_t i = len; i < maxLen; ++i) { + curve[i] = maximum; + } } void CLASS parse_kodak_ifd (int base) From 38a8aa81602d536f6277f0f62f786c0d761db723 Mon Sep 17 00:00:00 2001 From: Beep6581 Date: Sun, 18 Dec 2022 09:41:06 +0100 Subject: [PATCH 080/134] Added external screenshot to README.md (#6648) See #6642 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a30a77212..c43bfc2f4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ ![RawTherapee logo](https://raw.githubusercontent.com/Beep6581/RawTherapee/dev/rtdata/images/rt-logo-text-white.svg) +![RawTherapee screenshot](http://rawtherapee.com/images/carousel/100_rt59_provence_local_maskxxx.jpg) + RawTherapee is a powerful, cross-platform raw photo processing program, released as [libre software](https://en.wikipedia.org/wiki/Free_software) under the [GNU General Public License Version 3](https://opensource.org/licenses/gpl-3.0.html). It is written mostly in C++ using a [GTK+](https://www.gtk.org) front-end. It uses a patched version of [dcraw](https://www.dechifro.org/dcraw/) for reading raw files, with an in-house solution which adds the highest quality support for certain camera models unsupported by dcraw and enhances the accuracy of certain raw files already supported by dcraw. It is notable for the advanced control it gives the user over the demosaicing and development process. ## Target Audience From 9019c6dccd0bb942e568e3dd4e98764e5788e9fb Mon Sep 17 00:00:00 2001 From: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> Date: Mon, 19 Dec 2022 13:28:20 -0800 Subject: [PATCH 081/134] Update libtiff DLL version for Windows workflow --- .github/workflows/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 296037812..f6f83f567 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -159,7 +159,7 @@ jobs: "libstdc++-6.dll" \ "libsystre-0.dll" \ "libthai-0.dll" \ - "libtiff-5.dll" \ + "libtiff-6.dll" \ "libtre-5.dll" \ "libwebp-7.dll" \ "libwinpthread-1.dll" \ From 2c9f5a735df5c9257d0627e531731060b4611215 Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Fri, 30 Dec 2022 23:51:22 -0800 Subject: [PATCH 082/134] Add raw_crop and masked_areas for Canon EOS R7 and R10 (#6608) Signed-off-by: Alex Forencich --- rtengine/camconst.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 189d8f3f4..b7151f2c8 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1231,12 +1231,16 @@ Camera constants: { // Quality C "make_model": "Canon EOS R7", - "dcraw_matrix" : [10424, -3138, -1300, -4221, 11938, 2584, -547, 1658, 6183] + "dcraw_matrix" : [10424, -3138, -1300, -4221, 11938, 2584, -547, 1658, 6183], + "raw_crop": [ 144, 72, 6984, 4660 ], + "masked_areas" : [ 70, 20, 4724, 138 ] }, { // Quality C "make_model": "Canon EOS R10", - "dcraw_matrix" : [9269, -2012, -1107, -3990, 11762, 2527, -569, 2093, 4913] + "dcraw_matrix" : [9269, -2012, -1107, -3990, 11762, 2527, -569, 2093, 4913], + "raw_crop": [ 144, 40, 6048, 4020 ], + "masked_areas" : [ 38, 20, 4052, 138 ] }, { // Quality C, CHDK DNGs, raw frame correction From 22831866cd72c20a1d2f6952d76883b39e9ed4f7 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Sat, 31 Dec 2022 10:16:38 +0100 Subject: [PATCH 083/134] Change RT logo to black version in README.md so text is visible --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c43bfc2f4..21f219a83 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![RawTherapee logo](https://raw.githubusercontent.com/Beep6581/RawTherapee/dev/rtdata/images/rt-logo-text-white.svg) +![RawTherapee logo](https://raw.githubusercontent.com/Beep6581/RawTherapee/dev/rtdata/images/rt-logo-text-black.svg) ![RawTherapee screenshot](http://rawtherapee.com/images/carousel/100_rt59_provence_local_maskxxx.jpg) From 401727fba9ab391ed8f4992e042e33860e2e272e Mon Sep 17 00:00:00 2001 From: Nicolas Turlais Date: Sat, 31 Dec 2022 10:51:30 +0100 Subject: [PATCH 084/134] Add filter for Paths to dynamic profiles (#6284) Work by @nicolas-t * Path filter in dynamic profile panel * Pass filename as a function argument * Removed unused include * Clearer translation --- rtdata/languages/default | 1 + rtengine/dynamicprofile.cc | 5 ++++- rtengine/dynamicprofile.h | 3 ++- rtengine/profilestore.cc | 4 ++-- rtengine/profilestore.h | 2 +- rtgui/dynamicprofilepanel.cc | 25 +++++++++++++++++++++++++ rtgui/dynamicprofilepanel.h | 6 ++++++ rtgui/main-cli.cc | 4 ++-- rtgui/thumbnail.cc | 2 +- 9 files changed, 44 insertions(+), 8 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 775b098f4..e5e053655 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -61,6 +61,7 @@ EXIFFILTER_IMAGETYPE;Image type EXIFFILTER_ISO;ISO EXIFFILTER_LENS;Lens EXIFFILTER_METADATAFILTER;Enable metadata filters +EXIFFILTER_PATH;File path EXIFFILTER_SHUTTER;Shutter EXIFPANEL_ADDEDIT;Add/Edit EXIFPANEL_ADDEDITHINT;Add new tag or edit tag. diff --git a/rtengine/dynamicprofile.cc b/rtengine/dynamicprofile.cc index 28516a1ee..6dbd2d0f0 100644 --- a/rtengine/dynamicprofile.cc +++ b/rtengine/dynamicprofile.cc @@ -77,7 +77,7 @@ bool DynamicProfileRule::operator< (const DynamicProfileRule &other) const } -bool DynamicProfileRule::matches (const rtengine::FramesMetaData *im) const +bool DynamicProfileRule::matches (const rtengine::FramesMetaData *im, const Glib::ustring& filename) const { return (iso (im->getISOSpeed()) && fnumber (im->getFNumber()) @@ -86,6 +86,7 @@ bool DynamicProfileRule::matches (const rtengine::FramesMetaData *im) const && expcomp (im->getExpComp()) && camera (im->getCamera()) && lens (im->getLens()) + && path (filename) && imagetype(im->getImageType(0))); } @@ -214,6 +215,7 @@ bool DynamicProfileRules::loadRules() get_double_range (rule.expcomp, kf, group, "expcomp"); get_optional (rule.camera, kf, group, "camera"); get_optional (rule.lens, kf, group, "lens"); + get_optional (rule.path, kf, group, "path"); get_optional (rule.imagetype, kf, group, "imagetype"); try { @@ -247,6 +249,7 @@ bool DynamicProfileRules::storeRules() set_double_range (kf, group, "expcomp", rule.expcomp); set_optional (kf, group, "camera", rule.camera); set_optional (kf, group, "lens", rule.lens); + set_optional (kf, group, "path", rule.path); set_optional (kf, group, "imagetype", rule.imagetype); kf.set_string (group, "profilepath", rule.profilepath); } diff --git a/rtengine/dynamicprofile.h b/rtengine/dynamicprofile.h index d91b91aee..654db3a8e 100644 --- a/rtengine/dynamicprofile.h +++ b/rtengine/dynamicprofile.h @@ -51,7 +51,7 @@ public: }; DynamicProfileRule(); - bool matches (const rtengine::FramesMetaData *im) const; + bool matches (const rtengine::FramesMetaData *im, const Glib::ustring& filename) const; bool operator< (const DynamicProfileRule &other) const; int serial_number; @@ -62,6 +62,7 @@ public: Range expcomp; Optional camera; Optional lens; + Optional path; Optional imagetype; Glib::ustring profilepath; }; diff --git a/rtengine/profilestore.cc b/rtengine/profilestore.cc index 7d937e736..f83ddd385 100644 --- a/rtengine/profilestore.cc +++ b/rtengine/profilestore.cc @@ -508,7 +508,7 @@ void ProfileStore::dumpFolderList() printf ("\n"); } -PartialProfile *ProfileStore::loadDynamicProfile (const FramesMetaData *im) +PartialProfile *ProfileStore::loadDynamicProfile (const FramesMetaData *im, const Glib::ustring& filename) { if (storeState == STORESTATE_NOTINITIALIZED) { parseProfilesOnce(); @@ -521,7 +521,7 @@ PartialProfile *ProfileStore::loadDynamicProfile (const FramesMetaData *im) } for (auto rule : dynamicRules) { - if (rule.matches (im)) { + if (rule.matches (im, filename)) { if (settings->verbose) { printf ("found matching profile %s\n", rule.profilepath.c_str()); } diff --git a/rtengine/profilestore.h b/rtengine/profilestore.h index 460facb72..e8e48c17f 100644 --- a/rtengine/profilestore.h +++ b/rtengine/profilestore.h @@ -209,7 +209,7 @@ public: void addListener (ProfileStoreListener *listener); void removeListener (ProfileStoreListener *listener); - rtengine::procparams::PartialProfile* loadDynamicProfile (const rtengine::FramesMetaData *im); + rtengine::procparams::PartialProfile* loadDynamicProfile (const rtengine::FramesMetaData *im, const Glib::ustring& filename); void dumpFolderList(); }; diff --git a/rtgui/dynamicprofilepanel.cc b/rtgui/dynamicprofilepanel.cc index 865603b3a..feb6aea70 100644 --- a/rtgui/dynamicprofilepanel.cc +++ b/rtgui/dynamicprofilepanel.cc @@ -42,6 +42,7 @@ DynamicProfilePanel::EditDialog::EditDialog (const Glib::ustring &title, Gtk::Wi add_optional (M ("EXIFFILTER_CAMERA"), has_camera_, camera_); add_optional (M ("EXIFFILTER_LENS"), has_lens_, lens_); + add_optional (M ("EXIFFILTER_PATH"), has_path_, path_); imagetype_ = Gtk::manage (new MyComboBoxText()); imagetype_->append(Glib::ustring("(") + M("DYNPROFILEEDITOR_IMGTYPE_ANY") + ")"); @@ -93,6 +94,9 @@ void DynamicProfilePanel::EditDialog::set_rule ( has_lens_->set_active (rule.lens.enabled); lens_->set_text (rule.lens.value); + has_path_->set_active (rule.path.enabled); + path_->set_text (rule.path.value); + if (!rule.imagetype.enabled) { imagetype_->set_active(0); } else if (rule.imagetype.value == "STD") { @@ -136,6 +140,9 @@ DynamicProfileRule DynamicProfilePanel::EditDialog::get_rule() ret.lens.enabled = has_lens_->get_active(); ret.lens.value = lens_->get_text(); + ret.path.enabled = has_path_->get_active(); + ret.path.value = path_->get_text(); + ret.imagetype.enabled = imagetype_->get_active_row_number() > 0; switch (imagetype_->get_active_row_number()) { case 1: @@ -296,6 +303,16 @@ DynamicProfilePanel::DynamicProfilePanel(): *this, &DynamicProfilePanel::render_lens)); } + cell = Gtk::manage (new Gtk::CellRendererText()); + cols_count = treeview_.append_column (M ("EXIFFILTER_PATH"), *cell); + col = treeview_.get_column (cols_count - 1); + + if (col) { + col->set_cell_data_func ( + *cell, sigc::mem_fun ( + *this, &DynamicProfilePanel::render_path)); + } + cell = Gtk::manage (new Gtk::CellRendererText()); cols_count = treeview_.append_column (M ("EXIFFILTER_IMAGETYPE"), *cell); col = treeview_.get_column (cols_count - 1); @@ -375,6 +392,7 @@ void DynamicProfilePanel::update_rule (Gtk::TreeModel::Row row, row[columns_.expcomp] = rule.expcomp; row[columns_.camera] = rule.camera; row[columns_.lens] = rule.lens; + row[columns_.path] = rule.path; row[columns_.imagetype] = rule.imagetype; row[columns_.profilepath] = rule.profilepath; } @@ -398,6 +416,7 @@ DynamicProfileRule DynamicProfilePanel::to_rule (Gtk::TreeModel::Row row, ret.expcomp = row[columns_.expcomp]; ret.camera = row[columns_.camera]; ret.lens = row[columns_.lens]; + ret.path = row[columns_.path]; ret.profilepath = row[columns_.profilepath]; ret.imagetype = row[columns_.imagetype]; return ret; @@ -510,6 +529,12 @@ void DynamicProfilePanel::render_lens ( RENDER_OPTIONAL_ (lens); } +void DynamicProfilePanel::render_path ( + Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter) +{ + RENDER_OPTIONAL_ (path); +} + void DynamicProfilePanel::render_imagetype ( Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter) { diff --git a/rtgui/dynamicprofilepanel.h b/rtgui/dynamicprofilepanel.h index 972ca1c4a..03b9e7c62 100644 --- a/rtgui/dynamicprofilepanel.h +++ b/rtgui/dynamicprofilepanel.h @@ -55,6 +55,7 @@ private: add (expcomp); add (camera); add (lens); + add (path); add (profilepath); add (imagetype); } @@ -66,6 +67,7 @@ private: Gtk::TreeModelColumn> expcomp; Gtk::TreeModelColumn camera; Gtk::TreeModelColumn lens; + Gtk::TreeModelColumn path; Gtk::TreeModelColumn imagetype; Gtk::TreeModelColumn profilepath; }; @@ -78,6 +80,7 @@ private: void render_expcomp (Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); void render_camera (Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); void render_lens (Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); + void render_path (Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); void render_imagetype (Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); void render_profilepath (Gtk::CellRenderer* cell, const Gtk::TreeModel::iterator& iter); @@ -114,6 +117,9 @@ private: Gtk::CheckButton *has_lens_; Gtk::Entry *lens_; + Gtk::CheckButton *has_path_; + Gtk::Entry *path_; + MyComboBoxText *imagetype_; ProfileStoreComboBox *profilepath_; diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc index 8375ffe8b..cebced274 100644 --- a/rtgui/main-cli.cc +++ b/rtgui/main-cli.cc @@ -743,7 +743,7 @@ int processLineParams ( int argc, char **argv ) if (options.defProfRaw == DEFPROFILE_DYNAMIC) { rawParams->deleteInstance(); delete rawParams; - rawParams = ProfileStore::getInstance()->loadDynamicProfile (ii->getMetaData()); + rawParams = ProfileStore::getInstance()->loadDynamicProfile (ii->getMetaData(), inputFile); } std::cout << " Merging default raw processing profile." << std::endl; @@ -752,7 +752,7 @@ int processLineParams ( int argc, char **argv ) if (options.defProfImg == DEFPROFILE_DYNAMIC) { imgParams->deleteInstance(); delete imgParams; - imgParams = ProfileStore::getInstance()->loadDynamicProfile (ii->getMetaData()); + imgParams = ProfileStore::getInstance()->loadDynamicProfile (ii->getMetaData(), inputFile); } std::cout << " Merging default non-raw processing profile." << std::endl; diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index cc8e9ad81..2baf03247 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -266,7 +266,7 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu // Should we ask all frame's MetaData ? imageMetaData = rtengine::FramesMetaData::fromFile (fname, nullptr, true); } - PartialProfile *pp = ProfileStore::getInstance()->loadDynamicProfile(imageMetaData); + PartialProfile *pp = ProfileStore::getInstance()->loadDynamicProfile(imageMetaData, fname); delete imageMetaData; int err = pp->pparams->save(outFName); pp->deleteInstance(); From d74524f2c57c4a4084352281ec7e6b3ba3f7e1ac Mon Sep 17 00:00:00 2001 From: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 1 Jan 2023 01:50:11 -0800 Subject: [PATCH 086/134] Camconst support for multiple crops (#6473) Adapted from ART Co-authored-by: Alberto Griggio * camconst: support for multiple image sizes in raw_crop and masked_areas * Clean up code after porting raw crop changes * fixed raw crop for Canon R6 reduced-resolution raws * Add Canon EOS R5 1.6 crop raw crop & masked areas --- rtengine/camconst.cc | 195 ++++++++++++++++++++++++++++++----------- rtengine/camconst.h | 27 +++--- rtengine/camconst.json | 42 +++++++-- rtengine/rawimage.cc | 25 ++++-- 4 files changed, 213 insertions(+), 76 deletions(-) diff --git a/rtengine/camconst.cc b/rtengine/camconst.cc index aab2a252c..64fc4d4ba 100644 --- a/rtengine/camconst.cc +++ b/rtengine/camconst.cc @@ -28,8 +28,6 @@ namespace rtengine CameraConst::CameraConst() : pdafOffset(0) { memset(dcraw_matrix, 0, sizeof(dcraw_matrix)); - memset(raw_crop, 0, sizeof(raw_crop)); - memset(raw_mask, 0, sizeof(raw_mask)); white_max = 0; globalGreenEquilibration = -1; } @@ -192,6 +190,68 @@ CameraConst* CameraConst::parseEntry(const void *cJSON_, const char *make_model) std::unique_ptr cc(new CameraConst); cc->make_model = make_model; + const auto get_raw_crop = + [](int w, int h, const cJSON *ji, CameraConst *cc) -> bool + { + std::array rc; + + if (ji->type != cJSON_Array) { + //fprintf(stderr, "\"raw_crop\" must be an array\n"); + return false; + } + + int i; + + for (i = 0, ji = ji->child; i < 4 && ji != nullptr; i++, ji = ji->next) { + if (ji->type != cJSON_Number) { + //fprintf(stderr, "\"raw_crop\" array must contain numbers\n"); + return false; + } + + //cc->raw_crop[i] = ji->valueint; + rc[i] = ji->valueint; + } + + if (i != 4 || ji != nullptr) { + //fprintf(stderr, "\"raw_crop\" must contain 4 numbers\n"); + return false; + } + + cc->raw_crop[std::make_pair(w, h)] = rc; + return true; + }; + + const auto get_masked_areas = + [](int w, int h, const cJSON *ji, CameraConst *cc) -> bool + { + std::array, 2> rm; + + if (ji->type != cJSON_Array) { + //fprintf(stderr, "\"masked_areas\" must be an array\n"); + return false; + } + + int i; + + for (i = 0, ji = ji->child; i < 2 * 4 && ji != nullptr; i++, ji = ji->next) { + if (ji->type != cJSON_Number) { + //fprintf(stderr, "\"masked_areas\" array must contain numbers\n"); + return false; + } + + //cc->raw_mask[i / 4][i % 4] = ji->valueint; + rm[i / 4][i % 4] = ji->valueint; + } + + if (i % 4 != 0) { + //fprintf(stderr, "\"masked_areas\" array length must be divisable by 4\n"); + return false; + } + + cc->raw_mask[std::make_pair(w, h)] = rm; + return true; + }; + const cJSON *ji = cJSON_GetObjectItem(js, "dcraw_matrix"); if (ji) { @@ -216,24 +276,32 @@ CameraConst* CameraConst::parseEntry(const void *cJSON_, const char *make_model) if (ji) { if (ji->type != cJSON_Array) { - fprintf(stderr, "\"raw_crop\" must be an array\n"); + fprintf(stderr, "invalid entry for raw_crop.\n"); return nullptr; - } - - int i; - - for (i = 0, ji = ji->child; i < 4 && ji; i++, ji = ji->next) { - if (ji->type != cJSON_Number) { - fprintf(stderr, "\"raw_crop\" array must contain numbers\n"); - return nullptr; + } else if (!get_raw_crop(0, 0, ji, cc.get())) { + cJSON *je; + cJSON_ArrayForEach(je, ji) { + if (!cJSON_IsObject(je)) { + fprintf(stderr, "invalid entry for raw_crop.\n"); + return nullptr; + } else { + auto js = cJSON_GetObjectItem(je, "frame"); + if (!js || js->type != cJSON_Array || + cJSON_GetArraySize(js) != 2 || + !cJSON_IsNumber(cJSON_GetArrayItem(js, 0)) || + !cJSON_IsNumber(cJSON_GetArrayItem(js, 1))) { + fprintf(stderr, "invalid entry for raw_crop.\n"); + return nullptr; + } + int w = cJSON_GetArrayItem(js, 0)->valueint; + int h = cJSON_GetArrayItem(js, 1)->valueint; + js = cJSON_GetObjectItem(je, "crop"); + if (!js || !get_raw_crop(w, h, js, cc.get())) { + fprintf(stderr, "invalid entry for raw_crop.\n"); + return nullptr; + } + } } - - cc->raw_crop[i] = ji->valueint; - } - - if (i != 4 || ji) { - fprintf(stderr, "\"raw_crop\" must contain 4 numbers\n"); - return nullptr; } } @@ -241,24 +309,32 @@ CameraConst* CameraConst::parseEntry(const void *cJSON_, const char *make_model) if (ji) { if (ji->type != cJSON_Array) { - fprintf(stderr, "\"masked_areas\" must be an array\n"); + fprintf(stderr, "invalid entry for masked_areas.\n"); return nullptr; - } - - int i; - - for (i = 0, ji = ji->child; i < 2 * 4 && ji; i++, ji = ji->next) { - if (ji->type != cJSON_Number) { - fprintf(stderr, "\"masked_areas\" array must contain numbers\n"); - return nullptr; + } else if (!get_masked_areas(0, 0, ji, cc.get())) { + cJSON *je; + cJSON_ArrayForEach(je, ji) { + if (!cJSON_IsObject(je)) { + fprintf(stderr, "invalid entry for masked_areas.\n"); + return nullptr; + } else { + auto js = cJSON_GetObjectItem(je, "frame"); + if (!js || js->type != cJSON_Array || + cJSON_GetArraySize(js) != 2 || + !cJSON_IsNumber(cJSON_GetArrayItem(js, 0)) || + !cJSON_IsNumber(cJSON_GetArrayItem(js, 1))) { + fprintf(stderr, "invalid entry for masked_areas.\n"); + return nullptr; + } + int w = cJSON_GetArrayItem(js, 0)->valueint; + int h = cJSON_GetArrayItem(js, 1)->valueint; + js = cJSON_GetObjectItem(je, "areas"); + if (!js || !get_masked_areas(w, h, js, cc.get())) { + fprintf(stderr, "invalid entry for masked_areas.\n"); + return nullptr; + } + } } - - cc->raw_mask[i / 4][i % 4] = ji->valueint; - } - - if (i % 4 != 0) { - fprintf(stderr, "\"masked_areas\" array length must be divisible by 4\n"); - return nullptr; } } @@ -399,29 +475,41 @@ void CameraConst::update_pdafOffset(int other) pdafOffset = other; } -bool CameraConst::has_rawCrop() const + +bool CameraConst::has_rawCrop(int raw_width, int raw_height) const { - return raw_crop[0] != 0 || raw_crop[1] != 0 || raw_crop[2] != 0 || raw_crop[3] != 0; + return raw_crop.find(std::make_pair(raw_width, raw_height)) != raw_crop.end() || raw_crop.find(std::make_pair(0, 0)) != raw_crop.end(); } -void CameraConst::get_rawCrop(int& left_margin, int& top_margin, int& width, int& height) const + +void CameraConst::get_rawCrop(int raw_width, int raw_height, int &left_margin, int &top_margin, int &width, int &height) const { - left_margin = raw_crop[0]; - top_margin = raw_crop[1]; - width = raw_crop[2]; - height = raw_crop[3]; + auto it = raw_crop.find(std::make_pair(raw_width, raw_height)); + if (it == raw_crop.end()) { + it = raw_crop.find(std::make_pair(0, 0)); + } + if (it != raw_crop.end()) { + left_margin = it->second[0]; + top_margin = it->second[1]; + width = it->second[2]; + height = it->second[3]; + } else { + left_margin = top_margin = width = height = 0; + } } -bool CameraConst::has_rawMask(int idx) const + +bool CameraConst::has_rawMask(int raw_width, int raw_height, int idx) const { if (idx < 0 || idx > 1) { return false; } - return (raw_mask[idx][0] | raw_mask[idx][1] | raw_mask[idx][2] | raw_mask[idx][3]) != 0; + 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(); } -void CameraConst::get_rawMask(int idx, int& top, int& left, int& bottom, int& right) const + +void CameraConst::get_rawMask(int raw_width, int raw_height, int idx, int &top, int &left, int &bottom, int &right) const { top = left = bottom = right = 0; @@ -429,10 +517,17 @@ void CameraConst::get_rawMask(int idx, int& top, int& left, int& bottom, int& ri return; } - top = raw_mask[idx][0]; - left = raw_mask[idx][1]; - bottom = raw_mask[idx][2]; - right = raw_mask[idx][3]; + 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()) { + top = it->second[idx][0]; + left = it->second[idx][1]; + bottom = it->second[idx][2]; + right = it->second[idx][3]; + } } void CameraConst::update_Levels(const CameraConst *other) @@ -464,9 +559,7 @@ void CameraConst::update_Crop(CameraConst *other) return; } - if (other->has_rawCrop()) { - other->get_rawCrop(raw_crop[0], raw_crop[1], raw_crop[2], raw_crop[3]); - } + raw_crop.insert(other->raw_crop.begin(), other->raw_crop.end()); } bool CameraConst::get_Levels(camera_const_levels & lvl, int bw, int iso, float fnumber) const diff --git a/rtengine/camconst.h b/rtengine/camconst.h index aa0702439..273bdd7a1 100644 --- a/rtengine/camconst.h +++ b/rtengine/camconst.h @@ -1,9 +1,11 @@ -/* +/* -*- C++ -*- + * * This file is part of RawTherapee. */ #pragma once #include +#include #include #include @@ -17,17 +19,17 @@ class ustring; namespace rtengine { -struct camera_const_levels { - int levels[4]; -}; - class CameraConst final { private: + struct camera_const_levels { + int levels[4]; + }; + std::string make_model; short dcraw_matrix[12]; - int raw_crop[4]; - int raw_mask[2][4]; + std::map, std::array> raw_crop; + std::map, std::array, 2>> raw_mask; int white_max; std::map mLevels[2]; std::map mApertureScaling; @@ -47,10 +49,10 @@ public: const short *get_dcrawMatrix(void) const; const std::vector& get_pdafPattern() const; int get_pdafOffset() const {return pdafOffset;}; - bool has_rawCrop(void) const; - void get_rawCrop(int& left_margin, int& top_margin, int& width, int& height) const; - bool has_rawMask(int idx) const; - void get_rawMask(int idx, int& top, int& left, int& bottom, int& right) const; + bool has_rawCrop(int raw_width, int raw_height) const; + void get_rawCrop(int raw_width, int raw_height, int& left_margin, int& top_margin, int& width, int& height) const; + bool has_rawMask(int raw_width, int raw_height, int idx) const; + void get_rawMask(int raw_width, int raw_height, int idx, int& top, int& left, int& bottom, int& right) const; int get_BlackLevel(int idx, int iso_speed) const; int get_WhiteLevel(int idx, int iso_speed, float fnumber) const; bool has_globalGreenEquilibration() const; @@ -77,4 +79,5 @@ public: const CameraConst *get(const char make[], const char model[]) const; }; -} +} // namespace rtengine + diff --git a/rtengine/camconst.json b/rtengine/camconst.json index b7151f2c8..be7b3b800 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -70,6 +70,14 @@ Examples: // cropped so the "negative number" way is not totally safe. "raw_crop": [ 10, 20, 4000, 3000 ], + // multi-aspect support (added 2020-12-03) + // "frame" defines the full dimensions the crop applies to + // (with [0, 0] being the fallback crop if none of the other applies) + "raw_crop" : [ + { "frame" : [4100, 3050], "crop": [10, 20, 4050, 3020] }, + { "frame" : [0, 0], "crop": [10, 20, 4000, 3000] } + ] + // Almost same as MaskedAreas DNG tag, used for black level measuring. Here up to two areas can be defined // by tetrads of numbers: "masked_areas": [ 51, 2, 3804, 156, 51, 5794, 3804, 5792 ], @@ -84,6 +92,14 @@ Examples: // instead, to take care of possible light leaks from the light sensing area to the optically black (masked) // area or sensor imperfections at the outer borders. + // multi-aspect support (added 2020-12-03) + // "frame" defines the full dimensions the masked areas apply to + // (with [0, 0] being the fallback crop if none of the other applies) + "masked_areas" : [ + { "frame" : [4100, 3050], "areas": [10, 20, 4050, 3020] }, + { "frame" : [0, 0], "areas": [10, 20, 4000, 3000] } + ] + // list of indices of the rows with on-sensor PDAF pixels, for cameras that have such features. The indices here form a pattern that is repeated for the whole height of the sensor. The values are relative to the "pdaf_offset" value (see below) "pdaf_pattern" : [ 0,12,36,54,72,90,114,126,144,162,180,204,216,240,252,270,294,306,324,342,366,384,396,414,432,450,474,492,504,522,540,564,576,594,606,630 ], // index of the first row of the PDAF pattern in the sensor (0 is the topmost row). Allowed to be negative for convenience (this means that the first repetition of the pattern doesn't start from the first row) @@ -1216,16 +1232,28 @@ Camera constants: { // Quality C "make_model": "Canon EOS R5", "dcraw_matrix" : [9766, -2953, -1254, -4276, 12116, 2433, -437, 1336, 5131], - "raw_crop" : [ 128, 96, 8224, 5490 ], - "masked_areas" : [ 94, 20, 5578, 122 ], + "raw_crop" : [ + { "frame" : [ 8352, 5586 ], "crop" : [ 128, 96, 8224, 5490 ] }, + { "frame" : [ 5248, 3510 ], "crop" : [ 128, 96, 5120, 3382 ] } + ], + "masked_areas" : [ + { "frame" : [ 8352, 5586 ], "areas": [ 94, 20, 5578, 122 ] }, + { "frame" : [ 5248, 3510 ], "areas": [ 94, 20, 3510, 122 ] } + ], "ranges" : { "white" : 16382 } }, { // Quality C "make_model": "Canon EOS R6", "dcraw_matrix" : [8293, -1611, -1132, -4759, 12710, 2275, -1013, 2415, 5508], - "raw_crop": [ 72, 38, 5496, 3670 ], - "masked_areas" : [ 40, 10, 5534, 70 ], + "raw_crop": [ + { "frame": [5568, 3708], "crop" : [ 72, 38, 5496, 3670 ] }, + { "frame": [3584, 2386], "crop" : [ 156, 108, 3404, 2270 ] } + ], + "masked_areas" : [ + { "frame": [5568, 3708], "areas": [ 40, 10, 5534, 70 ] }, + { "frame": [3584, 2386], "areas": [ 40, 10, 2374, 110 ] } + ], "ranges" : { "white" : 16382 } }, @@ -1381,7 +1409,11 @@ Camera constants: { // Quality C "make_model": [ "FUJIFILM GFX 100", "FUJIFILM GFX100S" ], "dcraw_matrix" : [ 16212, -8423, -1583, -4336, 12583, 1937, -195, 726, 6199 ], // taken from ART - "raw_crop": [ 0, 2, 11664, 8734 ] + "raw_crop": [ + // multi-aspect crop to account for 16-shot pixel shift images + { "frame" : [11808, 8754], "crop" : [ 0, 2, 11664, 8734 ] }, + { "frame" : [23616, 17508], "crop" : [ 0, 4, 23328, 17468 ] } + ] }, { // Quality B diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 2354f343a..8478d56ab 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -548,11 +548,18 @@ int RawImage::loadRaw(bool loadData, unsigned int imageNum, bool closeFile, Prog CameraConstantsStore* ccs = CameraConstantsStore::getInstance(); const CameraConst *cc = ccs->get(make, model); + bool raw_crop_cc = false; + int orig_raw_width = width; + int orig_raw_height = height; if (raw_image) { - if (cc && cc->has_rawCrop()) { + orig_raw_width = raw_width; + orig_raw_height = raw_height; + + if (cc && cc->has_rawCrop(raw_width, raw_height)) { + raw_crop_cc = true; int lm, tm, w, h; - cc->get_rawCrop(lm, tm, w, h); + cc->get_rawCrop(raw_width, raw_height, lm, tm, w, h); if (isXtrans()) { shiftXtransMatrix(6 - ((top_margin - tm) % 6), 6 - ((left_margin - lm) % 6)); @@ -584,9 +591,9 @@ int RawImage::loadRaw(bool loadData, unsigned int imageNum, bool closeFile, Prog } } - if (cc && cc->has_rawMask(0)) { - for (int i = 0; i < 8 && cc->has_rawMask(i); i++) { - cc->get_rawMask(i, mask[i][0], mask[i][1], mask[i][2], mask[i][3]); + if (cc && cc->has_rawMask(orig_raw_width, orig_raw_height, 0)) { + for (int i = 0; i < 2 && cc->has_rawMask(orig_raw_width, orig_raw_height, i); i++) { + cc->get_rawMask(orig_raw_width, orig_raw_height, i, mask[i][0], mask[i][1], mask[i][2], mask[i][3]); } } @@ -594,9 +601,10 @@ int RawImage::loadRaw(bool loadData, unsigned int imageNum, bool closeFile, Prog free(raw_image); raw_image = nullptr; } else { - if (get_maker() == "Sigma" && cc && cc->has_rawCrop()) { // foveon images + if (get_maker() == "Sigma" && cc && cc->has_rawCrop(width, height)) { // foveon images + raw_crop_cc = true; int lm, tm, w, h; - cc->get_rawCrop(lm, tm, w, h); + cc->get_rawCrop(width, height, lm, tm, w, h); left_margin = lm; top_margin = tm; @@ -692,11 +700,12 @@ int RawImage::loadRaw(bool loadData, unsigned int imageNum, bool closeFile, Prog printf("no constants in camconst.json exists for \"%s %s\" (relying only on dcraw defaults)\n", make, model); } + printf("raw dimensions: %d x %d\n", orig_raw_width, orig_raw_height); printf("black levels: R:%d G1:%d B:%d G2:%d (%s)\n", get_cblack(0), get_cblack(1), get_cblack(2), get_cblack(3), black_from_cc ? "provided by camconst.json" : "provided by dcraw"); printf("white levels: R:%d G1:%d B:%d G2:%d (%s)\n", get_white(0), get_white(1), get_white(2), get_white(3), white_from_cc ? "provided by camconst.json" : "provided by dcraw"); - printf("raw crop: %d %d %d %d (provided by %s)\n", left_margin, top_margin, iwidth, iheight, (cc && cc->has_rawCrop()) ? "camconst.json" : "dcraw"); + printf("raw crop: %d %d %d %d (provided by %s)\n", left_margin, top_margin, iwidth, iheight, raw_crop_cc ? "camconst.json" : "dcraw"); printf("color matrix provided by %s\n", (cc && cc->has_dcrawMatrix()) ? "camconst.json" : "dcraw"); } } From a9b8ece33583727ecccef9d3d1be374ce79cb391 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Sun, 1 Jan 2023 11:01:48 +0100 Subject: [PATCH 087/134] Add raw crop for EOS R3 Fully fixes #6420 --- rtengine/camconst.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index be7b3b800..69b272d23 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1226,7 +1226,8 @@ Camera constants: { // Quality C "make_model": "Canon EOS R3", - "dcraw_matrix" : [9423,-2839,-1195,-4532,12377,2415,-483,1374,5276] + "dcraw_matrix" : [ 9423, -2839, -1195, -4532, 12377, 2415, -483, 1374, 5276 ], + "raw_crop": [ 160, 120, 6024, 4024 ] }, { // Quality C From 21a7c97ede0953e1c87e7c99d14cfc92d506b80d Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Sun, 1 Jan 2023 11:43:54 +0100 Subject: [PATCH 088/134] Multiple crop support for ILCE-7S Fixes #3960 --- rtengine/camconst.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 69b272d23..ebe195c60 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -3025,7 +3025,10 @@ Camera constants: { // Quality B, correction for frame width "make_model": [ "Sony ILCE-7S", "Sony ILCE-7SM2" ], "dcraw_matrix": [ 5838,-1430,-246,-3497,11477,2297,-748,1885,5778 ], // DNG_v9.2 D65 - "raw_crop": [ 0, 0, 4254, 2848 ], + "raw_crop" : [ + { "frame" : [ 2816, 1872 ], "crop" : [ 0, 0, 2792, 1872 ] }, + { "frame" : [ 4254, 2848 ], "crop" : [ 0, 0, 4254, 2848 ] } + ], "ranges": { "black": 512, "white": 16300 } }, From 646065f64310aa4d1e83a5a2d2920ccb80849b96 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 1 Jan 2023 21:22:47 -0800 Subject: [PATCH 089/134] Remove unused code Remove the preferences code for selecting the external editor since it is superseded by the multiple external editor preferences. --- rtgui/preferences.cc | 129 ------------------------------------------- 1 file changed, 129 deletions(-) diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 2c993d65e..85816e39f 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -34,8 +34,6 @@ #include #endif -//#define EXT_EDITORS_RADIOS // TODO: Remove the corresponding code after testing. - namespace { void placeSpinBox(Gtk::Container* where, Gtk::SpinButton* &spin, const std::string &labelText, int digits, int inc0, int inc1, int maxLength, int range0, int range1, const std::string &toolTip = "") { Gtk::Box* HB = Gtk::manage ( new Gtk::Box () ); @@ -1205,78 +1203,16 @@ Gtk::Widget* Preferences::getGeneralPanel() Gtk::Frame* fdg = Gtk::manage(new Gtk::Frame(M("PREFERENCES_EXTERNALEDITOR"))); setExpandAlignProperties(fdg, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); -#ifdef EXT_EDITORS_RADIOS - Gtk::Grid* externaleditorGrid = Gtk::manage(new Gtk::Grid()); - externaleditorGrid->set_column_spacing(4); - externaleditorGrid->set_row_spacing(4); - setExpandAlignProperties(externaleditorGrid, false, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - - edOther = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EDITORCMDLINE") + ":")); - setExpandAlignProperties(edOther, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - editorToSendTo = Gtk::manage(new Gtk::Entry()); - setExpandAlignProperties(editorToSendTo, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_BASELINE); - Gtk::RadioButton::Group ge = edOther->get_group(); - -#ifdef __APPLE__ - edGimp = Gtk::manage(new Gtk::RadioButton("GIMP")); - setExpandAlignProperties(edGimp, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - edGimp->set_group(ge); - externaleditorGrid->attach_next_to(*edGimp, Gtk::POS_TOP, 2, 1); - - edPS = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_PSPATH") + ":")); - setExpandAlignProperties(edPS, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - psDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); - setExpandAlignProperties(psDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - externaleditorGrid->attach_next_to(*edPS, *edGimp, Gtk::POS_BOTTOM, 1, 1); - externaleditorGrid->attach_next_to(*psDir, *edPS, Gtk::POS_RIGHT, 1, 1); - edPS->set_group(ge); - - externaleditorGrid->attach_next_to(*edOther, *edPS, Gtk::POS_BOTTOM, 1, 1); - externaleditorGrid->attach_next_to(*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1); -#elif defined WIN32 - edGimp = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_GIMPPATH") + ":")); - setExpandAlignProperties(edGimp, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - gimpDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_GIMPPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); - setExpandAlignProperties(gimpDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - externaleditorGrid->attach_next_to(*edGimp, Gtk::POS_TOP, 1, 1); - externaleditorGrid->attach_next_to(*gimpDir, *edGimp, Gtk::POS_RIGHT, 1, 1); - edGimp->set_group(ge); - - edPS = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_PSPATH") + ":")); - setExpandAlignProperties(edPS, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - psDir = Gtk::manage(new MyFileChooserButton(M("PREFERENCES_PSPATH"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); - setExpandAlignProperties(psDir, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - externaleditorGrid->attach_next_to(*edPS, *edGimp, Gtk::POS_BOTTOM, 1, 1); - externaleditorGrid->attach_next_to(*psDir, *edPS, Gtk::POS_RIGHT, 1, 1); - edPS->set_group(ge); - - externaleditorGrid->attach_next_to(*edOther, *edPS, Gtk::POS_BOTTOM, 1, 1); - externaleditorGrid->attach_next_to(*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1); -#else - edGimp = Gtk::manage(new Gtk::RadioButton("GIMP")); - setExpandAlignProperties(edGimp, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - externaleditorGrid->attach_next_to(*edGimp, Gtk::POS_TOP, 2, 1); - edGimp->set_group(ge); - - externaleditorGrid->attach_next_to(*edOther, *edGimp, Gtk::POS_BOTTOM, 1, 1); - externaleditorGrid->attach_next_to(*editorToSendTo, *edOther, Gtk::POS_RIGHT, 1, 1); -#endif -#endif externalEditors = Gtk::manage(new ExternalEditorPreferences()); externalEditors->set_size_request(-1, 200); -#ifdef EXT_EDITORS_RADIOS - externaleditorGrid->attach_next_to(*externalEditors, *edOther, Gtk::POS_BOTTOM, 2, 1); -#endif // fdg->add(*externaleditorGrid); editor_dir_temp = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_TEMP"))); editor_dir_current = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_CURRENT"))); editor_dir_custom = Gtk::manage(new Gtk::RadioButton(M("PREFERENCES_EXTEDITOR_DIR_CUSTOM") + ": ")); editor_dir_custom_path = Gtk::manage(new MyFileChooserButton("", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER)); -#ifndef EXT_EDITORS_RADIOS Gtk::RadioButton::Group ge; -#endif ge = editor_dir_temp->get_group(); editor_dir_current->set_group(ge); editor_dir_custom->set_group(ge); @@ -1296,12 +1232,7 @@ Gtk::Widget* Preferences::getGeneralPanel() f->add(*vb); hb = Gtk::manage(new Gtk::Box()); -#ifdef EXT_EDITORS_RADIOS - externaleditorGrid->attach_next_to(*externalEditors, *edOther, Gtk::POS_BOTTOM, 2, 1); - hb->pack_start(*externaleditorGrid); -#else hb->pack_start(*externalEditors); -#endif hb->pack_start(*f, Gtk::PACK_EXPAND_WIDGET, 4); vb = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); @@ -1773,35 +1704,6 @@ void Preferences::storePreferences() moptions.pseudoHiDPISupport = pseudoHiDPI->get_active(); -#ifdef EXT_EDITORS_RADIOS -#ifdef WIN32 - moptions.gimpDir = gimpDir->get_filename(); - moptions.psDir = psDir->get_filename(); -#elif defined __APPLE__ - moptions.psDir = psDir->get_filename(); -#endif - moptions.customEditorProg = editorToSendTo->get_text(); - - if (edGimp->get_active()) { - moptions.editorToSendTo = 1; - } - -#ifdef WIN32 - else if (edPS->get_active()) { - moptions.editorToSendTo = 2; - } - -#elif defined __APPLE__ - else if (edPS->get_active()) { - moptions.editorToSendTo = 2; - } - -#endif - else if (edOther->get_active()) { - moptions.editorToSendTo = 3; - } -#endif - const std::vector &editors = externalEditors->getEditors(); moptions.externalEditors.resize(editors.size()); moptions.externalEditorIndex = -1; @@ -2083,37 +1985,6 @@ void Preferences::fillPreferences() hlThresh->set_value(moptions.highlightThreshold); shThresh->set_value(moptions.shadowThreshold); -#ifdef EXT_EDITORS_RADIOS - edGimp->set_active(moptions.editorToSendTo == 1); - edOther->set_active(moptions.editorToSendTo == 3); -#ifdef WIN32 - edPS->set_active(moptions.editorToSendTo == 2); - - if (Glib::file_test(moptions.gimpDir, Glib::FILE_TEST_IS_DIR)) { - gimpDir->set_current_folder(moptions.gimpDir); - } else { - gimpDir->set_current_folder(Glib::get_home_dir()); - } - - if (Glib::file_test(moptions.psDir, Glib::FILE_TEST_IS_DIR)) { - psDir->set_current_folder(moptions.psDir); - } else { - psDir->set_current_folder(Glib::get_home_dir()); - } - -#elif defined __APPLE__ - edPS->set_active(moptions.editorToSendTo == 2); - - if (Glib::file_test(moptions.psDir, Glib::FILE_TEST_IS_DIR)) { - psDir->set_current_folder(moptions.psDir); - } else { - psDir->set_current_folder(Glib::get_home_dir()); - } - -#endif - editorToSendTo->set_text(moptions.customEditorProg); -#endif - std::vector editorInfos; for (const auto &editor : moptions.externalEditors) { editorInfos.push_back(ExternalEditorPreferences::EditorInfo( From 3423a7ac55451ac5504f982787d1a39043a64d4f Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Mon, 2 Jan 2023 21:24:15 +0100 Subject: [PATCH 090/134] Support for GX680 digital back including DCP (#6655) * Initial support for GX680 digital back With help from LibRaw for decoding support. Estimates for color calibration are very rough... * Small modification to black level, add DCP --- rtdata/dcpprofiles/FUJIFILM DBP for GX680.dcp | Bin 0 -> 65374 bytes rtengine/camconst.json | 6 +++ rtengine/dcraw.cc | 37 ++++++++++++++++++ rtengine/dcraw.h | 1 + 4 files changed, 44 insertions(+) create mode 100644 rtdata/dcpprofiles/FUJIFILM DBP for GX680.dcp diff --git a/rtdata/dcpprofiles/FUJIFILM DBP for GX680.dcp b/rtdata/dcpprofiles/FUJIFILM DBP for GX680.dcp new file mode 100644 index 0000000000000000000000000000000000000000..dcfc174c70ab74330c92ea3c193c86f98b29ae7a GIT binary patch literal 65374 zcmZ_0cT`i&_dN`PpfpiHP!s_bQ7oV$*w_<$@4eFONbfyB5?bg@KoKky1sf_LLT2m@ z>;(&A1q%u`6w%*2`hC~>_{W>IvhHMZ6K?iBbLO0V_F?ACMU%V8$;ow-(>~uxPM41u ze;S=vk?YEjb^K}ke`8~LIk{Em73BCqt~-CO{=e~mpK1HQ&u-;!em}1$r@-gJ`1r?p zRk^+W8zR4X3m*wIAziT!;LQPhSOJ!u{M{J%bYDIr#VPY&fwnf z-~SzhI{kfZ-2C^o!pOg`Ta^ADr~djoAHy%~zw=-5ANk+0W8mN8f!4q8pJ@MkT-x;a z*k<|n{f!*P|IUy9zxTEN?{&M;-}(Q)>s-Zug8_g3f4@ggE)@Sg&5QzMqFdYXQ#}~w zCh6qx9dBF>4nR=CXVQ6g2p*sEMfu7O((OnH3gx_^y`_%G9}0w@DsCqf!fI+ToOkEfb z=sDqdLaQvTQG_E6+u-!ZkS0hXv8Z?(G^(f2gZrW}d(k#@T5Cr$tzwbAdn@4g@*93>+b=q2#Jv63ETS9O)Z!O37zsFyk!w!4N zY=^9an`JOAjuaF9(cWl&9)P0nFG=b6P z?`SofcBv50m+*T$P({}48H~2h+tKMus;t;80FN#@!Ds3-*(2W&yb5rFlSg;@YPJyD zKW~HAAycZdDh$))wqfA|3%cQ97{)kkLFSYpbV6wu2KCwmk4imSIwlN5cR1qMpw4t= ztq@1G?D3=HqpUSw2#cEam^-CSHoQ%Uq4U;Z^;lKZ^j$!!MLLi@kA*1mbSbCuFv^5N{Oy(a%Osu;@iNo?rLDk-?n=7i~na zl6hg>{5E2uDaPfO9$4P?g8X?(>sm&V6rvE=?tTa4SjM%L$O7?xMB!$k80*-3LD zn!Bxo%eit{pM$|5SJ$GZ?+e*jjR0s}S_{{QiuB2HKd3(7_vKm-YOnrxUjM;9*bD~H`u*yKQ$9@($<=0VVpwh8h_S1?RNriqV7Z|q6#VFEp&$z8KkaaM%=)U2 z_E9L_Y75goPSs)aA~7>@J(AY9R*yR+Mw$6~xZ97HZPOQ_zutQ2!&mmGEF60J>kmF`5A=-=iehmlTP< zbNz5QL_=_IR}2CQe6aIJH^G|EQVbgAjpudhg46HfasR0&8c%i=_?0Fi_nZf8H!BJT zuSmw{I(JNT`bn~`q+p$aJGAb+Cs&$MQ6J-mD*cD#vRxWx^>xFE;A%1;J{9XPx?<1i zY|?`!qjR(?Cgix2MOPD1wAK}sDHdeAd;%I ze*rml?%Q8)zyQ@xU|KP_YU_ylInQC46%8A62RNK9!K8pFeAr-*`&pS)Gm|3Fugng| ztEAO5A_9}UI{t(6)>&ql@NE+kj|YS9E+OffA!zLvgm3=e$k#Jslm`SL;*`3e?r02} zU;1Hrg^oaPRy-1&eR1l8u0Xp-659Iupth{1VB(4tczpAMino^F{ggC({NahCZ#4u9 zUZ=yv#1ju)y9x$P*nt=?4{TOY5KJ=9MBkV0m=yb!Xza?wdslbF^>|L6EXc%89e1$a zSIGX!JCJ_U4Xu|BlP~wu@v+biXTPTrnQI#QrMsbWWhfD7q@p&~4ac9XBX`FoV`GpT zZu?CmuY`%%W$6an$5!NPb3ByNUD0vLf(%NE!?q$9q^uc9mUv6yFL8!qkrg?-BNiT$ zw&U||kmQdsnE!qo_NdGtR-0pRFk>r9a_5mxjnPnAvIRb7lgWQLI~i=ow@oeh59gbA zHe&gzUFcjUMvdX7e{l9J*Ce{jwI(8Q zms& z+l~*T$B~zNB)HLM+dnwdP+y`b=ZUG$f^mLm3pubtj9pN(a!IM?Wxzq=1mS>@jdtYjykep-cFQ1@j$F;4Ow+56H#p*c%8t=r_c2*<&wFh65*`tg^1rfNw>Z6 zxY)%DE8b)gm%(wcuk}Q!UKUw@E*5&8p4e!bMOOI6fN;F*m!m z2}Xh^KKa<8?Sr-7dJ7JAF2JvY-dG52L6lwrRxI&GuvA^3Se}pGoxD-fq9o|kx*rP; zdEwL!IYIZ7eW+UR1Ahk8L=`JA-dWaFTj7y2KsBUW)c zFn*>N9F%X8lY(@ti}u3sPM3+_xKwnn_d=KFjHIkjMy8cF`dq6d+x8}6T9h{;Zk{Cl zIwb&CyE#2AG0-*V(+(I1?{TD@`fUM?B- zjmJ^kX43m*ku!ynunzP52j_+fkI41BF!;&yoJ37u(Dz0H_MHmC=nEqRhut#q!6^{O z1FQvor{rR?WdH^Z87FA#yB~8*{J|tv0_(6sT$=6&>5P$rnO6=#hsPunlFS4qyZ_sO<1ZKL0Fn-{Ts2&|;iswGOzUPg1E5DHTC%K5@c~PcSGkNa23kM#1QPq<$>_gER5)!ywTy zqFWG+vY~!Bu<*#A`9)@a|KJ>RQ(iFZqXfEYA?WqlRIuGW9deg~kYzni@bhafp7;l1 zzXuUGE-1v;sR1bNLj*>4C72I?yeJ+oXsS4Z0#`r0KR;Tq^3pN9sPl!Tbg00kz7&DJ ze6PIGUl2FpIDWzxZ3FZL2fH0dPZM90?Gc9ST?~QwgV>!Ue;H@H^2{w9VLiQuf&R9zL+Z;EVylT8tXU? zYqR?aRCP{6{je|2^H}A(b0u2N`C?h9n!v;36b`ofVoiaf;Nz-ttRL-%)9*US!yly> zo#F@ig`dfR*uyCK>W8mG-x0N`2hnw@KfKqzB(}o~kXPi7!F%h;jD>sA^vxft2kOXz zvfX$f;FyfOOAc+?iJP$jP|~?c=-Ny;Jq$n_YDh|II?9I!V)wzzB)v;2c8deCdi4cz z{!kKZo&~~o{#mj$A^|f=5W2)t5*ZqY^*KRs*QzG+Ik6b?D+soQ6-2<}4MKtuKu(fq z?oXNoLC_su`3L7dw*vmbdAUO$!BpoIH0XxlS(vq8)0%u-zYv6vI+F#PLQAnZA`nGE zQv`9tPveYT0A`vK!Rv<erUP>nauxn8gJ+MBT=b|)V?dj z@OpnVe0f3?HA`{AB>+#h-z5S5hp?kP0N;FSNoxNCm=nPB){aZ$Lg#$EeZ%*W4d=*% zk$ZSv83gN%lzcgmgY1eR#6CDp6t`#dSSuKp_g9c1t~+o@5{${!C&{mpG#vgAjAgx# zlOg?6aC=1vG>#o5Rp%3NhlRjfe3&dtiN~Ivp@>K-Awwim+@2i@MZF?YRU$=6Z3vF` zKS;(eibYj?2=320{Rd}Ng`j_MPVHkP_}#D@`T-#rUtuYD^|c%iO+#>I#00^6^-Dl~ zFl_9`3*^#oz*!uO6?ZKK&7OC_G=kyYF;s9;<1Ple2EnM!NN_`X8|MoH5qn8T(Bs(+ z9#;gwYf)E$TxAVrRQf|Z{s$p9uOO)_zel%Tkr&z*ff9e54!lp!TQCfD48Rx9tK?@$ zB}DpxSh;|ao@OWUz9tY!kIPB^=%eW6AB1DyjuO+|DI53PD(2F8MNM7d9J)!uQNBvR^9;X11ZYKQWs)4b8y7oKR>h zWRkuCsYrYripDM(MD<4!V)TV*oSsIs_a;Dpr4YdtDWs6^j}y~`c(5Un#9fHP+CgCm zUYtS}OqJr5eAqvB{=Ynu*V$fzUDJ=jlwZSQ=^(+cuo^5}8;XLnLj*S`J%J0qhUkf= z0_pZwSbIN|?;l2jwak@T=XuBLh!I4mWT`eN>Eb?*d zN+^mlgd}YK9*k}Z#h^!lWboM>BpC`ZAlQd23(LkSCm}XBx|2;oJ23L35CPwui4xBR z=E{X3KVch*>7IgVGs3VxXEV8!lZYAdVMutgk-R<|hex$xxPEOJA)n$ghI33l?#swL zuQ)`k#- zNMks9D;^?0>R!W3GXgIAGRYFNr!W{7f#E8#WMt)CY;ljkr{WNjY+M7QLlJNtv5nkv zIge`}B4E&M715SfW65X{KHi&6BG;88IZy;yZ$chiK8BeWMR>n`3@NBAK|ftFy1EZ1 zU5$%Sx><}NcLtGO@Ajdvl5-hLjER*-9twI$kYC=Hh6g!i_TN3cTN`wQ4 zI+ME6IE-x&VdQizqF)sUp{D2`oZmM*C1*V^!zz*6+w(@EliY}$sY1-{@|rXSen%)@ z3te)b5K)yJS$-@GH}bBNJ3jJ6Xd2Fl z+zaSsEkf5h4Jh=N;j_I6CUWPordI{D6GYhKatO0*OW|BCg3aA*h{qhl-H#$PiKK9o z6ruY7F|@cHD^A+ac`q@%Ip1osA`e~S#b~|18a=9ZVc~f(zVDxlms_$B_e+e(Hv&vs zoPixy5_DKwqnAf2=DSHyHNhP7&Lkn@fCNL$!FlL7xW1EM%tJ$bK9Ydr6D06UG5tHg zUV_Pb3iz}qp5J%LKRD+sDk1lN)WCuJhfdAK#H`^xW;k+RbgzJX2>6W?Bf~I!Uk<7M zsX(^0g+X^{66cx}Ny+|j^z{rSxrz#;cvJ*l?O8@v&;1SCoe`*znUcyu-w@Ljfz@?i zP}hi@3oc%09gk@3H$q%Jy>Mh2mM<1#ROAg`CBr)KrUA>~Y2o2lB zu)APZeKTu6W~GU-`<6}hzWh8Kr(*c6o>y(qIR~xp#W>!vs=BH$3-^0VFmL>Z>NBw! zm@-3x+Q9AA*Y~HQm$w96bv>&OwD34&uLSq^tg3#=abER6g6I#P)zwcE5Lp(9!oi#V z%Y&TqpG@IA@1MtCo`1wOSF+>&EnF!M#f`)3iN&r@hzS>B!ozvQxvdj< z=okj8&~ap_k1{!B6ONlR49WCGT}Yi=1m>RUfNYHtdA2J8Bi|Kcva}OX(GkJPW*Fq} zv?F$l2%;a2r%WSSp->>gsdCk7VeV`EzAM7)Ah+sw%OAn%w+N{}^QuEP-9+mkF?y(+ zukLi}67&~|apm)~YLEU5p21?=DE?7>(ESv;7xQzJm1P5j$8m-8-HlBevh3l9VW%m9 z&jKBpwcPeuAJuu%d@=>S>#_beZPW#$lnQg zVHSl2R{j6X51tY*!@Qhepd*vm7Kha11BJ$kwmO z#_EAlXj6-oof*0VrCXx#JU>>}Zk2|Rk|`0<$RWWpINu8~07vrIO-tP<EE`hD5_U^Sq2^?0}npG{&`^mu=5VL(Ao8w2ZhQTU(P1svpC7fhyT^ZqJ{* zW8h|XRxh(I2eoL^M1)1wd981^N%3e*>CEIKx;OP5EMuzASKQ|F#S(EI} zJ#BJ(ju`8Aw#oL6(jX6?{pTMP=|Nv5k~&p_`W>n?cJVI^iIbqRK$DK%(~L>A5)|#! zrXuSGyyP6>$x>Y!V}2Lo9e7ODvo|$WyoSZ)kr>>pPn}1cL#}odbXN7Hr&d*Aqem3J zyBg5WbIY*fb`;_#_oK@7N0DL`jWbXB(dD0u@tW5>uFWx|IX;D$A|HdNsfN^c#Xh)h ziosr)A&rm9l>xR_ucqYc|jK#G|LwYSI9m9F;t)r_Uz3ZO> zM`tOrWP0>JoYS96v9P`mwTetceIc(WIraK8ulYiXr8W9g$v6QEE=d2u`GWgpSykT_ z;5*NiHnz!1j8w^ep5w?hb)jwwJ;~~=;h4s2&Gvr!L|hnw1%`T5ZcZQa^Qs8`>kX*U zIz1viCdTuh18C7+O)_wn1mAX=(R~_S$hCtKoH%Ylduz*){BIIOp0cFlt3SX5k=Xgb znl3hYhVOCQPg;$qvT^rt`)wpXcAiN4o7KQ$0gq8P+EB&y=dq^jB3K}SFvzLnsydknVE6i}0`MVQF71)A#wR6Le*t-RK# zuu?#muFS)Si?R4+BcKbacj3o)Dc)-dsG>s_Rvwa~`$IyvOw2%=aU3M6Hh*yLof(HO znPX@J$N6sWc(n6t_TG_*)VerW%(412e}m75z8y=~4N1U}A94TSyzGh!4S4nq-?|8~ zxZglp-Mbr6o)w0IZKLR}iM`2(9G-)ePM|j``Vq6%2n2~H)3K`!Nu`MxV;0Y(Nm=?t zj{8{KPxI*Wk{-mkPy*4|C3M)@uB1#Y5=9qQP`9UYq=N59Gfu3gnqNPnyf_j^zpkY( z1D|7=S`^Py*3+c3_p#eI3aa02sqTqd)V_&AuXlE|@1qMywvEQmG<$mEgAAANM`Ndw z106;yaAi>pvZp%Gf?>zepWElTH4fBO|1dIbY|^GNXqf~Xh-#)XW%r6$B&C^=^bv*4d;0M zc;Hg{l;fqKF+ zzrkK?;5pmEh%oBCVmA)W;59j$Fj{*v8@LsZUSEW?yLboW*CoKIB#7STIP0|}z;UbR zADqj$zmQ$@qjenTy77rHAL8|AK3|fE6T^LJxkUn6Z4>{&`QiOlbW10?~}8?pFtqSG7Dxn3YJCHW-qSN(pAw zCQ)^v4!JNl5;ZN!ROFyaT2JwMe02)FlirE!?;nLwl1f*<_zeHlC}{6XrS#Zq4AhE- z>f2PBeC83(W<=vz_cVIb=@!sG2CMp{(bF@opy_Z77HXtXYwfeRNn&x1pD*2g8n!oM zvAHaj7GF7uVH>0f^+}~o0Y~wnO^SN6RJvkkFS{W81%s3wVf>P-9Z+p?D zEFRScDYT+jE?&${z^=+ zB;=?`=>v|l-!?v<_IJLcG6@dDV(FTZ2^f%^^bgK9>0wl^L5Wz76+&r73O!$~PZn{# z$dtgHbkl@E#EnGYq0%0DR%0kRc2bh$*CI2?|745`~hYLMrV34YpmQ@!?bctBFH~G@tg_Rf5aT@$l8kr=1mxAncX^Y3hD@N45`pxn5+M z&VJf8#qGJvlw?fG%>0A1Pir#v z#P9rr^Y0zW@cR6Beq2j3FnKQx=6};|aLPY8tN3M5U8X{^X9}?;-~f#qXh;I@gkjm( z53Z(%>y5eMDG~`&s%e|0F6r|y z5^W0AG{#h&INS2P>0}k{AFD{tG;s||P!$ax{v9a+(U@pcMJIfE3lp6fuFpA5zssJ& zx-Hb{-FxWAu^nr4nzrq%!I_`j$L3bjs-73Hc`vtHol5#YrE8+&!hx*$rUt6d4%J6Na>Uek?RSXU6hHvN0O0v=kOn#bGN0S|I!2W3Ag9afvG5PE}{3i zJ&(GOg33dG=S>ErqIh=&^;sPUPp{N}aK5W_h{l}OAf~H0*NQWAMAiUuhVvLUuGeVR z{ShRU#~9~_-=ddhk0SL`#ZYU#Lo;6wCyRGTaCP}z8eiO>ob}_e?!`M)@1-tD?;C~K zmfO_4n+Dl>BnqpoZd0G|&SdlKXb1{!QIUB&wBK>PSMOVN+spSDpB#f~;Y~Uu@frFd z7Iz=spseaXT$*E1V|s&{=wAofE#1Ra3Zt3-^>xkB4{U0}zqBqZOtOxM-t z!Et#q+PYn)6XkMv{+@!yZWn15$JzU83Veq#dXwAp`@~deZLXw`InGm;ry)JzEbU#B z!1X7oIQr%+74TS3V?!FO3!l?byv|~*pYadQ36|&Sq#HfRovlL7?LMS4`V1zzeZsM! z$1CchI-2M|j=-W*Z|P{CG30?z4EFv#jhtgn`dpV_-2V6U%klvv_y~_BeBaSrsUB%v z7ll*3-_m*Q8f0*%Xsr6(M6bChk*)`$5!knhrmJ_L+v*tTp^;8J_yO77Vqv@THEkI6 z0tE3XLK4;?5u;m%O zX;6uYq6DOGY@q#Sok0H?d~e$Llum0oj2zV@^xIlb8x#&At~Lo_9#3eHC$AYLC&MEA zF>SHhgN0n*b7jXP`gBSTe)dU4PqjLl$#G8P7^=U#MQ?DNMJLjD4dB`zoR>?|F-7qq z9WED-xT|Ss_IgYMd&XkQ(sUH;`9Ll2^Zjb|zc{;VKBOZ?tCEGbLaaR1LiaB)Bxe=E z@w??GEodAKv6I)$vKl#kWM>j?&>#~s2GbOyMEGz ziuGu&h()1SJ5}s=2m3swVAFrl7xq_i&^!*Kdw!=TJI*4YISvlbztI^Pr%_lOkD?=A z>11*eueK*ZH~b52^*MsC!xOP;>$tG6TvJ$Q93gp4~`~bQLk1yl~vp_ zBA*i@uwt(oyLoQ_G3UIl#Yc5^e~J+?_miOJqB=XgM~@WwL?Yw88e3eaL2SoIA*NoH z?H{g0lp3SpcteE++W*33o>L^!jN%|QK+6kNLYn-18Wf-fBB4|}<72>AL4Ps2G$2d&YKgLpdEpPg*`;~%QD zGH^Yrm5xh_z^`W+$ZG#dgKZ@!-|;Wb$(3?!U_%?ObFHd&vN~I7+Kqg=6^0{?T5P~= zJ+jd$0_HPx*{BwMa_^G}JrC-!J~q9`i0Kk+i`8R}Dm_Ta{78gn>9UH|T}h+?_Zu5} zvTcjyiN?(+B%11Q)$A864v9uVw&yL@R0_O*| z1Z%Q6MYT}hCdJu+ZfvRl1#~lu!>&LLrqYw=Derh55vInRBZm*nYnfF*yLauR?O(k+8d>~yegSw6bX&PM(oXI1)}mJ z64RF(vI)c6@ToKkZ<`HRe&Sn9+YpW8lD@3nr~w84X*YHHFr~ozsNi{=B&s({8gv6T z@jUNn&|}g|m+@)26yf%|?8C=1DC!r7MCG0=tj}qDd>MzcW!g-9^91a<-&p0P#oRTH z;FA~k&l7vFi)RiX5Q(7OyR-0@`|+S_61ui_V_BQ>@b-2RLZ4`GMe#0V>`umjd+O|o zLnf{|@qF*08oS4RtgtFV2NF-Py0hkI>Uvh|2r@SfYIglJ|u{^vQ&& zj#MU^#t~f0I)tf?P$3T!MUV~~$~y1rLWVr#oTu(kR++6peBVp(v$Gk?SNnmfHJqP} z9n73wzJqN-6t=eyVp`)HaAHa{&TlbcpO@c*&(~-yyE1@n?Wn=K12LGR)}Q5Hxq$bZ zV&P|E#7=rs7@JA4ynjEIS9=N_T>E>YdtcVK`~)O?zc0|%XBX}s!IZRkd|TFwC7(Ko z1C9x>KCH`De$B@nu9-9M+mlsB@4**^Bq;9GW=-xnP`HzXWh1m$LVgzB?N7$5Tiscn zQ3mq-QVBG6+={c905T!=o81~EDDd#Lk#@W{#$ z?8mqc#C3$DefTIgV6!~AX)D6+6QkLX!E)qSo*0YLM>Fk)Z}2)UL5k}r<`wh~zp^6H zaLa;Czw#8mj#1d!%be{oy^EoJqfxPLID7c{Dr~PuqbYqTd!>2~5fPlHEgZsH460x` zF&4AKP1%5VC-J#G78lG-SpEE?kjbP-KHs06v*J3j=r{~sZp4nH7GU*C?l(Rdu-R+& zLS)7{g|t3wcF1nX$6OlMfj|FD#KZ~v41=qe!$L=9& z%ztVmLbz6S#0OMa@^Ne-*CC8| zjD*fdYqskRuZ3A~PPnrbYhQF3N1CJHZ(zwvo>6?~vBzYKQH(}b;M(#S4AHY-j`F1# zsS%65$A+`jY9;Ww6pNS2Ls^cr07Ijt7-Kn@xrXjR)qL(ZmYJ}yr@OGYS3G(K_h(M~ zGBJ|(3Culi$h6L-;mUDt+no$pj%70URf(9tS)a}0`scl?lW?s`kL`aQ3rCA&%!=&E zHuHMO?JgA3iZKqG8igTN%XO3f~Iw!EiEgEwytl7HNhmbHZ2Ae)v zvK>nb5l|O{or_1Yn({s9ksOOfQ_Y#F(=OyJkYe%Iq0HT92X^=1JrzlV*?|`+7!w^h%4}9~yw=+=ncj-kp`L@`f?@A*q)&*xCj+OfgPF4|g?oxnetL z8_!3e!WtX4Am@5IJok5D9%H@GH#;4@PAIc^MP6|2|1Zu8*G*XP%>qo(5+b|%ICi#N zhJ*9MFgQO)S?AS#y3vWjr(EHM^e8yxy_b zn#H#7#Q3}z{JLey-rUVV>55pCEFH;4UrXlPuoM+8!`X&koMXEsMe&v)tV9%zqp5M& z?`XohZWLqLDqdrDHD-@?gn=3+z$nFlRgDZrPGbVRZue%V%Y9IBBoPs#blH~*H@pu> z!lR>FtZ;}E22W4MwZ)oD@%Kh-(Mmz4p*mafp7&`zO+olT6}C~}0Ifr*xM!=(f(z`B z8Jvb8HxyZ;p)FR=PsfBiitK^M7OZ}ghO9jb%-(u4E-vDF(Eq7-C$^e0QlE`N6(Q!G zn8>PXk7Dzi%@1ZlUY7GiC)!W z)E}M3)E*tiD4xH(IWd`?iYP=4*O?sIN7$IeJUm1cmX=RshZbZbwLJ=l+sCnh%W06~ z_1>c_%rp#{^HMq>Z%Sg4l{Wu>3OVVxw!i1&k7Iqz*8 zuqX~!`uAtg7WtrDD;|1I2FxPH4Uu=_@wB-Yiyq;E>6u(-d|Zc(Z+F7Qb%_W(-JSJm z+=>tVlc21i!FIN6#<8X(bPrcybF??1*WqN;j#FmBxf?LTCk5XJDY7A14p2oZF3*r> zDeZQ+q@0F2s}8z&yDh{w((p!2o(*6Q&<;(*3nzK@s>U88c-`xNajuRY%skhnVnHV% z*CK)uw|%&5!s}KAGgvbBlS3ATBdK^c%e#CCTAWkb>^7S{<2AU`A`$kEp2=D+b*Y2R*;lR+8}W$iUu9g~J z7;D7gz~Mg3(AyJ+*W%zWugCJ*+;A(F>r|4o*xr3E_%tVh>o2>pTCeR`qMnF7+f~_J zhiz!MmWa@!%B+6d7No`{VdgMJ)+1&U0_G=U-9tGxzj_0TIM=b9=ck{P96@fTU{3NE zdc@Wq4k@V!)A&d|uh?QD=Q=#Ef1_QF+2NIX8pgN%q~knnQF@cx(Er%;g5QIg$@OGd z{|LokOTyH6obo`6+jGkdw(N2aWFy0IvDa+2BWO2_W^#MpJCi9++KEr|L{RH8ja|RX zb5Ma8Q4HAd;ZbD+*!fhqDRq zBVaWm8sUa!td_6$$1kJtc#O&o@Ilcn{9$1o*iq zvef2n_~4g_erM%a=GQG~woC$z|3O!1ZN`4CiJ9E;iB6cj5u=Kekx}@b_7gdxa&rpy zo_I}-?%Tta^Ku!jZ)w3e2h8r7id*a7(wzc(e2q`V@I7CtL$)pKQvSucd+8A7&-Y=+ z)=+e<0Hc{{*uk}4eFf85bY41KwfS28F`XG#rXj%~0_`uSFw1<-tMn4#_EoT_&3rBL zJ*LO=vFt%x96oaG%InXgScGycesHanozHN#g!_zlu8~-kF_>LHB*u;rQJ6PxAUnV{ zAm+S2m9fEyB~Rf!1$n%$EWR((+rTwwt733i)QipV3PLcio9v#b!%PCW&h%<5jy}<3 z&(HhdhFFRtJRjUS%?l?4ad@(}3%mB-9d?z@n+&t{ z`)&$UKMHYg`&6crl!{4QujsRK3Nw(T!1YTwB9r;O@JT}E%Lr&Fk7YiM@#r|u^YK;- zraVfDfGn;j)Hh>~q|xZSQG)ev2e4(lrX4ak67NL)*eI^yvTBUPrw6?mrQvwACkmgB z_GG7C3UOj>G~%!HU<0gq48U{7ls6hIVsj9NT#rFey9$%f=bGrKSiDtMW?p@KK_^Qw z)=+^>JLQG>9h^Je^^4B;^FYrNap-ROjTX*#!|CnuxX}3{eK^(yY6B85U$co0vfPe$ z_Y?4I(KFhPZCD$dh>cetQpw6K@UlrlL%<#CCESEHACgdRS4&Tw+<=)m$ru`Pi8}vu zK;XO-*sZ%lL$e(5(u&tmwp^sHmmE+kPQuuXTH1^6o22C5y47;!VNA-oTha4Syt@FV zJvtd9>v^s4@nrUCZ!*U6-f7J%ge~&mvFEjLhQ{sGV7+yHEFk^;ki?RUFJP@8+lF8MNN*4yXB9h>D-=se5bp8cpr?s z6pseA()_XB_*gDQ@anfz+}#u4d%%~H7xdS6H`JKKqt56Fef7Zw8|&gR{@6X5-okN? zNkD@A4eIi18ytC!&&K=;_3614O^t~-)At4bo-@4qR_d-|{(k`)sY#^=;pWwgU&GwcdDM;~^STA$sB^_#Zgb(F$hI$ zr}3<9LI8fu4@FG#L^h*u5I%7HJq}v4CL!;iC<=wM`Uo~I#~<=sCsys#pY^i#Meegu z6iRg2)brd=e&QPM>1u32oCog932|j!C+1(m|8Inv5WXir(a~nEc&;l%+OwDRXPYzT z4dDFM^E$dt!5O!yFl>IKIhy6DLK|&0?SU{6X zH{qAR5Xy`8(CQZ(@zhg@sX04olKMt8^LmHbiFDd#u>mXB3bAQ-A|0^Q5uW@SCT)$O zbNn4p$hjc>Kr!_jvH{_>yk|ZnoXS-=!sTN)D8lG{xs5Ph_OJeVfYg|Et6YzC{}AZD zwq$}{8=)nv8CiC?obHdsPfpVIC_A3( z`=Qs9BC1nuhl%`uP@Hng<+Un%MBVX4YWFPa7;2AsQ+yGepGGqp?Q#964o=sC_ZZql)4@89c*y&3WrxLd^*~2#+wF<%xncA} zZ%6cg>w%Lhfpk-w16G;we$R3@T16e8Z|9D=b{pxF00*4oz06+?S5f1k4(NBt6+aB; z(jWKiA-Lp%_K^$d!;X#6?;DEmp0lW4!A5+T7K)QUXVWEbH(}&8t~L6fxbFCeUaXLZm^st!cq#USEtMwt>*l9n8$9EkW|Y0E}zw%?_6>#)UdR^xoQ) zW!Egi1)(p-9D7d_zAnU8{@Y8RT%u1s7h-R@7mCgm(ydMlVZO{0*YCyAYcCgK$9H$U z+2TPvWJ|Cj-yLO7mr`HXRp`(AUSEHlL{*~J0Ty0x$+V{Ttn4s;j~C?6jH1ha+G9+H z7rg5%=s6olyq)L;TVg?NEjM6jnI{HZF{hfpH{ik`&;Li&S%yW~eO+9o1Qf9o8ymaP zS!YmD6tNQo6qQCo1d;A;K}u;v8YBc{?sL<2cjseacfI@l_V?RdT=VeAo-^m(XP>ox z3wLv;@JWTcVROt0BXqU+{zc}vu*C^lo5%CKW^-I!?t~ArQT)*q3;Yas!jjM-{F;Xa zW>44)&BwiY-vSHF80(B~sw#ZIaSOcg+lM#Fe}tw43#?z@iaXbP@@|S&7{3g*$MM2L&t81}Wh-#sf9vdD)m=P%c{ZK-JTU(EXz`lLLU<{=!}ju6@i7PH4{*aM z_n~4$97EbbSNyl4yC}0_C{Wo)^Yae=_Zc947%Li%M2Hv{c4RG)OMrFp`}ZVtFO-y0HxQepTU2i*JUh1wM-glW?q za7o7ti_-*QVP6NBM0-MLZW2mf+Cx#%6M~TN96Sl%Jp)h3+UZ!}VwIo?suCNE261>rGQm~-1(hgRKe2{&)NKoo)hn}H6Q1!_Y z(z0#Q`I`^)uU89=rgmuA>;KPszE|;`YrY$agt;D==Snkn>3D1mal_V}A)@KRNi++0 z!Eeo8;vqvV7?BU!=Ee_h;H(8lT}M>sHS+nRwUE7Q4+iWDeq;D;L*lw|gg z+%O=5W+`cx8l3&z;piHGq-Voqi~hJ{DS1G8Uki|}ZgfZ0UGh^LZIemH5c7n3p0KTo z!Ue+v@aayyqrzxmkB=M11kgEi+dM%pi}s}6{&1*UB-C0TsKL)a{mcbR(E6{f#ssgd+OdqB_VF_p3r3!M;5XR&g3bz#F7M=a|I z#IC(RWV2U0B0o6@DmNwyKV~{&K)}Cx{+oNx@Cuv02qflFVsKaSqDntVy6?v-_a35P zI1u~OoDpUqFLH4ZJ`Hn3zY*8DZI%Z5btOK`uN2-pYbwlJ_aLQEpYKv$0@GuTaNsY6 zYp$E2w95tXT`Aa2qqS=80p-?14J`}zVfGIn%-?vmJybC1;yh(?&%MxvG-=PLJIUT{_JjuU zm}-_xmNi$oqm}xEW!T@a?x!21BSO)vk}T;pc0V2;2!osTZj6)AIdpIYG#cY2BPO_D z#Z0=#oY@P7Y#*-ujlg`d?qu#~XH1#?Z(rBrQYK$248&XRjz?85c%M{d^bA1WuQ0ZTd?eQvhroGI9xJ9ZV?7VY z`jv%D*Eke9+EHjx%w!6Np;(hgcdTI%>~>KILPo{F<;*T-OkVYmcj%7$-30d8hcr7~ zqw%!n5ll7)BIa=ZJNx?Vn0GZ#$#8=FKC(WNA2T(^+-CR4~NrdjhK-Qq-h1v4S7)HFE-g@rnIv^EV2}omaR+`))gI7~NLGLZ8OM-zx>*jSsW!kE5|jE(Pc1{Mky3@%qFJjYfPquP=5IRpyfqzsa8%up| z!nafyRHw2bbl)`K@?jYKJ<96nnHE`|j*S`>Oy9{HYLS_+e^JZQdJ{)#Yc^?>jaX1>G|<%hG-#UhHSmU_abHS?c3_evhY*Ax%M)l_%bsHO5L3Gx{Ba37ZJ zIK_w7e3Cq=w?|^qX?}d$Pf5=LYdm$y6ka4lf7D^*S++4ndE@cre7trjWp@^nmv`?m{J4_FQV)1zvO)eobxybaA`EKRz)&Z5;&z2|1^Yje zc@y>_{eBbocX%v0FWG~6ug~$dWzQsGhL*T~EQi-WmB*^}yTLP;@+;0`aATeYG~TBP z8>g<#DkadL)Wpg){ZZMw6y5yu z;p4Daq5aJkoXN3A#0DRU?(85a(OJ0Q`aEV|odo}J;TUG=$A*v0g1_t_K3h`e}|Jgyoa?hqmF~fx?M)kt~RDn5DPoIa?JYE%-&Z=;mOf*DE<~%5^2xNew5=(7a0q9 z9*RDZ70~Ei%l48tt5D}S^(e=gzE%)CJ|0JjMG^Ch55SM0N=)pQ%Zh0ptox}F9}5n% zwnkrkUQh*{)rXk=KtH%DRYL#LL6${*j>)1*ls($U%IKa%A*1S_I&W{;BJ7VFfZJaW z;Nwa|ZkK&u^3h-~`rm2bpPH*A4Kda@yyhNn(LXK`9-HC%$YMUe=z(OGoGC)mwE6if zBN0YF*E9(iI*#oICOP84m^TfpjG_^E-47u<>(M+W6a7K=q~`~+?xT+(wRaLWA6m#< zMij#2b2_wtZe!i<97E%VJUlz>!yf<4gI`f0bd3|)pN~11ZB&NJ8Aa@zZx#$}E0H$7 zntkt`j`s!CIM=I+9hOgpT%Q_LT`DKdS|V1wtA^W_V)ksj*m6x3kMw`A7yTPS7@Jb`?jIA*?xh&E=Y5TD;!F1``(GgH#oc62>1nEJErzDMx-dmX0i@?^n_Q}AsEzh*>$r- zcsbUiY;IIDcen2v(BID(X-z?wu1KaSug8hj)^Sg zMG(aE_0ZlnjP2hafX*lD@#yb=kgX(5UFb>Je=37)lpl6zHsGC?ykyEXAB1cW{;Bf~ z?G{WF`$KF!fbXVtf`?{>?<8NXcu1nP zcPsL|4EVYy%6NLm7^Rg<~`#k6?*{W@V9aBpAP3dZh zR_tb|Ic(%JFWi<)TWd(?ae1DS~!svft>z+_&zjWNOaG^%DO1{Z;lY8 zX=Qk^AO&t}X2P@5Dr}#SgVZVG1g*Q(7>YNg1-`Wl%b4E~)BQglQ`{2GVzH?aZTiFjR!y>35RP+=wa7ni#vDiUeo8dlc3p%DpK|eqw|M`H1=Kt3V z8;EFZIoz;Eo%BAPMC8x!Xt+VX^SWG)&esOX4il%La6QNF#yPTm)RQco$T6*g%O0!K zz0;3>>ueBQ$|_4oVi~d33fA9dD5{klH77=>&PNvOv_!K1n+0?dlv#xKy@dg%jPd>D z7`}g@)>W&LtbfhUg1xcWt6UzJKNsWq@OSU|>z+9_` z(om;I3$1dEp>t7A`rEU+B*teG4()j@>}s!<41cx-1EI-(YAwarzBag4F@gVCACAf9 zzUW-6N&dbZ=omyH;@cp;ctJVjSqfGacH^~QsxdPo2adD83wJ$EV3}Pp0#4l!R%F%S z+WAVT$=3K1tYau6ObCcoE}W-M!RAy0iUMzLm`j`I*6T?@eDoF??P z^AYCS_#tU@6Ru6M7W&bw&iPg2KXrb)sbYi}%N>(j0LDq~UY5DUBlIv!hVcMfeFgkTja$}+q`c=;5t#+%hX{;SI z?i!E}E(*DpG=FPY#fMMNgTcmVgnH<5p}7Lm1*uqZehyzZ{sca_=ECUl7(Up!7Tx-k z;Kk#h-RdRC*Ue?9cOe-PrXR^ULAfG)~+1rya$=(aWz3+S9syu1K7 z-i#3YCP6+l7fU)?Frv#zVfxPuj4f-$#81`2p(66Ejcmh-v&V(=*+~fA(1uRqD}cluLlFVr~g>*u`v}>%9WTnbhZ0slzdS?8Pz}W=D=da^m z(v5H?(*bQc&irp)9Hex2xMa!!zTD;*HqjjBN`@o<{u|rd^<8neGmkZ_PLvFXl#8iB#{2ScxxLRRX+&J&xT-Y zRV)7T4?^IuAjp2SAgS@Gup^r|G`TJ4T7FwtGa`^a)0Thgd|S|vF3OvRzM90>iaRB3 znR!OihxX^)YIAhjh8>iwD6m3++A^JM+HMk)r8{u-Vytx3)=0_jB}Q0N{ZN?kt0x|q zn?dXKULNty1~J3;A@oQT*A7U++`u60coWCd1B>Zd9uK9xQM{w91{z0?;Oyf-u3%Y@ zkspqtVuc&OTwIURL#41;ZqD=j)?vqoD%=^okvCh`V5n9-Y&I(xW@-gIp%tGU)HvF*|$*X@KM&OWkl=UCR zpZrS3wYYX@#tq?D<|X1*YddCC58_GXaTq3R$H!d*c>vw%`+BzHWZ(dPNuS&h5)4x+pJ)_>~U%Wk|hsM|~| zpgQ*-{zCe_>t)FaPba+UtF3dpp;VH2)0%isb9FAypkD5j88XWZrNbvzNNislqy8pw z1{BB9T+kfnwIX@)Z%<-m9e`>|4nIN9pmDmSol8H)h2a$#-6;{JdO3V{LLJhJG9Wpc z!jDdA!1KAs@O@+q|8e;w`e>J-XlM|h@}v&YeX4QT*qsmSaRLKA*FiCF`6PboSUpyEs>Z8~Xuh=U1ippWA?|W8zocJ< za6=i^y(9DB^D^{VAi^iXoomjdKE<^OH81w^Td7AeMbd)w5Ia6>RyNF2Tk%Po{OR)P zSf1X7-)O#Veml1$_LNscJGzZB=D`=pclE3t(Yc0vj(-e}TqJLK#ulz% zL#&>FcIYT==8*wm7^KpUr)M_uGV(4s+O?rYPMqn+VvK2>L1^fSq|sdjkmq^7ej>8xbx<=r^C!I=I0 z(-{L4cAJ=i--o=sCxe#u)Rb1nx3_fBRG>Z#(jrmCoE3d-2oteC8O)bj4)xs|} znOjg_ZI;=9(KqAyLj7`hT5{~263umzi_pKY5zq_glCJq!>C+7Dzrj2@m-@-iEwpb3 z@-GL{aYwxkrq}#^ zOK$waJDPjjw_|U+D^FGl$NL`b$WC|QH*&)f^Scc%E?Myyr7#R^Y{TTIx_nS*FbY=u zTjxJAJ?Q}Rx#-lx9Xnsk>8#(`8-wZIWz=;|oso8(V83+_l#@H8U%o$=4BBb|zY`~A zuXsPa(6b;GbOQgVYejrNQ`p+-8s@`$j9v+7czOVSXUIJRT97gH! z2mHEfBiuA|@#nwG+>Lt7img=Vj8^{Of&jxqWw39o=gWsQz?9D9zQGlI?#EhOl-6R; z#{&M%xEg)hPNHr{F1M;E2MZAJxjlp5>RgPvvm(AfOXK!V~(UGKNSXhsb8Ie!q%v)hpz8^vFfhHE;l z`H>SN`9Oy#SZKFH_j@?c3#0SP_clC93*|lih`~s&j|2ztM=!$A<4W5<>->M$^B38A z>5AVAuyM3I+75QsslPXzc)a`2IBTHJRrBtc?q`pg%7Qeie`gGPY>64~T7(lDCZZ|L z8Uf~IT>gS5%!=L6{`Nnf_#zVumBBcu`Ne=7rt{0>^B(wyo}r{Q zawX4&%Lm$X>eF}+l?V*E)P|$?llkeONPKxh-wVfsyor1sAL;Wdz8}HO4u<1G!oTbJ zRMuwc&!`nJj&sM1EO+6CK(sOmhLKM2kR4mhA5E6o_Lh8#O*!b^RH5$*JBWU*%AJR%cZ762BY6^8|a(c^SEbg zp~xKZwf9s0g!Zv>%{~}ut|B&EDur}q1f1UY6o+5rXe~VijTdTS$<$VwlcmFJU02b@ zvK8Z+bMeWdv*=UMjQ3#$IG05Fr4fx7bE^c4l3()~GX>25T!GZ^Cp@FmNqAqchV#CA zy!+J}eABGMm#Uk5V)x_le|!?3v#)Y-LkZj#2r%n;i6^!mL--sKPad4(8n(G`x!nkj zE@$}N<>V=t(u^d_c0Pf6>AMT)+}ER(+m_`$f;=wY$mf2E!$Ord z3}3~0-jisgt!%^l;FG+Y1F`*0TacD`g5M#3xp`{~F3-y4=F1|;x7`Lqn^OKeB@!L; z{_UT8ZqbuwPO`u+J7UGR+?6(KEQ7OIlc1vv>?nK&Qi9!

M~b zzU7kbC-8lHE&A5KFy~RUs9ENvnGmZt`;48`;eS;Y-cU3(V`qB+J8>7^{7yF zgyw|5d?9(u9_DzXcjtj(#@A!m6&woh*(1c$p|yzZ9uMz9!^BtG0xk?lLGbwj;-fAc zla+~;bG4_ab%%P47g?}sQx%6QH{gp;9%lAd5<{QXVbACScw5Mc{pk!opqzYev7N;2 zBdc(`wG7{7zxWrrKiM_+IIcYY#>*m#kV@xthh3k!%a(k6{;wKmrhMR&400gOJAtor z-jbIg1EC9QVL@DlkEhe%^|KZSJ6`YsTj*@)T}S-W=lse*^0{8C!+5u+d`-7_SSi&b zIfgh7PcLu09Oxii2LORiJ0r<_m@Oh~!HGeq`0jKw%*N**M z{q-WuePD-ET0i+lZPM&e9+mgh!Qv9*BiKAK5U=Nt5#Qb{f$CxMkMtTNj-eUF_mKzj zG;X-KOYsD9(vl#{87QjP*TCvUDxBbxc2z_z{xwUFy*R55^SI)w!>8fIE>2Vm% z%Z1FMt7v3e4)uZg*s@enyn3P-M$~)%-YzfRd3g+Tx)o8c+eM5YnTOx>T$KCMNnGKa zg-!cP;6R)Ng^nXAoKlMPKRMB44?dNm=Ydbe zLx{uJr=>JQ`@rvgibjd76!V_H;|oYv?mVUppYOlr2`{73Z*Un7ZGXtBF*Yw0dqURAWdnTN&qvha9?vbZ}U8xqAF z49rpz^Yt@OO!qY>l@-OAV)NOfn?j{2ic z7P*Kz&`DfIvyM&Ua?vXL!_~>3czVTwx z?-YdRz;e|$z9p7C{ciLO{-1M-%b-a1;gKygNoQO2%wIbD+j>ms?uNw1XzAH&i*c{O z8Bv#1rJtO&(cZ-Y30b{)>D@V)>1cz-PWO4w+s0^kXb<5r?ZcCam%PCpA%^3`K^v2h ztxH9Y0oSx$S9(m9SD{DY&4f7qwh8~ zQSVp=ZXHU&k;-o3-1~>2Gb$Ck)m6o%bcfU3C>784DvK|?lEBxdV%RGsao^trg!WIx z0XIc4Hai|&YE!Utyn?vGJ{DEWQn3BEocMNoG#oA_lUKTnxO{yKjNT;Uqb+36Cll;K^KDF!M&9d3HG__pyQVFE#Ov?taXcbB5!h z(IU%?K-67NRE(Y|W_LOSiz9xhOdT(_?M%Z+VzTLf7$wf3ed6$hVBFrMAnRSiI}GKivFLuahgdoy6&tBu&qk?%V`#qV2kM^U^XPyFHhC=}Moi|ZSsarI6VbT#G0 zdBii%jG+1N_0Hm|Rnd66AR1B8oyA`-qHuHIzx=v)W`}U2Vh@I0@IZ*4j2f`N46xgWf^mOY)wab@qr2>f{!zj@dns=HvPHL|G=A@e4ot^cp;p#e^qjc^ z-}~9Yd*5L3(J>$RWH@7!o~D==Nvxwu?l8~O6w66dq)L8)Q;H)*JJSSIk;Yz27$gQe z9)gLgFLqS)6Fcos#=$?ns33o3QhX{NHBj!_gude7-)Y$F8i*JB`iQc;G;FO6!YrrW zV#RLCIPf7Y;^1E5&eO>lek~aHebmKDg(S4|U~H7Bi9=@-TZ8mwK5x5;@s8yGBS!Io ziK=2{TO4Wa0`W0OSm2~h~&<&W#*<;AqY(YW*8 z9~p^q;%xsYEK4Dt!-URa@r@{`1O)>BbrQ?MqQFc7|5?u()w&Hn>+G@ejt7E=kCtjJ zHA2@kH<)}{D(!Y;6}qzu1SK#p>e4p|O}U#|1h$>f#ad>J?Y)$FT)HMJ1m^WbJUr^G!X)4U-Qc zb-5>0&Z>*W1&P=+%L|D|dx%w~2^c{+4pY0UiCgsuSbM1L2PB2`XaT zvsk3YxxrSut2nqmhPb8`t!g)b$*#uA#)MzG55I# zoD-F$L#7+Uy2TCsb*D-v7pz765EnQ)Jz~8#>SG0*peWFjchhp5aNdKu@e8^2NPRr` zO?t47A|A4Q4Sx2p#E_mZ`9hN|7ItANyL6F4`QWUsXk`92ZzTus~7|RWV_X z5AH3qME6Q1aR%w!V(Bi@|FnWAnNEBZ4NGkKq$nB=h`^5!E7*MMD$X~LM!Jy==8aSl z4TjJj5M_%a6IH~?#1-;YY`gcrd7tNzI8tGXuY-Q_xkZs^wK2h}Ip2Bbz(@>R zV2t#-&%BpBF%sx^F7Nu8za|gv0W&M4`@iQ&#K%eu*up5N}1PL&nK&3-rz)Mw_Xi~=%d(PM#Y|(dKR1<+g zaprj2@|(Z2i$Z5_a}+E6g0x*f<1d(GcmrhC8*+iBgr;9Js&h49-1b$-wJ3=iVNb7ORrKI4m> zB8g+Y4c*>8{|mgvE(p(#(E8tWgRd1rG4zc&tS3I? zLBs}rr(!`~#pj$)h=Rc#bM)T#g3m~aLfkrY@+>^(dI!n>x_vh;UwX`q*GA#ppk0`D z{~jOlGZJbUW-yv?i_bn5i9P*xAo{>He%Fp_a>x`LXI|k|#P*0?XadQO%Y5NV;+*s~ z#;Kc^dC#4Zu%LX{V5iI6*f#FwnSaQRP( zjW6DSUV9v1BQ+6LY}^dPAUk~S(}QPtZNqlzJj?0S|zzZ!{% z_MMas)XI}7-^5DY44;xjZaN{7_;TCHcO&CdyHI|_8PcV!ZQyG=MdG^~t>O0#{NC_L zTy@-r9`6M{z=(9~RYv$cRNyo9h^;$w8+Og${Ihu^oNgJR*<0jicSj=r%{F{dYUFG8 zMq-3)+dp-7c^D+PnAqcpf+uoQ64)g2G!0&Q0A0MkvBX?MG)!}aQsfQh9KIPFl%4T3 ze;rFcy&1Q=I3oJuLD}OohG^5guIGZFJH?VbA-P;A3B_L> zOO(H;;On|ZAX3W`dD4^IxRSo_f&~h;%lJ)NtLx7Y)4{%uM<1uW9_`(*`gENCKW}*7 z#+_IcRLlq6iNJ1?|M$z~^Py=G_(tnZ=Xf4ZkB-3YZ^l?L@+j9mPMlqF8$#la@p|$x zm%cQ@HN9f~(6V&KdoD zWu?(Sb#6!x7phP0!D(erNY$d*eOogmZ971o_pi)Mg*0@#U9o@se=M$gD-3oyc9egyjKu8ml%5Z}!c1>@t{p`YZtv_F9Srti#ds4Wi0Q=Zy?-s1HQ{37`k_?aDKT1-H#J5lkVJK zR0Z)x#NjZ66}nZ&@VPG{@Y=)@_}YpH^NZgR9@*uxj);D@I5G-+fbb?;*C&{pTkq=bBU+_ z_J7aaodaTp)|CBd@biLaTe5JTQ3l;l>Ny=Vgl$ju!`xFk(lsOyf0rlYx zg33c*7-V?hIBzQn;VuR3m5a~zg z-!N`MgV2w(BoSLY;6Xnh2+GEpLq0yO1_7%Bu&9p*Ql>NrMW&Q{-r)|1X$?YyJ>?O# zkOqKWKlBbj3Hcq4)B6v^1i*+i`9>b*!nkC2*eiQuNy!!==;#5c%<#r_y{W>}bFK(J zPAq``nQvS#SEI}qd!!b6;r!rX!ig?>&~KF&p7fq9xOkE0`kN;@nidGpqR4w#?upoy zD}+&h?BL-?{zt1VLTJt&xY&~aF@3j?YDK-CJ!QJ-ISPB{I^bE5C)AG}5EME&BDKg9 zONaRgpKd$i!VU654)GI?QlHpO&I_An`U^?cdyzce3;C`7Lg|~m*hyR-GqnI=AZgyW zn^Wf6@Braklrx;%y9L} zz4zggix(d3^cU3o?}O_eFDRM#3)2QshUYFXL~Nw@XzWABRxj*!9v}=VcE{Ibs^ z2ITX)_W$R#_p-hvf4MgrPRR-VgQ`%6`d_}W-185lux+rs5gdukQd%Qaf24IeipjQ3zNv>Ijhwh zMK9$9^_y8qU3EtH-e za+G=3Q(oxU>xRwhJ~%d9Ua&NA!{H%5$Q>;&tka`x$#KMR9x5+9o9>1$(|zDi@3$L5 zHC*U}XY<@-FKBP9H}w6d&YqvH;_F~v*#4%x!lnkSr1zfwKt8S;IanrmquU!Vm=klv z)6E+f=;uA>8$)-KH|de7CN7#N(etKkH*e%w-InlW-q=Rpoo(4>l0gQV<{`jY)q&E6 zc>3-(o%5wWGO8g+>WL?$ulV16!{P2i_Vjlkih2?IY57d{R3#9ZBfJr~YCM~>hw`bW zdn0R_2Ae2P+B~Y`icRWlKe39xQ!Q3bkYjyl|Lh3##`LkTk+#~Oa$~5@UoO$V!=HKp zZ&)SP;i;lOW(}Y-_K#f3jV2!6S|4~=B%pJXAErh4KrKBCKePN0-9#+eg_N%r;D@*` zK6L-$2Oo1k%-8fq;cH*4(DTFHHNI$j;)@Lv{Lt6K7atA%uvNtmnt8r>H#P3)^wUk@!hxJZDuu!MGK{r1{H4zW)nh);e z_(A=A5Z0vmpzWd`#ugHr&&&r~|M+1o<+m~V{F5j8VieGBpP)h#S-+isieinN@jJTfO=)cK_C@5jI{Mb?ocJBa4rB7=yOs?QDQ571K@JU4+n;J zWjlIO{@W0L{7Uai*_!^iYvhlY1C`miv6Rbqm~scal$m!0-EBVbhxDv6Gi8489z_{v zomE&1t<7HM0npG;VegE6VP6n{L8Dbzr}sWcdq;U*gH>4f03XE74uq+a3ez0y13jAe z-iv>S(4IbcYx?iJZlGTjt3Dcy0rR~Pd^nu-^o>HIy*El)gW1*WNW9MTM)y_z>;d&T zy&h4f=Oa(HhJ38UhWp^Wu$L8+ZXsod53zNuSn+atoll&QgQo1w={J91(*5E;X38pZ1cy%AM@FR@L()Xr`K`X?DXp(T z>%Qb4c3|CHBOyPF*giE@>>7P`QE`5dSngt}wsbCd?}u$6+u5D>;ZQapUcpKew$LLS zyK||Zb2eu6#F#(+!=H4V#w_$`82ai5;N>r4wve75_L%{&&oW^p6GH)-A%8M3WdjzF zXOVoEKVF)$npKn&NO@a&_S@M93(8>B3BuL;+nHBzApR5w;qQVS%(0kyHjQ8m4&A{b zZ~5a9eSVg$JD6oRe^~ww#<0&jSo$K;blZjCc3(60&C3@99)>_;k{Q$H$Y#;6Q z>~0^*pP{|rfA{BoTFK01Dlw4hnKX4}5{qv>gzYDZ!?P`s)vWc}W-($y2V9;tRJTi%pxsCDrSlIgz%7qR_rKSt(Pxk<4V}h|T&V@a148r1G#PxmR!dh!7S2I2Ynj>AA zel7LY#Km%4>&iZIe@sgY#bH-hHktP9QIzenEy0yJKljDg{4g{Wy0Yc+zBo879Q}S- zvEMenh<*HTUR$61IM(p&Fz!2f!{c=v>#{BluW5hK?h(g)XNQhNVNO0V3Fmt-YvM69&md;+V-ME% zEalh;!SGJ;WGUpeZ!!qM_!VC4;h0c7y%z$LOJ2<5SumJGDB5~>vm<3e7^_J9hcVu) zp6*6o6RU8}EN?c|f>>Fz!m*i>b{4Jm$M$pK@YeNax=Z|!X%T_o72Yh4(oIgtMPlMr zCuUyfi|IxG=7`N%9LVm*ksh0RhLNX&Sm~tvNv;`1H&Q3k_fo3sceDg=TG|{n>f)3}*WJp*7!^O-V?Gft)|yPW541NJo(A zPv^H(FSe%S5LPMD{y5Hqg`ZBu+n@jpA4cB)_X$u@4#eH~{p>OEttW*9Qs3sv&KVxW zH>DsP@8-&O9*KuG@f_!Ub73*-NPFKi7!_KstRyc6FA9QTe$bU&`9t1uy$~>s{cOA$ zgBE!jJ>Z zU=d}?X+$8j^Z>g+nV&Y4zZTg{uUm-==SZ`p3kR4h`R=a_jY9t`2Ur&uU#OgkLfVBr zESbK?lW0Evzx&2uyiH^ z>XXLXvyDOqGHJgJr{C%0nvNGc{owq;jy=~of(;-1FoxT*^dX0#=uM0}a~pO}E)8G0 z({o3~n(2Q{!S58}&!4hn7GFr)HlA`bxdp4~l#Hd-f$;fb&c60d!e{zByN8*xSLFLU zMtxSpE^~HwWg-Ss9+|19IeSJqF!EhOU@Vxk?;&w`Toi)t!z@^@e7Zw1qFl>J3#LQ7 zx{B^$&{nWy+lEC_o_H8c_FJ;KuHksMHyjF2ELq#*P<)?23|?5VB2&uDd=vqN5G&^P zCJ31{*Kj0A(M{UJM{kV6-6vM;(6j)2?MYr6+8^?sQU35b(#I%Uv%b_WG zL(k18WB%m?23AdH4=xpw50|pGv$dI4{xJ-qy&}z9%5I%Mib3yu5bwQ&rH{!&LWD2= z%wEQ39LYiG|8ez}VNrJN_pse!VPFS}-gYWd9HIsFBh!)Wvn<3OhO#%;G7226r1Y_m}>3{AI&u7 zs((Dr{BT8~oTgYTilc`dJ$Cj_Q*QQ+W$q1gg#xB2Xc~jACsdfSd79GrZxpjt`Rtoc zQ||wW#HHV?XDy~F=G7u`IoJb{(R@#6IJ`&l-g!Jt*|(L?0?*v5W2P%w<6u0^R+Ha5 zU9q9hVTz>}ZZ?>qR1OV*&j4?%*fv8+oaqOX&)%>)J44B{XQn)T1GD%a6Vprma@2yD@^wU z;&}5}%FT<;h?*1x`{Iepa$6TPyk0fmYI5u=v|5vgd6kYl|7$2A)pB6Y8YS>;1Et;P zO!Q&>(BHqA(z643Sm)RirO;o+A`MQ~F39t5tE{-5g6duAL8R`Wd|H}}$P@GoJ=96* z@+k?2h{f2g>Y|uMCgNyo6|DTaD!<8XIa{fM&H8T2EBZG)S>q1lM*51~Yi7hW^1zND zeP!&K7@vY@npCXJ$lqU&OyMP&V_quT9LlRj;1P(qM0R zUZjul!k$XrS$fJ+L#S`pQyJRc6Z_o)a66)>(snQN2bKq-cYaUh{A)Li9UFvahk7bs zEqGS9)!^9qp33}RT$}G2KF=MMe^`@WtVYhw|NZ+Pp5%zkOJi~HZ4n&K6KCKo)_ht4 z+J`vd41JBw>gT~|zBBSe(y*{*4*qSz9wFrb2KCHB+%Xs2I&~NyHfNx(9nS~%vuJrX z4LkT;?H+j*{U)ZO-4i!#9DExC&mY;qV4V z7GY?S?TxG@Z&B}OFc$dwU~iXqaHmgsI5GE}bIg_`&ogwMAFSsS7 zn%*tjih`lJ{{fa=T(B#F9>sZgaNsU`$F!<`xoabTR}R=(3VYTV<&8#Gwow;j{sAX^ zI=gA?%3(#&r&jspJv+l0Rt2cH(FMhZXARGm=V8}WSDf;$3#+EN_|Tg**vl@g(X-J= zM}^3S!!hDQCM@5pus41(a>i!h%td!xnm-SZ^V9H|>v{dUDH;z-#nBMvkltC1xbkF- z*+U;!osFnAZy#1H_QC_suoq8BL^C7$5}R(t#aVI48c*+5hwW%-9u4=2zBoI52Nrrq zpgy1X>>E3A@OCI1$yssfw;NF=Ex*SV=CyCGJUOj5Y2>`eX1Wp6NfWnFq#P zF#6hT@VCL7W!{K!4#wr0#M@S?vC}UEkCxhEmV*br(i47sj4cv#RcMwGhLz`Rard(; zv$Dgn@1rg3r!o)ocm(y8ixJKqz4UlhpY4yvkF|a2e_(cvSkRUO+O^tZlorr)+do8` z^rZ-nLC$Ddf0y>ws6tfibisX-DcV!&d>m$9Z`!M?wmCU~jfv;F?x~^eJw6AWx~tH! z=7q}sDOvDqNd5V$l*;SPn72qT=>0!cm2uAL=yu%$zuK5qp8m;ouJ9z@II>dNn}SR9 zCAK`?sZy_gGUm8@;nh%`$_KrZP-e+K^Kp$z`_A$BYtH=__qiguWelw6`eOc{rxm*7 z)=rw@N506d3e}1*G%@tYaJP#UDfIbB7!rV&WhX1%jSIs4-hpUpc(|hGQ}PnK1!2R3 z%8KcnP5)`9L6~D{#bA2zmgxp#@%Q}|(_QFA-8ckK3<@h2@_txSHxxP_^D1Uma6eZM z!|AcP6=uADru-s5?`w9&^T{sA_!5qTwoNMg(Z6lMys#?g#=tE`LStNtr#Boi{(fKa zWZMC>DRDxtRqe#Ny#4sgzQa<#ktqJR5D8AibrS#8M$Rk1^bM}id-q&BDlZQk=eWTj z{;IYf{a0+qFz;jKG3~QG*{E&cj<#P*wL>0eLcAN zi5at!v;#+^;@%lGLOkNM=_ScXE%L&l>M`2%`ui{~ig_Q-QQEa{$+&NE?exOREZ5KO8QfD4VowJ$<~uzaUimHko;q(?ZbD zCseB(rAJxsP@b234|~(ujlvK-KUCX+ePa3RFz6LTXzvkIIb&FLo#$Wm7B+87iM

cP)W8`;kHZ7UJH zhApnc#r?av=rNC3V>kMV9HSguU~lW5V<3KKWkEfVIKY=KqF?Jwob5zUxsVPb(?~EvaPUwmx{$d)KDh35z|+vVAf+VoWI*j=Niyr%!S8lj1S)SFc&-9 z#L*LxGuI<#qTTfH{2{?`lpn~HPg9w=1kVcyzQ zTsp%nwObk_)G`&RU%A(I1oPZjCZ-az8Qv%a^SsT(oR-8x&Q!ez-)ws*&JHd|KJg-p z8JERa+ftODpoj3syl_f{h`iWT#1f})`y4Ey{!NBz05K+2u$Xlq5ktQCV8z&Ap-hT{ zI+Jtm+QDM=_b9wG^+Vh>jhKIn-f0ba{$^{$==UKgWoAudwMMiaqCp&aU>7%NL}>zb z5X@uJo2e1CNBE&z3O&S!X~f9)-sol=gv@RlQHOk0#}`3ZsjCsrT<3)z8u-`Kh_>9% z2fH)l<8P2qkWnFchjX&3slP;IT^syr*{r*>M z*QeLTIbz&DKZ+wRC2-U_qtm_TVjHyxlUNr%A9P0TYx1v<|7IRumb|bf)7*31($3(=79O$s8P5X36EHchUjE^VkKNjLqY$jY)%!ofy zDZHMgW7A${!EdP$TY9CzcnkZrpmL#Jl7jc9K6t5HF8V!9#GS6b@GdPA2CL%Gm}l#5 zt1?m2AR3PXnCmgDOf+~Aj_DKpVOXt9?D-vnW*?ccd$ClEh6Z*q0eF^KDz;|^;LMaj zEb=WC-{{*koY@DRc9n{*U%l}-Gzi;Qm5P#6>=VcEew<$_9#qhWjae$MrJRM&uE*TIfI~0OCt; zWtc`R&aG5OejQMX!^b(BSYKZr2tR<~f;by}WA@i5Ms}$yRz0gG<2M#zSuy7>zkZ4` zY6U!sn1j&vi|M*C}X_SOF^zd%e4 zeIR;~%d~Dx5Rx4qh@CZjP(e?4_pJ}az$Y&`7AQW?YH>@@rvihyZd}? z`apCe&Rwhu!AyRAKo1wp<^59roUh$y)Nt)c{<*8i@C0 zwd9*se%Q%yhbwut%hlTou#Q;FqV-+mtI|9){^WrU6FNzk&p9~%)f3AiJIG+YY>ef6MKNtJ4-e0T z>1QvfH@1^OYtj++&Ksl3+REKEQjtc^)`BT*rIA?@zOvrU`k*H-osC1St>jGS=*g0; z(KtNNAJR@wW=@X4()a%K)7F!VXNO`H&xrM7^yC@VYgiiy>z;b@%4=p15qrJfR!{ES z#SG}nL73fKPuB0|gD!mEyT*EQ#yd4uj|s+$MtX87>-{o@ewxdGDOxOk=ZL@$3uL3B3K%~lURNK|{@Mu6hnWxCrJuCg9E$5N1JI^UKlv;{L#;n^#6IlK6|>q}qxp6k4NZ5W2E>?dFF9_-z?YW@7Ka+maZs73FOte;Ib%d7J$vF(i$dR$v0 z_ns*S-Z>*K#$4K?3|GF;n|jd_IX1Zjr~bNP*R}a_$=_n!pmzRswK?+Jl>Io^#vT70 zoGGh06=Ga>4~*BDE)VU?r=K3P8*UiO*`>K?KSGVK&8NuIr?RnXtQTzQFY*0VCOwpi zp9dJpG=mI$Wq&QsPn4a^QW4spy@bg`IW;2*9m(^4@_vFG)G8is#D8|APmtyX(fBvY zAES3qkgMDx;JP{h)#px-_dG+fuNO0pM@^9L>Aze4n)O@n335wY<`8BFp+>g}a%GGk zIb9lT={!O9Frs$2cQA%^ognQSdg1bOo)rcYq{CYeSS7JW>_0(fzf$3;St#y|m>>^V zqwjH>Fz8O4AZ2gP>(7TVH)Vnx-kg2nj;iZC{+3E^vlXbtnRU~TPIB<4N@RUCWLrQ*jTUj*G=EE}IrLT73cOdJ+Vr@`?^VL!5T%woCnY&2{x zQXAZOvD^?7@qcxN`P)VEGPPNQSQ~%4xkyG{(BN(VAZX4nlIlKzc=;s=&CV>6`?CBn zx0JckXBWx!#P(*{1;hUGA{nCVh3|$T=yzw4T>9Aq>#56X^L&vU`c{R4%2339UL;>~ zuf1fhv2l&X(v|f_$5G)JzhSY|^4v(iRdt>Hw+6~tEhL_NV}8nfA34Kci=RK}#kR;( zu4`I}ku_bQ(NW1|F6Hp$^I$dAMTS2t#YoQI^*=gFzkf=g;hfI$rJY>5xES@Oy5pOl zjXb)g2%U+^`ybpbopu!9>L%*iw(pepcIMH0ialVEmAvPggFh}_@X*^XyJlzMsE;>h zeBUbbzh$6)C}*_ew#t3ksZcqS^LliPyzn{+tIYh+dFvKAb9Ox14E0Cnp#CNPH`&XqbVu}N z4>|Wi5lnY`z_OaV%(+>BbWcy5z2qj3Udw|=IOoC-T&2fz>bX ze9A*-*|!aOJ30{6#DJ!2FTTh`IuO$hIKc8`FwURJrup*vcXRda?8fyTi#gk&{tmD zpNYfd-G+zw%KqO|QAu9@`*ptZ0x*o}7`sa(9OqY~B%o9s_)( z{gVjXoe>CwKEAT>F86cyAhhP|F|~t{_LKEnKVR94*oMnl?(f0;o+o+U#|0yk-$%RB z2OqbEph)qR|LS?+=(teKo8l`kzVX2BraT`^eC1iz8}05=gSW_6o_^p8nI4Yq%YEhl zxIEUoBA|Ry%k&@A+R#Jbzc~N)vxSU=E5cmX8?_eX$Sy^NnE%2FT?{hhvhDP^cJHt&7-^E6!R&Vr z=<7tw3zyUIk=W6LlacZhv5Rf`Y7`!dko~9Ahr@s~`cL7qMp_aE_ToJ_FI-;eLSJIe z?93mB$vP$R=-B(Vo(YaVucJm__Gfd9?NDsWa)T8bQlS|u0pcApqp&P@b$?{Ng zSOTzeZJ2CzRD;OKK;-fDtLcH*%yZ+;hA_E~`pW&r8vL~klm5j%NbMMm?K{Kd#85A6 z{1}X~y$>6LaEJ<%T4sOBl|69Jy@=QUEO5*&%Ir8m> zWK=71!Ly1?sSMnQ_VhC?nvpK2-AY7ax*IG9rb@^438+UN#eCCbS#UQFo#Wi``ec&y znG%a>Va)a3l_>Y+N5jt76K9qt$lC_=StZUpc6YqoL*1}y7c+Se$I0FF(pkB|8*P+0 z=}{{T`pbN%1!9KO^$@IPKe(zQR@xI+&?Od{n-D9fvHL?h~=BU;ugljCfY{y+Tr&%so=CPu><6?r}@ zQe+>)AlQ5-zhZc@Z2vd_#pF>$joT;nLj7^%kec^>l2k7xmx+8M)8~oOc8D(qdDC;> zIZ@8g_krV9A4E<}ly3~Y(PzFd#&=4T_eXf41#!`o`iW9!t{PoB`D5I_39{J^@{wvW z6ZS`fTpQs5w-*8E$kz>zFmvoIHHW_v=3OJ*jEl9^ixyzlvn*K+Y#uJHw(NUrxN}i<`t)AAQV`Z~js* z)7lkd1G8j}RzBqTyJC!OhRh|Fx$lA-rX-|Eg>`=YZ1&(aQst7Xp5#ur!!SHqE>7oJ zx6%U!Yxc?6j^t&I@&2)*l~p6&nrFt#7Gbt9vbDdaeM$ULW)_!Am#>*wdfqG?x;@YNo*=!iKHo;ZvIz9Sn zPc3pq_5F@meLG)1=FDXp^UIc;%a*msC)zv08HG_9vf>T7tkqrc{!^+fB(K%`vJ&US7RVjed1^)V~rdGi&XI^J#Z< zjEiACV}m!G36(}h%a|$FXl>?+T}Ptit{e1c>i$0+eU$vPVHXCxR%2#Vq&)ub4&2K3 z!pQNF@<+H8BKgdZtQ9G}MsJ6`;zPf+2zlY*RyfzC_OCQT_V(L?*t5RO5{-}siY3ld zTi7cgLT>qDfo7(hAv#CMBiWmEGW)O{JswnWvj~@P=5u)uYVKe7V+C0cF5m>HZ4IQUE7*Bg*toB7C{g5}?? zThK!lh>PBlvJ-t@7Sl85zx#Z)jFw@hHc%g{$}2d}&-%a`?y+!k<(G!YyRGaoa+DK! zu|YDqqXTsBJ3-$uKyD~@z$H&-6hHTq@!uU_NglE$%va8T>wpiBT`+r>k6aPwKu;uB zWbN>l3tKv%1v4Bw`FhERbM4Xc6S-beEt{`qu5KLpa*fo|+GH=L&v3`Ot)6mRcUvs| zPQS>P9@65CH8v)AAj;N5w#?gu%hQ;J)Wt(iW%lli&*UTCaF+#RcHus`g?;1P<&t_k zacz7>#tkk);r>UQ`}{C=61Xb^TzFN?(#YH&aK$X@2u`FuPvu<0Cj8b_f>L& zvIQEAFU|;+{L|Hv8E}4Bn4prk>utuYXT1W@hHI4k`eP@3o~y3&z9wGMJZCRvdO5<@%U$lG2f&OD%v)UH zChJgx(yWkY^(z-S=r;8+tX&%3b(TGwlTZ4}88394y5zK*`w*56t7UTKMoeW_V+G%h&gDT?Htj`Xq!CiW{;iK$hmE9DGPQwpr3~m zOov!VC+bmVwBSs(-6omX+Y!3)&fLQr<%^+?xITcrOp}dr9yI~4CHu!?8)Q@JU1I0D zqL$AF8AT0KzbCHvGH-+QyvVFb<{k}iw?S6^vBURT z3u)Ip(dETjdHmi^93~GV#CNS+|8NIhzfq%MzqL~DxfL}8oGBb%Ba7Z|#|C=D=Ph3& zTm9aKLw???>K;_D*I(l(=`gC7Rf zQp+oMHX)wA63xE{O1XIh&-JRjul0`?%9nHP@XOK>j#KB#SI3zj^vDt4o6VN#Sq`vR zMy#WoiF`;+jq!CS=4Z{4In=3SFK~v#I1_nyF}=RXY5acFM0S|(h*yiq$zMHNZXL~h zs9P?0N*phY`l@wiuEAyXZ6N$!vq!@?OzSoP-*$_Rf};mziNwu14`+6KVg& zia5U)l9n%%iQ}x$?vNKkrfek3avRz;s=Ci#zS|>JCR0H`(l*1=J0y?(_fd z=ft}sb!SGlf5J4d24Vi$1;o49=rPxoBBFddKlQF6*;B#Ee)mjY&$fmufp$QL#eUe zi?m&wH(xW9H52H6{8)v)=M3fFQ#LS}?T+_}hO+s0Yq(dk_g`!%_t1y0ytfDH^Lvh4 zxCh_ZD;e93l@@AxlhpCVsn28NOYJTMTQM`P`gpn2np#5gPRDF8k|udO@rX6gkO52O z$?x0Aon)4?$1=J9+IC#5$sWqULYmy)ir>`G{vKs7&$wCQEOWL_4RMqjLrcW!R^{c6 z$l@mglV@IGbMU}(plvUG?8{I0uV!k?b4UPYittZlpeJ=ZrZ@pxZr!4~V$fGUnCA(g*!L26lXg|G|RJFB% z0sSV@kM@-B*HGun+OkXUo^oZu9z3K+(+<@DnK5J!c6fQ9uGa{u`+FB6r+QY|=e;*h zm)_Ak@cXJ7O<%8)cTaDFL%MgB^SrXr4mqWA3o3Q0<_{VheHC|h+M{qH?=zbZVwZ5h z9Ut!9`X5B|366Mh!x3*6e-am5IoF~-abm|mDUMjtj^*~DotB3WXaN8E_ z-Kg2*jKp?CI~l*g20p#r;nztk_e@@?t<15s-r?Wx^HrbBEy}VEV@8AE&%XNOeTWq18IK3xxx6f=9rbfi=c%Ka# zxm`?-;l6fpg#HI>@tFI1EBA4bsf$Rf$L!fB+}{;m;_5&rEN$b2pLW4w6#JW%GsqeH z9xHxOGxW^G39a^|3v+KL%q(N?GqO-j@nik+k$TLqa#7Ek&xC<99>yFJNprdWOP$eo z-3d`{;DlgbYTrJb5j*%?%#qY;jlUq;@!lx=MxA%cYo1-tE(rY|)P+;ixvAp?@p*$Ceo$MY zBwiEaI`aO_rk>|N`+UdlZ^EG0UR>a3_bZ}<9GY(pORoRz3wm;>yEWSMa7St80GUIN zVL`3SRj;{n_I@j@SXEUAG=IevZQH;-n9F`+?xSPcTWf4k_R0b8&L7u)f-U4T2RvVO zMcZ9%i`;7t7_{`YcBu`sunPFQj;S@{gGnLw zSl4!nsQ%R&J$}-^)YM#*23o^>k{ui}cL>AL*4XN@7sz%IapUM6`_dK%!@Y!GwlxYv zY_Y9&pqS9y2G7UYLhnV0DBNO$#q@3(W)dNMj@zJRhz$-cjuM?Z+M*w9&~;F>NTLVl z!DrUE)-YO(IBd(=jy1ycqQr?-d+~iZdARBbp|f!>-rw7Utt)~=D)sS?xyM3s14S-h zx8mnCt4^Nie!(7_>N}&f-C^O=-X2p}QynmCBS#OQ9()KjTz{)ezXP`Do#KX~y9QD? z?SbLcs{8!E``OAR!?4XW?o%E1=XGuw*3Bd))14UUtp|q6PbZj<;n}+6u;H`n&Pba{ zE$1W`!;)LP4;PXzo#ilgVi+^C=2CAMGqLg`&j%uEc)#yY<-+HV7}}O~Ufw)yB=1eL zV-DyZ7ozoKz1?^Wd&{*_`{uL*wbJ&uT<~1`i#?IobNVwJs4a#*w8x79^oUrYE9?^O ziBa*{uHIRkQ`^InyyJFuJw>F(9wtLMZ z5AyDx$5B7r-dU)4clTl4_1}GdI8G}Z8atpPah^8I+DJ9me#en#zj)hQg$wf>ao}5ZW$QB5Q2ZGQXR9f@C#%pl-x0ZWzaylk3Lmc0 zE8y5u42^SR?gO9aXJ=s4%MHExoWE$B4ck;cmv0@>?IQF2x)aa4ze^MSThAG% z$J^uD%Bfnj57aal*`Y(%HQFn$=p``D4*CzRwB?*3H+r!bPxkE58dDz@l*v5T?>n^Z zJ2<04&FqrJo3xvWjWysMx%W?;HgS|QhBmN6j&+Q-$jBMdwVCBzQK;QhK^?iD1B88n z_9rp;w!segX*EOKAt%n{uM_e{x{0gpobdeu?-%lg{`ahPBH!Dq@}amzpOW*rZdJ}_ zC!a~m+CgfBvp&9qaVWx7D9M2Uz zi*KAZR=(#m*V%_Wgbm{qXFX5+!#=&tVyL2L<$+Vjs3+>#L+N&$-hfA#w>nE#dB8re zHu3F@d)1UoM-}XyoG|On4a}qt_%)vgzjXz;PhDotPp&yJwI9@LMrX2za$ke*2bs6X z&*jvU;W+I}&JXL7!2C9tu*DT$Z#W?ALmfOfcSZA12WYLUq3JTtNq6z{I$8r!{Ca!( zX{>W@hzaXlIR~bf;M}c-s}{MUQ-A|LZgMhwy_6ZY#At@E4KHt@a>b4Xj__L0q5Ogy zbCl?_V74So8~ok{t>c}Lu>GSpXqgKlJ5@c;?S=*m>&5ipFs-Vi*RI&BjJ@xR5xo0G zYaEp!V4_8?e^jYYt45Gi*NgL{6Yq}}3|K|&Iop+vvtCDxY2MhbM zPM+ed{A%d~Q|?8RBYTzo#@-l~?9Bdfo3ei=x%s@yGW}L6BgxsXf0%nfcee7Hxb)&o z)*;WwD)-tlXNUdH(5e3@Lv~OLNPYdi*w#w$Gk1h??@pOtSMl0SJT--S^`2jFx0^cx z);Xc}$wx4JL2WUyuhY6W(fJ^GI{Hp{6L=LasVeC3^}V=jm>;Tw&oC$Sym1T1sP$gX zwU`}Qj8W8M4x8fyJ{e7^U@S9uW>gjW`vch?J0{BHyy z`mrOHx&$e!N`jESg0q!Z!OCaqh`;iChTjcU>Q&IombF2HpJB@4Kh%1kWtQiSFy&~c z0PGyBM4xkaJawnT9%?xx`g>!SsZ>%HL2AT=?S*s}A*)@4g;b+K|0f);sjpcwjZTM@IVZ zvEI)E{rXc|6?EBfG<9RU_;>Ai^00CxKQGS#Ro7V>g(%50!jR9i!n$sll42c(kGib8 zVj`5Mc9NbCfimjj2(t2rd|} z#F9^bmRenV%>*SgRgEI@jfXrLtY|aT*hue)c{7G6V~D>xbH4^g=qqj!YQ$x8@1D|E zCIzVxSxkH^qNQRMN}a_y-b48x0A8TrrnV+Sm}be|M>j#g zi(_d@vrb_cyVMQuPNpl>PKDsk9XHOA)0EK`!8kZpg`LaxDQ9%(&Av^AMcZSP7TQ4k zwNgQEbFk9HBLJEyDnxJcQWkCZ=VwSihoer4tt;~#qIqZk+@b6|>WhCCx=>YBi;~Tp=>Aic91;4s9u(e^#N}P>N{LMn<+ys zd*d?i{+NB{%E1h8^j^%fqsT;ANiIpPiR=?=&Q`4Ayy38fyl4IK%7s{Zj+v;CGG)B- ziQ2>1rSv%2*o3u{D@fAf6t8?4ZW2Hm*e5gGr7dUTj_Bno--Ww zb-}($s#QFijB`e}djZPaQ*mh8+=U(YBi6m5D0e5rA(Y?P*~(hJAQ9n=S1Pgc69$N`{_%Z`@uN-)pF z4%eyED-KiALp1nIkBePP{FJkEf-q;DJ8B+PDT~LFhuGX58P%PX7;^KQv0qMg*{du| z_eaT76~brPDDRv5W3vwZG45L{E&TjY!^9nfR@*2o+Y+-+VW!$*TV+YEFXlG)!0mhs zC4#)jqnF+Bxcz2jOrkHEG~kT*vYBF>?@OORchst8uJj5g@2oa`s^6F>8FBP!{6a1e z*MAh}13PQd583w>H8TOY=i!A$T~gph?L`*3djDPLfsVVCJ8{YII!#Px*DmFde=-L0 zuBljLtyJ%jj27O`xM1R-SS{a&XwJK5e05Qb)+V9dM)tYpo{G-UMD#LsLwS&&VstSc zx-(SxQZGd5F)5p-vV^yDRt=d>=wIc)Ry!#AwCn>wsWEqor_ydu z6iRoiF=@ZE@-Qg^jpnPdBga}EPv~#otgNOM#FXEse=`du zoqEiF-;qO5*Fw2up+VQKp(nN=Y?+W zW{N>sAf`9-LjG_wC3+{ZdFn%3U7f9TC5LxaUoR+!XDdrM4^+?b!nen_FqfLnMT31Y z`jihA%@0O!q92R~Ez%av3WJ&+G4y888U=))*D+0%{aiMpi4r&?7k7WNr?^>9dDS%+ z$?P{DdDc~~_~sz4s|&ohG*G@|WW(La73GVYDG@GNXiDw&52Nw* zmUIlEw?L6HR$1bnii_lFysI-?(I>~|M-w#+eymV>bz^?(Pc>#gTBTg({tw>fg^2-6 z6|3-Ac-VVkxyM|kwr4a>nt4G#aHf)+8Hs~Km>t!AhEl731atkoFk{S2<#BWvJn3Wd z)r__MhEVo~UNHPTTbaHw1YY#osM&mu5)r|B`7+n)s)-W%mim;1ygNJ2Qd%w0pw@S9 zZ2U1n`5mW$F3;aZZWEN?IT{pEYu~=DzVenjw)e|@u>8BOa^!R{{-L+VfA{T+vVSXf zuhh_|IuO3caci&JZkk#?ciyFcu}wFd{Ff&5bgUGp+`$6tiNK9=KcC^p_ak+8g67J1IZGjMv7*!Hjw+4^twrw!JrUR`gaf7lotG zbZ`}C4J`W(wn=_Bs8WUMRFr*4&N=)&b11|^jaDe3hvv| z5VT0v;Ey$5)4xo4PEGxz8e$MN0xw!uUFVyRZdX_~FNITI*5U6GD_>nH;To`Jn|Qx6 zN52H~OI#2#=W}Jxb_Y<AJcm;dGX%AKu>kaE!-;ntTcMz$(|C%wqq z&zNNRwk#L*$?59fwl2yWX5$0-MNgBBP`z^oKRa*O=x&6@AQgA%@40rH2Rx?kgYI>2 z4DB6{FNp~#xa5sSNfl_!bAB}aTgFwt35Ovu*munvY3c9r#32fQ$shP!{}Y#PBBVMIrb3Y%{ikw>6D?0`5^kBXFbhM%4 z=zYju?1Otv8sm3-BC^Rlde&tb;wL8Hsfu3PtZ!~Nj>p*(KG@aS4PRfzB2V!}Dt$fc z+=;>UC-l=;W{EnlqA|484*@qeGh-ndyQvR4vU(d#21KFzN%CQwVhj&n4M!2BS5@7&)>qny{XBbWe%7Fm=qAGSz0i43 zFdX}i5EI*bAcFPlf9s7sbw`SO38naVGV5fUnWFuw5{!r^#(UOOIQ=QcC3^gs7_Ao; z4*M~YbLy>sH;Wr@$SHlU!V*tQVLY_}pBM9fueL#)56r_{!QO1;GVxBEgMtS1#PFFS zJP&2TrlU9FKlc+$qL|_HfEjW_nu)Jl(_p&LhuKvRwQ_R`BFHUY6%(&DPTq&X<;;e6 zovQuZHVKi}$?s}&v~t101O)u@VK&71is3%-s37<5%aM*1Q`f{{73-~;leHB)r^Vv= zFh9&*)2uRPdJM+=^utfx=9Q1uM#Je9vp1&Ht{m$T1$|~x{&(O0s`S)m(%0e0kw9E~ zcT+q2WDruX1|g}zPwn5-02Hj&;On&-!ss7=^t;K|6}lpBqz_ys2cuK8uK2i;USuV~ zC`z6sN;o%bWL0&YADwU)-#V0`>r~W0g-9D)P^}(A<4aF?m zB&4!ej}5+|UE41adzSkmBqT%o&%g258tcnU%24f0YBu%%`eMILsPd5;5#W= zYhw_N>eSTBg)!Ra`H?vG&L94>qP2VH&`071`HgQQwK0FfkWG!-Ee-c=ZYX^21ywn3 z&voe~&a)47>&iRNW2ksqOO1dW4W92a5;guI-=TgmHdam(`u1+Pxi%QB_02^16lZ+S zth&xC5(>nqh%$PQaQ2rW#Jz6JuB6vb?~bQLuTvweruF!f!9N5%vLSeXOOJ;ur+mar6}1*-|7%1>kK9>acpW6uxJucl!{8 z(|2{ntfutgzoMzKZ$}K>EauizL3Sp0I@C(6B{ndVXL991Cn1&-SG!(yozFJDFY;QK zQ%gz?Qir#~OjU~W>CV`d_e1=1@&In=xMB-utdHOBN84TGC^o1gO<9vPBd>jhUwt{| zc|N@#Jog_X=-@SZYUe9%f$3d)?KbO(!+v-=h8pk2X5zM)4}92r3~Oj64!8Hh%T52Q$;`yapUkvr6@;G+%tU{3cl(~A zuY|6du&CvRlkOV0b~Y2H)L8YJN}Yg#nYg;f38F~|%8N8&O(4(RhE?^j!&G(T%8+u@ zoK4MOZ5_G$Whrw=ol(zNSMF<8f?CvQC6?*Qrfrxt$8{dy*ip8tQG_#Bi4_KRmDv~b zk;b|3&+_gv#y6Mza8KOcVj%mCrv{TgW}61}ke?f6qKgZ?2<~-|-N&V){!(vv>o<{$ zAEsgfu~enOUol}{3P$AmFo*1+xVAeP8C+*E;iS+xnuN3jdN@8W5$o0Qu&z!n{@5&W zbrL<4s0r$qn<#2`iNp`BAO1dy;EqlXCt`cpLy_s6i?!J<4g5MjE^`ts3; zSF8;>MFwDcO^x^`$p`iN210c^NK9bOzU^cnhCU7wM#DXEa(fWE^F2Q~1AnWp!IFL& zv1uf|i0)~SYpM~AOvx>$=3KbIOZZ_;TQB!JcC~fX$U>N@fyB9;`eS>sd9pa7e@Ac)0=cyRO zzQA&&t{i_N1>?h6>kg|eU5b)1k~Qt0haW_ncKhfFPk;6))MeA>q&ablx}3dEFN$Hl zfgg10o)R}gBGLVuA8NKgEb^nmU}oWuE-SU-(sBBfJoiWC>T+?iZ4g{H2f#b0RP+z< z$Gl$w=zF6?4CBv92n<9$-x5*q$O{pJgK$(+B084Q=jLt@dY>#2$Ftlqms;<*Hl;$Z z#0`bR!2)kGJSU^UJb#O&1FJE{`q{{s_Q&-#SrNjT7h5li5+E) zk@t(s(2-scrr{H0T1p96(4&8#u^hLv7>nq$k(4`A_U&1OJLl+wbbXHOc03=dmc&xB z=1bibxi~xC6ZM$uvArJ8=hPL>~2VvVh3dei+*_Urk}JMcCA}0GbR;bFLnFR^ftoij`++smvO^}iQtvZFvsjjgrepqZFZlL1mU)}gFuc+m z35FwN=Z&fGvgCgL)>GcxmVz5Cs6%PlK~Da(4{h?8F|(zmG^Ib@xG{eCdZvk#>9IIY zkAe%y4dpaujV)$IT~ty%`7$;f%OClpz_X5Abv}f6Gy6FG+HyyC4YkjKh@MtUMn(r9 zJ}(emZq<}8Sp(i&$QedaP1&8A@>2GCb&k}OH4dvW=YR(BUu#N3dM&tZ52l}5EtykF z-&bN=e|@N(Cugef4{B!a)sh<$GPL*T~_k^lu}f7afRDlYkB!`@&BvpyyIg`yEm@wDq$CkgkVKkC0I40UV;?_ zS-lf2q_-)VOcLp3CQTxhR3TjmAtabfeTlX@t9MZs8};RP_UHX${q>CJGc)qJpL_26 zKIdH5_u!~sC??(T<9U~IysHkwI{N@#cvXgDk~3VfFM#zUB~K#k;EqT9S#7%oB|UXm zQ(w&q?!}n-lOD+h4qX1F5Fa1v@pG$r)Lt(@q3EUtjF`Y(xAJjR_M`)ohqB9a@gFr6 zR*Y$1nkhG7Lmgps9KCkP@R;J>w35bK;TT>3}o`$aC z1M1nW9Y4)UM!&slrFWGHjZ4-+xilW%4KrcAZsJX8l7R8Ij9Df=&Ak-~n0>;S&!w-2 zo8+NFYmDhRK`+eLL^LrsVROkNhTcnrX`l&rNRDA+zVNATn@}V9?<9|8G-}t1K|4ax zs&g{B<}~Nf^bmM@e>=|SCuzB?^M2t;1Y(wD5F3A}Lid9~sI3+aWQK5)ei08$VgysV zR^Uj0?1ND{cF!osVj1TxYxER=K5T_SSKM6B@T#qFHjPAHNd$jhzXjV(MTdMmnB%V$ z<8^&K&YEj@)u#xqlHa&tx0)@N7GmZGS)a@1aFRm-%!Dg#Z9S0ew()zi7orG z+wEk$5^l`*ZTm2Puz2ES4)4?T=9%Jn>{y-vE8E@-mGj7!w(Br;dT$1O5MS5%b?6h^ zo5?5i=$4R(#^>dAMI;QflQ3v#ANp5GuD4^d#NBEck#x%cfjYxYHQMgD$N+sV0PbquFD?8UXCLGXCGmN~V15MUmHGQV|f1Mi^ZhR*1TYyjb!m1uk`qhyZdEGo<9yVHjQP}@bzesD)ZTG3|}~=V4-+6 z8<$$qPuA4_4H8gcW5onvV;b#CKx{uNwyG9pm3AGRCtGp7f)H?lq?GU`_Y3Z%}PP@cy4t9wy-LRj|gGnhTS5*MYOn6o^KzU38I7!is_s%(xn z-HGpIeYX86n?@PiG5dqCzOQBQ==^PP_(9mJ+BEKUD#gksIvjeRz(IeO2y;S*$)EKs zNGnGCQ8`P82D4X85q^u482m>yPp1{4M11T4o{lWYEx?4fF|hw(IrV1waCs*F?qiFY z)nF5*7D=zllMDDoYCvK3!i+AP$8w1QmzxQbXXISEA6bu@Yise=W)3Ufq~J_yJiH9E z+0i-)o98AVD0DX8S0>8`Z+F?!9+5T^fitE?1c2t>!R7@>r3sNhl4O z!zH4RUOqe-bsNm(=c)+2Ya;zYBj++l&Rhqtr69L_E?*xFM~dX~TECsk8FF7C_y0Z4 zs(Cp)yUT!N`#_BCn8!0y_TivtKWY{fvTIo-)Z)>4YF*5~zTb`4QK4vYyqIlQ@5CfI zZ#>B^;>cIqaq7MFrVPku28A1AByso1jdZOkMeg@HEbFv^RW4gF?zs;BH3@XKEWvL_ z^e~CiGvn7{n9F>=UmMKap+%S=e$3O)e7VQ6Q2O@9z&1$5_S^EYLHaCizTnBq_)Rdq z5({@*civo@13RhX-iULh$AnB=wUb!R-i7squ@=)c9=l7OX(AqL^T+X+Gu@duorGbf z!j&5C%+q7mp__Ugx-W3%=8J1F%qkJtx#C%fkpD;6fcu-eu>0(2_*_d8PmT)%M(UAK zl8h!lxiWo(_@@Kp`DMD&Aew6j$vxfN>%cDKBQWGp3JxBZxgoW+M<(C;2V<{p;jdOi zqJ!una<eC4y6KH+D z81rO()_fPug_nc{;U;X8u@PKRU5IVdW3a|4REVSnI4Wn1$UlNPs?%niYbw9a71NR zaz%L=ZZ?fX=A#{)*k~K-G}6KSZ86;nOR-<_{NwX;xj%RdPXD17=D-HF_mOp5YRrpr zlX%6e7>)JP$59*4+C@bu*2vyh8_N#Dh8^c3JuhQpy&RuX3Ph-UV@7&uhO`N2J!V@E|nyH?hL%4inLTD`(a>Ix;1 z>_1wEolO&wUmMO6InVBRl?eA+8WzNbBXaGxOw1isPh&^td4 zHZRuFc7yaPm%8u2=lQ?q^F6Oq?AoCa?S-@bqVYMpU(LrCiCI#7E^w=39(s#rud3}u zE|z#I8_vQucNnsZFK=eyz%JpO?ki=-B4Pd2h*!d)fVZSRd+z5@6jtTZVTvMZ-`aK1A`-R%K@(?!B<`4rXw#)NP;JNKD!$gOS3X+LINAms``R?2>{bZ)Hsj zNN3njNidb)@O*VTYh~ZNRveCk=yWz25|3_15t6q_XMM*wG;of<@Q>*Rjoe&~7~kz7poQ_`H^d z#q)V~B$i68?cd{EvGpti`eZ;mDFEXJU*Z^TI`$_ApsnT#J7h>N@f+e>xqgLJ73)#Q zBoG;j%ba>I4YgK*_!$@IHaHD&^8;~b`WZU!k$p!zEI+v=?AEDOojh= z(Y3x3|9D6$l6r~;edBiS+?k39(X9VHzl6763K#To047K0b3nH=q>8>Y8k^X6avB;O z5{>1+jkLU)3hRRb=+G#K4JV|ar@SY7ayA!jNP?Zz>kr+?V)pBGi2f*A*1{}ylsIpU zXfK~MT`~uex(?4JK4vCjv$^qDVB>>euVQX|EA^t~8azqL{H{w zt!#c228_0`8m&{aI4DKu~Jqtj5bryLokM1e)Y3q4O`}g4jr` zGFBinu!#B)9fpK>BGrBqXN2lu_SzloBD0tg9)+>aZm1Q;!j@;zxU}CDbMn%dBV&~% zb@;y4soc{(7Rwbb_`yAev(jSl=7KZQUM6$;r)c!+>n!^AWLD0S_|D%62Xd2{QW}Mc zM;)<$Z!&lN5QY9mj;MZ}EM8PS`q?;0pW+mLxi7I)#A@_RP2ngz@iZS=g?1lPSa?r- zZ(r=;vN)9%;(_xYZjVA$66b%4#HKawu-=%&@M7^P+Pb6gega3uW!b=D1I-4 zdnwU%kw50OIlw~}N>~;7;_jaZIe(}MNgt)RT;M_0w@{Du&dv0~y;VhA92*RWKuuz|=o8 zSR~KF!^;EPDue}eU34@pJ@B$9k*5MB<}GnY_lkJ-xfz9r1KjcFjyPWZ5{=CDZpcu^ za^?IOJg?^_dbJpCk+FTCaD@kA_{c9BXRf>8ef=2by^g}jQ7%~YcQi9sMWG_u83~Pr z$#X*wK5@bX%NQmulsv|8C(Q7P;Va?&pN?>Z#jzOPanr%_yaRT0jAf;)$L)T0fP*5I zv73e4@3z|^G4Gq-dLk6q_w9OH#e)G z7`T~l#mBuyr4$c!HXBOZvuTY2jUKFLmZxZ1>4i~cNxUUFzgdI5a9!g1r}p7UtoB68 zV<<=bqQioIPFQ6h%F95Ef-$XNzUI(G~C|YbzG023Qs&gs^U;#%!Kvx#PU2P4KkiR z_IRM;p@JjEMWJ?t2QK<4`1+k5(YxHSYrcZsq93s|cgG?(1>4WnV@0YPhHO#rlGNlE z*LOoZBPEv{&|#*dE6RM7%wMB}$7vVb`Af->V|92r&;|Wgs<=eB;Gn+zSbsatY3IXP@1_a{gFj4_I^G(sLhWilJf5Iu!fqAD zH}i${B^^69^~S?0AM98aNo{K%ObwMad0;rl?C`}_4{vny3ZXm29~Y@c_>w?2jtE5E zGr|#A?#l#A$<2;Y!5J#XTnoX1%Sv=8ai{Gv(Zhx-G3uog@9qu9|Trt3IDSgMt zXZ5bKH`xiBPT0|Lga)xs>mohM{X7RnKx4RfK#+-WSd0ggZ(c8#jfQt>x_MuS8zxWDeV?6aAzTf7IHr<5rpfxeDp^Ys0i+ z@znHFV3ofOJ;kr#TJD8c!8RNqUYlvMc5TYD;ZmJ2IJbJ@@0&LC3y`tx>50o-CNoT< z!_`a=Sc})#SfxW~YvFekPG*|CHjQ$}f}xXn%wAqsyW`^g$!xG%@;9Nv_4sJRdL}v; z8{EGc=g*UE*!GSZcJ82K4{B1dV zk`}tRK3KMR3NMxV!Lh#&R3(#`)i(fb)@oo=V9mc10@10B1`l-OIO0tZ9#wivj}0u+=Bfjrehr?GP5k`VWGo~Kn1!Tv*0wTvn70yz5Bfdi(RB{<>Lhl^C9dK zCHaHDJrOc%2s=w`a?;%sh8Gsh>?F_Vh9^FJKZM84b@)Eh6BZ9F8TdRBz8Rk1jB|9| zUTiqu8*e&GpVUA4Q2ShsszLrpj{TKoIyqNN^h5t<{dncB29~bA2rT`TEstx_r$mdg zU47}((jO0-YB6J0A9kH6Uhr5SblPIhSFwTc9OQ$)?)Id2b&z=8HLz{lgHxZ2Z}^x7 z4Lp8f=}Ymx6=-m$VK*k9mRe1;2BV&Lp`%_rbgmkF?%IVf#c!$}ufhEdow;IjI5xG^ z;FLvYZumj^T%Ga8PZ!O2YDEP4ukpsbATvJS5`k1RZ}he?N1TpBZ;LN5V>ew^A`?w(tw%mZ{Kqz8TH#M56yg;S^}hcu$_i00$*ZQ_UD6Jk)wM z3N$P;qhF%*402N7;~X<;{bf9V62^zU8Dr$U+WJog?j7#Vy%Hndmb3T2L;GA=IkK;R=ba~=Y43-c9y>IvGc`|-YrTwfNMe1>1}F%TBMw#f{CmEkyFHw&GK5@J}5l2w}an_+j*qbVvg@xIrb_Q6<9Q?AGhL$4wqJhW`e zixOKqX?&3Mw-LRDhNH!B9~kX1Vu?pMn!nbde}WO?awVsdtHHYfBlZ@}{?XqxIOk`? zqje*2^qn{Agc{MRujtUzy-`ozKX`rw7LM}9^jstM6W!~8>+;(vH{z}`@e|AM=st}& z@|LV)CTh6q+c0>vXwti?@G`Ltt0gyc{<-jjayzo6@Z83aP<}Jco{i5MPFZLqm%j${ z4qY+Szv_)<;zb|U_NKwyUxQA@{#Yhjquf(IxF6<+vZx1!%yrTqyoDc}tsfi4X8Ysi z9@z_>o*2|Cq{p%Ni0?gqYIq=?uod>c__+O<;qGeDGc1(P{Q1oATD(&u7Wral>NCUH zH`2dvsV}tspBeO#A);Xuj?C$&hWNUnh*;)}#Q{$ZJM2PHcdjo&hdwnt5wFR$F}^r? z?}@?rUMQM&_C<2Q6GNkx($lF{_KrSJ40WX*9V&j~cb{tv;SzH#jnTs7X^kPrFAUi; zwdnPz#xNi~3@44XSpKZWaHKK}eJ}fqbB5;19>_J8Ua2VuS$oPK=Z^JT6$=x+q{coKAnblvt z^wXEBXRco9xzv5-%1&d)_N()@eVsbZyVt4nM}x1|yY;_b7dHEP-EQ*rTDR`kYd!g< zf8PI4Ui@>N-r?)DpYhl0&)%adG Dvh#e+ literal 0 HcmV?d00001 diff --git a/rtengine/camconst.json b/rtengine/camconst.json index ebe195c60..7a143e850 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1586,6 +1586,12 @@ Camera constants: "raw_crop": [ 0, 5, 7752, 5184 ] }, + { // Quality C + "make_model": "FUJIFILM DBP for GX680", + "dcraw_matrix": [ 12741, -4916, -1420, -8510, 16791, 1715, -1767, 2302, 7771 ], // same as S2Pro as per LibRaw + "ranges": { "white": 4096, "black": 132 } + }, + { // Quality C, Leica C-Lux names can differ? "make_model" : [ "LEICA C-LUX", "LEICA CAM-DC25" ], "dcraw_matrix" : [7790, -2736, -755, -3452, 11870, 1769, -628, 1647, 4898] diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 4ab1694b8..bdd92c7da 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -2464,6 +2464,30 @@ void CLASS unpacked_load_raw() } } +// RT - from LibRaw +void CLASS unpacked_load_raw_FujiDBP() +/* +for Fuji DBP for GX680, aka DX-2000 + DBP_tile_width = 688; + DBP_tile_height = 3856; + DBP_n_tiles = 8; +*/ +{ + int scan_line, tile_n; + int nTiles = 8; + tile_width = raw_width / nTiles; + ushort *tile; + tile = (ushort *) calloc(raw_height, tile_width * 2); + for (tile_n = 0; tile_n < nTiles; tile_n++) { + read_shorts(tile, tile_width * raw_height); + for (scan_line = 0; scan_line < raw_height; scan_line++) { + memcpy(&raw_image[scan_line * raw_width + tile_n * tile_width], + &tile[scan_line * tile_width], tile_width * 2); + } + } + free(tile); + fseek(ifp, -2, SEEK_CUR); // avoid EOF error +} // RT void CLASS sony_arq_load_raw() @@ -10067,6 +10091,9 @@ canon_a5: } else if (!strcmp(model, "X-Pro3") || !strcmp(model, "X-T3") || !strcmp(model, "X-T30") || !strcmp(model, "X-T4") || !strcmp(model, "X100V") || !strcmp(model, "X-S10")) { width = raw_width = 6384; height = raw_height = 4182; + } else if (!strcmp(model, "DBP for GX680")) { // Special case for #4204 + width = raw_width = 5504; + height = raw_height = 3856; } top_margin = (raw_height - height) >> 2 << 1; left_margin = (raw_width - width ) >> 2 << 1; @@ -10074,6 +10101,16 @@ canon_a5: if (width == 4032 || width == 4952 || width == 6032 || width == 8280) left_margin = 0; if (width == 3328 && (width -= 66)) left_margin = 34; if (width == 4936) left_margin = 4; + if (width == 5504) { // #4204, taken from LibRaw + left_margin = 32; + top_margin = 8; + width = raw_width - 2*left_margin; + height = raw_height - 2*top_margin; + load_raw = &CLASS unpacked_load_raw_FujiDBP; + filters = 0x16161616; + load_flags = 0; + flip = 6; + } if (!strcmp(model,"HS50EXR") || !strcmp(model,"F900EXR")) { width += 2; diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index 849012cb7..f78bd8aa6 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -432,6 +432,7 @@ void parse_hasselblad_gain(); void hasselblad_load_raw(); void leaf_hdr_load_raw(); void unpacked_load_raw(); +void unpacked_load_raw_FujiDBP(); void sinar_4shot_load_raw(); void imacon_full_load_raw(); void packed_load_raw(); From 2101b846c386035f8d1ca5f2d68fe9fc3227d43d Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Mon, 2 Jan 2023 21:27:12 +0100 Subject: [PATCH 091/134] Implement file sorting in thumbnail view (#6449) * Use mtime as fallback timestamp for files without EXIF data As suggested in #6449, with date-based sorting it can be useful to have at least *some* sort of time-relevant information for EXIF-less files, to prevent them from falling back to getting sorted alphabetically all the time. This commit simply defaults the file timestamp to the file's mtime as returned by g_stat. For annoying reasons, it doesn't suffice to merely forward the timestamp to the FileData structs - we also need to keep track of it inside FilesData to cover the case of a file with 0 frames in it. * Add DateTime to Thumbnail Putting it here facilitate easier sorting without having to re-construct the DateTime on every comparison. To simplify things moving forwards, use the Glib::DateTime struct right away. This struct also contains timezone information, but we don't currently care about timezone - so just use the local timezone as the best approximation. (Nothing currently depends on getting the timezone right, anyway) In addition to the above, this commit also changes the logic to allow generating datetime strings even for files with missing EXIF (which makes sense as a result of the previous commit allowing the use of mtime instead). * Implement file sorting in thumbnail view For simplicity, I decided to only implement the attributes that I could verily easily reach from the existing metadata exported by Thumbnail. Ideally, I would also like to be able to sort by "last modified" but I'm not sure of the best way to reach this from this place in the code. It's worth pointing out that, with the current implementation, the list will not dynamically re-sort itself until you re-select the sorting method - even if you make changes to the files that would otherwise affect the sorting (e.g. changing the rank while sorting by rank). One might even call this a feature, not a bug, since it prevents thumbnails from moving around while you're trying to re-label them. You can always re-select "sort by ..." from the context menu to force a re-sort. Fixes #3317 Co-authored-by: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> --- rtdata/languages/default | 8 +++ rtengine/imagedata.cc | 39 +++++++++++---- rtengine/imagedata.h | 4 +- rtgui/batchqueueentry.cc | 2 +- rtgui/filebrowser.cc | 89 +++++++++++++++++++++++++-------- rtgui/filebrowser.h | 5 ++ rtgui/filebrowserentry.cc | 4 +- rtgui/options.cc | 17 +++++++ rtgui/options.h | 11 +++++ rtgui/thumbbrowserbase.cc | 44 ++++++++++++++++- rtgui/thumbbrowserbase.h | 3 +- rtgui/thumbbrowserentrybase.cc | 5 +- rtgui/thumbbrowserentrybase.h | 32 ++++++++++-- rtgui/thumbnail.cc | 90 ++++++++++++++++++++-------------- rtgui/thumbnail.h | 3 ++ 15 files changed, 275 insertions(+), 81 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index e5e053655..a33b2a9cd 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -166,6 +166,7 @@ FILEBROWSER_POPUPREMOVE;Delete permanently FILEBROWSER_POPUPREMOVEINCLPROC;Delete permanently, including queue-processed version FILEBROWSER_POPUPRENAME;Rename FILEBROWSER_POPUPSELECTALL;Select all +FILEBROWSER_POPUPSORTBY;Sort Files FILEBROWSER_POPUPTRASH;Move to trash FILEBROWSER_POPUPUNRANK;Unrank FILEBROWSER_POPUPUNTRASH;Remove from trash @@ -2060,6 +2061,13 @@ SAVEDLG_WARNFILENAME;File will be named SHCSELECTOR_TOOLTIP;Click right mouse button to reset the position of those 3 sliders. SOFTPROOF_GAMUTCHECK_TOOLTIP;Highlight pixels with out-of-gamut colors with respect to:\n- the printer profile, if one is set and soft-proofing is enabled,\n- the output profile, if a printer profile is not set and soft-proofing is enabled,\n- the monitor profile, if soft-proofing is disabled. SOFTPROOF_TOOLTIP;Soft-proofing simulates the appearance of the image:\n- when printed, if a printer profile is set in Preferences > Color Management,\n- when viewed on a display that uses the current output profile, if a printer profile is not set. +SORT_ASCENDING;Ascending +SORT_BY_NAME;By Name +SORT_BY_DATE;By Date +SORT_BY_EXIF;By EXIF +SORT_BY_RANK;By Rank +SORT_BY_LABEL;By Color Label +SORT_DESCENDING;Descending TC_PRIM_BLUX;Bx TC_PRIM_BLUY;By TC_PRIM_GREX;Gx diff --git a/rtengine/imagedata.cc b/rtengine/imagedata.cc index 3c10e7dc0..fb2fcaf3a 100644 --- a/rtengine/imagedata.cc +++ b/rtengine/imagedata.cc @@ -19,6 +19,7 @@ #include #include +#include #include @@ -57,7 +58,8 @@ template T getFromFrame( const std::vector>& frames, std::size_t frame, - const std::function& function + const std::function& function, + T defval = {} ) { if (frame < frames.size()) { @@ -66,7 +68,7 @@ T getFromFrame( if (!frames.empty()) { return function(*frames[0]); } - return {}; + return defval; } const std::string& validateUft8(const std::string& str, const std::string& on_error = "???") @@ -85,11 +87,21 @@ FramesMetaData* FramesMetaData::fromFile(const Glib::ustring& fname, std::unique return new FramesData(fname, std::move(rml), firstFrameOnly); } -FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir) : +static struct tm timeFromTS(const time_t ts) +{ +#if !defined(WIN32) + struct tm tm; + return *gmtime_r(&ts, &tm); +#else + return *gmtime(&ts); +#endif +} + +FrameData::FrameData(rtexif::TagDirectory* frameRootDir_, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir, time_t ts) : frameRootDir(frameRootDir_), iptc(nullptr), - time{}, - timeStamp{}, + time(timeFromTS(ts)), + timeStamp(ts), iso_speed(0), aperture(0.), focal_len(0.), @@ -1068,7 +1080,8 @@ tm FramesData::getDateTime(unsigned int frame) const [](const FrameData& frame_data) { return frame_data.getDateTime(); - } + }, + modTime ); } @@ -1080,7 +1093,8 @@ time_t FramesData::getDateTimeAsTS(unsigned int frame) const [](const FrameData& frame_data) { return frame_data.getDateTimeAsTS(); - } + }, + modTimeStamp ); } @@ -1366,6 +1380,11 @@ failure: FramesData::FramesData(const Glib::ustring& fname, std::unique_ptr rml, bool firstFrameOnly) : iptc(nullptr), dcrawFrameCount(0) { + GStatBuf statbuf = {}; + g_stat(fname.c_str(), &statbuf); + modTimeStamp = statbuf.st_mtime; + modTime = timeFromTS(modTimeStamp); + if (rml && (rml->exifBase >= 0 || rml->ciffBase >= 0)) { FILE* f = g_fopen(fname.c_str(), "rb"); @@ -1384,7 +1403,7 @@ FramesData::FramesData(const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0), modTimeStamp))); } for (auto currRoot : roots) { @@ -1410,7 +1429,7 @@ FramesData::FramesData(const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0), modTimeStamp))); } rewind(exifManager.f); // Not sure this is necessary @@ -1430,7 +1449,7 @@ FramesData::FramesData(const Glib::ustring& fname, std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0)))); + frames.push_back(std::unique_ptr(new FrameData(currFrame, currFrame->getRoot(), roots.at(0), modTimeStamp))); } for (auto currRoot : roots) { diff --git a/rtengine/imagedata.h b/rtengine/imagedata.h index 4bf9bdf5b..752fafab3 100644 --- a/rtengine/imagedata.h +++ b/rtengine/imagedata.h @@ -72,7 +72,7 @@ protected: public: - FrameData (rtexif::TagDirectory* frameRootDir, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir); + FrameData (rtexif::TagDirectory* frameRootDir, rtexif::TagDirectory* rootDir, rtexif::TagDirectory* firstRootDir, time_t ts = 0); virtual ~FrameData (); bool getPixelShift () const; @@ -109,6 +109,8 @@ private: std::vector roots; IptcData* iptc; unsigned int dcrawFrameCount; + struct tm modTime; + time_t modTimeStamp; public: explicit FramesData (const Glib::ustring& fname, std::unique_ptr rml = nullptr, bool firstFrameOnly = false); diff --git a/rtgui/batchqueueentry.cc b/rtgui/batchqueueentry.cc index 31a6f40c7..9fe4dd605 100644 --- a/rtgui/batchqueueentry.cc +++ b/rtgui/batchqueueentry.cc @@ -34,7 +34,7 @@ bool BatchQueueEntry::iconsLoaded(false); Glib::RefPtr BatchQueueEntry::savedAsIcon; BatchQueueEntry::BatchQueueEntry (rtengine::ProcessingJob* pjob, const rtengine::procparams::ProcParams& pparams, Glib::ustring fname, int prevw, int prevh, Thumbnail* thm, bool overwrite) : - ThumbBrowserEntryBase(fname), + ThumbBrowserEntryBase(fname, thm), opreview(nullptr), origpw(prevw), origph(prevh), diff --git a/rtgui/filebrowser.cc b/rtgui/filebrowser.cc index 66c84d86e..ac4a27dec 100644 --- a/rtgui/filebrowser.cc +++ b/rtgui/filebrowser.cc @@ -167,6 +167,41 @@ FileBrowser::FileBrowser () : pmenu->attach (*Gtk::manage(selall = new Gtk::MenuItem (M("FILEBROWSER_POPUPSELECTALL"))), 0, 1, p, p + 1); p++; + /*********************** + * sort + ***********************/ + const std::array cnameSortOrders = { + M("SORT_ASCENDING"), + M("SORT_DESCENDING"), + }; + + const std::array cnameSortMethods = { + M("SORT_BY_NAME"), + M("SORT_BY_DATE"), + M("SORT_BY_EXIF"), + M("SORT_BY_RANK"), + M("SORT_BY_LABEL"), + }; + + pmenu->attach (*Gtk::manage(menuSort = new Gtk::MenuItem (M("FILEBROWSER_POPUPSORTBY"))), 0, 1, p, p + 1); + p++; + Gtk::Menu* submenuSort = Gtk::manage (new Gtk::Menu ()); + Gtk::RadioButtonGroup sortOrderGroup, sortMethodGroup; + for (size_t i = 0; i < cnameSortOrders.size(); i++) { + submenuSort->attach (*Gtk::manage(sortOrder[i] = new Gtk::RadioMenuItem (sortOrderGroup, cnameSortOrders[i])), 0, 1, p, p + 1); + p++; + sortOrder[i]->set_active (i == options.sortDescending); + } + submenuSort->attach (*Gtk::manage(new Gtk::SeparatorMenuItem ()), 0, 1, p, p + 1); + p++; + for (size_t i = 0; i < cnameSortMethods.size(); i++) { + submenuSort->attach (*Gtk::manage(sortMethod[i] = new Gtk::RadioMenuItem (sortMethodGroup, cnameSortMethods[i])), 0, 1, p, p + 1); + p++; + sortMethod[i]->set_active (i == options.sortMethod); + } + submenuSort->show_all (); + menuSort->set_submenu (*submenuSort); + /*********************** * rank ***********************/ @@ -427,6 +462,14 @@ FileBrowser::FileBrowser () : inspect->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), inspect)); } + for (int i = 0; i < 2; i++) { + sortOrder[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), sortOrder[i])); + } + + for (int i = 0; i < Options::SORT_METHOD_COUNT; i++) { + sortMethod[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), sortMethod[i])); + } + for (int i = 0; i < 6; i++) { rank[i]->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), rank[i])); } @@ -610,27 +653,7 @@ void FileBrowser::addEntry_ (FileBrowserEntry* entry) entry->getThumbButtonSet()->setButtonListener(this); entry->resize(getThumbnailHeight()); entry->filtered = !checkFilter(entry); - - // find place in abc order - { - MYWRITERLOCK(l, entryRW); - - fd.insert( - std::lower_bound( - fd.begin(), - fd.end(), - entry, - [](const ThumbBrowserEntryBase* a, const ThumbBrowserEntryBase* b) - { - return *a < *b; - } - ), - entry - ); - - initEntry(entry); - } - redraw(entry); + insertEntry(entry); } FileBrowserEntry* FileBrowser::delEntry (const Glib::ustring& fname) @@ -724,6 +747,18 @@ void FileBrowser::menuItemActivated (Gtk::MenuItem* m) return; } + for (int i = 0; i < 2; i++) + if (m == sortOrder[i]) { + sortOrderRequested (i); + return; + } + + for (int i = 0; i < Options::SORT_METHOD_COUNT; i++) + if (m == sortMethod[i]) { + sortMethodRequested (i); + return; + } + for (int i = 0; i < 6; i++) if (m == rank[i]) { rankingRequested (mselected, i); @@ -1632,6 +1667,18 @@ void FileBrowser::fromTrashRequested (std::vector tbe) applyFilter (filter); } +void FileBrowser::sortMethodRequested (int method) +{ + options.sortMethod = Options::SortMethod(method); + resort (); +} + +void FileBrowser::sortOrderRequested (int order) +{ + options.sortDescending = !!order; + resort (); +} + void FileBrowser::rankingRequested (std::vector tbe, int rank) { diff --git a/rtgui/filebrowser.h b/rtgui/filebrowser.h index 4602ba9bb..0df1cf9eb 100644 --- a/rtgui/filebrowser.h +++ b/rtgui/filebrowser.h @@ -83,9 +83,12 @@ protected: Gtk::MenuItem* open; Gtk::MenuItem* inspect; Gtk::MenuItem* selall; + Gtk::RadioMenuItem* sortMethod[Options::SORT_METHOD_COUNT]; + Gtk::RadioMenuItem* sortOrder[2]; Gtk::MenuItem* copyTo; Gtk::MenuItem* moveTo; + Gtk::MenuItem* menuSort; Gtk::MenuItem* menuRank; Gtk::MenuItem* menuLabel; Gtk::MenuItem* menuFileOperations; @@ -131,6 +134,8 @@ protected: void toTrashRequested (std::vector tbe); void fromTrashRequested (std::vector tbe); + void sortMethodRequested (int method); + void sortOrderRequested (int order); void rankingRequested (std::vector tbe, int rank); void colorlabelRequested (std::vector tbe, int colorlabel); void requestRanking (int rank); diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc index bf3f11a79..b89fe340d 100644 --- a/rtgui/filebrowserentry.cc +++ b/rtgui/filebrowserentry.cc @@ -45,10 +45,8 @@ Glib::RefPtr FileBrowserEntry::hdr; Glib::RefPtr FileBrowserEntry::ps; FileBrowserEntry::FileBrowserEntry (Thumbnail* thm, const Glib::ustring& fname) - : ThumbBrowserEntryBase (fname), wasInside(false), iatlistener(nullptr), press_x(0), press_y(0), action_x(0), action_y(0), rot_deg(0.0), landscape(true), cropParams(new rtengine::procparams::CropParams), cropgl(nullptr), state(SNormal), crop_custom_ratio(0.f) + : ThumbBrowserEntryBase (fname, thm), wasInside(false), iatlistener(nullptr), press_x(0), press_y(0), action_x(0), action_y(0), rot_deg(0.0), landscape(true), cropParams(new rtengine::procparams::CropParams), cropgl(nullptr), state(SNormal), crop_custom_ratio(0.f) { - thumbnail = thm; - feih = new FileBrowserEntryIdleHelper; feih->fbentry = this; feih->destroyed = false; diff --git a/rtgui/options.cc b/rtgui/options.cc index a1cc88c03..b2ef17d77 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -685,6 +685,8 @@ void Options::setDefaults() lastICCProfCreatorDir = ""; gimpPluginShowInfoDialog = true; maxRecentFolders = 15; + sortMethod = SORT_BY_NAME; + sortDescending = false; rtSettings.lensfunDbDirectory = ""; // set also in main.cc and main-cli.cc cropGuides = CROP_GUIDE_FULL; cropAutoFit = false; @@ -1150,6 +1152,19 @@ void Options::readFromFile(Glib::ustring fname) if (keyFile.has_key("File Browser", "RecentFolders")) { recentFolders = keyFile.get_string_list("File Browser", "RecentFolders"); } + + if (keyFile.has_key("File Browser", "SortMethod")) { + int v = keyFile.get_integer("File Browser", "SortMethod"); + if (v < int(0) || v >= int(SORT_METHOD_COUNT)) { + sortMethod = SORT_BY_NAME; + } else { + sortMethod = SortMethod(v); + } + } + + if (keyFile.has_key("File Browser", "SortDescending")) { + sortDescending = keyFile.get_boolean("File Browser", "SortDescending"); + } } if (keyFile.has_group("Clipping Indication")) { @@ -2217,6 +2232,8 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_string_list("File Browser", "RecentFolders", temp); } + keyFile.set_integer("File Browser", "SortMethod", sortMethod); + keyFile.set_boolean("File Browser", "SortDescending", sortDescending); keyFile.set_integer("Clipping Indication", "HighlightThreshold", highlightThreshold); keyFile.set_integer("Clipping Indication", "ShadowThreshold", shadowThreshold); keyFile.set_boolean("Clipping Indication", "BlinkClipped", blinkClipped); diff --git a/rtgui/options.h b/rtgui/options.h index bc5e41c91..d7523e699 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -452,6 +452,17 @@ public: size_t maxRecentFolders; // max. number of recent folders stored in options file std::vector recentFolders; // List containing all recent folders + enum SortMethod { + SORT_BY_NAME, + SORT_BY_DATE, + SORT_BY_EXIF, + SORT_BY_RANK, + SORT_BY_LABEL, + SORT_METHOD_COUNT, + }; + SortMethod sortMethod; // remembers current state of file browser + bool sortDescending; + Options (); diff --git a/rtgui/thumbbrowserbase.cc b/rtgui/thumbbrowserbase.cc index 06c662e51..8f3499c2a 100644 --- a/rtgui/thumbbrowserbase.cc +++ b/rtgui/thumbbrowserbase.cc @@ -1091,6 +1091,25 @@ bool ThumbBrowserBase::Internal::on_scroll_event (GdkEventScroll* event) } +void ThumbBrowserBase::resort () +{ + { + MYWRITERLOCK(l, entryRW); + + std::sort( + fd.begin(), + fd.end(), + [](const ThumbBrowserEntryBase* a, const ThumbBrowserEntryBase* b) + { + bool lt = a->compare(*b, options.sortMethod); + return options.sortDescending ? !lt : lt; + } + ); + } + + redraw (); +} + void ThumbBrowserBase::redraw (ThumbBrowserEntryBase* entry) { @@ -1218,9 +1237,30 @@ void ThumbBrowserBase::enableTabMode(bool enable) } } -void ThumbBrowserBase::initEntry (ThumbBrowserEntryBase* entry) +void ThumbBrowserBase::insertEntry (ThumbBrowserEntryBase* entry) { - entry->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value())); + // find place in sort order + { + MYWRITERLOCK(l, entryRW); + + fd.insert( + std::lower_bound( + fd.begin(), + fd.end(), + entry, + [](const ThumbBrowserEntryBase* a, const ThumbBrowserEntryBase* b) + { + bool lt = a->compare(*b, options.sortMethod); + return options.sortDescending ? !lt : lt; + } + ), + entry + ); + + entry->setOffset ((int)(hscroll.get_value()), (int)(vscroll.get_value())); + } + + redraw (); } void ThumbBrowserBase::getScrollPosition (double& h, double& v) diff --git a/rtgui/thumbbrowserbase.h b/rtgui/thumbbrowserbase.h index 2d41cdfab..8c1ec49c8 100644 --- a/rtgui/thumbbrowserbase.h +++ b/rtgui/thumbbrowserbase.h @@ -208,12 +208,13 @@ public: return fd; } void on_style_updated () override; + void resort (); // re-apply sort method void redraw (ThumbBrowserEntryBase* entry = nullptr); // arrange files and draw area void refreshThumbImages (); // refresh thumbnail sizes, re-generate thumbnail images, arrange and draw void refreshQuickThumbImages (); // refresh thumbnail sizes, re-generate thumbnail images, arrange and draw void refreshEditedState (const std::set& efiles); - void initEntry (ThumbBrowserEntryBase* entry); + void insertEntry (ThumbBrowserEntryBase* entry); void getScrollPosition (double& h, double& v); void setScrollPosition (double h, double v); diff --git a/rtgui/thumbbrowserentrybase.cc b/rtgui/thumbbrowserentrybase.cc index 306b491be..3d1e6bdc4 100644 --- a/rtgui/thumbbrowserentrybase.cc +++ b/rtgui/thumbbrowserentrybase.cc @@ -119,7 +119,7 @@ Glib::ustring getPaddedName(const Glib::ustring& name) } -ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname) : +ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname, Thumbnail *thm) : fnlabw(0), fnlabh(0), dtlabw(0), @@ -153,7 +153,8 @@ ThumbBrowserEntryBase::ThumbBrowserEntryBase (const Glib::ustring& fname) : bbPreview(nullptr), cursor_type(CSUndefined), collate_name(getPaddedName(dispname).casefold_collate_key()), - thumbnail(nullptr), + collate_exif(getPaddedName(thm->getExifString()).casefold_collate_key()), + thumbnail(thm), filename(fname), selected(false), drawable(false), diff --git a/rtgui/thumbbrowserentrybase.h b/rtgui/thumbbrowserentrybase.h index 764f806fd..3db03a96e 100644 --- a/rtgui/thumbbrowserentrybase.h +++ b/rtgui/thumbbrowserentrybase.h @@ -26,6 +26,8 @@ #include "guiutils.h" #include "lwbuttonset.h" #include "threadutils.h" +#include "options.h" +#include "thumbnail.h" #include "../rtengine/coord2d.h" @@ -95,6 +97,7 @@ protected: private: const std::string collate_name; + const std::string collate_exif; public: @@ -117,7 +120,7 @@ public: bool updatepriority; eWithFilename withFilename; - explicit ThumbBrowserEntryBase (const Glib::ustring& fname); + explicit ThumbBrowserEntryBase (const Glib::ustring& fname, Thumbnail *thm); virtual ~ThumbBrowserEntryBase (); void setParent (ThumbBrowserBase* l) @@ -174,9 +177,32 @@ public: void setPosition (int x, int y, int w, int h); void setOffset (int x, int y); - bool operator <(const ThumbBrowserEntryBase& other) const + bool compare (const ThumbBrowserEntryBase& other, Options::SortMethod method) const { - return collate_name < other.collate_name; + int cmp = 0; + switch (method){ + case Options::SORT_BY_NAME: + return collate_name < other.collate_name; + case Options::SORT_BY_DATE: + cmp = thumbnail->getDateTime().compare(other.thumbnail->getDateTime()); + break; + case Options::SORT_BY_EXIF: + cmp = collate_exif.compare(other.collate_exif); + break; + case Options::SORT_BY_RANK: + cmp = thumbnail->getRank() - other.thumbnail->getRank(); + break; + case Options::SORT_BY_LABEL: + cmp = thumbnail->getColorLabel() - other.thumbnail->getColorLabel(); + break; + case Options::SORT_METHOD_COUNT: abort(); + } + + // Always fall back to sorting by name + if (!cmp) + cmp = collate_name.compare(other.collate_name); + + return cmp < 0; } virtual void refreshThumbnailImage () = 0; diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 2baf03247..30766ebc9 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -31,6 +31,7 @@ #include "../rtengine/procparams.h" #include "../rtengine/rtthumbnail.h" #include +#include #include "../rtengine/dynamicprofile.h" #include "../rtengine/profilestore.h" @@ -718,11 +719,44 @@ rtengine::IImage8* Thumbnail::upgradeThumbImage (const rtengine::procparams::Pro void Thumbnail::generateExifDateTimeStrings () { + if (cfs.timeValid) { + std::string dateFormat = options.dateFormat; + std::ostringstream ostr; + bool spec = false; - exifString = ""; - dateTimeString = ""; + for (size_t i = 0; i < dateFormat.size(); i++) + if (spec && dateFormat[i] == 'y') { + ostr << cfs.year; + spec = false; + } else if (spec && dateFormat[i] == 'm') { + ostr << (int)cfs.month; + spec = false; + } else if (spec && dateFormat[i] == 'd') { + ostr << (int)cfs.day; + spec = false; + } else if (dateFormat[i] == '%') { + spec = true; + } else { + ostr << (char)dateFormat[i]; + spec = false; + } + + ostr << " " << (int)cfs.hour; + ostr << ":" << std::setw(2) << std::setfill('0') << (int)cfs.min; + ostr << ":" << std::setw(2) << std::setfill('0') << (int)cfs.sec; + + dateTimeString = ostr.str (); + dateTime = Glib::DateTime::create_local(cfs.year, cfs.month, cfs.day, + cfs.hour, cfs.min, cfs.sec); + } + + if (!dateTime.gobj() || !cfs.timeValid) { + dateTimeString = ""; + dateTime = Glib::DateTime::create_now_utc(0); + } if (!cfs.exifValid) { + exifString = ""; return; } @@ -731,33 +765,6 @@ void Thumbnail::generateExifDateTimeStrings () if (options.fbShowExpComp && cfs.expcomp != "0.00" && !cfs.expcomp.empty()) { // don't show exposure compensation if it is 0.00EV;old cache files do not have ExpComp, so value will not be displayed. exifString = Glib::ustring::compose ("%1 %2EV", exifString, cfs.expcomp); // append exposure compensation to exifString } - - std::string dateFormat = options.dateFormat; - std::ostringstream ostr; - bool spec = false; - - for (size_t i = 0; i < dateFormat.size(); i++) - if (spec && dateFormat[i] == 'y') { - ostr << cfs.year; - spec = false; - } else if (spec && dateFormat[i] == 'm') { - ostr << (int)cfs.month; - spec = false; - } else if (spec && dateFormat[i] == 'd') { - ostr << (int)cfs.day; - spec = false; - } else if (dateFormat[i] == '%') { - spec = true; - } else { - ostr << (char)dateFormat[i]; - spec = false; - } - - ostr << " " << (int)cfs.hour; - ostr << ":" << std::setw(2) << std::setfill('0') << (int)cfs.min; - ostr << ":" << std::setw(2) << std::setfill('0') << (int)cfs.sec; - - dateTimeString = ostr.str (); } const Glib::ustring& Thumbnail::getExifString () const @@ -772,6 +779,12 @@ const Glib::ustring& Thumbnail::getDateTimeString () const return dateTimeString; } +const Glib::DateTime& Thumbnail::getDateTime () const +{ + + return dateTime; +} + void Thumbnail::getAutoWB (double& temp, double& green, double equal, double tempBias) { if (cfs.redAWBMul != -1.0) { @@ -802,6 +815,16 @@ int Thumbnail::infoFromImage (const Glib::ustring& fname, std::unique_ptrgetDateTimeAsTS() > 0) { + cfs.year = 1900 + idata->getDateTime().tm_year; + cfs.month = idata->getDateTime().tm_mon + 1; + cfs.day = idata->getDateTime().tm_mday; + cfs.hour = idata->getDateTime().tm_hour; + cfs.min = idata->getDateTime().tm_min; + cfs.sec = idata->getDateTime().tm_sec; + cfs.timeValid = true; + } + if (idata->hasExif()) { cfs.shutter = idata->getShutterSpeed (); cfs.fnumber = idata->getFNumber (); @@ -814,18 +837,11 @@ int Thumbnail::infoFromImage (const Glib::ustring& fname, std::unique_ptrgetPixelShift (); cfs.frameCount = idata->getFrameCount (); cfs.sampleFormat = idata->getSampleFormat (); - cfs.year = 1900 + idata->getDateTime().tm_year; - cfs.month = idata->getDateTime().tm_mon + 1; - cfs.day = idata->getDateTime().tm_mday; - cfs.hour = idata->getDateTime().tm_hour; - cfs.min = idata->getDateTime().tm_min; - cfs.sec = idata->getDateTime().tm_sec; - cfs.timeValid = true; - cfs.exifValid = true; cfs.lens = idata->getLens(); cfs.camMake = idata->getMake(); cfs.camModel = idata->getModel(); cfs.rating = idata->getRating(); + cfs.exifValid = true; if (idata->getOrientation() == "Rotate 90 CW") { deg = 90; diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h index cda69f030..491151028 100644 --- a/rtgui/thumbnail.h +++ b/rtgui/thumbnail.h @@ -22,6 +22,7 @@ #include #include +#include #include "cacheimagedata.h" #include "threadutils.h" @@ -73,6 +74,7 @@ class Thumbnail // exif & date/time strings Glib::ustring exifString; Glib::ustring dateTimeString; + Glib::DateTime dateTime; bool initial_; @@ -124,6 +126,7 @@ 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 getSpotWB (int x, int y, int rect, double& temp, double& green); From 8d29d361a84b21d6c248e581f81d2ce4c1cf54e2 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Mon, 2 Jan 2023 21:30:06 +0100 Subject: [PATCH 092/134] Support dnggainmap (embedded correction) for Bayer files (#6382) * dng gainmap support, #6379 * dng GainMap: control sensitivity of checkbox, #6379 * dng GainMap: partial paste * dng GainMap: moved isGainMapSupported() from dcraw.h to dcraw.cc * RawImageSource::applyDngGainMap: small speedup * Change GUI to separate gainmap from other flat-field; also reorder checkbox Co-authored-by: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> --- rtdata/languages/default | 3 + rtengine/array2D.h | 8 +++ rtengine/dcraw.cc | 109 +++++++++++++++++++++++++++++++++- rtengine/dcraw.h | 20 ++++++- rtengine/dnggainmap.h | 43 ++++++++++++++ rtengine/imagesource.h | 1 + rtengine/improccoordinator.cc | 2 +- rtengine/procparams.cc | 4 ++ rtengine/procparams.h | 1 + rtengine/rawimage.h | 5 -- rtengine/rawimagesource.cc | 35 ++++++++++- rtengine/rawimagesource.h | 4 ++ rtengine/rtengine.h | 2 +- rtengine/stdimagesource.h | 5 ++ rtgui/flatfield.cc | 36 ++++++++++- rtgui/flatfield.h | 8 ++- rtgui/paramsedited.cc | 8 ++- rtgui/paramsedited.h | 1 + rtgui/partialpastedlg.cc | 9 +++ rtgui/partialpastedlg.h | 3 +- rtgui/toolpanelcoord.cc | 11 ++-- rtgui/toolpanelcoord.h | 2 +- 22 files changed, 299 insertions(+), 21 deletions(-) create mode 100644 rtengine/dnggainmap.h diff --git a/rtdata/languages/default b/rtdata/languages/default index a33b2a9cd..82216f18f 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1406,6 +1406,7 @@ HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold HISTORY_MSG_EDGEFFECT;Edge Attenuation response +HISTORY_MSG_FF_FROMMETADATA;Flat-Field - From Metadata HISTORY_MSG_FILMNEGATIVE_BALANCE;FN - Reference output HISTORY_MSG_FILMNEGATIVE_COLORSPACE;Film negative color space HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative @@ -1736,6 +1737,7 @@ PARTIALPASTE_EXPOSURE;Exposure PARTIALPASTE_FILMNEGATIVE;Film negative PARTIALPASTE_FILMSIMULATION;Film simulation PARTIALPASTE_FLATFIELDAUTOSELECT;Flat-field auto-selection +PARTIALPASTE_FLATFIELDFROMMETADATA;Flat-field from Metadata PARTIALPASTE_FLATFIELDBLURRADIUS;Flat-field blur radius PARTIALPASTE_FLATFIELDBLURTYPE;Flat-field blur type PARTIALPASTE_FLATFIELDCLIPCONTROL;Flat-field clip control @@ -2481,6 +2483,7 @@ TP_FLATFIELD_BT_VERTHORIZ;Vertical + Horizontal TP_FLATFIELD_BT_VERTICAL;Vertical TP_FLATFIELD_CLIPCONTROL;Clip control TP_FLATFIELD_CLIPCONTROL_TOOLTIP;Clip control avoids clipped highlights caused by applying the flat field. If there are already clipped highlights before applying the flat field, value 0 is used. +TP_FLATFIELD_FROMMETADATA;From Metadata TP_FLATFIELD_LABEL;Flat-Field TP_GENERAL_11SCALE_TOOLTIP;The effects of this tool are only visible or only accurate at a preview scale of 1:1. TP_GRADIENT_CENTER;Center diff --git a/rtengine/array2D.h b/rtengine/array2D.h index 10d797999..eee6c3210 100644 --- a/rtengine/array2D.h +++ b/rtengine/array2D.h @@ -248,6 +248,14 @@ public: return *this; } + // import from flat data + void operator()(std::size_t w, std::size_t h, const T* const copy) + { + ar_realloc(w, h); + for (std::size_t y = 0; y < h; ++y) { + std::copy(copy + y * w, copy + y * w + w, rows.data()[y]); + } + } int getWidth() const { diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index bdd92c7da..8eca727b4 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -6938,7 +6938,6 @@ it under the terms of the one of two licenses as you choose: unsigned oldOrder = order; order = 0x4d4d; // always big endian per definition in https://www.adobe.com/content/dam/acom/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf chapter 7 unsigned ntags = get4(); // read the number of opcodes - if (ntags < ifp->size / 12) { // rough check for wrong value (happens for example with DNG files from DJI FC6310) while (ntags-- && !ifp->eof) { unsigned opcode = get4(); @@ -6957,8 +6956,48 @@ it under the terms of the one of two licenses as you choose: break; } case 51009: /* OpcodeList2 */ - meta_offset = ftell(ifp); - break; + { + meta_offset = ftell(ifp); + const unsigned oldOrder = order; + order = 0x4d4d; // always big endian per definition in https://www.adobe.com/content/dam/acom/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf chapter 7 + unsigned ntags = get4(); // read the number of opcodes + if (ntags < ifp->size / 12) { // rough check for wrong value (happens for example with DNG files from DJI FC6310) + while (ntags-- && !ifp->eof) { + unsigned opcode = get4(); + if (opcode == 9 && gainMaps.size() < 4) { + fseek(ifp, 4, SEEK_CUR); // skip 4 bytes as we know that the opcode 4 takes 4 byte + fseek(ifp, 8, SEEK_CUR); // skip 8 bytes as they don't interest us currently + GainMap gainMap; + gainMap.Top = get4(); + gainMap.Left = get4(); + gainMap.Bottom = get4(); + gainMap.Right = get4(); + gainMap.Plane = get4(); + gainMap.Planes = get4(); + gainMap.RowPitch = get4(); + gainMap.ColPitch = get4(); + gainMap.MapPointsV = get4(); + gainMap.MapPointsH = get4(); + gainMap.MapSpacingV = getreal(12); + gainMap.MapSpacingH = getreal(12); + gainMap.MapOriginV = getreal(12); + gainMap.MapOriginH = getreal(12); + gainMap.MapPlanes = get4(); + const std::size_t n = static_cast(gainMap.MapPointsV) * static_cast(gainMap.MapPointsH) * static_cast(gainMap.MapPlanes); + gainMap.MapGain.reserve(n); + for (std::size_t i = 0; i < n; ++i) { + gainMap.MapGain.push_back(getreal(11)); + } + gainMaps.push_back(std::move(gainMap)); + } else { + fseek(ifp, 8, SEEK_CUR); // skip 8 bytes as they don't interest us currently + fseek(ifp, get4(), SEEK_CUR); + } + } + } + order = oldOrder; + break; + } case 64772: /* Kodak P-series */ if (len < 13) break; fseek (ifp, 16, SEEK_CUR); @@ -11079,6 +11118,70 @@ void CLASS nikon_14bit_load_raw() free(buf); } +bool CLASS isGainMapSupported() const { + if (!(dng_version && isBayer())) { + return false; + } + const auto n = gainMaps.size(); + if (n != 4) { // we need 4 gainmaps for bayer files + if (rtengine::settings->verbose) { + std::cout << "GainMap has " << n << " maps, but 4 are needed" << std::endl; + } + return false; + } + unsigned int check = 0; + bool noOp = true; + for (const auto &m : gainMaps) { + if (m.MapGain.size() < 1) { + if (rtengine::settings->verbose) { + std::cout << "GainMap has invalid size of " << m.MapGain.size() << std::endl; + } + return false; + } + if (m.MapGain.size() != static_cast(m.MapPointsV) * static_cast(m.MapPointsH) * static_cast(m.MapPlanes)) { + if (rtengine::settings->verbose) { + std::cout << "GainMap has size of " << m.MapGain.size() << ", but needs " << m.MapPointsV * m.MapPointsH * m.MapPlanes << std::endl; + } + return false; + } + if (m.RowPitch != 2 || m.ColPitch != 2) { + if (rtengine::settings->verbose) { + std::cout << "GainMap needs Row/ColPitch of 2/2, but has " << m.RowPitch << "/" << m.ColPitch << std::endl; + } + return false; + } + if (m.Top == 0){ + if (m.Left == 0) { + check += 1; + } else if (m.Left == 1) { + check += 2; + } + } else if (m.Top == 1) { + if (m.Left == 0) { + check += 4; + } else if (m.Left == 1) { + check += 8; + } + } + for (size_t i = 0; noOp && i < m.MapGain.size(); ++i) { + if (m.MapGain[i] != 1.f) { // we have at least one value != 1.f => map is not a nop + noOp = false; + } + } + } + if (noOp || check != 15) { // all maps are nops or the structure of the combination of 4 maps is not correct + if (rtengine::settings->verbose) { + if (noOp) { + std::cout << "GainMap is a nop" << std::endl; + } else { + std::cout << "GainMap has unsupported type : " << check << std::endl; + } + } + return false; + } + return true; +} + /* RT: Delete from here */ /*RT*/#undef SQR /*RT*/#undef MAX diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index f78bd8aa6..e0a6cda92 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -19,9 +19,12 @@ #pragma once +#include + #include "myfile.h" #include - +#include "dnggainmap.h" +#include "settings.h" class DCraw { @@ -165,6 +168,8 @@ protected: PanasonicRW2Info(): bpp(0), encoding(0) {} }; PanasonicRW2Info RT_pana_info; + std::vector gainMaps; + public: struct CanonCR3Data { // contents of tag CMP1 for relevant track in CR3 file @@ -193,6 +198,18 @@ public: int crx_track_selected; short CR3_CTMDtag; }; + + bool isBayer() const + { + return (filters != 0 && filters != 9); + } + + const std::vector& getGainMaps() const { + return gainMaps; + } + + bool isGainMapSupported() const; + struct CanonLevelsData { unsigned cblack[4]; unsigned white; @@ -200,6 +217,7 @@ public: bool white_ok; CanonLevelsData(): cblack{0}, white{0}, black_ok(false), white_ok(false) {} }; + protected: CanonCR3Data RT_canon_CR3_data; diff --git a/rtengine/dnggainmap.h b/rtengine/dnggainmap.h new file mode 100644 index 000000000..25a01fd0f --- /dev/null +++ b/rtengine/dnggainmap.h @@ -0,0 +1,43 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 Ingo Weyrich + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#pragma once + +#include +#include + +struct GainMap +{ + std::uint32_t Top; + std::uint32_t Left; + std::uint32_t Bottom; + std::uint32_t Right; + std::uint32_t Plane; + std::uint32_t Planes; + std::uint32_t RowPitch; + std::uint32_t ColPitch; + std::uint32_t MapPointsV; + std::uint32_t MapPointsH; + double MapSpacingV; + double MapSpacingH; + double MapOriginV; + double MapOriginH; + std::uint32_t MapPlanes; + std::vector MapGain; +}; diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 6cb279efc..a8ea8f851 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -137,6 +137,7 @@ public: virtual ImageMatrices* getImageMatrices () = 0; virtual bool isRAW () const = 0; + virtual bool isGainMapSupported () const = 0; virtual DCPProfile* getDCP (const procparams::ColorManagementParams &cmp, DCPProfileApplyState &as) { return nullptr; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 8d377d30c..df354bfd8 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -407,7 +407,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) // If high detail (=100%) is newly selected, do a demosaic update, since the last was just with FAST if (imageTypeListener) { - imageTypeListener->imageTypeChanged(imgsrc->isRAW(), imgsrc->getSensorType() == ST_BAYER, imgsrc->getSensorType() == ST_FUJI_XTRANS, imgsrc->isMono()); + imageTypeListener->imageTypeChanged(imgsrc->isRAW(), imgsrc->getSensorType() == ST_BAYER, imgsrc->getSensorType() == ST_FUJI_XTRANS, imgsrc->isMono(), imgsrc->isGainMapSupported()); } if ((todo & M_RAW) diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 04ece8bc3..c9c420b44 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -5633,6 +5633,7 @@ bool RAWParams::PreprocessWB::operator !=(const PreprocessWB& other) const RAWParams::RAWParams() : df_autoselect(false), ff_AutoSelect(false), + ff_FromMetaData(false), ff_BlurRadius(32), ff_BlurType(getFlatFieldBlurTypeString(FlatFieldBlurType::AREA)), ff_AutoClipControl(false), @@ -5658,6 +5659,7 @@ bool RAWParams::operator ==(const RAWParams& other) const && df_autoselect == other.df_autoselect && ff_file == other.ff_file && ff_AutoSelect == other.ff_AutoSelect + && ff_FromMetaData == other.ff_FromMetaData && ff_BlurRadius == other.ff_BlurRadius && ff_BlurType == other.ff_BlurType && ff_AutoClipControl == other.ff_AutoClipControl @@ -7484,6 +7486,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo 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_AutoSelect, "RAW", "FlatFieldAutoSelect", raw.ff_AutoSelect, keyFile); + saveToKeyfile(!pedited || pedited->raw.ff_FromMetaData, "RAW", "FlatFieldFromMetaData", raw.ff_FromMetaData, 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); saveToKeyfile(!pedited || pedited->raw.ff_AutoClipControl, "RAW", "FlatFieldAutoClipControl", raw.ff_AutoClipControl, keyFile); @@ -10130,6 +10133,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } assignFromKeyfile(keyFile, "RAW", "FlatFieldAutoSelect", pedited, raw.ff_AutoSelect, pedited->raw.ff_AutoSelect); + assignFromKeyfile(keyFile, "RAW", "FlatFieldFromMetaData", pedited, raw.ff_FromMetaData, pedited->raw.ff_FromMetaData); assignFromKeyfile(keyFile, "RAW", "FlatFieldBlurRadius", pedited, raw.ff_BlurRadius, pedited->raw.ff_BlurRadius); assignFromKeyfile(keyFile, "RAW", "FlatFieldBlurType", pedited, raw.ff_BlurType, pedited->raw.ff_BlurType); assignFromKeyfile(keyFile, "RAW", "FlatFieldAutoClipControl", pedited, raw.ff_AutoClipControl, pedited->raw.ff_AutoClipControl); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index d730316e2..309bcb2ab 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -2440,6 +2440,7 @@ struct RAWParams { Glib::ustring ff_file; bool ff_AutoSelect; + bool ff_FromMetaData; int ff_BlurRadius; Glib::ustring ff_BlurType; bool ff_AutoClipControl; diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index 871267dac..2b1cd2156 100644 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -245,11 +245,6 @@ public: return zero_is_bad == 1; } - bool isBayer() const - { - return (filters != 0 && filters != 9); - } - bool isXtrans() const { return filters == 9; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 48d7b0904..550c59e9c 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -39,6 +39,7 @@ #include "rawimage.h" #include "rawimagesource_i.h" #include "rawimagesource.h" +#include "rescale.h" #include "rt_math.h" #include "rtengine.h" #include "rtlensfun.h" @@ -1347,7 +1348,6 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le rif = ffm.searchFlatField(idata->getMake(), idata->getModel(), idata->getLens(), idata->getFocalLen(), idata->getFNumber(), idata->getDateTimeAsTS()); } - bool hasFlatField = (rif != nullptr); if (hasFlatField && settings->verbose) { @@ -1387,6 +1387,9 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le } //FLATFIELD end + if (raw.ff_FromMetaData && isGainMapSupported()) { + applyDngGainMap(c_black, ri->getGainMaps()); + } // Always correct camera badpixels from .badpixels file const std::vector *bp = DFManager::getInstance().getBadPixels(ri->get_maker(), ri->get_model(), idata->getSerialNumber()); @@ -6259,6 +6262,36 @@ void RawImageSource::getRawValues(int x, int y, int rotate, int &R, int &G, int } } +bool RawImageSource::isGainMapSupported() const { + return ri->isGainMapSupported(); +} + +void RawImageSource::applyDngGainMap(const float black[4], const std::vector &gainMaps) { + // now we can apply each gain map to raw_data + array2D mvals[2][2]; + for (auto &m : gainMaps) { + mvals[m.Top & 1][m.Left & 1](m.MapPointsH, m.MapPointsV, m.MapGain.data()); + } + + // now we assume, col_scale and row scale is the same for all maps + const float col_scale = float(gainMaps[0].MapPointsH-1) / float(W); + const float row_scale = float(gainMaps[0].MapPointsV-1) / float(H); + +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic, 16) +#endif + for (std::size_t y = 0; y < static_cast(H); ++y) { + const float rowBlack[2] = {black[FC(y,0)], black[FC(y,1)]}; + const float ys = y * row_scale; + float xs = 0.f; + for (std::size_t x = 0; x < static_cast(W); ++x, xs += col_scale) { + const float f = getBilinearValue(mvals[y & 1][x & 1], xs, ys); + const float b = rowBlack[x & 1]; + rawData[y][x] = rtengine::max((rawData[y][x] - b) * f + b, 0.f); + } + } +} + void RawImageSource::cleanup () { delete phaseOneIccCurve; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 41a400dd9..d7549fe71 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -24,6 +24,7 @@ #include "array2D.h" #include "colortemp.h" +#include "dnggainmap.h" #include "iimage.h" #include "imagesource.h" #include "procparams.h" @@ -177,6 +178,8 @@ public: return true; } + bool isGainMapSupported() const override; + void setProgressListener (ProgressListener* pl) override { plistener = pl; @@ -304,6 +307,7 @@ protected: void vflip (Imagefloat* im); void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) override; void captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold, double &radius) override; + void applyDngGainMap(const float black[4], const std::vector &gainMaps); }; } diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index b9fc916f6..989ca3354 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -493,7 +493,7 @@ class ImageTypeListener { public: virtual ~ImageTypeListener() = default; - virtual void imageTypeChanged(bool isRaw, bool isBayer, bool isXtrans, bool is_Mono = false) = 0; + virtual void imageTypeChanged(bool isRaw, bool isBayer, bool isXtrans, bool is_Mono = false, bool isGainMapSupported = false) = 0; }; class AutoContrastListener diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 9b95fe34e..f83c58a04 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -100,6 +100,11 @@ public: return false; } + bool isGainMapSupported() const override + { + return false; + } + void setProgressListener (ProgressListener* pl) override { plistener = pl; diff --git a/rtgui/flatfield.cc b/rtgui/flatfield.cc index 71fa0aab6..f493ba0b9 100644 --- a/rtgui/flatfield.cc +++ b/rtgui/flatfield.cc @@ -18,6 +18,7 @@ */ #include +#include "eventmapper.h" #include "flatfield.h" #include "guiutils.h" @@ -32,6 +33,9 @@ using namespace rtengine::procparams; FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_LABEL")) { + auto m = ProcEventMapper::getInstance(); + EvFlatFieldFromMetaData = m->newEvent(DARKFRAME, "HISTORY_MSG_FF_FROMMETADATA"); + hbff = Gtk::manage(new Gtk::Box()); flatFieldFile = Gtk::manage(new MyFileChooserButton(M("TP_FLATFIELD_LABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); bindCurrentFolder (*flatFieldFile, options.lastFlatfieldDir); @@ -42,6 +46,8 @@ FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_L hbff->pack_start(*flatFieldFile); hbff->pack_start(*flatFieldFileReset, Gtk::PACK_SHRINK); flatFieldAutoSelect = Gtk::manage(new Gtk::CheckButton((M("TP_FLATFIELD_AUTOSELECT")))); + flatFieldFromMetaData = Gtk::manage(new CheckBox((M("TP_FLATFIELD_FROMMETADATA")), multiImage)); + flatFieldFromMetaData->setCheckBoxListener (this); ffInfo = Gtk::manage(new Gtk::Label("-")); setExpandAlignProperties(ffInfo, true, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER); flatFieldBlurRadius = Gtk::manage(new Adjuster (M("TP_FLATFIELD_BLURRADIUS"), 0, 200, 2, 32)); @@ -70,8 +76,10 @@ FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_L flatFieldClipControl->show(); flatFieldClipControl->set_tooltip_markup (M("TP_FLATFIELD_CLIPCONTROL_TOOLTIP")); - pack_start( *hbff, Gtk::PACK_SHRINK); + pack_start( *flatFieldFromMetaData, Gtk::PACK_SHRINK); + pack_start( *Gtk::manage( new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), Gtk::PACK_SHRINK, 0 ); pack_start( *flatFieldAutoSelect, Gtk::PACK_SHRINK); + pack_start( *hbff, Gtk::PACK_SHRINK); pack_start( *ffInfo, Gtk::PACK_SHRINK); pack_start( *hbffbt, Gtk::PACK_SHRINK); pack_start( *flatFieldBlurRadius, Gtk::PACK_SHRINK); @@ -128,12 +136,14 @@ void FlatField::read(const rtengine::procparams::ProcParams* pp, const ParamsEdi } flatFieldAutoSelect->set_active (pp->raw.ff_AutoSelect); + flatFieldFromMetaData->set_active (pp->raw.ff_FromMetaData); flatFieldBlurRadius->setValue (pp->raw.ff_BlurRadius); flatFieldClipControl->setValue (pp->raw.ff_clipControl); flatFieldClipControl->setAutoValue (pp->raw.ff_AutoClipControl); if(pedited ) { flatFieldAutoSelect->set_inconsistent (!pedited->raw.ff_AutoSelect); + flatFieldFromMetaData->set_inconsistent (!pedited->raw.ff_FromMetaData); flatFieldBlurRadius->setEditedState( pedited->raw.ff_BlurRadius ? Edited : UnEdited ); flatFieldClipControl->setEditedState( pedited->raw.ff_clipControl ? Edited : UnEdited ); flatFieldClipControl->setAutoInconsistent(multiImage && !pedited->raw.ff_AutoClipControl); @@ -214,6 +224,7 @@ void FlatField::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedit { pp->raw.ff_file = flatFieldFile->get_filename(); pp->raw.ff_AutoSelect = flatFieldAutoSelect->get_active(); + pp->raw.ff_FromMetaData = flatFieldFromMetaData->get_active(); pp->raw.ff_BlurRadius = flatFieldBlurRadius->getIntValue(); pp->raw.ff_clipControl = flatFieldClipControl->getIntValue(); pp->raw.ff_AutoClipControl = flatFieldClipControl->getAutoValue(); @@ -227,6 +238,7 @@ void FlatField::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedit if (pedited) { pedited->raw.ff_file = ffChanged; pedited->raw.ff_AutoSelect = !flatFieldAutoSelect->get_inconsistent(); + pedited->raw.ff_FromMetaData = !flatFieldFromMetaData->get_inconsistent(); pedited->raw.ff_BlurRadius = flatFieldBlurRadius->getEditedState (); pedited->raw.ff_clipControl = flatFieldClipControl->getEditedState (); pedited->raw.ff_AutoClipControl = !flatFieldClipControl->getAutoInconsistent(); @@ -352,6 +364,13 @@ void FlatField::flatFieldBlurTypeChanged () } } +void FlatField::checkBoxToggled (CheckBox* c, CheckValue newval) +{ + if (listener && c == flatFieldFromMetaData) { + listener->panelChanged (EvFlatFieldFromMetaData, flatFieldFromMetaData->getLastActive() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + void FlatField::flatFieldAutoSelectChanged() { if (batchMode) { @@ -419,3 +438,18 @@ void FlatField::flatFieldAutoClipValueChanged(int n) } ); } + +void FlatField::setGainMap(bool enabled) { + flatFieldFromMetaData->set_sensitive(enabled); + if (!enabled) { + idle_register.add( + [this, enabled]() -> bool + { + disableListener(); + flatFieldFromMetaData->setValue(false); + enableListener(); + return false; + } + ); + } +} diff --git a/rtgui/flatfield.h b/rtgui/flatfield.h index 0d6f167e1..be46d5a1d 100644 --- a/rtgui/flatfield.h +++ b/rtgui/flatfield.h @@ -23,6 +23,7 @@ #include #include "adjuster.h" +#include "checkbox.h" #include "guiutils.h" #include "toolpanel.h" @@ -42,7 +43,7 @@ public: // add other info here }; -class FlatField final : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public rtengine::FlatFieldAutoClipListener +class FlatField final : public ToolParamBlock, public AdjusterListener, public CheckBoxListener, public FoldableToolPanel, public rtengine::FlatFieldAutoClipListener { protected: @@ -52,6 +53,7 @@ protected: Gtk::Label *ffInfo; Gtk::Button *flatFieldFileReset; Gtk::CheckButton* flatFieldAutoSelect; + CheckBox* flatFieldFromMetaData; Adjuster* flatFieldClipControl; Adjuster* flatFieldBlurRadius; MyComboBoxText* flatFieldBlurType; @@ -64,8 +66,10 @@ protected: Glib::ustring lastShortcutPath; bool b_filter_asCurrent; bool israw; + rtengine::ProcEvent EvFlatFieldFromMetaData; IdleRegister idle_register; + public: FlatField (); @@ -90,4 +94,6 @@ public: ffp = p; }; void flatFieldAutoClipValueChanged(int n = 0) override; + void checkBoxToggled(CheckBox* c, CheckValue newval) override; + void setGainMap(bool enabled); }; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index a7963b7dc..9c7a92f39 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -519,6 +519,7 @@ void ParamsEdited::set(bool v) raw.df_autoselect = v; raw.ff_file = v; raw.ff_AutoSelect = v; + raw.ff_FromMetaData = v; raw.ff_BlurRadius = v; raw.ff_BlurType = v; raw.ff_AutoClipControl = v; @@ -1930,6 +1931,7 @@ void ParamsEdited::initFrom(const std::vector& raw.df_autoselect = raw.df_autoselect && p.raw.df_autoselect == other.raw.df_autoselect; raw.ff_file = raw.ff_file && p.raw.ff_file == other.raw.ff_file; raw.ff_AutoSelect = raw.ff_AutoSelect && p.raw.ff_AutoSelect == other.raw.ff_AutoSelect; + raw.ff_FromMetaData = raw.ff_FromMetaData && p.raw.ff_FromMetaData == other.raw.ff_FromMetaData; raw.ff_BlurRadius = raw.ff_BlurRadius && p.raw.ff_BlurRadius == other.raw.ff_BlurRadius; raw.ff_BlurType = raw.ff_BlurType && p.raw.ff_BlurType == other.raw.ff_BlurType; raw.ff_AutoClipControl = raw.ff_AutoClipControl && p.raw.ff_AutoClipControl == other.raw.ff_AutoClipControl; @@ -6644,6 +6646,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.raw.ff_AutoSelect = mods.raw.ff_AutoSelect; } + if (raw.ff_FromMetaData) { + toEdit.raw.ff_FromMetaData = mods.raw.ff_FromMetaData; + } + if (raw.ff_BlurRadius) { toEdit.raw.ff_BlurRadius = mods.raw.ff_BlurRadius; } @@ -7375,7 +7381,7 @@ bool RAWParamsEdited::XTransSensor::isUnchanged() const bool RAWParamsEdited::isUnchanged() const { return bayersensor.isUnchanged() && xtranssensor.isUnchanged() && ca_autocorrect && ca_avoidcolourshift && caautoiterations && cared && cablue && hotPixelFilter && deadPixelFilter && hotdeadpix_thresh && darkFrame - && df_autoselect && ff_file && ff_AutoSelect && ff_BlurRadius && ff_BlurType && exPos && ff_AutoClipControl && ff_clipControl; + && df_autoselect && ff_file && ff_AutoSelect && ff_FromMetaData && ff_BlurRadius && ff_BlurType && exPos && ff_AutoClipControl && ff_clipControl; } bool LensProfParamsEdited::isUnchanged() const diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 0c0c79f7c..3c108f33d 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -1489,6 +1489,7 @@ struct RAWParamsEdited { bool df_autoselect; bool ff_file; bool ff_AutoSelect; + bool ff_FromMetaData; bool ff_BlurRadius; bool ff_BlurType; bool ff_AutoClipControl; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index a9f79d854..81847adc0 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -301,6 +301,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren //--- ff_file = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FLATFIELDFILE"))); ff_AutoSelect = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FLATFIELDAUTOSELECT"))); + ff_FromMetaData = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FLATFIELDFROMMETADATA"))); ff_BlurType = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FLATFIELDBLURTYPE"))); ff_BlurRadius = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FLATFIELDBLURRADIUS"))); ff_ClipControl = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_FLATFIELDCLIPCONTROL"))); @@ -423,6 +424,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren vboxes[8]->pack_start (*Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)), Gtk::PACK_SHRINK, 0); vboxes[8]->pack_start (*ff_file, Gtk::PACK_SHRINK, 2); vboxes[8]->pack_start (*ff_AutoSelect, Gtk::PACK_SHRINK, 2); + vboxes[8]->pack_start (*ff_FromMetaData, Gtk::PACK_SHRINK, 2); vboxes[8]->pack_start (*ff_BlurType, Gtk::PACK_SHRINK, 2); vboxes[8]->pack_start (*ff_BlurRadius, Gtk::PACK_SHRINK, 2); vboxes[8]->pack_start (*ff_ClipControl, Gtk::PACK_SHRINK, 2); @@ -574,6 +576,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren //--- ff_fileConn = ff_file->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); ff_AutoSelectConn = ff_AutoSelect->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); + ff_FromMetaDataConn = ff_FromMetaData->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); ff_BlurTypeConn = ff_BlurType->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); ff_BlurRadiusConn = ff_BlurRadius->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); ff_ClipControlConn = ff_ClipControl->signal_toggled().connect (sigc::bind (sigc::mem_fun(*raw, &Gtk::CheckButton::set_inconsistent), true)); @@ -655,6 +658,7 @@ void PartialPasteDlg::rawToggled () ConnectionBlocker df_AutoSelectBlocker(df_AutoSelectConn); ConnectionBlocker ff_fileBlocker(ff_fileConn); ConnectionBlocker ff_AutoSelectBlocker(ff_AutoSelectConn); + ConnectionBlocker ff_FromMetaDataBlocker(ff_FromMetaDataConn); ConnectionBlocker ff_BlurTypeBlocker(ff_BlurTypeConn); ConnectionBlocker ff_BlurRadiusBlocker(ff_BlurRadiusConn); ConnectionBlocker ff_ClipControlBlocker(ff_ClipControlConn); @@ -685,6 +689,7 @@ void PartialPasteDlg::rawToggled () df_AutoSelect->set_active (raw->get_active ()); ff_file->set_active (raw->get_active ()); ff_AutoSelect->set_active (raw->get_active ()); + ff_FromMetaData->set_active (raw->get_active ()); ff_BlurType->set_active (raw->get_active ()); ff_BlurRadius->set_active (raw->get_active ()); ff_ClipControl->set_active (raw->get_active ()); @@ -1173,6 +1178,10 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param filterPE.raw.ff_AutoSelect = falsePE.raw.ff_AutoSelect; } + if (!ff_FromMetaData->get_active ()) { + filterPE.raw.ff_FromMetaData = falsePE.raw.ff_FromMetaData; + } + if (!ff_BlurRadius->get_active ()) { filterPE.raw.ff_BlurRadius = falsePE.raw.ff_BlurRadius; } diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index 19e1eb462..dcf44bb72 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -214,6 +214,7 @@ public: Gtk::CheckButton* df_AutoSelect; Gtk::CheckButton* ff_file; Gtk::CheckButton* ff_AutoSelect; + Gtk::CheckButton* ff_FromMetaData; Gtk::CheckButton* ff_BlurRadius; Gtk::CheckButton* ff_BlurType; Gtk::CheckButton* ff_ClipControl; @@ -230,7 +231,7 @@ public: sigc::connection distortionConn, cacorrConn, vignettingConn, lcpConn; sigc::connection coarserotConn, finerotConn, cropConn, resizeConn, prsharpeningConn, perspectiveConn, commonTransConn; sigc::connection metadataConn, exifchConn, iptcConn, icmConn; - sigc::connection df_fileConn, df_AutoSelectConn, ff_fileConn, ff_AutoSelectConn, ff_BlurRadiusConn, ff_BlurTypeConn, ff_ClipControlConn; + sigc::connection df_fileConn, df_AutoSelectConn, ff_fileConn, ff_AutoSelectConn, ff_FromMetaDataConn, ff_BlurRadiusConn, ff_BlurTypeConn, ff_ClipControlConn; sigc::connection raw_caredblueConn, raw_ca_autocorrectConn, raw_ca_avoid_colourshiftconn, raw_hotpix_filtConn, raw_deadpix_filtConn, raw_pdaf_lines_filterConn, raw_linenoiseConn, raw_greenthreshConn, raw_ccStepsConn, raw_methodConn, raw_borderConn, raw_imagenumConn, raw_dcb_iterationsConn, raw_lmmse_iterationsConn, raw_pixelshiftConn, raw_dcb_enhanceConn, raw_exposConn, raw_blackConn; sigc::connection filmNegativeConn; sigc::connection captureSharpeningConn; diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 9c14aeb6e..fe8b4f1bf 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -343,12 +343,12 @@ ToolPanelCoordinator::~ToolPanelCoordinator () delete toolBar; } -void ToolPanelCoordinator::imageTypeChanged(bool isRaw, bool isBayer, bool isXtrans, bool isMono) +void ToolPanelCoordinator::imageTypeChanged(bool isRaw, bool isBayer, bool isXtrans, bool isMono, bool isGainMapSupported) { if (isRaw) { if (isBayer) { idle_register.add( - [this]() -> bool + [this, isGainMapSupported]() -> bool { rawPanelSW->set_sensitive(true); sensorxtrans->FoldableToolPanel::hide(); @@ -362,6 +362,7 @@ void ToolPanelCoordinator::imageTypeChanged(bool isRaw, bool isBayer, bool isXtr preprocessWB->FoldableToolPanel::show(); preprocess->FoldableToolPanel::show(); flatfield->FoldableToolPanel::show(); + flatfield->setGainMap(isGainMapSupported); pdSharpening->FoldableToolPanel::show(); retinex->FoldableToolPanel::setGrayedOut(false); return false; @@ -369,7 +370,7 @@ void ToolPanelCoordinator::imageTypeChanged(bool isRaw, bool isBayer, bool isXtr ); } else if (isXtrans) { idle_register.add( - [this]() -> bool + [this, isGainMapSupported]() -> bool { rawPanelSW->set_sensitive(true); sensorxtrans->FoldableToolPanel::show(); @@ -383,6 +384,7 @@ void ToolPanelCoordinator::imageTypeChanged(bool isRaw, bool isBayer, bool isXtr preprocessWB->FoldableToolPanel::show(); preprocess->FoldableToolPanel::show(); flatfield->FoldableToolPanel::show(); + flatfield->setGainMap(isGainMapSupported); pdSharpening->FoldableToolPanel::show(); retinex->FoldableToolPanel::setGrayedOut(false); return false; @@ -390,7 +392,7 @@ void ToolPanelCoordinator::imageTypeChanged(bool isRaw, bool isBayer, bool isXtr ); } else if (isMono) { idle_register.add( - [this]() -> bool + [this, isGainMapSupported]() -> bool { rawPanelSW->set_sensitive(true); sensorbayer->FoldableToolPanel::hide(); @@ -403,6 +405,7 @@ void ToolPanelCoordinator::imageTypeChanged(bool isRaw, bool isBayer, bool isXtr preprocessWB->FoldableToolPanel::hide(); preprocess->FoldableToolPanel::hide(); flatfield->FoldableToolPanel::show(); + flatfield->setGainMap(isGainMapSupported); pdSharpening->FoldableToolPanel::show(); retinex->FoldableToolPanel::setGrayedOut(false); return false; diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 65e2f1e8f..cd4131ff4 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -260,7 +260,7 @@ public: void unsetTweakOperator (rtengine::TweakOperator *tOperator) override; // FilmNegProvider interface - void imageTypeChanged (bool isRaw, bool isBayer, bool isXtrans, bool isMono = false) override; + void imageTypeChanged (bool isRaw, bool isBayer, bool isXtrans, bool isMono = false, bool isGainMapSupported = false) override; // profilechangelistener interface void profileChange( From 57c1822b2c60c42b9b38caab6ade1c7f50201b16 Mon Sep 17 00:00:00 2001 From: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> Date: Mon, 2 Jan 2023 12:32:15 -0800 Subject: [PATCH 093/134] Strict temporary image file permissions (#6358) * Write temp images to private tmp directory (Linux) The directory is in /tmp with 700 permissions. * Reduce temp image file permissions in Linux Set temporary image file permissions to read/write for the user only. * Use private tmp directory for temp images in MacOS * Use private tmp directory for temp images Windows * Use GLib to create temporary directories * Reuse temp directory if possible --- rtengine/winutils.h | 124 +++++++++++++++++++++++ rtgui/editorpanel.cc | 235 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 rtengine/winutils.h diff --git a/rtengine/winutils.h b/rtengine/winutils.h new file mode 100644 index 000000000..757849dd1 --- /dev/null +++ b/rtengine/winutils.h @@ -0,0 +1,124 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2021 Lawrence Lee + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#pragma once + +#ifdef WIN32 + +#include +#include + +#include "noncopyable.h" + + +/** + * Wrapper for pointers to memory allocated by HeapAlloc. + * + * Memory is automatically freed when the object goes out of scope. + */ +template +class WinHeapPtr : public rtengine::NonCopyable +{ +private: + const T ptr; + +public: + WinHeapPtr() = delete; + + /** Allocates the specified number of bytes in the process heap. */ + explicit WinHeapPtr(SIZE_T bytes): ptr(static_cast(HeapAlloc(GetProcessHeap(), 0, bytes))) {}; + + ~WinHeapPtr() + { + // HeapFree does a null check. + HeapFree(GetProcessHeap(), 0, static_cast(ptr)); + } + + T operator ->() const + { + return ptr; + } + + operator T() const + { + return ptr; + } +}; + +/** + * Wrapper for HLOCAL pointers to memory allocated by LocalAlloc. + * + * Memory is automatically freed when the object goes out of scope. + */ +template +class WinLocalPtr : public rtengine::NonCopyable +{ +private: + const T ptr; + +public: + WinLocalPtr() = delete; + + /** Wraps a raw pointer. */ + WinLocalPtr(T pointer): ptr(pointer) {}; + + ~WinLocalPtr() + { + // LocalFree does a null check. + LocalFree(static_cast(ptr)); + } + + T operator ->() const + { + return ptr; + } + + operator T() const + { + return ptr; + } +}; + +/** + * Wrapper for HANDLEs. + * + * Handles are automatically closed when the object goes out of scope. + */ +class WinHandle : public rtengine::NonCopyable +{ +private: + const HANDLE handle; + +public: + WinHandle() = delete; + + /** Wraps a HANDLE. */ + WinHandle(HANDLE handle): handle(handle) {}; + + ~WinHandle() + { + CloseHandle(handle); + } + + operator HANDLE() const + { + return handle; + } +}; + +#endif diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 78a07ddd6..190897c89 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -44,6 +44,8 @@ #ifdef WIN32 #include "windows.h" + +#include "../rtengine/winutils.h" #endif using namespace rtengine::procparams; @@ -134,6 +136,235 @@ bool find_default_monitor_profile (GdkWindow *rootwin, Glib::ustring &defprof, G } #endif +bool hasUserOnlyPermission(const Glib::ustring &dirname) +{ +#if defined(__linux__) || defined(__APPLE__) + const Glib::RefPtr file = Gio::File::create_for_path(dirname); + const Glib::RefPtr file_info = file->query_info("owner::user,unix::mode"); + + if (!file_info) { + return false; + } + + const Glib::ustring owner = file_info->get_attribute_string("owner::user"); + const guint32 mode = file_info->get_attribute_uint32("unix::mode"); + + return (mode & 0777) == 0700 && owner == Glib::get_user_name(); +#elif defined(WIN32) + const Glib::RefPtr file = Gio::File::create_for_path(dirname); + const Glib::RefPtr file_info = file->query_info("owner::user"); + if (!file_info) { + return false; + } + + // Current user must be the owner. + const Glib::ustring user_name = Glib::get_user_name(); + const Glib::ustring owner = file_info->get_attribute_string("owner::user"); + if (user_name != owner) { + return false; + } + + // Get security descriptor and discretionary access control list. + PACL dacl = nullptr; + PSECURITY_DESCRIPTOR sec_desc_raw_ptr = nullptr; + auto win_error = GetNamedSecurityInfo( + dirname.c_str(), + SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION, + nullptr, + nullptr, + &dacl, + nullptr, + &sec_desc_raw_ptr + ); + const WinLocalPtr sec_desc_ptr(sec_desc_raw_ptr); + if (win_error != ERROR_SUCCESS) { + return false; + } + + // Must not inherit permissions. + SECURITY_DESCRIPTOR_CONTROL sec_desc_control; + DWORD revision; + if (!( + GetSecurityDescriptorControl(sec_desc_ptr, &sec_desc_control, &revision) + && sec_desc_control & SE_DACL_PROTECTED + )) { + return false; + } + + // Check that there is one entry allowing full access. + ULONG acl_entry_count; + PEXPLICIT_ACCESS acl_entry_list_raw = nullptr; + win_error = GetExplicitEntriesFromAcl(dacl, &acl_entry_count, &acl_entry_list_raw); + const WinLocalPtr acl_entry_list(acl_entry_list_raw); + if (win_error != ERROR_SUCCESS || acl_entry_count != 1) { + return false; + } + const EXPLICIT_ACCESS &ace = acl_entry_list[0]; + if ( + ace.grfAccessMode != GRANT_ACCESS + || (ace.grfAccessPermissions & FILE_ALL_ACCESS) != FILE_ALL_ACCESS + || ace.Trustee.TrusteeForm != TRUSTEE_IS_SID // Should already be SID, but double check. + ) { + return false; + } + + // ACE must be for the current user. + HANDLE process_token_raw; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &process_token_raw)) { + return false; + } + const WinHandle process_token(process_token_raw); + DWORD actual_token_info_size = 0; + GetTokenInformation(process_token, TokenUser, nullptr, 0, &actual_token_info_size); + if (!actual_token_info_size) { + return false; + } + const WinHeapPtr user_token_ptr(actual_token_info_size); + if (!user_token_ptr || !GetTokenInformation( + process_token, + TokenUser, + user_token_ptr, + actual_token_info_size, + &actual_token_info_size + )) { + return false; + } + return EqualSid(ace.Trustee.ptstrName, user_token_ptr->User.Sid); +#endif + return false; +} + +/** + * Sets read and write permissions, and optionally the execute permission, for + * the user and no permissions for others. + */ +void setUserOnlyPermission(const Glib::RefPtr file, bool execute) +{ +#if defined(__linux__) || defined(__APPLE__) + const Glib::RefPtr file_info = file->query_info("unix::mode"); + if (!file_info) { + return; + } + + guint32 mode = file_info->get_attribute_uint32("unix::mode"); + mode = (mode & ~0777) | (execute ? 0700 : 0600); + try { + file->set_attribute_uint32("unix::mode", mode, Gio::FILE_QUERY_INFO_NONE); + } catch (Gio::Error &) { + } +#elif defined(WIN32) + // Get the current user's SID. + HANDLE process_token_raw; + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &process_token_raw)) { + return; + } + const WinHandle process_token(process_token_raw); + DWORD actual_token_info_size = 0; + GetTokenInformation(process_token, TokenUser, nullptr, 0, &actual_token_info_size); + if (!actual_token_info_size) { + return; + } + const WinHeapPtr user_token_ptr(actual_token_info_size); + if (!user_token_ptr || !GetTokenInformation( + process_token, + TokenUser, + user_token_ptr, + actual_token_info_size, + &actual_token_info_size + )) { + return; + } + const PSID user_sid = user_token_ptr->User.Sid; + + // Get a handle to the file. + const Glib::ustring filename = file->get_path(); + const HANDLE file_handle_raw = CreateFile( + filename.c_str(), + READ_CONTROL | WRITE_DAC, + 0, + nullptr, + OPEN_EXISTING, + execute ? FILE_FLAG_BACKUP_SEMANTICS : FILE_ATTRIBUTE_NORMAL, + nullptr + ); + if (file_handle_raw == INVALID_HANDLE_VALUE) { + return; + } + const WinHandle file_handle(file_handle_raw); + + // Create the user-only permission and set it. + EXPLICIT_ACCESS ea = { + .grfAccessPermissions = FILE_ALL_ACCESS, + .grfAccessMode = GRANT_ACCESS, + .grfInheritance = NO_INHERITANCE, + }; + BuildTrusteeWithSid(&(ea.Trustee), user_sid); + PACL new_dacl_raw = nullptr; + auto win_error = SetEntriesInAcl(1, &ea, nullptr, &new_dacl_raw); + if (win_error != ERROR_SUCCESS) { + return; + } + const WinLocalPtr new_dacl(new_dacl_raw); + SetSecurityInfo( + file_handle, + SE_FILE_OBJECT, + DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, + nullptr, + nullptr, + new_dacl, + nullptr + ); +#endif +} + +/** + * Gets the path to the temp directory, creating it if necessary. + */ +Glib::ustring getTmpDirectory() +{ +#if defined(__linux__) || defined(__APPLE__) || defined(WIN32) + static Glib::ustring recent_dir = ""; + const Glib::ustring tmp_dir_root = Glib::get_tmp_dir(); + const Glib::ustring subdir_base = + Glib::ustring::compose("rawtherapee-%1", Glib::get_user_name()); + Glib::ustring dir = Glib::build_filename(tmp_dir_root, subdir_base); + + // Returns true if the directory doesn't exist or has the right permissions. + auto is_usable_dir = [](const Glib::ustring &dir_path) { + return !Glib::file_test(dir_path, Glib::FILE_TEST_EXISTS) || (Glib::file_test(dir_path, Glib::FILE_TEST_IS_DIR) && hasUserOnlyPermission(dir_path)); + }; + + if (!(is_usable_dir(dir) || recent_dir.empty())) { + // Try to reuse the random suffix directory. + dir = recent_dir; + } + + if (!is_usable_dir(dir)) { + // Create new directory with random suffix. + gchar *const rand_dir = g_dir_make_tmp((subdir_base + "-XXXXXX").c_str(), nullptr); + if (!rand_dir) { + return tmp_dir_root; + } + dir = recent_dir = rand_dir; + g_free(rand_dir); + Glib::RefPtr file = Gio::File::create_for_path(dir); + setUserOnlyPermission(file, true); + } else if (!Glib::file_test(dir, Glib::FILE_TEST_EXISTS)) { + // Create the directory. + Glib::RefPtr file = Gio::File::create_for_path(dir); + bool dir_created = file->make_directory(); + if (!dir_created) { + return tmp_dir_root; + } + setUserOnlyPermission(file, true); + } + + return dir; +#else + return Glib::get_tmp_dir(); +#endif +} } class EditorPanel::ColorManagementToolbar @@ -2058,7 +2289,7 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector *p dirname = options.editor_custom_out_dir; break; default: // Options::EDITOR_OUT_DIR_TEMP - dirname = Glib::get_tmp_dir(); + dirname = getTmpDirectory(); break; } Glib::ustring fullFileName = Glib::build_filename(dirname, shortname); @@ -2119,6 +2350,8 @@ bool EditorPanel::idle_sentToGimp (ProgressConnector *pc, rtengine::IImagef parent->setProgress (0.); bool success = false; + setUserOnlyPermission(Gio::File::create_for_path(filename), false); + if (options.editorToSendTo == 1) { success = ExtProgStore::openInGimp (filename); } else if (options.editorToSendTo == 2) { From 95cede9a1a20a53b3ae5842fed736898791dda60 Mon Sep 17 00:00:00 2001 From: Desmis Date: Tue, 3 Jan 2023 07:44:46 +0100 Subject: [PATCH 094/134] Color Appearance and lighting : Remove cat02preset and all dependencies issue 5664 (#6585) * Remove cat02preset and all dependencies issue 5664 * Normalize cmakelist --- rtengine/improccoordinator.cc | 10 +- rtengine/procparams.cc | 8 +- rtengine/procparams.h | 1 - rtgui/colorappearance.cc | 168 ---------------------------------- rtgui/colorappearance.h | 5 - rtgui/paramsedited.cc | 5 - rtgui/paramsedited.h | 1 - 7 files changed, 7 insertions(+), 191 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index df354bfd8..2a2f1079b 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1936,20 +1936,20 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) ipf.ciecam_02float(ncie, float (adap), pW, 2, nprevl, params.get(), customColCurve1, customColCurve2, customColCurve3, histLCAM, histCCAM, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 0, scale, execsharp, d, dj, yb, 1); - if ((params->colorappearance.autodegree || params->colorappearance.autodegreeout) && acListener && params->colorappearance.enabled && !params->colorappearance.presetcat02) { + if ((params->colorappearance.autodegree || params->colorappearance.autodegreeout) && acListener && params->colorappearance.enabled) { acListener->autoCamChanged(100.* (double)d, 100.* (double)dj); } - if (params->colorappearance.autoadapscen && acListener && params->colorappearance.enabled && !params->colorappearance.presetcat02) { + if (params->colorappearance.autoadapscen && acListener && params->colorappearance.enabled) { acListener->adapCamChanged(adap); //real value of adapt scene } - if (params->colorappearance.autoybscen && acListener && params->colorappearance.enabled && !params->colorappearance.presetcat02) { + if (params->colorappearance.autoybscen && acListener && params->colorappearance.enabled) { acListener->ybCamChanged((int) yb); //real value Yb scene } - // if (params->colorappearance.enabled && params->colorappearance.presetcat02 && params->colorappearance.autotempout) { - // if (params->colorappearance.enabled && params->colorappearance.presetcat02) { + // if (params->colorappearance.enabled && params->colorappearance.autotempout) { + // if (params->colorappearance.enabled) { // acListener->wbCamChanged(params->wb.temperature, params->wb.green); //real temp and tint // acListener->wbCamChanged(params->wb.temperature, 1.f); //real temp and tint = 1. // } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index c9c420b44..3f30374f7 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -1461,8 +1461,7 @@ ColorAppearanceParams::ColorAppearanceParams() : ybout(18), greenout(1.0), tempsc(5003), - greensc(1.0), - presetcat02(false) + greensc(1.0) { } @@ -1512,8 +1511,7 @@ bool ColorAppearanceParams::operator ==(const ColorAppearanceParams& other) cons && ybout == other.ybout && greenout == other.greenout && tempsc == other.tempsc - && greensc == other.greensc - && presetcat02 == other.presetcat02; + && greensc == other.greensc; } bool ColorAppearanceParams::operator !=(const ColorAppearanceParams& other) const @@ -6146,7 +6144,6 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->colorappearance.ybout, "Color appearance", "Ybout", colorappearance.ybout, keyFile); saveToKeyfile(!pedited || pedited->colorappearance.datacie, "Color appearance", "Datacie", colorappearance.datacie, keyFile); saveToKeyfile(!pedited || pedited->colorappearance.tonecie, "Color appearance", "Tonecie", colorappearance.tonecie, keyFile); - saveToKeyfile(!pedited || pedited->colorappearance.presetcat02, "Color appearance", "Presetcat02", colorappearance.presetcat02, keyFile); const std::map ca_mapping = { {ColorAppearanceParams::TcMode::LIGHT, "Lightness"}, @@ -8107,7 +8104,6 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Color appearance", "Ybout", pedited, colorappearance.ybout, pedited->colorappearance.ybout); assignFromKeyfile(keyFile, "Color appearance", "Datacie", pedited, colorappearance.datacie, pedited->colorappearance.datacie); assignFromKeyfile(keyFile, "Color appearance", "Tonecie", pedited, colorappearance.tonecie, pedited->colorappearance.tonecie); - assignFromKeyfile(keyFile, "Color appearance", "Presetcat02", pedited, colorappearance.presetcat02, pedited->colorappearance.presetcat02); const std::map tc_mapping = { {"Lightness", ColorAppearanceParams::TcMode::LIGHT}, diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 309bcb2ab..df319ffcc 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -709,7 +709,6 @@ struct ColorAppearanceParams { double greenout; int tempsc; double greensc; - bool presetcat02; ColorAppearanceParams(); diff --git a/rtgui/colorappearance.cc b/rtgui/colorappearance.cc index a0d341cf2..5cae8cce8 100644 --- a/rtgui/colorappearance.cc +++ b/rtgui/colorappearance.cc @@ -220,7 +220,6 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" milestones.push_back ( GradientMilestone (1., 1., 1., 1.) ); auto m = ProcEventMapper::getInstance(); - Evcatpreset = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_CAT02PRESET"); EvCATAutotempout = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_TEMPOUT"); EvCATillum = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ILLUM"); EvCATcomplex = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_CATCOMPLEX"); @@ -269,10 +268,6 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" catHBox->pack_start(*catmethod); genVBox->pack_start (*catHBox, Gtk::PACK_SHRINK); - presetcat02 = Gtk::manage (new Gtk::CheckButton (M ("TP_COLORAPP_PRESETCAT02"))); - presetcat02->set_tooltip_markup (M("TP_COLORAPP_PRESETCAT02_TOOLTIP")); - presetcat02conn = presetcat02->signal_toggled().connect( sigc::mem_fun(*this, &ColorAppearance::presetcat02pressed)); -// genVBox->pack_start (*presetcat02, Gtk::PACK_SHRINK); genFrame->add (*genVBox); pack_start (*genFrame, Gtk::PACK_EXPAND_WIDGET, 4); @@ -874,7 +869,6 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) tcmodeconn.block (true); tcmode2conn.block (true); tcmode3conn.block (true); - presetcat02conn.block (true); shape->setCurve (pp->colorappearance.curve); shape2->setCurve (pp->colorappearance.curve2); shape3->setCurve (pp->colorappearance.curve3); @@ -882,7 +876,6 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) toneCurveMode2->set_active (toUnderlying(pp->colorappearance.curveMode2)); toneCurveMode3->set_active (toUnderlying(pp->colorappearance.curveMode3)); curveMode3Changed(); // This will set the correct sensitive state of depending Adjusters - presetcat02->set_active(pp->colorappearance.presetcat02); nexttemp = pp->wb.temperature; nextgreen = 1.; //pp->wb.green; @@ -946,7 +939,6 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) if (!pedited->colorappearance.curveMode3) { toneCurveMode3->set_active (3); } - presetcat02->set_inconsistent(!pedited->colorappearance.presetcat02); } @@ -1134,10 +1126,6 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) ybout->setValue (pp->colorappearance.ybout); tempsc->setValue (pp->colorappearance.tempsc); greensc->setValue (pp->colorappearance.greensc); - presetcat02conn.block (true); - presetcat02->set_active (pp->colorappearance.presetcat02); - presetcat02conn.block (false); - lastpresetcat02 = pp->colorappearance.presetcat02; if (complexmethod->get_active_row_number() == 0) { updateGUIToMode(0); @@ -1202,7 +1190,6 @@ void ColorAppearance::write (ProcParams* pp, ParamsEdited* pedited) pp->colorappearance.ybout = ybout->getValue (); pp->colorappearance.tempsc = tempsc->getValue (); pp->colorappearance.greensc = greensc->getValue (); - pp->colorappearance.presetcat02 = presetcat02->get_active(); int tcMode = toneCurveMode->get_active_row_number(); @@ -1276,7 +1263,6 @@ void ColorAppearance::write (ProcParams* pp, ParamsEdited* pedited) pedited->colorappearance.ybout = ybout->getEditedState (); pedited->colorappearance.tempsc = tempsc->getEditedState (); pedited->colorappearance.greensc = greensc->getEditedState (); - pedited->colorappearance.presetcat02 = presetcat02->get_inconsistent (); // pedited->colorappearance.autotempout = !tempout->getAutoInconsistent(); } @@ -1397,10 +1383,6 @@ void ColorAppearance::convertParamToNormal() shape2->reset(); shape3->reset(); wbmodel->set_active (0); - if (presetcat02->get_active ()) { - wbmodel->set_active (2); - illumChanged(); - } if (catmethod->get_active_row_number() == 1 || catmethod->get_active_row_number() == 2) { wbmodel->set_active (2); illumChanged(); @@ -1705,140 +1687,6 @@ void ColorAppearance::badpix_toggled () { } */ -void ColorAppearance::presetcat02pressed () //keep in case of... -{ - if (presetcat02->get_active ()) { - disableListener(); - jlight->resetValue (false); - qbright->resetValue (false); - chroma->resetValue (false); - schroma->resetValue (false); - mchroma->resetValue (false); - rstprotection->resetValue (false); - contrast->resetValue (false); - qcontrast->resetValue (false); - colorh->resetValue (false); - tempout->resetValue (false); - greenout->resetValue (false); - ybout->resetValue (false); - tempsc->resetValue (false); - greensc->resetValue (false); - badpixsl->resetValue (false); - wbmodel->set_active (0); - illum->set_active (2); - toneCurveMode->set_active (0); - toneCurveMode2->set_active (1); - toneCurveMode3->set_active (0); - shape->reset(); - shape2->reset(); - shape3->reset(); - gamutconn.block (true); - gamut->set_active (true); - gamutconn.block (false); - degree->setAutoValue (true); - degree->resetValue (false); - degree->setValue(90); - adapscen->resetValue (false); - adapscen->setAutoValue (true); - degreeout->resetValue (false); - degreeout->setAutoValue (true); - ybscen->resetValue (false); - ybscen->setAutoValue (true); - surrsrc->set_active (0); - wbmodel->set_active (2); - tempsc->resetValue (false); - greensc->resetValue (false); - adapscen->setValue(400.); - ybscen->setValue(18); - surround->set_active (0); - adaplum->setValue(400.); - degreeout->setValue(90); - ybout->setValue(18); - tempout->setValue (nexttemp); - -/* if(tempout->getAutoValue()) { - tempout->resetValue (false); - } else { - tempout->setValue (nexttemp); - tempout->setAutoValue (true); - } -*/ - greenout->setValue (nextgreen); - enableListener(); - } else { - disableListener(); -/* jlight->resetValue (false); - qbright->resetValue (false); - chroma->resetValue (false); - schroma->resetValue (false); - mchroma->resetValue (false); - rstprotection->resetValue (false); - contrast->resetValue (false); - qcontrast->resetValue (false); - colorh->resetValue (false); - tempout->resetValue (false); - greenout->resetValue (false); - ybout->resetValue (false); - tempsc->resetValue (false); - greensc->resetValue (false); - badpixsl->resetValue (false); - wbmodel->set_active (0); - toneCurveMode->set_active (0); - toneCurveMode2->set_active (0); - toneCurveMode3->set_active (0); - shape->reset(); - shape2->reset(); - shape3->reset(); - gamutconn.block (true); - gamut->set_active (true); - gamutconn.block (false); -*/ - degree->setAutoValue (true); - degree->resetValue (false); - adapscen->resetValue (false); - adapscen->setAutoValue (true); - degreeout->resetValue (false); - degreeout->setAutoValue (true); - ybscen->resetValue (false); - ybscen->setAutoValue (true); - surrsrc->set_active (0); - wbmodel->set_active (0); - illum->set_active (2); - tempsc->resetValue (false); - greensc->resetValue (false); - adapscen->resetValue (false); - ybscen->resetValue (false); - surround->set_active (0); - adaplum->resetValue (false); - degreeout->resetValue (false); - ybout->resetValue (false); - tempout->resetValue (false); - greenout->resetValue (false); - enableListener(); - - } - if (batchMode) { - if (presetcat02->get_inconsistent()) { - presetcat02->set_inconsistent (false); - presetcat02conn.block (true); - presetcat02->set_active (false); - presetcat02conn.block (false); - } else if (lastpresetcat02) { - presetcat02->set_inconsistent (true); - } - - lastpresetcat02 = presetcat02->get_active (); - } - - if (listener) { - if (presetcat02->get_active ()) { - listener->panelChanged (Evcatpreset, M ("GENERAL_ENABLED")); - } else { - listener->panelChanged (Evcatpreset, M ("GENERAL_DISABLED")); - } - } - -} void ColorAppearance::datacie_toggled () { @@ -2001,9 +1849,6 @@ void ColorAppearance::autoCamChanged (double ccam, double ccamout) void ColorAppearance::adapCamChanged (double cadap) { - if(presetcat02->get_active()){ - return; - } idle_register.add( [this, cadap]() -> bool @@ -2034,9 +1879,6 @@ void ColorAppearance::wbCamChanged (double temp, double tin) void ColorAppearance::ybCamChanged (int ybsc) { - if(presetcat02->get_active()){ - return; - } idle_register.add( [this, ybsc]() -> bool @@ -2122,16 +1964,6 @@ void ColorAppearance::adjusterChanged(Adjuster* a, double newval) void ColorAppearance::adjusterAutoToggled(Adjuster* a) { - /* - if(presetcat02->get_active ()){ - if(tempout->getAutoValue()) { - tempout->resetValue (false); - } else { - tempout->setValue (nexttemp); - tempout->setAutoValue (true); - } - } -*/ if (multiImage) { if (degree->getAutoInconsistent()) { degree->setAutoInconsistent (false); diff --git a/rtgui/colorappearance.h b/rtgui/colorappearance.h index ce1971e85..d3953c11f 100644 --- a/rtgui/colorappearance.h +++ b/rtgui/colorappearance.h @@ -68,7 +68,6 @@ public: bool adapCamComputed_ (); void ybCamChanged (int yb) override; bool ybCamComputed_ (); - void presetcat02pressed (); void curveChanged (CurveEditor* ce) override; void curveMode1Changed (); bool curveMode1Changed_ (); @@ -106,7 +105,6 @@ public: void writeOptions (std::vector &tpOpen); private: - rtengine::ProcEvent Evcatpreset; rtengine::ProcEvent EvCATAutotempout; rtengine::ProcEvent EvCATillum; rtengine::ProcEvent EvCATcomplex; @@ -159,8 +157,6 @@ private: Gtk::CheckButton* tonecie; // Gtk::CheckButton* sharpcie; Gtk::Button* neutral; - Gtk::CheckButton* presetcat02; - sigc::connection presetcat02conn; MyComboBoxText* surrsrc; sigc::connection surrsrcconn; @@ -198,7 +194,6 @@ private: bool lastgamut; bool lastdatacie; bool lasttonecie; - bool lastpresetcat02; double nexttemp; double nextgreen; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 9c7a92f39..41b19edf2 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -254,7 +254,6 @@ void ParamsEdited::set(bool v) colorappearance.ybout = v; colorappearance.tempsc = v; colorappearance.greensc = v; - colorappearance.presetcat02 = v; //colorBoost.amount = v; //colorBoost.avoidclip = v; @@ -955,7 +954,6 @@ void ParamsEdited::initFrom(const std::vector& colorappearance.ybout = colorappearance.ybout && p.colorappearance.ybout == other.colorappearance.ybout; colorappearance.tempsc = colorappearance.tempsc && p.colorappearance.tempsc == other.colorappearance.tempsc; colorappearance.greensc = colorappearance.greensc && p.colorappearance.greensc == other.colorappearance.greensc; - colorappearance.presetcat02 = colorappearance.presetcat02 && p.colorappearance.presetcat02 == other.colorappearance.presetcat02; //colorBoost.amount = colorBoost.amount && p.colorBoost.amount == other.colorBoost.amount; //colorBoost.avoidclip = colorBoost.avoidclip && p.colorBoost.avoidclip == other.colorBoost.avoidclip; @@ -3034,9 +3032,6 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.colorappearance.tonecie = mods.colorappearance.tonecie; } - if (colorappearance.presetcat02) { - toEdit.colorappearance.presetcat02 = mods.colorappearance.presetcat02; - } // if (colorappearance.sharpcie) toEdit.colorappearance.sharpcie = mods.colorappearance.sharpcie; if (impulseDenoise.enabled) { diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 3c108f33d..43b4e4e40 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -305,7 +305,6 @@ struct ColorAppearanceParamsEdited { bool ybout; bool tempsc; bool greensc; - bool presetcat02; }; struct DirPyrDenoiseParamsEdited { From 21afbaf90bfceaedf0d0e6f836284c4f3f29cbe3 Mon Sep 17 00:00:00 2001 From: Desmis Date: Fri, 6 Jan 2023 06:43:21 +0100 Subject: [PATCH 095/134] CIECAM - Changes such as symmetric works and temperature output makes sense - issue #6656 (#6658) * changes such as symmetric works and temperature output makes sense * Comment code * other Comment code and small change * Change tint in tooltip temperature * Improve GUI for tempout and greenout --- rtdata/languages/default | 1 + rtengine/improccoordinator.cc | 58 +++++++++++++++++++++++++------ rtgui/colorappearance.cc | 65 ++++++++++++++++++++--------------- 3 files changed, 87 insertions(+), 37 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 2631278e5..894ca6963 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2259,6 +2259,7 @@ TP_COLORAPP_TCMODE_LIGHTNESS;Lightness TP_COLORAPP_TCMODE_SATUR;Saturation TP_COLORAPP_TEMP2_TOOLTIP;Either symmetrical mode temp = White balance.\nEither select illuminant always set Tint=1.\n\nA temp=2856\nD41 temp=4100\nD50 temp=5003\nD55 temp=5503\nD60 temp=6000\nD65 temp=6504\nD75 temp=7504 TP_COLORAPP_TEMP_TOOLTIP;To select an illuminant, always set Tint=1.\n\nA temp=2856\nD41 temp=4100\nD50 temp=5003\nD55 temp=5503\nD60 temp=6000\nD65 temp=6504\nD75 temp=7504 +TP_COLORAPP_TEMPOUT_TOOLTIP;Temperature and Tint.\nDepending on the choices made previously, the selected temperature is:\nWhite balance\nA temp=2856\nD41 temp=4100\nD50 temp=5003\nD55 temp=5503\nD60 temp=6000\nD65 temp=6504\nD75 temp=7504\nFree. TP_COLORAPP_TONECIE;Use CIECAM for tone mapping TP_COLORAPP_TONECIE_TOOLTIP;If this option is disabled, tone mapping is done in L*a*b* space.\nIf this option is enabled, tone mapping is done using CIECAM02.\nThe Tone Mapping tool must be enabled for this setting to take effect. TP_COLORAPP_VIEWINGF_TOOLTIP;Takes into account the support on which the final image will be viewed (monitor, TV, projector, printer, etc.), as well as its environment. This process will take the data coming from process 'Image Adjustments' and 'bring' it to the support in such a way that the viewing conditions and its environment are taken into account. diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 2a2f1079b..ec5ffc8ef 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1913,7 +1913,9 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) adap = pow(2.0, E_V - 3.0); // cd / m2 // end calculation adaptation scene luminosity } - + if(params->colorappearance.catmethod == "symg") {//force abolute luminance scenescene to 400 in symmetric + adap = 400.; + } float d, dj, yb; bool execsharp = false; @@ -1935,24 +1937,60 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) CAMBrightCurveQ.dirty = true; ipf.ciecam_02float(ncie, float (adap), pW, 2, nprevl, params.get(), customColCurve1, customColCurve2, customColCurve3, histLCAM, histCCAM, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 0, scale, execsharp, d, dj, yb, 1); - + //call listener if ((params->colorappearance.autodegree || params->colorappearance.autodegreeout) && acListener && params->colorappearance.enabled) { - acListener->autoCamChanged(100.* (double)d, 100.* (double)dj); + if(params->colorappearance.catmethod == "symg") {//force chromatic adaptation to 90 in symmetric + d = 0.9; + dj = 0.9; + } + acListener->autoCamChanged(100.* (double)d, 100.* (double)dj); } if (params->colorappearance.autoadapscen && acListener && params->colorappearance.enabled) { - acListener->adapCamChanged(adap); //real value of adapt scene + acListener->adapCamChanged(adap); //real value of adapt scene, force to 400 in symmetric } if (params->colorappearance.autoybscen && acListener && params->colorappearance.enabled) { + if(params->colorappearance.catmethod == "symg") {//force yb scene to 18 in symmetric + yb = 18; + } + acListener->ybCamChanged((int) yb); //real value Yb scene } - - // if (params->colorappearance.enabled && params->colorappearance.autotempout) { - // if (params->colorappearance.enabled) { - // acListener->wbCamChanged(params->wb.temperature, params->wb.green); //real temp and tint - // acListener->wbCamChanged(params->wb.temperature, 1.f); //real temp and tint = 1. - // } + double tempsym = 5003.; + int wmodel = 0;//wmodel allows - arbitrary - choice of illuminant and temp with choice + if (params->colorappearance.wbmodel == "RawT") { + wmodel = 0; + } else if (params->colorappearance.wbmodel == "RawTCAT02") { + wmodel = 1; + } else if (params->colorappearance.wbmodel == "free") { + wmodel = 2;//force white balance in symmetric + } + + if(params->colorappearance.catmethod == "symg" && wmodel == 2) { + tempsym = params->wb.temperature;//force white balance in symmetric + } else { + if (params->colorappearance.illum == "iA") {//otherwise force illuminant source + tempsym = 2856.; + } else if (params->colorappearance.illum == "i41") { + tempsym = 4100.; + } else if (params->colorappearance.illum == "i50") { + tempsym = 5003.; + } else if (params->colorappearance.illum == "i55") { + tempsym = 5503.; + } else if (params->colorappearance.illum == "i60") { + tempsym = 6000. ; + } else if (params->colorappearance.illum == "i65") { + tempsym = 6504.; + } else if (params->colorappearance.illum == "i75") { + tempsym = 7504.; + } else if (params->colorappearance.illum == "ifree") { + tempsym = params->wb.temperature;//force white balance in symmetric + } + } + if (params->colorappearance.enabled && params->colorappearance.autotempout) { + acListener->wbCamChanged(tempsym, 1.f); //real temp and tint = 1. + } } else { // CIECAM is disabled, we free up its image buffer to save some space diff --git a/rtgui/colorappearance.cc b/rtgui/colorappearance.cc index 5cae8cce8..89661a884 100644 --- a/rtgui/colorappearance.cc +++ b/rtgui/colorappearance.cc @@ -681,14 +681,22 @@ ColorAppearance::ColorAppearance () : FoldableToolPanel (this, "colorappearance" ybout->set_tooltip_markup (M ("TP_COLORAPP_YBOUT_TOOLTIP")); tempout->set_tooltip_markup (M ("TP_COLORAPP_TEMP2_TOOLTIP")); - // tempout->throwOnButtonRelease(); - // tempout->addAutoButton (M ("TP_COLORAPP_TEMPOUT_TOOLTIP")); - + 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 tempout->show(); greenout->show(); ybout->show(); - p3VBox->pack_start (*tempout); - p3VBox->pack_start (*greenout); + Gtk::Frame *tempgreenFrame; + tempgreenFrame = Gtk::manage(new Gtk::Frame()); + tempgreenFrame->set_label_align (0.025, 0.5); + Gtk::Box* tempgreenVBox; + tempgreenVBox = Gtk::manage ( new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); + tempgreenVBox->set_spacing (2); + tempgreenVBox->pack_start (*tempout); + tempgreenVBox->pack_start (*greenout); + tempgreenFrame->add(*tempgreenVBox); + p3VBox->pack_start(*tempgreenFrame); p3VBox->pack_start (*ybout); Gtk::Box* surrHBox = Gtk::manage (new Gtk::Box ()); @@ -822,7 +830,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); @@ -913,7 +921,7 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) adapscen->setAutoInconsistent (multiImage && !pedited->colorappearance.autoadapscen); ybscen->setAutoInconsistent (multiImage && !pedited->colorappearance.autoybscen); set_inconsistent (multiImage && !pedited->colorappearance.enabled); - // tempout->setAutoInconsistent (multiImage && !pedited->colorappearance.autotempout); + tempout->setAutoInconsistent (multiImage && !pedited->colorappearance.autotempout); shape->setUnChanged (!pedited->colorappearance.curve); shape2->setUnChanged (!pedited->colorappearance.curve2); @@ -1098,7 +1106,7 @@ void ColorAppearance::read (const ProcParams* pp, const ParamsEdited* pedited) lastAutoAdapscen = pp->colorappearance.autoadapscen; lastAutoDegreeout = pp->colorappearance.autodegreeout; lastAutoybscen = pp->colorappearance.autoybscen; -// lastAutotempout = pp->colorappearance.autotempout; + lastAutotempout = pp->colorappearance.autotempout; degree->setValue (pp->colorappearance.degree); degree->setAutoValue (pp->colorappearance.autodegree); @@ -1121,7 +1129,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); @@ -1185,7 +1193,7 @@ void ColorAppearance::write (ProcParams* pp, ParamsEdited* pedited) pp->colorappearance.curve2 = shape2->getCurve (); pp->colorappearance.curve3 = shape3->getCurve (); pp->colorappearance.tempout = tempout->getValue (); -// pp->colorappearance.autotempout = tempout->getAutoValue (); + pp->colorappearance.autotempout = tempout->getAutoValue (); pp->colorappearance.greenout = greenout->getValue (); pp->colorappearance.ybout = ybout->getValue (); pp->colorappearance.tempsc = tempsc->getValue (); @@ -1263,7 +1271,7 @@ void ColorAppearance::write (ProcParams* pp, ParamsEdited* pedited) pedited->colorappearance.ybout = ybout->getEditedState (); pedited->colorappearance.tempsc = tempsc->getEditedState (); pedited->colorappearance.greensc = greensc->getEditedState (); -// pedited->colorappearance.autotempout = !tempout->getAutoInconsistent(); + pedited->colorappearance.autotempout = !tempout->getAutoInconsistent(); } @@ -1355,7 +1363,9 @@ void ColorAppearance::updateGUIToMode(int mode) curveEditorG->hide(); curveEditorG2->hide(); curveEditorG3->hide(); - greenout->hide(); + //greenout->hide(); + greenout->set_sensitive(false); + badpixsl->hide(); datacie->hide(); } else { @@ -1364,7 +1374,8 @@ void ColorAppearance::updateGUIToMode(int mode) curveEditorG->show(); curveEditorG2->show(); curveEditorG3->show(); - greenout->show(); + // greenout->show(); + greenout->set_sensitive(true); badpixsl->show(); datacie->show(); } @@ -1470,13 +1481,13 @@ 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); + } else { + tempout->setValue (nexttemp); + tempout->setAutoValue (true); + } + greenout->setValue (nextgreen); enableListener(); @@ -1525,7 +1536,7 @@ void ColorAppearance::catmethodChanged() adaplum->resetValue (false); degreeout->resetValue (false); ybout->resetValue (false); - // tempout->resetValue (false); + tempout->resetValue (false); tempout->setValue (nexttemp); greenout->resetValue (false); enableListener(); @@ -1863,14 +1874,14 @@ void ColorAppearance::adapCamChanged (double cadap) void ColorAppearance::wbCamChanged (double temp, double tin) -{ +{//reactivate this function idle_register.add( [this, temp, tin]() -> bool { disableListener(); tempout->setValue(temp); - greenout->setValue(tin); + greenout->setValue(tin); enableListener(); return false; } @@ -1999,7 +2010,7 @@ void ColorAppearance::adjusterAutoToggled(Adjuster* a) ybscen->setAutoInconsistent (true); } -/* lastAutotempout = tempout->getAutoValue(); + lastAutotempout = tempout->getAutoValue(); if (tempout->getAutoInconsistent()) { tempout->setAutoInconsistent (false); @@ -2009,7 +2020,7 @@ void ColorAppearance::adjusterAutoToggled(Adjuster* a) } lastAutotempout = tempout->getAutoValue(); -*/ + } if (listener && (multiImage || getEnabled()) ) { @@ -2053,7 +2064,7 @@ void ColorAppearance::adjusterAutoToggled(Adjuster* a) listener->panelChanged (EvCATAutoyb, M ("GENERAL_DISABLED")); } } -/* + if (a == tempout) { if (tempout->getAutoInconsistent()) { listener->panelChanged (EvCATAutotempout, M ("GENERAL_UNCHANGED")); @@ -2063,7 +2074,7 @@ void ColorAppearance::adjusterAutoToggled(Adjuster* a) listener->panelChanged (EvCATAutotempout, M ("GENERAL_DISABLED")); } } -*/ + } } void ColorAppearance::enabledChanged () From 5468e74e57aa79af32080be91b2317231694ad35 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 8 Jan 2023 17:20:42 -0800 Subject: [PATCH 096/134] Fall back to custom external editor launcher --- rtgui/extprog.cc | 33 +++++++++++++++++++++++++++------ rtgui/extprog.h | 2 +- rtgui/rtwindow.h | 2 +- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/rtgui/extprog.cc b/rtgui/extprog.cc index e4cf63733..9ec87c548 100644 --- a/rtgui/extprog.cc +++ b/rtgui/extprog.cc @@ -318,22 +318,26 @@ bool ExtProgStore::openInPhotoshop (const Glib::ustring& fileName) return spawnCommandAsync (cmdLine); } -bool ExtProgStore::openInCustomEditor (const Glib::ustring& fileName) +bool ExtProgStore::openInCustomEditor (const Glib::ustring& fileName, const Glib::ustring* command) { + if (!command) { + command = &(options.customEditorProg); + } + #if defined WIN32 - const auto cmdLine = Glib::ustring("\"") + options.customEditorProg + Glib::ustring("\""); + const auto cmdLine = Glib::ustring("\"") + *command + Glib::ustring("\""); auto success = ShellExecute( NULL, "open", cmdLine.c_str(), ('"' + fileName + '"').c_str(), NULL, SW_SHOWNORMAL ); return (uintptr_t)success > 32; #elif defined __APPLE__ - const auto cmdLine = options.customEditorProg + Glib::ustring(" \"") + fileName + Glib::ustring("\""); + const auto cmdLine = *command + Glib::ustring(" \"") + fileName + Glib::ustring("\""); return spawnCommandAsync (cmdLine); #else - const auto cmdLine = options.customEditorProg + Glib::ustring(" ") + Glib::shell_quote(fileName); + const auto cmdLine = *command + Glib::ustring(" ") + Glib::shell_quote(fileName); return spawnCommandAsync (cmdLine); #endif @@ -342,13 +346,30 @@ bool ExtProgStore::openInCustomEditor (const Glib::ustring& fileName) bool ExtProgStore::openInExternalEditor(const Glib::ustring &fileName, const Glib::RefPtr &editorInfo) { + bool success = false; + try { - return editorInfo->launch(Gio::File::create_for_path(fileName)); + success = editorInfo->launch(Gio::File::create_for_path(fileName)); } catch (const Glib::Error &e) { std::cerr << "Error launching external editor.\n" << "Error code #" << e.code() << ": " << e.what() << std::endl; - return false; + success = false; } + + if (success) { + return true; + } + + if (rtengine::settings->verbose) { + std::cout << "Unable to launch external editor with Gio. Trying custom launcher." << std::endl; + } + Glib::ustring command = editorInfo->get_commandline(); +#if defined WIN32 + if (command.length() > 2 && command[0] == '"' && command[command.length() - 1] == '"') { + command = command.substr(1, command.length() - 2); + } +#endif + return openInCustomEditor(fileName, &command); } diff --git a/rtgui/extprog.h b/rtgui/extprog.h index cdcf14e48..6547896ef 100644 --- a/rtgui/extprog.h +++ b/rtgui/extprog.h @@ -69,7 +69,7 @@ public: static bool openInGimp (const Glib::ustring& fileName); static bool openInPhotoshop (const Glib::ustring& fileName); - static bool openInCustomEditor (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); }; diff --git a/rtgui/rtwindow.h b/rtgui/rtwindow.h index f62430190..985cd3893 100755 --- a/rtgui/rtwindow.h +++ b/rtgui/rtwindow.h @@ -33,7 +33,7 @@ class BatchQueueEntry; class BatchQueuePanel; class EditorPanel; -class ExternalEditor; +struct ExternalEditor; class FilePanel; class PLDBridge; class RTWindow final : From 194ef397a677eb1bdc435c376cfd075c14c51788 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 8 Jan 2023 22:17:21 -0800 Subject: [PATCH 097/134] Fix external editor file chooser filter (Windows) Look for files with the MIME type "application/x-msdownload", which are Windows executable files. The Gio function for determining if a file is executable does not work for Windows. --- rtgui/externaleditorpreferences.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rtgui/externaleditorpreferences.cc b/rtgui/externaleditorpreferences.cc index 58a562725..79dac52d2 100644 --- a/rtgui/externaleditorpreferences.cc +++ b/rtgui/externaleditorpreferences.cc @@ -274,7 +274,11 @@ void ExternalEditorPreferences::openFileChooserDialog() const auto exe_filter = Gtk::FileFilter::create(); exe_filter->set_name(M("FILECHOOSER_FILTER_EXECUTABLE")); exe_filter->add_custom(Gtk::FILE_FILTER_MIME_TYPE, [](const Gtk::FileFilter::Info &info) { +#ifdef WIN32 + return info.mime_type == "application/x-msdownload"; +#else return Gio::content_type_can_be_executable(info.mime_type); +#endif }); const auto all_filter = Gtk::FileFilter::create(); all_filter->set_name(M("FILECHOOSER_FILTER_ANY")); From 22edf5f0697dbdafa51744b9c03dcc673e7de957 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Sun, 15 Jan 2023 15:10:54 -0800 Subject: [PATCH 098/134] Add radio indicator to external editor selector Make it easier to see that the selector is for changing the current editor and not for immediately sending the image to the clicked-on editor. --- rtdata/themes/TooWaBlue-GTK3-20_.css | 5 ++ rtdata/themes/size - Legacy.css | 7 +- rtdata/themes/size.css | 5 ++ rtgui/editorpanel.cc | 16 ++-- rtgui/editorpanel.h | 1 + rtgui/guiutils.cc | 108 +++++++++++++++++++++------ rtgui/guiutils.h | 56 +++++++++++--- rtgui/popupcommon.cc | 35 ++++++--- rtgui/popupcommon.h | 9 ++- 9 files changed, 186 insertions(+), 56 deletions(-) diff --git a/rtdata/themes/TooWaBlue-GTK3-20_.css b/rtdata/themes/TooWaBlue-GTK3-20_.css index 4e7e192ad..d2a63dd2e 100644 --- a/rtdata/themes/TooWaBlue-GTK3-20_.css +++ b/rtdata/themes/TooWaBlue-GTK3-20_.css @@ -1278,6 +1278,11 @@ menuitem:hover > * { color: @text-hl-color; } +menu menuitem > radio + * image:not(.dummy), +#MyExpander menu menuitem > radio + * image:not(.dummy) { + margin-left: 1pt; +} + menu image:not(.dummy), #MyExpander menu image:not(.dummy) { min-height: 2em; diff --git a/rtdata/themes/size - Legacy.css b/rtdata/themes/size - Legacy.css index 08c39f973..089a909ee 100644 --- a/rtdata/themes/size - Legacy.css +++ b/rtdata/themes/size - Legacy.css @@ -383,6 +383,11 @@ menu arrow { margin: 0 -0.25em 0 0; } +menu menuitem > radio + * image:not(.dummy), +#MyExpander menu menuitem > radio + * image:not(.dummy) { + margin-left: 1pt; +} + menu image:not(.dummy), #MyExpander menu image:not(.dummy) { min-height: 2em; @@ -1029,4 +1034,4 @@ messagedialog headerbar button.titlebutton { min-height: 1.25em; margin: 0; } -/*** end ***************************************************************************************/ \ No newline at end of file +/*** end ***************************************************************************************/ diff --git a/rtdata/themes/size.css b/rtdata/themes/size.css index 2d23bf860..675ed51c2 100644 --- a/rtdata/themes/size.css +++ b/rtdata/themes/size.css @@ -351,6 +351,11 @@ menu arrow { margin: 0 -0.25em 0 0; } +menu menuitem > radio + * image:not(.dummy), +#MyExpander menu menuitem > radio + * image:not(.dummy) { + margin-left: 1pt; +} + menu image:not(.dummy), #MyExpander menu image:not(.dummy) { min-height: 2em; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 3a180cc58..ebcf221da 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -905,7 +905,6 @@ EditorPanel::EditorPanel (FilePanel* filePanel) send_to_external = Gtk::manage(new PopUpButton("", false)); send_to_external->set_tooltip_text(M("MAIN_BUTTON_SENDTOEDITOR_TOOLTIP")); setExpandAlignProperties(send_to_external->buttonGroup, false, false, Gtk::ALIGN_CENTER, Gtk::ALIGN_FILL); - send_to_external->addEntry("palette-brush.png", M("GENERAL_OTHER")); updateExternalEditorWidget( options.externalEditorIndex >= 0 ? options.externalEditorIndex : options.externalEditors.size(), options.externalEditors @@ -2748,10 +2747,14 @@ void EditorPanel::tbShowHideSidePanels_managestate() void EditorPanel::updateExternalEditorWidget(int selectedIndex, const std::vector &editors) { - // Remove the editors and leave the "Other" entry. - while (send_to_external->getEntryCount() > 1) { - send_to_external->removeEntry(0); + // Remove the editors. + while (send_to_external->getEntryCount()) { + send_to_external->removeEntry(send_to_external->getEntryCount() - 1); } + + // Create new radio button group because they cannot be reused: https://developer-old.gnome.org/gtkmm/3.16/classGtk_1_1RadioButtonGroup.html#details. + send_to_external_radio_group = Gtk::RadioButtonGroup(); + // Add the editors. for (unsigned i = 0; i < editors.size(); i++) { const auto & name = editors[i].name.empty() ? Glib::ustring(" ") : editors[i].name; @@ -2771,11 +2774,12 @@ void EditorPanel::updateExternalEditorWidget(int selectedIndex, const std::vecto gioIcon = Gio::Icon::deserialize(Glib::VariantBase(icon_variant)); } - send_to_external->insertEntry(i, gioIcon, name); + send_to_external->insertEntry(i, gioIcon, name, &send_to_external_radio_group); } else { - send_to_external->insertEntry(i, "palette-brush.png", name); + send_to_external->insertEntry(i, "palette-brush.png", name, &send_to_external_radio_group); } } + send_to_external->addEntry("palette-brush.png", M("GENERAL_OTHER"), &send_to_external_radio_group); send_to_external->setSelected(selectedIndex); send_to_external->show(); } diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index e822f1677..fa7f7943b 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -246,6 +246,7 @@ private: Gtk::Button* queueimg; Gtk::Button* saveimgas; PopUpButton* send_to_external; + Gtk::RadioButtonGroup send_to_external_radio_group; Gtk::Button* navSync; Gtk::Button* navNext; Gtk::Button* navPrev; diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index 522ec9b7f..18b82fe36 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -1506,48 +1506,110 @@ TextOrIcon::TextOrIcon (const Glib::ustring &fname, const Glib::ustring &labelTx } -MyImageMenuItem::MyImageMenuItem(Glib::ustring label, Glib::ustring imageFileName) +class ImageAndLabel::Impl { - RTImage* itemImage = nullptr; +public: + RTImage* image; + Gtk::Label* label; - if (!imageFileName.empty()) { - itemImage = Gtk::manage(new RTImage(imageFileName)); + Impl(RTImage* image, Gtk::Label* label) : image(image), label(label) {} + static std::unique_ptr createImage(const Glib::ustring& fileName); +}; + +std::unique_ptr ImageAndLabel::Impl::createImage(const Glib::ustring& fileName) +{ + if (fileName.empty()) { + return nullptr; } - - construct(label, itemImage); + return std::unique_ptr(new RTImage(fileName)); } -MyImageMenuItem::MyImageMenuItem(Glib::ustring label, RTImage* itemImage) { - construct(label, itemImage); +ImageAndLabel::ImageAndLabel(const Glib::ustring& label, const Glib::ustring& imageFileName) : + ImageAndLabel(label, Gtk::manage(Impl::createImage(imageFileName).release())) +{ } -void MyImageMenuItem::construct(Glib::ustring label, RTImage* itemImage) +ImageAndLabel::ImageAndLabel(const Glib::ustring& label, RTImage *image) : + pimpl(new Impl(image, Gtk::manage(new Gtk::Label(label)))) { - box = Gtk::manage (new Gtk::Grid()); - this->label = Gtk::manage( new Gtk::Label(label)); - box->set_orientation(Gtk::ORIENTATION_HORIZONTAL); + Gtk::Grid* grid = Gtk::manage(new Gtk::Grid()); + grid->set_orientation(Gtk::ORIENTATION_HORIZONTAL); - if (itemImage) { - image = itemImage; - box->attach_next_to(*image, Gtk::POS_LEFT, 1, 1); - } else { - image = nullptr; + if (image) { + grid->attach_next_to(*image, Gtk::POS_LEFT, 1, 1); } - box->attach_next_to(*this->label, Gtk::POS_RIGHT, 1, 1); - box->set_column_spacing(4); - box->set_row_spacing(0); - add(*box); + grid->attach_next_to(*(pimpl->label), Gtk::POS_RIGHT, 1, 1); + grid->set_column_spacing(4); + grid->set_row_spacing(0); + pack_start(*grid, Gtk::PACK_SHRINK, 0); +} + +const RTImage* ImageAndLabel::getImage() const +{ + return pimpl->image; +} + +const Gtk::Label* ImageAndLabel::getLabel() const +{ + return pimpl->label; +} + +class MyImageMenuItem::Impl +{ +private: + std::unique_ptr widget; + +public: + Impl(const Glib::ustring &label, const Glib::ustring &imageFileName) : + widget(new ImageAndLabel(label, imageFileName)) {} + Impl(const Glib::ustring &label, RTImage *itemImage) : + widget(new ImageAndLabel(label, itemImage)) {} + ImageAndLabel* getWidget() const { return widget.get(); } +}; + +MyImageMenuItem::MyImageMenuItem(const Glib::ustring& label, const Glib::ustring& imageFileName) : + pimpl(new Impl(label, imageFileName)) +{ + add(*(pimpl->getWidget())); +} + +MyImageMenuItem::MyImageMenuItem(const Glib::ustring& label, RTImage* itemImage) : + pimpl(new Impl(label, itemImage)) +{ + add(*(pimpl->getWidget())); } const RTImage *MyImageMenuItem::getImage () const { - return image; + return pimpl->getWidget()->getImage(); } const Gtk::Label* MyImageMenuItem::getLabel () const { - return label; + return pimpl->getWidget()->getLabel(); +} + +class MyRadioImageMenuItem::Impl +{ + std::unique_ptr widget; + +public: + Impl(const Glib::ustring &label, RTImage *image) : + widget(new ImageAndLabel(label, image)) {} + ImageAndLabel* getWidget() const { return widget.get(); } +}; + +MyRadioImageMenuItem::MyRadioImageMenuItem(const Glib::ustring& label, RTImage *image, Gtk::RadioButton::Group& group) : + Gtk::RadioMenuItem(group), + pimpl(new Impl(label, image)) +{ + add(*(pimpl->getWidget())); +} + +const Gtk::Label* MyRadioImageMenuItem::getLabel() const +{ + return pimpl->getWidget()->getLabel(); } MyProgressBar::MyProgressBar(int width) : w(rtengine::max(width, 10 * RTScalable::getScale())) {} diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index d133599f2..938c81c42 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -482,20 +482,56 @@ public: TextOrIcon (const Glib::ustring &filename, const Glib::ustring &labelTx, const Glib::ustring &tooltipTx); }; -class MyImageMenuItem final : public Gtk::MenuItem +/** + * Widget with image and label placed horizontally. + */ +class ImageAndLabel final : public Gtk::Box { -private: - Gtk::Grid *box; - RTImage *image; - Gtk::Label *label; - - void construct(Glib::ustring label, RTImage* image); + class Impl; + std::unique_ptr pimpl; public: - MyImageMenuItem (Glib::ustring label, Glib::ustring imageFileName); - MyImageMenuItem (Glib::ustring label, RTImage* image); + ImageAndLabel(const Glib::ustring& label, const Glib::ustring& imageFileName); + ImageAndLabel(const Glib::ustring& label, RTImage* image); + const RTImage* getImage() const; + const Gtk::Label* getLabel() const; +}; + +/** + * Menu item with an image and label. + */ +class MyImageMenuItemInterface +{ +public: + virtual const Gtk::Label* getLabel() const = 0; +}; + +/** + * Basic image menu item. + */ +class MyImageMenuItem final : public Gtk::MenuItem, public MyImageMenuItemInterface +{ + class Impl; + std::unique_ptr pimpl; + +public: + MyImageMenuItem (const Glib::ustring& label, const Glib::ustring& imageFileName); + MyImageMenuItem (const Glib::ustring& label, RTImage* image); const RTImage *getImage () const; - const Gtk::Label* getLabel () const; + const Gtk::Label* getLabel() const override; +}; + +/** + * Image menu item with radio selector. + */ +class MyRadioImageMenuItem final : public Gtk::RadioMenuItem, public MyImageMenuItemInterface +{ + class Impl; + std::unique_ptr pimpl; + +public: + MyRadioImageMenuItem(const Glib::ustring& label, RTImage* image, Gtk::RadioButton::Group& group); + const Gtk::Label* getLabel() const override; }; class MyProgressBar final : public Gtk::ProgressBar diff --git a/rtgui/popupcommon.cc b/rtgui/popupcommon.cc index 1dbde833e..a6d9b6046 100644 --- a/rtgui/popupcommon.cc +++ b/rtgui/popupcommon.cc @@ -73,44 +73,50 @@ PopUpCommon::~PopUpCommon () { } -bool PopUpCommon::addEntry (const Glib::ustring& fileName, const Glib::ustring& label) +bool PopUpCommon::addEntry (const Glib::ustring& fileName, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup) { - return insertEntry(getEntryCount(), fileName, label); + return insertEntry(getEntryCount(), fileName, label, radioGroup); } -bool PopUpCommon::insertEntry(int position, const Glib::ustring& fileName, const Glib::ustring& label) +bool PopUpCommon::insertEntry(int position, const Glib::ustring& fileName, const Glib::ustring& label, Gtk::RadioButtonGroup *radioGroup) { RTImage* image = nullptr; if (!fileName.empty()) { image = Gtk::manage(new RTImage(fileName)); } - bool success = insertEntryImpl(position, fileName, Glib::RefPtr(), image, label); + bool success = insertEntryImpl(position, fileName, Glib::RefPtr(), image, label, radioGroup); if (!success && image) { delete image; } return success; } -bool PopUpCommon::insertEntry(int position, const Glib::RefPtr& gIcon, const Glib::ustring& label) +bool PopUpCommon::insertEntry(int position, const Glib::RefPtr& gIcon, const Glib::ustring& label, Gtk::RadioButtonGroup *radioGroup) { RTImage* image = Gtk::manage(new RTImage(gIcon, Gtk::ICON_SIZE_BUTTON)); - bool success = insertEntryImpl(position, "", gIcon, image, label); + bool success = insertEntryImpl(position, "", gIcon, image, label, radioGroup); if (!success) { delete image; } return success; } -bool PopUpCommon::insertEntryImpl(int position, const Glib::ustring& fileName, const Glib::RefPtr& gIcon, RTImage* image, const Glib::ustring& label) +bool PopUpCommon::insertEntryImpl(int position, const Glib::ustring& fileName, const Glib::RefPtr& gIcon, RTImage* image, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup) { if (label.empty() || position < 0 || position > getEntryCount()) return false; // Create the menu item and image - MyImageMenuItem *newItem = Gtk::manage(new MyImageMenuItem(label, image)); + Gtk::MenuItem *newItem; + if (radioGroup) { + newItem = Gtk::manage(new MyRadioImageMenuItem(label, image, *radioGroup)); + } + else { + newItem = Gtk::manage(new MyImageMenuItem(label, image)); + } imageIcons.insert(imageIcons.begin() + position, gIcon); imageFilenames.insert(imageFilenames.begin() + position, fileName); - images.insert(images.begin() + position, newItem->getImage()); + images.insert(images.begin() + position, image); // When there is at least 1 choice, we add the arrow button if (images.size() == 1) { @@ -154,9 +160,8 @@ void PopUpCommon::removeEntry(int position) setButtonHint(); } - MyImageMenuItem *menuItem = dynamic_cast(menu->get_children()[position]); + std::unique_ptr menuItem(menu->get_children()[position]); menu->remove(*menuItem); - delete menuItem; imageIcons.erase(imageIcons.begin() + position); imageFilenames.erase(imageFilenames.begin() + position); images.erase(images.begin() + position); @@ -222,6 +227,12 @@ bool PopUpCommon::setSelected (int entryNum) changeImage(entryNum); selected = entryNum; setButtonHint(); + + auto radioMenuItem = dynamic_cast(menu->get_children()[entryNum]); + if (radioMenuItem && menu->get_active() != radioMenuItem) { + radioMenuItem->set_active(); + } + return true; } } @@ -248,7 +259,7 @@ void PopUpCommon::setButtonHint() if (selected > -1) { auto widget = menu->get_children ()[selected]; - auto item = dynamic_cast(widget); + auto item = dynamic_cast(widget); if (item) { hint += escapeHtmlChars(item->getLabel()->get_text()); diff --git a/rtgui/popupcommon.h b/rtgui/popupcommon.h index 59a5b8d0e..9ca6b2030 100644 --- a/rtgui/popupcommon.h +++ b/rtgui/popupcommon.h @@ -40,6 +40,7 @@ class Grid; class Menu; class Button; class ImageMenuItem; +class RadioButtonGroup; class Widget; } @@ -60,9 +61,9 @@ public: explicit PopUpCommon (Gtk::Button* button, const Glib::ustring& label = ""); virtual ~PopUpCommon (); - bool addEntry (const Glib::ustring& fileName, const Glib::ustring& label); - bool insertEntry(int position, const Glib::ustring& fileName, const Glib::ustring& label); - bool insertEntry(int position, const Glib::RefPtr& gIcon, const Glib::ustring& label); + bool addEntry (const Glib::ustring& fileName, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup = nullptr); + bool insertEntry(int position, const Glib::ustring& fileName, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup = nullptr); + bool insertEntry(int position, const Glib::RefPtr& gIcon, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup = nullptr); int getEntryCount () const; bool setSelected (int entryNum); int getSelected () const; @@ -91,7 +92,7 @@ private: void changeImage(int position); void changeImage(const Glib::ustring& fileName, const Glib::RefPtr& gIcon); void entrySelected(Gtk::Widget* menuItem); - bool insertEntryImpl(int position, const Glib::ustring& fileName, const Glib::RefPtr& gIcon, RTImage* image, const Glib::ustring& label); + bool insertEntryImpl(int position, const Glib::ustring& fileName, const Glib::RefPtr& gIcon, RTImage* image, const Glib::ustring& label, Gtk::RadioButtonGroup* radioGroup); void showMenu(GdkEventButton* event); protected: From 48b1b6f9be55303046bda82edff70fc6c3bccad2 Mon Sep 17 00:00:00 2001 From: Lawrence Lee <45837045+Lawrence37@users.noreply.github.com> Date: Tue, 17 Jan 2023 22:06:58 -0800 Subject: [PATCH 099/134] Add OM-1 raw decoding and basic camconst entry --- rtengine/camconst.json | 10 ++++++++++ rtengine/dcraw.cc | 8 ++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 7a143e850..d90cc169b 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -2170,6 +2170,16 @@ Camera constants: "dcraw_matrix" : [8360, -2420, -880, -3928, 12353, 1739, -1381, 2416, 5173] // DNG }, + { // Quality C + "make_model": ["OM Digital Solutions OM-1"], + "ranges": { "white": 4095 }, + "raw_crop" : [ + { "frame" : [10400, 7792], "crop": [0, 0, 10390, 7792] }, + { "frame" : [8180, 6132], "crop": [0, 0, 8172, 6132] }, + { "frame" : [5220, 3912], "crop": [0, 0, 5220, 3912] } + ] + }, + { // Quality B "make_model": [ "Panasonic DC-LX100M2" ], "dcraw_matrix": [ 11577, -4230, -1106, -3967, 12211, 1957, -759, 1762, 5610 ], // DNG v13.2 diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 8eca727b4..7a2a5b4d5 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -5546,9 +5546,11 @@ void CLASS parse_makernote (int base, int uptag) offset = get4(); fseek (ifp, offset-8, SEEK_CUR); } else if (!strcmp (buf,"OLYMPUS") || - !strcmp (buf,"PENTAX ")) { + !strcmp (buf,"PENTAX ") || + !strncmp(buf,"OM SYS",6)) { // From LibRaw base = ftell(ifp)-10; fseek (ifp, -2, SEEK_CUR); + if (buf[1] == 'M') get4(); // From LibRaw order = get2(); if (buf[0] == 'O') get2(); } else if (!strncmp (buf,"SONY",4) || @@ -7172,7 +7174,7 @@ void CLASS apply_tiff() if (tiff_ifd[raw].bytes*4 == raw_width*raw_height*7) break; load_flags = 0; case 16: load_raw = &CLASS unpacked_load_raw; - if (!strncmp(make,"OLYMPUS",7) && + if ((!strncmp(make,"OLYMPUS",7) || !strncmp(make, "OM Digi", 7)) && // OM Digi from LibRaw tiff_ifd[raw].bytes*7 > raw_width*raw_height) load_raw = &CLASS olympus_load_raw; // ------- RT ------- @@ -8704,6 +8706,8 @@ void CLASS adobe_coeff (const char *make, const char *model) { 10901,-4095,-1074,-1141,9208,2293,-62,1417,5158 } }, { "Olympus XZ-2", 0, 0, { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, + { "OM Digital Solutions OM-1", 0, 0, + { 9488, -3984, -714, -2887, 10945, 2229, -137, 960, 5786 } }, // From LibRaw { "OmniVision", 0, 0, /* DJC */ { 12782,-4059,-379,-478,9066,1413,1340,1513,5176 } }, { "Pentax *ist DL2", 0, 0, From 7afdfc1e2bc17b8c4268397651a344fe7fb9dc15 Mon Sep 17 00:00:00 2001 From: Desmis Date: Tue, 24 Jan 2023 14:29:50 +0100 Subject: [PATCH 100/134] Abstract profile - Gamut improvment (#6665) * Gamut control when the chosen primaries are different from working profile * Gamut control abstract * Gamut label and history * Change to Wx Wz * Fixed crash if y primaries are set to zero * Fomated with Astylert ImProcFunctions::workingtrc and Color::primaries_to_xyz * Fixed black becomes green wit gamt abstract profile * Harmonize types in color.cc * Try to fix Multiplication result converted to larger type --- rtdata/languages/default | 2 + rtengine/color.cc | 176 ++++++++++++++++++++++++++++++-- rtengine/color.h | 7 ++ rtengine/iplab2rgb.cc | 211 +++++++++++++++++++++++++++++++-------- rtengine/procparams.cc | 4 + rtengine/procparams.h | 1 + rtgui/icmpanel.cc | 53 ++++++++++ rtgui/icmpanel.h | 5 + rtgui/paramsedited.cc | 6 ++ rtgui/paramsedited.h | 1 + 10 files changed, 415 insertions(+), 51 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 894ca6963..8120419d2 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1421,6 +1421,7 @@ HISTORY_MSG_ICM_AINTENT;Abstract profile intent HISTORY_MSG_ICM_BLUX;Primaries Blue X HISTORY_MSG_ICM_BLUY;Primaries Blue Y HISTORY_MSG_ICM_FBW;Black and White +HISTORY_MSG_ICM_GAMUT;Gamut control HISTORY_MSG_ICM_GREX;Primaries Green X HISTORY_MSG_ICM_GREY;Primaries Green Y HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries @@ -2529,6 +2530,7 @@ TP_ICM_DCPILLUMINANT;Illuminant TP_ICM_DCPILLUMINANT_INTERPOLATED;Interpolated TP_ICM_DCPILLUMINANT_TOOLTIP;Select which embedded DCP illuminant to employ. Default is 'interpolated' which is a mix between the two based on white balance. The setting is only available if a dual-illuminant DCP with interpolation support is selected. TP_ICM_FBW;Black-and-White +TP_ICM_GAMUT;Gamut control TP_ICM_ILLUMPRIM_TOOLTIP;Choose the illuminant closest to the shooting conditions.\nChanges can only be made when the 'Destination primaries' selection is set to 'Custom (sliders)'. TP_ICM_INPUTCAMERA;Camera standard TP_ICM_INPUTCAMERAICC;Auto-matched camera profile diff --git a/rtengine/color.cc b/rtengine/color.cc index d6c35208d..085fd41ce 100644 --- a/rtengine/color.cc +++ b/rtengine/color.cc @@ -24,6 +24,7 @@ #include "sleef.h" #include "opthelper.h" #include "iccstore.h" +#include using namespace std; @@ -1910,6 +1911,152 @@ void Color::Lch2Luv(float c, float h, float &u, float &v) v = c * sincosval.y; } +void Color::primaries_to_xyz(double p[6], double Wx, double Wz, double *pxyz) +{ + //calculate Xr, Xg, Xb, Yr, Yb, Tg, Zr,Zg Zb + double Wy = 1.0; + double Xr = p[0] / p[1]; + double Yr = 1.0; + double Zr = (1.0 - p[0] - p[1]) / p[1]; + double Xg = p[2] / p[3]; + double Yg = 1.0; + double Zg = (1.0 - p[2] - p[3]) / p[3]; + double Xb = p[4] / p[5]; + double Yb = 1.0; + double Zb = (1.0 - p[4] - p[5]) / p[5]; + + using Triple = std::array; + + using Matrix = std::array; + + Matrix input_prim; + Matrix inv_input_prim = {}; + input_prim[0][0] = Xr; + input_prim[0][1] = Yr; + input_prim[0][2] = Zr; + input_prim[1][0] = Xg; + input_prim[1][1] = Yg; + input_prim[1][2] = Zg; + input_prim[2][0] = Xb; + input_prim[2][1] = Yb; + input_prim[2][2] = Zb; + + //invert matrix + if (!rtengine::invertMatrix(input_prim, inv_input_prim)) { + std::cout << "Matrix is not invertible, skipping" << std::endl; + } + + //white point D50 used by LCMS + double Wdx = 0.96420; + double Wdy = 1.0; + double Wdz = 0.82490; + + double Sr = Wx * inv_input_prim [0][0] + Wy * inv_input_prim [1][0] + Wz * inv_input_prim [2][0]; + double Sg = Wx * inv_input_prim [0][1] + Wy * inv_input_prim [1][1] + Wz * inv_input_prim [2][1]; + double Sb = Wx * inv_input_prim [0][2] + Wy * inv_input_prim [1][2] + Wz * inv_input_prim [2][2]; + + //XYZ matrix for primaries and temp + Matrix mat_xyz = {}; + mat_xyz[0][0] = Sr * Xr; + mat_xyz[0][1] = Sr * Yr; + mat_xyz[0][2] = Sr * Zr; + mat_xyz[1][0] = Sg * Xg; + mat_xyz[1][1] = Sg * Yg; + mat_xyz[1][2] = Sg * Zg; + mat_xyz[2][0] = Sb * Xb; + mat_xyz[2][1] = Sb * Yb; + mat_xyz[2][2] = Sb * Zb; + + //chromatic adaptation Bradford + Matrix MaBradford = {}; + MaBradford[0][0] = 0.8951; + MaBradford[0][1] = -0.7502; + MaBradford[0][2] = 0.0389; + MaBradford[1][0] = 0.2664; + MaBradford[1][1] = 1.7135; + MaBradford[1][2] = -0.0685; + MaBradford[2][0] = -0.1614; + MaBradford[2][1] = 0.0367; + MaBradford[2][2] = 1.0296; + + Matrix Ma_oneBradford = {}; + Ma_oneBradford[0][0] = 0.9869929; + Ma_oneBradford[0][1] = 0.4323053; + Ma_oneBradford[0][2] = -0.0085287; + Ma_oneBradford[1][0] = -0.1470543; + Ma_oneBradford[1][1] = 0.5183603; + Ma_oneBradford[1][2] = 0.0400428; + Ma_oneBradford[2][0] = 0.1599627; + Ma_oneBradford[2][1] = 0.0492912; + Ma_oneBradford[2][2] = 0.9684867; + + //R G B source + double Rs = Wx * MaBradford[0][0] + Wy * MaBradford[1][0] + Wz * MaBradford[2][0]; + double Gs = Wx * MaBradford[0][1] + Wy * MaBradford[1][1] + Wz * MaBradford[2][1]; + double Bs = Wx * MaBradford[0][2] + Wy * MaBradford[1][2] + Wz * MaBradford[2][2]; + + // R G B destination + double Rd = Wdx * MaBradford[0][0] + Wdy * MaBradford[1][0] + Wdz * MaBradford[2][0]; + double Gd = Wdx * MaBradford[0][1] + Wdy * MaBradford[1][1] + Wdz * MaBradford[2][1]; + double Bd = Wdx * MaBradford[0][2] + Wdy * MaBradford[1][2] + Wdz * MaBradford[2][2]; + + //cone destination + Matrix cone_dest_sourc = {}; + cone_dest_sourc [0][0] = Rd / Rs; + cone_dest_sourc [0][1] = 0.; + cone_dest_sourc [0][2] = 0.; + cone_dest_sourc [1][0] = 0.; + cone_dest_sourc [1][1] = Gd / Gs; + cone_dest_sourc [1][2] = 0.; + cone_dest_sourc [2][0] = 0.; + cone_dest_sourc [2][1] = 0.; + cone_dest_sourc [2][2] = Bd / Bs; + + //cone dest + Matrix cone_ma_one = {}; + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + cone_ma_one[i][j] = 0; + + for (int k = 0; k < 3; ++k) { + cone_ma_one[i][j] += cone_dest_sourc [i][k] * Ma_oneBradford[k][j]; + } + } + } + + //generate adaptation bradford matrix + Matrix adapt_chroma = {}; + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + adapt_chroma [i][j] = 0; + + for (int k = 0; k < 3; ++k) { + adapt_chroma[i][j] += MaBradford[i][k] * cone_ma_one[k][j]; + } + } + } + + Matrix mat_xyz_brad = {}; + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + mat_xyz_brad[i][j] = 0; + + for (int k = 0; k < 3; ++k) { + mat_xyz_brad[i][j] += mat_xyz[i][k] * adapt_chroma[k][j]; + } + } + } + + //push result in pxyz + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + pxyz[i * 3 + j] = mat_xyz_brad[i][j]; + } + } +} /* * Gamut mapping algorithm @@ -1931,13 +2078,19 @@ void Color::Lch2Luv(float c, float h, float &u, float &v) * columns of the matrix p=xyz_rgb are RGB tristimulus primaries in XYZ * c is the color fixed on the boundary; and m=0 for c=0, m=1 for c=255 */ + void Color::gamutmap(float &X, float Y, float &Z, const double p[3][3]) { - float u = 4 * X / (X + 15 * Y + 3 * Z) - u0; - float v = 9 * Y / (X + 15 * Y + 3 * Z) - v0; - + float epsil = 0.0001f; + float intermXYZ = X + 15 * Y + 3 * Z; + if(intermXYZ <= 0.f) { + intermXYZ = epsil; + } + + float u = 4 * X / (intermXYZ) - u0; + float v = 9 * Y / (intermXYZ) - v0; float lam[3][2]; - float lam_min = 1.0; + float lam_min = 1.0f; for (int c = 0; c < 3; c++) for (int m = 0; m < 2; m++) { @@ -1955,17 +2108,24 @@ void Color::gamutmap(float &X, float Y, float &Z, const double p[3][3]) p[0][c] * (5 * Y * p[1][c1] + m * 65535 * p[1][c1] * p[2][c2] + Y * p[2][c1] - m * 65535 * p[1][c2] * p[2][c1]) + m * 65535 * p[0][c2] * (p[1][c1] * p[2][c] - p[1][c] * p[2][c1]))); - if (lam[c][m] < lam_min && lam[c][m] > 0) { + if (lam[c][m] < lam_min && lam[c][m] > 0.f) { lam_min = lam[c][m]; } } - u = u * lam_min + u0; - v = v * lam_min + v0; + u = u * (double) lam_min + u0; + v = v * (double) lam_min + v0; X = (9 * u * Y) / (4 * v); - Z = (12 - 3 * u - 20 * v) * Y / (4 * v); + float intermuv = 12 - 3 * u - 20 * v; + if(intermuv < 0.f) { + intermuv = 0.f; + } + Z = (intermuv) * Y / (4 * v); + + + } void Color::skinredfloat ( float J, float h, float sres, float Sp, float dred, float protect_red, int sk, float rstprotection, float ko, float &s) diff --git a/rtengine/color.h b/rtengine/color.h index f602ade83..3622a9e36 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -1847,6 +1847,13 @@ static inline void Lab2XYZ(vfloat L, vfloat a, vfloat b, vfloat &x, vfloat &y, v */ static void gamutmap(float &X, float Y, float &Z, const double p[3][3]); + /** + * @brief Convert primaries in XYZ values in function of illuminant + * @param p primaries red, gree, blue + * @param Wx Wy white for illuminant + * @param pxyz return matrix XYZ + */ + static void primaries_to_xyz (double p[6], double Wx, double Wz, double *pxyz); /** * @brief Get HSV's hue from the Lab's hue diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc index f48b2e52e..dd02b8f0f 100644 --- a/rtengine/iplab2rgb.cc +++ b/rtengine/iplab2rgb.cc @@ -416,6 +416,8 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, { const TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); + double wprofprim[3][3];//store primaries to XYZ + bool gamutcontrol = params->icm.gamut; const float toxyz[3][3] = { { static_cast(wprof[0][0] / ((normalizeIn ? 65535.0 : 1.0))), //I have suppressed / Color::D50x @@ -440,57 +442,64 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, if (settings->verbose) { printf("profile not accepted\n"); } + return; } if (mul == -5 && gampos == 2.4 && slpos == 12.92310) {//must be change if we change settings RT sRGB //only in this case we can shortcut..all process..no gamut control..because we reduce...leads to very small differences, but big speedup #ifdef _OPENMP - #pragma omp parallel for schedule(dynamic, 16) if (multiThread) + #pragma omp parallel for schedule(dynamic, 16) if (multiThread) #endif - for (int i = 0; i < ch; ++i) - for (int j = 0; j < cw; ++j) { - float r = src->r(i, j); - float g = src->g(i, j); - float b = src->b(i, j); - r = (Color::igammatab_srgb[r]) / 65535.f; - g = (Color::igammatab_srgb[g]) / 65535.f; - b = (Color::igammatab_srgb[b]) / 65535.f; - dst->r(i, j) = r; - dst->g(i, j) = g; - dst->b(i, j) = b; - } - return; + for (int i = 0; i < ch; ++i) + for (int j = 0; j < cw; ++j) { + float r = src->r(i, j); + float g = src->g(i, j); + float b = src->b(i, j); + r = (Color::igammatab_srgb[r]) / 65535.f; + g = (Color::igammatab_srgb[g]) / 65535.f; + b = (Color::igammatab_srgb[b]) / 65535.f; + dst->r(i, j) = r; + dst->g(i, j) = g; + dst->b(i, j) = b; + } + + return; } - - if (mul == 1 ||(params->icm.wprim == ColorManagementParams::Primaries::DEFAULT && params->icm.will == ColorManagementParams::Illuminant::DEFAULT)) {//shortcut and speedup when no call primaries and illuminant - no gamut control...in this case be careful + + if (mul == 1 || (params->icm.wprim == ColorManagementParams::Primaries::DEFAULT && params->icm.will == ColorManagementParams::Illuminant::DEFAULT)) { //shortcut and speedup when no call primaries and illuminant - no gamut control...in this case be careful GammaValues g_a; //gamma parameters double pwr = 1.0 / static_cast(gampos); Color::calcGamma(pwr, slpos, g_a); // call to calcGamma with selected gamma and slope #ifdef _OPENMP -# pragma omp parallel for schedule(dynamic,16) if (multiThread) + # pragma omp parallel for schedule(dynamic,16) if (multiThread) #endif + for (int y = 0; y < ch; ++y) { int x = 0; #ifdef __SSE2__ + for (; x < cw - 3; x += 4) { - STVFU(dst->r(y,x), F2V(65536.f) * gammalog(LVFU(src->r(y,x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); - STVFU(dst->g(y,x), F2V(65536.f) * gammalog(LVFU(src->g(y,x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); - STVFU(dst->b(y,x), F2V(65536.f) * gammalog(LVFU(src->b(y,x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); - } + STVFU(dst->r(y, x), F2V(65536.f) * gammalog(LVFU(src->r(y, x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); + STVFU(dst->g(y, x), F2V(65536.f) * gammalog(LVFU(src->g(y, x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); + STVFU(dst->b(y, x), F2V(65536.f) * gammalog(LVFU(src->b(y, x)), F2V(gampos), F2V(slpos), F2V(g_a[3]), F2V(g_a[4]))); + } + #endif + for (; x < cw; ++x) { - dst->r(y,x) = 65536.f * gammalog(src->r(y,x), gampos, slpos, g_a[3], g_a[4]); - dst->g(y,x) = 65536.f * gammalog(src->g(y,x), gampos, slpos, g_a[3], g_a[4]); - dst->b(y,x) = 65536.f * gammalog(src->b(y,x), gampos, slpos, g_a[3], g_a[4]); + dst->r(y, x) = 65536.f * gammalog(src->r(y, x), gampos, slpos, g_a[3], g_a[4]); + dst->g(y, x) = 65536.f * gammalog(src->g(y, x), gampos, slpos, g_a[3], g_a[4]); + dst->b(y, x) = 65536.f * gammalog(src->b(y, x), gampos, slpos, g_a[3], g_a[4]); } } + return; } - + float redxx = params->icm.redx; float redyy = params->icm.redy; @@ -498,6 +507,7 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, float bluyy = params->icm.bluy; float grexx = params->icm.grex; float greyy = params->icm.grey; + float epsil = 0.0001f; if (prim == 12) {//convert datas area to xy float redgraphx = params->icm.labgridcieALow; @@ -519,11 +529,34 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, greyy = 0.55f * (gregraphy + 1.f) - 0.1f; greyy = rtengine::LIM(greyy, 0.5f, 1.f); } + //fixed crash when there is no space or too small..just a line...Possible if bx, by aligned with Gx,Gy Rx,Ry - float ac = (greyy - redyy) / (grexx - redxx); + //fix crash if user select 0 for redyy, bluyy, greyy + if (redyy == 0.f) { + redyy = epsil; + } + + if (bluyy == 0.f) { + bluyy = epsil; + } + + if (greyy == 0.f) { + greyy = epsil; + } + + //fix crash if grexx - redxx = 0 + float grered = 1.f; + grered = grexx - redxx; + + if (grered == 0.f) { + grered = epsil; + } + + float ac = (greyy - redyy) / grered; float bc = greyy - ac * grexx; float yc = ac * bluxx + bc; - if ((bluyy < yc + 0.0004f) && (bluyy > yc - 0.0004f)) {//under 0.0004 in some case crash because space too small + + if ((bluyy < yc + 0.0004f) && (bluyy > yc - 0.0004f)) { //under 0.0004 in some case crash because space too small return; } @@ -564,7 +597,6 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, } case ColorManagementParams::Primaries::ACES_P0: { - profile = "ACESp0"; break; } @@ -593,11 +625,13 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, break; } } - - if (settings->verbose && prim != 0) { - printf("prim=%i Profile Destination=%s\n", prim, profile.c_str()); - } + + if (settings->verbose && prim != 0) { + printf("prim=%i Profile Destination=%s\n", prim, profile.c_str()); + } + cmsHTRANSFORM hTransform = nullptr; + if (transform) { hTransform = transform; } else { @@ -622,7 +656,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, }; double tempv4 = 5003.; - float p[6]; //primaries + double p[6]; //primaries + double Wx = 1.0; + double Wz = 1.0; //primaries for 10 working profiles ==> output profiles if (profile == "WideGamut") { @@ -633,6 +669,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[4] = 0.1570; p[5] = 0.0180; illum = toUnderlying(ColorManagementParams::Illuminant::D50); + Wx = 0.964295676; + Wz = 0.825104603; + } else if (profile == "Adobe RGB") { p[0] = 0.6400; //Adobe primaries p[1] = 0.3300; @@ -642,6 +681,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[5] = 0.0600; tempv4 = 6504.; illum = toUnderlying(ColorManagementParams::Illuminant::D65); + Wx = 0.95045471; + Wz = 1.08905029; + } else if (profile == "sRGB") { p[0] = 0.6400; // sRGB primaries p[1] = 0.3300; @@ -651,6 +693,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[5] = 0.0600; tempv4 = 6504.; illum = toUnderlying(ColorManagementParams::Illuminant::D65); + Wx = 0.95045471; + Wz = 1.08905029; + } else if (profile == "BruceRGB") { p[0] = 0.6400; // Bruce primaries p[1] = 0.3300; @@ -660,7 +705,10 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[5] = 0.0600; tempv4 = 6504.; illum = toUnderlying(ColorManagementParams::Illuminant::D65); - } else if (profile == "Beta RGB") { + Wx = 0.95045471; + Wz = 1.08905029; + + } else if (profile == "Beta RGB") { p[0] = 0.6888; // Beta primaries p[1] = 0.3112; p[2] = 0.1986; @@ -668,6 +716,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[4] = 0.1265; p[5] = 0.0352; illum = toUnderlying(ColorManagementParams::Illuminant::D50); + Wx = 0.964295676; + Wz = 0.825104603; + } else if (profile == "BestRGB") { p[0] = 0.7347; // Best primaries p[1] = 0.2653; @@ -676,6 +727,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[4] = 0.1300; p[5] = 0.0350; illum = toUnderlying(ColorManagementParams::Illuminant::D50); + Wx = 0.964295676; + Wz = 0.825104603; + } else if (profile == "Rec2020") { p[0] = 0.7080; // Rec2020 primaries p[1] = 0.2920; @@ -685,6 +739,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[5] = 0.0460; tempv4 = 6504.; illum = toUnderlying(ColorManagementParams::Illuminant::D65); + Wx = 0.95045471; + Wz = 1.08905029; + } else if (profile == "ACESp0") { p[0] = 0.7347; // ACES P0 primaries p[1] = 0.2653; @@ -694,6 +751,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[5] = -0.0770; tempv4 = 6004.; illum = toUnderlying(ColorManagementParams::Illuminant::D60); + Wx = 0.952646075; + Wz = 1.008825184; + } else if (profile == "ACESp1") { p[0] = 0.713; // ACES P1 primaries p[1] = 0.293; @@ -703,6 +763,9 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[5] = 0.044; tempv4 = 6004.; illum = toUnderlying(ColorManagementParams::Illuminant::D60); + Wx = 0.952646075; + Wz = 1.008825184; + } else if (profile == "ProPhoto") { p[0] = 0.7347; //ProPhoto and default primaries p[1] = 0.2653; @@ -711,8 +774,11 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, p[4] = 0.0366; p[5] = 0.0001; illum = toUnderlying(ColorManagementParams::Illuminant::D50); + Wx = 0.964295676; + Wz = 0.825104603; + } else if (profile == "Custom") { - p[0] = redxx; + p[0] = redxx; p[1] = redyy; p[2] = grexx; p[3] = greyy; @@ -743,11 +809,13 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, gammaParams[3] = 1. / slpos; gammaParams[5] = 0.0; gammaParams[6] = 0.0; - // printf("ga0=%f ga1=%f ga2=%f ga3=%f ga4=%f\n", ga0, ga1, ga2, ga3, ga4); + // printf("ga0=%f ga1=%f ga2=%f ga3=%f ga4=%f\n", ga0, ga1, ga2, ga3, ga4); // 7 parameters for smoother curves cmsCIExyY xyD; + Glib::ustring ills = "D50"; + switch (ColorManagementParams::Illuminant(illum)) { case ColorManagementParams::Illuminant::DEFAULT: case ColorManagementParams::Illuminant::STDA: @@ -802,55 +870,95 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, cmsWhitePointFromTemp(&xyD, tempv4); switch (ColorManagementParams::Illuminant(illum)) { - case ColorManagementParams::Illuminant::DEFAULT: - case ColorManagementParams::Illuminant::D55: + case ColorManagementParams::Illuminant::DEFAULT: { + break; + } + + case ColorManagementParams::Illuminant::D55: { + Wx = 0.956565934; + Wz = 0.920253249; + break; + } + case ColorManagementParams::Illuminant::D80: { + Wx = 0.950095542; + Wz = 1.284213976; break; } case ColorManagementParams::Illuminant::D41: { + Wx = 0.991488263; + Wz = 0.631604625; break; } case ColorManagementParams::Illuminant::D50: { xyD = {0.3457, 0.3585, 1.0}; // near LCMS values but not perfect... it's a compromise!! + Wx = 0.964295676; + Wz = 0.825104603; break; } case ColorManagementParams::Illuminant::D60: { + Wx = 0.952646075; + Wz = 1.008825184; xyD = {0.32168, 0.33767, 1.0}; break; } case ColorManagementParams::Illuminant::D65: { + Wx = 0.95045471; + Wz = 1.08905029; xyD = {0.312700492, 0.329000939, 1.0}; break; } case ColorManagementParams::Illuminant::D120: { + Wx = 0.979182; + Wz = 1.623623; xyD = {0.269669, 0.28078, 1.0}; break; } case ColorManagementParams::Illuminant::STDA: { + Wx = 1.098500393; + Wz = 0.355848714; xyD = {0.447573, 0.407440, 1.0}; ills = "stdA 2875K"; break; } case ColorManagementParams::Illuminant::TUNGSTEN_2000K: { + Wx = 1.274335; + Wz = 0.145233; xyD = {0.526591, 0.41331, 1.0}; ills = "Tungsten 2000K"; break; } case ColorManagementParams::Illuminant::TUNGSTEN_1500K: { + Wx = 1.489921; + Wz = 0.053826; xyD = {0.585703, 0.393157, 1.0}; ills = "Tungsten 1500K"; break; } } + double wprofpri[9]; + + if (gamutcontrol) { + //xyz in functiuon primaries and illuminant + Color::primaries_to_xyz(p, Wx, Wz, wprofpri); + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + wprofprim[i][j] = (double) wprofpri[j * 3 + i]; + //xyz in TMatrix format + } + } + } + //D41 0.377984 0.381229 //D55 0.332424 0.347426 //D80 0.293755 0.309185 @@ -869,7 +977,7 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, cmsWriteTag(oprofdef, cmsSigGreenTRCTag, GammaTRC[1]); cmsWriteTag(oprofdef, cmsSigBlueTRCTag, GammaTRC[2]); - //to read XYZ values and illuminant + //to read XYZ values and illuminant if (rtengine::settings->verbose) { cmsCIEXYZ *redT = static_cast(cmsReadTag(oprofdef, cmsSigRedMatrixColumnTag)); cmsCIEXYZ *greenT = static_cast(cmsReadTag(oprofdef, cmsSigGreenMatrixColumnTag)); @@ -881,6 +989,7 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, } cmsFreeToneCurve(GammaTRC[0]); + if (oprofdef) { constexpr cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE | cmsFLAGS_BLACKPOINTCOMPENSATION | cmsFLAGS_GAMUTCHECK; const cmsHPROFILE iprof = ICCStore::getInstance()->getXYZProfile(); @@ -889,7 +998,10 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, lcmsMutex->unlock(); } } + if (hTransform) { + + #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif @@ -901,19 +1013,30 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, #pragma omp for schedule(dynamic, 16) nowait #endif - for (int i = 0; i < ch; ++i) { + for (int i = 0; i < ch; ++i) + { float *p = pBuf.data; + for (int j = 0; j < cw; ++j) { const float r = src->r(i, j); const float g = src->g(i, j); const float b = src->b(i, j); + float X = toxyz[0][0] * r + toxyz[0][1] * g + toxyz[0][2] * b; + float Y = toxyz[1][0] * r + toxyz[1][1] * g + toxyz[1][2] * b; + float Z = toxyz[2][0] * r + toxyz[2][1] * g + toxyz[2][2] * b; - *(p++) = toxyz[0][0] * r + toxyz[0][1] * g + toxyz[0][2] * b; - *(p++) = toxyz[1][0] * r + toxyz[1][1] * g + toxyz[1][2] * b; - *(p++) = toxyz[2][0] * r + toxyz[2][1] * g + toxyz[2][2] * b; + if (gamutcontrol) { + Color::gamutmap(X, Y, Z, wprofprim);//gamut control + } + + *(p++) = X; + *(p++) = Y; + *(p++) = Z; } + p = pBuf.data; cmsDoTransform(hTransform, p, p, cw); + for (int j = 0; j < cw; ++j) { dst->r(i, j) = *(p++) * normalize; dst->g(i, j) = *(p++) * normalize; @@ -921,10 +1044,12 @@ void ImProcFunctions::workingtrc(const Imagefloat* src, Imagefloat* dst, int cw, } } } + if (!keepTransForm) { cmsDeleteTransform(hTransform); hTransform = nullptr; } + transform = hTransform; } } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 3f30374f7..371731b93 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -2276,6 +2276,7 @@ ColorManagementParams::ColorManagementParams() : bluy(0.0001), preser(0.), fbw(false), + gamut(false), labgridcieALow(0.51763),//Prophoto red = (0.7347+0.1) * 1.81818 - 1 labgridcieBLow(-0.33582), labgridcieAHigh(-0.75163),//Prophoto blue @@ -2322,6 +2323,7 @@ bool ColorManagementParams::operator ==(const ColorManagementParams& other) cons && labgridcieWy == other.labgridcieWy && preser == other.preser && fbw == other.fbw + && gamut == other.gamut && aRendIntent == other.aRendIntent && outputProfile == other.outputProfile && outputIntent == other.outputIntent @@ -7190,6 +7192,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->icm.labgridcieWy, "Color Management", "LabGridcieWy", icm.labgridcieWy, keyFile); saveToKeyfile(!pedited || pedited->icm.preser, "Color Management", "Preser", icm.preser, keyFile); saveToKeyfile(!pedited || pedited->icm.fbw, "Color Management", "Fbw", icm.fbw, keyFile); + saveToKeyfile(!pedited || pedited->icm.gamut, "Color Management", "Gamut", icm.gamut, keyFile); saveToKeyfile(!pedited || pedited->icm.outputProfile, "Color Management", "OutputProfile", icm.outputProfile, keyFile); saveToKeyfile( !pedited || pedited->icm.aRendIntent, @@ -9455,6 +9458,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Color Management", "Bluy", pedited, icm.bluy, pedited->icm.bluy); assignFromKeyfile(keyFile, "Color Management", "Preser", pedited, icm.preser, pedited->icm.preser); assignFromKeyfile(keyFile, "Color Management", "Fbw", pedited, icm.fbw, pedited->icm.fbw); + assignFromKeyfile(keyFile, "Color Management", "Gamut", pedited, icm.gamut, pedited->icm.gamut); assignFromKeyfile(keyFile, "Color Management", "LabGridcieALow", pedited, icm.labgridcieALow, pedited->icm.labgridcieALow); assignFromKeyfile(keyFile, "Color Management", "LabGridcieBLow", pedited, icm.labgridcieBLow, pedited->icm.labgridcieBLow); assignFromKeyfile(keyFile, "Color Management", "LabGridcieAHigh", pedited, icm.labgridcieAHigh, pedited->icm.labgridcieAHigh); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index df319ffcc..24e1ca036 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1936,6 +1936,7 @@ struct ColorManagementParams { double bluy; double preser; bool fbw; + bool gamut; double labgridcieALow; double labgridcieBLow; double labgridcieAHigh; diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index 95a890443..3140fbea3 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -62,6 +62,7 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha EvICMpreser = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_PRESER"); EvICMLabGridciexy = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICL_LABGRIDCIEXY"); EvICMfbw = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_FBW"); + EvICMgamut = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_ICM_GAMUT"); isBatchMode = lastToneCurve = lastApplyLookTable = lastApplyBaselineExposureOffset = lastApplyHueSatMap = false; ipDialog = Gtk::manage(new MyFileChooserButton(M("TP_ICM_INPUTDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN)); @@ -263,8 +264,12 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha wprimBox->pack_start(*wprim, Gtk::PACK_EXPAND_WIDGET); fbw = Gtk::manage(new Gtk::CheckButton((M("TP_ICM_FBW")))); fbw->set_active(true); + gamut = Gtk::manage(new Gtk::CheckButton((M("TP_ICM_GAMUT")))); + gamut->set_active(false); + trcProfVBox->pack_start(*wprimBox, Gtk::PACK_EXPAND_WIDGET); trcProfVBox->pack_start(*fbw, Gtk::PACK_EXPAND_WIDGET); + trcProfVBox->pack_start(*gamut, Gtk::PACK_EXPAND_WIDGET); neutral = Gtk::manage (new Gtk::Button (M ("TP_ICM_NEUTRAL"))); setExpandAlignProperties (neutral, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_START); @@ -468,6 +473,7 @@ ICMPanel::ICMPanel() : FoldableToolPanel(this, "icm", M("TP_ICM_LABEL")), iuncha wprimconn = wprim->signal_changed().connect(sigc::mem_fun(*this, &ICMPanel::wprimChanged)); fbwconn = fbw->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::fbwChanged)); + gamutconn = gamut->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::gamutChanged)); obpcconn = obpc->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::oBPCChanged)); tcurveconn = ckbToneCurve->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::toneCurveChanged)); ltableconn = ckbApplyLookTable->signal_toggled().connect(sigc::mem_fun(*this, &ICMPanel::applyLookTableChanged)); @@ -513,6 +519,7 @@ void ICMPanel::neutral_pressed () wSlope->setValue(defPar.workingTRCSlope);//12.92 preser->setValue(defPar.preser); fbw->set_active(defPar.fbw); + gamut->set_active(defPar.gamut); wTRC->set_active(toUnderlying(ColorManagementParams::WorkingTrc::NONE));//reset to none will->set_active(toUnderlying(ColorManagementParams::Illuminant::DEFAULT));//reset to default - after wprim } @@ -765,6 +772,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) ConnectionBlocker obpcconn_(obpcconn); ConnectionBlocker fbwconn_(fbwconn); + ConnectionBlocker gamutconn_(gamutconn); ConnectionBlocker ipc_(ipc); ConnectionBlocker tcurveconn_(tcurveconn); ConnectionBlocker ltableconn_(ltableconn); @@ -838,6 +846,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) obpc->set_active(pp->icm.outputBPC); fbw->set_active(pp->icm.fbw); + gamut->set_active(pp->icm.gamut); ckbToneCurve->set_active(pp->icm.toneCurve); lastToneCurve = pp->icm.toneCurve; ckbApplyLookTable->set_active(pp->icm.applyLookTable); @@ -862,6 +871,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) iunchanged->set_active(!pedited->icm.inputProfile); obpc->set_inconsistent(!pedited->icm.outputBPC); fbw->set_inconsistent(!pedited->icm.fbw); + gamut->set_inconsistent(!pedited->icm.gamut); ckbToneCurve->set_inconsistent(!pedited->icm.toneCurve); ckbApplyLookTable->set_inconsistent(!pedited->icm.applyLookTable); ckbApplyBaselineExposureOffset->set_inconsistent(!pedited->icm.applyBaselineExposureOffset); @@ -920,6 +930,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(false); wprim->set_sensitive(false); fbw->set_sensitive(false); + gamut->set_sensitive(false); wprimlab->set_sensitive(false); riaHBox->set_sensitive(false); redFrame->hide(); @@ -931,6 +942,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { redFrame->hide(); @@ -973,6 +985,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -990,6 +1003,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -1007,6 +1021,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); redFrame->show(); wGamma->set_sensitive(false); @@ -1025,6 +1040,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); riaHBox->set_sensitive(true); if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { @@ -1042,6 +1058,7 @@ void ICMPanel::read(const ProcParams* pp, const ParamsEdited* pedited) willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -1143,6 +1160,7 @@ void ICMPanel::write(ProcParams* pp, ParamsEdited* pedited) pp->icm.applyHueSatMap = ckbApplyHueSatMap->get_active(); pp->icm.outputBPC = obpc->get_active(); pp->icm.fbw = fbw->get_active(); + pp->icm.gamut = gamut->get_active(); pp->icm.workingTRCGamma = wGamma->getValue(); pp->icm.workingTRCSlope = wSlope->getValue(); pp->icm.redx = redx->getValue(); @@ -1162,6 +1180,7 @@ void ICMPanel::write(ProcParams* pp, ParamsEdited* pedited) pedited->icm.aRendIntent = aRendIntent->getSelected() < 4; pedited->icm.outputBPC = !obpc->get_inconsistent(); pedited->icm.fbw = !fbw->get_inconsistent(); + pedited->icm.gamut = !gamut->get_inconsistent(); pedited->icm.dcpIlluminant = dcpIll->get_active_text() != M("GENERAL_UNCHANGED"); pedited->icm.toneCurve = !ckbToneCurve->get_inconsistent(); pedited->icm.applyLookTable = !ckbApplyLookTable->get_inconsistent(); @@ -1268,6 +1287,7 @@ void ICMPanel::wtrcinChanged() willulab->set_sensitive(false); wprim->set_sensitive(false); fbw->set_sensitive(false); + gamut->set_sensitive(false); wprimlab->set_sensitive(false); redFrame->hide(); riaHBox->set_sensitive(false); @@ -1278,6 +1298,7 @@ void ICMPanel::wtrcinChanged() will->set_sensitive(false); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); willulab->set_sensitive(true); if (ColorManagementParams::Primaries(wprim->get_active_row_number()) == ColorManagementParams::Primaries::DEFAULT) { @@ -1311,6 +1332,7 @@ void ICMPanel::wtrcinChanged() willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -1336,6 +1358,7 @@ void ICMPanel::wtrcinChanged() willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); riaHBox->set_sensitive(true); @@ -1362,6 +1385,7 @@ void ICMPanel::wtrcinChanged() willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -1389,6 +1413,7 @@ void ICMPanel::wtrcinChanged() willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -1416,6 +1441,7 @@ void ICMPanel::wtrcinChanged() willulab->set_sensitive(true); wprim->set_sensitive(true); fbw->set_sensitive(true); + gamut->set_sensitive(true); wprimlab->set_sensitive(true); wGamma->set_sensitive(false); wSlope->set_sensitive(false); @@ -2023,6 +2049,33 @@ void ICMPanel::fbwChanged() } } +void ICMPanel::gamutChanged() +{ + if (multiImage) { + if (gamut->get_inconsistent()) { + gamut->set_inconsistent(false); + gamutconn.block(true); + gamut->set_active(false); + gamutconn.block(false); + } else if (lastgamut) { + gamut->set_inconsistent(true); + } + + lastgamut = gamut->get_active(); + } + + if (listener) { + if (gamut->get_inconsistent()) { + listener->panelChanged(EvICMgamut, M("GENERAL_UNCHANGED")); + } else if (fbw->get_active()) { + listener->panelChanged(EvICMgamut, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(EvICMgamut, M("GENERAL_DISABLED")); + } + } +} + + void ICMPanel::setRawMeta(bool raw, const rtengine::FramesData* pMeta) { diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 8d52fb25f..31ae6b664 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -81,6 +81,8 @@ protected: bool lastfbw; sigc::connection fbwconn; bool isBatchMode; + bool lastgamut; + sigc::connection gamutconn; private: rtengine::ProcEvent EvICMprimariMethod; @@ -107,6 +109,7 @@ private: rtengine::ProcEvent EvICMpreser; rtengine::ProcEvent EvICMLabGridciexy; rtengine::ProcEvent EvICMfbw; + rtengine::ProcEvent EvICMgamut; LabGrid *labgridcie; IdleRegister idle_register; @@ -121,6 +124,7 @@ private: Gtk::Box* iVBox; Gtk::Box* wTRCBox; Gtk::CheckButton* fbw; + Gtk::CheckButton* gamut; Gtk::CheckButton* obpc; Gtk::RadioButton* inone; @@ -196,6 +200,7 @@ public: void aiChanged(int n); void oBPCChanged(); void fbwChanged(); + void gamutChanged(); void ipChanged(); void ipSelectionChanged(); void dcpIlluminantChanged(); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 41b19edf2..acdda4e8a 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -452,6 +452,7 @@ void ParamsEdited::set(bool v) icm.bluy = v; icm.preser = v; icm.fbw = v; + icm.gamut = v; icm.labgridcieALow = v; icm.labgridcieBLow = v; icm.labgridcieAHigh = v; @@ -1871,6 +1872,7 @@ void ParamsEdited::initFrom(const std::vector& icm.labgridcieWy = icm.labgridcieWy && p.icm.labgridcieWy == other.icm.labgridcieWy; icm.preser = icm.preser && p.icm.preser == other.icm.preser; icm.fbw = icm.fbw && p.icm.fbw == other.icm.fbw; + icm.gamut = icm.gamut && p.icm.gamut == other.icm.gamut; icm.aRendIntent = icm.aRendIntent && p.icm.aRendIntent == other.icm.aRendIntent; icm.workingTRC = icm.workingTRC && p.icm.workingTRC == other.icm.workingTRC; icm.will = icm.will && p.icm.will == other.icm.will; @@ -6377,6 +6379,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.icm.fbw = mods.icm.fbw; } + if (icm.gamut) { + toEdit.icm.gamut = mods.icm.gamut; + } + if (icm.labgridcieALow) { toEdit.icm.labgridcieALow = mods.icm.labgridcieALow; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 43b4e4e40..56d71cfa3 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -1230,6 +1230,7 @@ struct ColorManagementParamsEdited { bool bluy; bool preser; bool fbw; + bool gamut; bool labgridcieALow; bool labgridcieBLow; bool labgridcieAHigh; From 311f3422fd25b8306a11186d866d902057fbccb2 Mon Sep 17 00:00:00 2001 From: Mattia Verga Date: Wed, 25 Jan 2023 14:16:19 +0100 Subject: [PATCH 101/134] Add missing include for GCC13 compatibility Signed-off-by: Mattia Verga --- rtengine/dcraw.h | 1 + 1 file changed, 1 insertion(+) diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index e0a6cda92..aadc0b969 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -19,6 +19,7 @@ #pragma once +#include #include #include "myfile.h" From b1490e24c73dc06d3cb343fc910b75aa47bab35e Mon Sep 17 00:00:00 2001 From: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> Date: Thu, 26 Jan 2023 05:03:37 -0800 Subject: [PATCH 102/134] Fix Windows build libsharpyuv-0.dll error (#6672) --- .github/workflows/windows.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index f6f83f567..ab81edec6 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -155,6 +155,7 @@ jobs: "libpixman-1-0.dll" \ "libpng16-16.dll" \ "librsvg-2-2.dll" \ + "libsharpyuv-0.dll" \ "libsigc-2.0-0.dll" \ "libstdc++-6.dll" \ "libsystre-0.dll" \ From 9a245c1acb9bbbe5dd82ee3a4da4dcddc8903f35 Mon Sep 17 00:00:00 2001 From: Desmis Date: Tue, 31 Jan 2023 12:32:31 +0100 Subject: [PATCH 103/134] Avoid Color shift - Gamut and Munsell Review in RT - branch Munsellgamut (#6673) * Fixed numerous problems with gamut and Munsell in Local adjustments * change gamut-munsell in lab adjustmnts - gamut in ciecam * Improve XYZ colorimetry and tooltip * Change event - format code - change labels tooltips * Removed avoid_ and avoidmun_ * Removed avoidcolorshift in labcurve * Push change proposed by Lawrence37 - compatibility with old pp3 --- rtdata/languages/default | 11 +- rtengine/improcfun.cc | 482 ++++++++++++++++++++++---------------- rtengine/improcfun.h | 2 +- rtengine/iplocallab.cc | 150 +++++++++--- rtengine/procevents.h | 6 +- rtengine/procparams.cc | 51 ++-- rtengine/procparams.h | 6 +- rtengine/refreshmap.cc | 3 +- rtgui/blackwhite.cc | 3 +- rtgui/controlspotpanel.cc | 145 ++++++------ rtgui/controlspotpanel.h | 19 +- rtgui/labcurve.cc | 465 ++++++++++++++++++++---------------- rtgui/labcurve.h | 9 +- rtgui/locallab.cc | 56 ++++- rtgui/paramsedited.cc | 30 +-- rtgui/paramsedited.h | 5 +- 16 files changed, 855 insertions(+), 588 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 8120419d2..0396b9d8d 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1414,6 +1414,7 @@ HISTORY_MSG_FILMNEGATIVE_COLORSPACE;Film negative color space HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative HISTORY_MSG_FILMNEGATIVE_REF_SPOT;FN - Reference input HISTORY_MSG_FILMNEGATIVE_VALUES;Film negative values +HISTORY_MSG_GAMUTMUNSEL;Gamut-Munsell HISTORY_MSG_HISTMATCHING;Auto-matched tone curve HISTORY_MSG_HLBL;Color propagation - blur HISTORY_MSG_ICL_LABGRIDCIEXY;Cie xy @@ -1441,6 +1442,7 @@ HISTORY_MSG_LOCALCONTRAST_DARKNESS;Local Contrast - Darkness HISTORY_MSG_LOCALCONTRAST_ENABLED;Local Contrast HISTORY_MSG_LOCALCONTRAST_LIGHTNESS;Local Contrast - Lightness HISTORY_MSG_LOCALCONTRAST_RADIUS;Local Contrast - Radius +HISTORY_MSG_LOCAL_GAMUTMUNSEL;Local - Gamut-Munsell HISTORY_MSG_METADATA_MODE;Metadata copy mode HISTORY_MSG_MICROCONTRAST_CONTRAST;Microcontrast - Contrast threshold HISTORY_MSG_PDSHARPEN_AUTO_CONTRAST;CS - Auto threshold @@ -2608,8 +2610,6 @@ TP_ICM_WORKING_TRC_SRGB;sRGB g=2.4 s=12.92 TP_ICM_WORKING_TRC_TOOLTIP;Only for built-in profiles. TP_IMPULSEDENOISE_LABEL;Impulse Noise Reduction TP_IMPULSEDENOISE_THRESH;Threshold -TP_LABCURVE_AVOIDCOLORSHIFT;Avoid color shift -TP_LABCURVE_AVOIDCOLORSHIFT_TOOLTIP;Fit colors into gamut of the working color space and apply Munsell correction (Uniform Perceptual Lab). TP_LABCURVE_BRIGHTNESS;Lightness TP_LABCURVE_CHROMATICITY;Chromaticity TP_LABCURVE_CHROMA_TOOLTIP;To apply B&W toning, set Chromaticity to -100. @@ -2674,7 +2674,7 @@ TP_LOCALLAB_ARTIF_TOOLTIP;ΔE scope threshold increases the range of ΔE scope. TP_LOCALLAB_AUTOGRAY;Auto mean luminance (Yb%) TP_LOCALLAB_AUTOGRAYCIE;Auto TP_LOCALLAB_AVOID;Avoid color shift -TP_LOCALLAB_AVOIDCOLORSHIFT_TOOLTIP;Fit colors into gamut of the working color space and apply Munsell correction (Uniform Perceptual Lab).\nMunsell correction always disabled when Jz or CAM16 is used. +TP_LOCALLAB_AVOIDCOLORSHIFT_TOOLTIP;Fit colors into gamut of the working color space and apply Munsell correction (Uniform Perceptual Lab).\nMunsell correction always disabled when Jz or CAM16 or Color Appearance and Lighting is used.\n\nDefault: Munsell.\nMunsell correction: fixes Lab mode hue drifts due to non-linearity, when chromaticity is changed (Uniform Perceptual Lab).\nLab: applies a gamut control, in relative colorimetric, Munsell is then applied.\nXYZ Absolute, applies gamut control, in absolute colorimetric, Munsell is then applied.\nXYZ Relative, applies gamut control, in relative colorimetric, Munsell is then applied. TP_LOCALLAB_AVOIDMUN;Munsell correction only TP_LOCALLAB_AVOIDMUN_TOOLTIP;Munsell correction always disabled when Jz or CAM16 is used. TP_LOCALLAB_AVOIDRAD;Soft radius @@ -2904,6 +2904,11 @@ TP_LOCALLAB_GAMM;Gamma TP_LOCALLAB_GAMMASKCOL;Gamma TP_LOCALLAB_GAMMASK_TOOLTIP;Adjusting Gamma and Slope can provide a soft and artifact-free transformation of the mask by progressively modifying 'L' to avoid any discontinuities. TP_LOCALLAB_GAMSH;Gamma +TP_LOCALLAB_GAMUTNON;None +TP_LOCALLAB_GAMUTLABRELA;Lab +TP_LOCALLAB_GAMUTXYZABSO;XYZ Absolute +TP_LOCALLAB_GAMUTXYZRELA;XYZ Relative +TP_LOCALLAB_GAMUTMUNSELL;Munsell only TP_LOCALLAB_GAMW;Gamma (wavelet pyramids) TP_LOCALLAB_GRADANG;Gradient angle TP_LOCALLAB_GRADANG_TOOLTIP;Rotation angle in degrees: -180 0 +180. diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 15ebcc2e6..0e08a28eb 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -54,7 +54,8 @@ #pragma GCC diagnostic warning "-Wextra" #pragma GCC diagnostic warning "-Wdouble-promotion" -namespace { +namespace +{ using namespace rtengine; @@ -218,32 +219,37 @@ void proPhotoBlue(float *rtemp, float *gtemp, float *btemp, int istart, int tH, } } -void customToneCurve(const ToneCurve &customToneCurve, ToneCurveMode curveMode, float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize, PerceptualToneCurveState ptcApplyState) { +void customToneCurve(const ToneCurve &customToneCurve, ToneCurveMode curveMode, float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize, PerceptualToneCurveState ptcApplyState) +{ if (curveMode == ToneCurveMode::STD) { // Standard - const StandardToneCurve& userToneCurve = static_cast (customToneCurve); + const StandardToneCurve& userToneCurve = static_cast(customToneCurve); + for (int i = istart, ti = 0; i < tH; i++, ti++) { userToneCurve.BatchApply(0, tW - jstart, &rtemp[ti * tileSize], >emp[ti * tileSize], &btemp[ti * tileSize]); } } else if (curveMode == ToneCurveMode::FILMLIKE) { // Adobe like - const AdobeToneCurve& userToneCurve = static_cast (customToneCurve); + const AdobeToneCurve& userToneCurve = static_cast(customToneCurve); + for (int i = istart, ti = 0; i < tH; i++, ti++) { userToneCurve.BatchApply(0, tW - jstart, &rtemp[ti * tileSize], >emp[ti * tileSize], &btemp[ti * tileSize]); } } else if (curveMode == ToneCurveMode::SATANDVALBLENDING) { // apply the curve on the saturation and value channels - const SatAndValueBlendingToneCurve& userToneCurve = static_cast (customToneCurve); + const SatAndValueBlendingToneCurve& userToneCurve = static_cast(customToneCurve); + for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { userToneCurve.Apply(rtemp[ti * tileSize + tj], gtemp[ti * tileSize + tj], btemp[ti * tileSize + tj]); } } } else if (curveMode == ToneCurveMode::WEIGHTEDSTD) { // apply the curve to the rgb channels, weighted - const WeightedStdToneCurve& userToneCurve = static_cast (customToneCurve); + const WeightedStdToneCurve& userToneCurve = static_cast(customToneCurve); + for (int i = istart, ti = 0; i < tH; i++, ti++) { userToneCurve.BatchApply(0, tW - jstart, &rtemp[ti * tileSize], >emp[ti * tileSize], &btemp[ti * tileSize]); } } else if (curveMode == ToneCurveMode::LUMINANCE) { // apply the curve to the luminance channel - const LuminanceToneCurve& userToneCurve = static_cast (customToneCurve); + const LuminanceToneCurve& userToneCurve = static_cast(customToneCurve); for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { @@ -251,7 +257,8 @@ void customToneCurve(const ToneCurve &customToneCurve, ToneCurveMode curveMode, } } } else if (curveMode == ToneCurveMode::PERCEPTUAL) { // apply curve while keeping color appearance constant - const PerceptualToneCurve& userToneCurve = static_cast (customToneCurve); + const PerceptualToneCurve& userToneCurve = static_cast(customToneCurve); + for (int i = istart, ti = 0; i < tH; i++, ti++) { userToneCurve.BatchApply(0, tW - jstart, &rtemp[ti * tileSize], >emp[ti * tileSize], &btemp[ti * tileSize], ptcApplyState); } @@ -277,7 +284,7 @@ namespace rtengine using namespace procparams; -ImProcFunctions::~ImProcFunctions () +ImProcFunctions::~ImProcFunctions() { if (monitorTransform) { cmsDeleteTransform(monitorTransform); @@ -307,7 +314,7 @@ void ImProcFunctions::updateColorProfiles(const Glib::ustring& monitorProfile, R #if !defined(__APPLE__) // No support for monitor profiles on OS X, all data is sRGB monitor = ICCStore::getInstance()->getProfile(monitorProfile); #else - monitor = ICCStore::getInstance()->getProfile (settings->srgb); + monitor = ICCStore::getInstance()->getProfile(settings->srgb); #endif } @@ -325,7 +332,7 @@ void ImProcFunctions::updateColorProfiles(const Glib::ustring& monitorProfile, R if (softProof) { cmsHPROFILE oprof = nullptr; RenderingIntent outIntent; - + flags = cmsFLAGS_SOFTPROOFING | cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE; if (!settings->printerProfile.empty()) { @@ -334,9 +341,11 @@ void ImProcFunctions::updateColorProfiles(const Glib::ustring& monitorProfile, R if (settings->printerBPC) { flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; } + outIntent = RenderingIntent(settings->printerIntent); } else { oprof = ICCStore::getInstance()->getProfile(params->icm.outputProfile); + if (params->icm.outputBPC) { flags |= cmsFLAGS_BLACKPOINTCOMPENSATION; } @@ -352,20 +361,23 @@ void ImProcFunctions::updateColorProfiles(const Glib::ustring& monitorProfile, R // } const auto make_gamma_table = - [](cmsHPROFILE prof, cmsTagSignature tag) -> void + [](cmsHPROFILE prof, cmsTagSignature tag) -> void { + cmsToneCurve *tc = static_cast(cmsReadTag(prof, tag)); + + if (tc) { - cmsToneCurve *tc = static_cast(cmsReadTag(prof, tag)); - if (tc) { - const cmsUInt16Number *table = cmsGetToneCurveEstimatedTable(tc); - cmsToneCurve *tc16 = cmsBuildTabulatedToneCurve16(nullptr, cmsGetToneCurveEstimatedTableEntries(tc), table); - if (tc16) { - cmsWriteTag(prof, tag, tc16); - cmsFreeToneCurve(tc16); - } + const cmsUInt16Number *table = cmsGetToneCurveEstimatedTable(tc); + cmsToneCurve *tc16 = cmsBuildTabulatedToneCurve16(nullptr, cmsGetToneCurveEstimatedTableEntries(tc), table); + + if (tc16) { + cmsWriteTag(prof, tag, tc16); + cmsFreeToneCurve(tc16); } - }; + } + }; cmsHPROFILE softproof = ProfileContent(oprof).toProfile(); + if (softproof) { make_gamma_table(softproof, cmsSigRedTRCTag); make_gamma_table(softproof, cmsSigGreenTRCTag); @@ -439,7 +451,7 @@ void ImProcFunctions::updateColorProfiles(const Glib::ustring& monitorProfile, R void ImProcFunctions::firstAnalysis(const Imagefloat* const original, const ProcParams ¶ms, LUTu & histogram) { - TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params.icm.workingProfile); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params.icm.workingProfile); lumimul[0] = wprof[1][0]; lumimul[1] = wprof[1][1]; @@ -956,18 +968,20 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb float cz, wh, pfl; int c16 = 1; + if (params->colorappearance.modelmethod == "02") { c16 = 1; - }else if (params->colorappearance.modelmethod == "16") { + } else if (params->colorappearance.modelmethod == "16") { c16 = 16; - } //I don't use PQ here...hence no 21 + } //I don't use PQ here...hence no 21 + float plum = 100.f; - Ciecam02::initcam1float (yb, pilot, f, la, xw, yw, zw, n, d, nbb, ncb, cz, aw, wh, pfl, fl, c, c16, plum); + Ciecam02::initcam1float(yb, pilot, f, la, xw, yw, zw, n, d, nbb, ncb, cz, aw, wh, pfl, fl, c, c16, plum); //printf ("wh=%f \n", wh); const float pow1 = pow_F(1.64f - pow_F(0.29f, n), 0.73f); float nj, nbbj, ncbj, czj, awj, flj; - Ciecam02::initcam2float (yb2, pilotout, f2, la2, xw2, yw2, zw2, nj, dj, nbbj, ncbj, czj, awj, flj, c16, plum); + Ciecam02::initcam2float(yb2, pilotout, f2, la2, xw2, yw2, zw2, nj, dj, nbbj, ncbj, czj, awj, flj, c16, plum); #ifdef __SSE2__ const float reccmcz = 1.f / (c2 * czj); #endif @@ -1011,7 +1025,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb //matrix for current working space - TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.workingProfile); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix(params->icm.workingProfile); const float wip[3][3] = { { (float)wiprof[0][0], (float)wiprof[0][1], (float)wiprof[0][2]}, { (float)wiprof[1][0], (float)wiprof[1][1], (float)wiprof[1][2]}, @@ -1084,7 +1098,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb Q, M, s, aw, fl, wh, x, y, z, xw1, yw1, zw1, - c, nc, pow1, nbb, ncb, pfl, cz, d, c16, plum); + c, nc, pow1, nbb, ncb, pfl, cz, d, c16, plum); Jbuffer[k] = J; Cbuffer[k] = C; hbuffer[k] = h; @@ -1122,7 +1136,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb Q, M, s, aw, fl, wh, x, y, z, xw1, yw1, zw1, - c, nc, pow1, nbb, ncb, pfl, cz, d, c16, plum); + c, nc, pow1, nbb, ncb, pfl, cz, d, c16, plum); #endif float Jpro, Cpro, hpro, Qpro, Mpro, spro; Jpro = J; @@ -1132,6 +1146,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb Mpro = M; spro = s; bool jp = false; + if ((hasColCurve1) && (curveMode == ColorAppearanceParams::TcMode::BRIGHT)) { jp = true; float Qq = Qpro * coefQ; @@ -1141,6 +1156,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb Qq = Qq / coefQ; Qpro = 0.2f * (Qq - Qold) + Qold; } + if ((hasColCurve2) && (curveMode2 == ColorAppearanceParams::TcMode::BRIGHT)) { jp = true; float Qq2 = Qpro * coefQ; @@ -1149,10 +1165,12 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb userColCurveB2.Apply(Qq2); Qq2 = Qq2 / coefQ; Qpro = 0.2f * (Qq2 - Qold2) + Qold2; - } - if(jp) { + } + + if (jp) { Jpro = SQR((10.f * Qpro) / wh); } + // we cannot have all algorithms with all chroma curves if (alg == 0) { Jpro = CAMBrightCurveJ[Jpro * 327.68f]; //lightness CIECAM02 + contrast @@ -1240,73 +1258,73 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb } if (hasColCurve1 && (curveMode == ColorAppearanceParams::TcMode::LIGHT)) { - float Jj = (float) Jpro * 327.68f; - float Jold = Jj; - float Jold100 = (float) Jpro; - float redu = 25.f; - float reduc = 1.f; - const Lightcurve& userColCurveJ1 = static_cast(customColCurve1); - userColCurveJ1.Apply(Jj); + float Jj = (float) Jpro * 327.68f; + float Jold = Jj; + float Jold100 = (float) Jpro; + float redu = 25.f; + float reduc = 1.f; + const Lightcurve& userColCurveJ1 = static_cast(customColCurve1); + userColCurveJ1.Apply(Jj); - if (Jj > Jold) { - if (Jj < 65535.f) { - if (Jold < 327.68f * redu) { - Jj = 0.3f * (Jj - Jold) + Jold; //divide sensibility - } else { - reduc = LIM((100.f - Jold100) / (100.f - redu), 0.f, 1.f); - Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights - } + if (Jj > Jold) { + if (Jj < 65535.f) { + if (Jold < 327.68f * redu) { + Jj = 0.3f * (Jj - Jold) + Jold; //divide sensibility + } else { + reduc = LIM((100.f - Jold100) / (100.f - redu), 0.f, 1.f); + Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights } - } else if (Jj > 10.f) { - Jj = 0.8f * (Jj - Jold) + Jold; - } else if (Jj >= 0.f) { - Jj = 0.90f * (Jj - Jold) + Jold; // not zero ==>artifacts } + } else if (Jj > 10.f) { + Jj = 0.8f * (Jj - Jold) + Jold; + } else if (Jj >= 0.f) { + Jj = 0.90f * (Jj - Jold) + Jold; // not zero ==>artifacts + } - Jpro = (float)(Jj / 327.68f); + Jpro = (float)(Jj / 327.68f); - if (Jpro < 1.f) { - Jpro = 1.f; - } + if (Jpro < 1.f) { + Jpro = 1.f; + } } - if (hasColCurve2 && (curveMode2 == ColorAppearanceParams::TcMode::LIGHT)) { - float Jj = (float) Jpro * 327.68f; - float Jold = Jj; - float Jold100 = (float) Jpro; - float redu = 25.f; - float reduc = 1.f; - const Lightcurve& userColCurveJ2 = static_cast(customColCurve2); - userColCurveJ2.Apply(Jj); + if (hasColCurve2 && (curveMode2 == ColorAppearanceParams::TcMode::LIGHT)) { + float Jj = (float) Jpro * 327.68f; + float Jold = Jj; + float Jold100 = (float) Jpro; + float redu = 25.f; + float reduc = 1.f; + const Lightcurve& userColCurveJ2 = static_cast(customColCurve2); + userColCurveJ2.Apply(Jj); - if (Jj > Jold) { - if (Jj < 65535.f) { - if (Jold < 327.68f * redu) { - Jj = 0.3f * (Jj - Jold) + Jold; //divide sensibility - } else { - reduc = LIM((100.f - Jold100) / (100.f - redu), 0.f, 1.f); - Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights - } - } - } else if (Jj > 10.f) { - if (!t1L) { - Jj = 0.8f * (Jj - Jold) + Jold; - } else { - Jj = 0.4f * (Jj - Jold) + Jold; - } - } else if (Jj >= 0.f) { - if (!t1L) { - Jj = 0.90f * (Jj - Jold) + Jold; // not zero ==>artifacts - } else { - Jj = 0.5f * (Jj - Jold) + Jold; + if (Jj > Jold) { + if (Jj < 65535.f) { + if (Jold < 327.68f * redu) { + Jj = 0.3f * (Jj - Jold) + Jold; //divide sensibility + } else { + reduc = LIM((100.f - Jold100) / (100.f - redu), 0.f, 1.f); + Jj = 0.3f * reduc * (Jj - Jold) + Jold; //reduct sensibility in highlights } } - - Jpro = (float)(Jj / 327.68f); - - if (Jpro < 1.f) { - Jpro = 1.f; + } else if (Jj > 10.f) { + if (!t1L) { + Jj = 0.8f * (Jj - Jold) + Jold; + } else { + Jj = 0.4f * (Jj - Jold) + Jold; } + } else if (Jj >= 0.f) { + if (!t1L) { + Jj = 0.90f * (Jj - Jold) + Jold; // not zero ==>artifacts + } else { + Jj = 0.5f * (Jj - Jold) + Jold; + } + } + + Jpro = (float)(Jj / 327.68f); + + if (Jpro < 1.f) { + Jpro = 1.f; + } } if (hasColCurve3) {//curve 3 with chroma saturation colorfullness @@ -1456,47 +1474,33 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb #else float xx, yy, zz; //process normal==> viewing + TMatrix wprofc = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); + const double wpc[3][3] = {//improve precision with double + {wprofc[0][0], wprofc[0][1], wprofc[0][2]}, + {wprofc[1][0], wprofc[1][1], wprofc[1][2]}, + {wprofc[2][0], wprofc[2][1], wprofc[2][2]} + }; Ciecam02::jch2xyz_ciecam02float(xx, yy, zz, J, C, h, xw2, yw2, zw2, - c2, nc2, pow1n, nbbj, ncbj, flj, czj, dj, awj, c16, plum); + c2, nc2, pow1n, nbbj, ncbj, flj, czj, dj, awj, c16, plum); float x, y, z; x = xx * 655.35f; y = yy * 655.35f; z = zz * 655.35f; float Ll, aa, bb; + //convert xyz=>lab - Color::XYZ2Lab(x, y, z, Ll, aa, bb); - - // gamut control in Lab mode; I must study how to do with cIECAM only if (gamu == 1) { - float Lprov1, Chprov1; - Lprov1 = Ll / 327.68f; - Chprov1 = sqrtf(SQR(aa) + SQR(bb)) / 327.68f; - float2 sincosval; - - if (Chprov1 == 0.0f) { - sincosval.y = 1.f; - sincosval.x = 0.0f; - } else { - sincosval.y = aa / (Chprov1 * 327.68f); - sincosval.x = bb / (Chprov1 * 327.68f); - } - - - //gamut control : Lab values are in gamut - Color::gamutLchonly(sincosval, Lprov1, Chprov1, wip, highlight, 0.15f, 0.96f); - lab->L[i][j] = Lprov1 * 327.68f; - lab->a[i][j] = 327.68f * Chprov1 * sincosval.y; - lab->b[i][j] = 327.68f * Chprov1 * sincosval.x; - - } else { - lab->L[i][j] = Ll; - lab->a[i][j] = aa; - lab->b[i][j] = bb; + Color::gamutmap(x, y, z, wpc); } + Color::XYZ2Lab(x, y, z, Ll, aa, bb); + lab->L[i][j] = Ll; + lab->a[i][j] = aa; + lab->b[i][j] = bb; + #endif } } @@ -1592,7 +1596,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb if (params->defringe.enabled) if (execsharp) { lab->deleteLab(); - defringecam (ncie);//defringe adapted to CIECAM + defringecam(ncie); //defringe adapted to CIECAM lab->reallocLab(); } @@ -1603,7 +1607,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb const bool hotbad = params->dirpyrequalizer.skinprotect != 0.0; lab->deleteLab(); - badpixcam (ncie, artifact / scale, 5, 2, chrom, hotbad); //enabled remove artifacts for cbDL + badpixcam(ncie, artifact / scale, 5, 2, chrom, hotbad); //enabled remove artifacts for cbDL lab->reallocLab(); } @@ -1611,7 +1615,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb if (params->colorappearance.badpixsl > 0 && execsharp) { int mode = params->colorappearance.badpixsl; lab->deleteLab(); - badpixcam (ncie, 3.0, 10, mode, 0, true);//for bad pixels CIECAM + badpixcam(ncie, 3.0, 10, mode, 0, true); //for bad pixels CIECAM lab->reallocLab(); } @@ -1620,17 +1624,17 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb buffers[0] = lab->L; buffers[1] = lab->a; buffers[2] = lab->b; - impulsedenoisecam (ncie, buffers); //impulse adapted to CIECAM + impulsedenoisecam(ncie, buffers); //impulse adapted to CIECAM } if (params->sharpenMicro.enabled)if (execsharp) { - MLmicrocontrastcam (ncie); + MLmicrocontrastcam(ncie); } if (params->sharpening.enabled) if (execsharp) { float **buffer = lab->L; // We can use the L-buffer from lab as buffer to save some memory - sharpeningcam (ncie, buffer, showSharpMask); // sharpening adapted to CIECAM + sharpeningcam(ncie, buffer, showSharpMask); // sharpening adapted to CIECAM } //if(params->dirpyrequalizer.enabled) if(execsharp) { @@ -1643,7 +1647,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb float t_l = static_cast(params->dirpyrequalizer.hueskin.getTopLeft()) / 100.0f; float t_r = static_cast(params->dirpyrequalizer.hueskin.getTopRight()) / 100.0f; lab->deleteLab(); - dirpyr_equalizercam (ncie, ncie->sh_p, ncie->sh_p, ncie->W, ncie->H, ncie->h_p, ncie->C_p, params->dirpyrequalizer.mult, params->dirpyrequalizer.threshold, params->dirpyrequalizer.skinprotect, b_l, t_l, t_r, scale); //contrast by detail adapted to CIECAM + dirpyr_equalizercam(ncie, ncie->sh_p, ncie->sh_p, ncie->W, ncie->H, ncie->h_p, ncie->C_p, params->dirpyrequalizer.mult, params->dirpyrequalizer.threshold, params->dirpyrequalizer.skinprotect, b_l, t_l, t_r, scale); //contrast by detail adapted to CIECAM lab->reallocLab(); } @@ -1666,6 +1670,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb #ifdef _OPENMP #pragma omp for schedule(dynamic, 10) #endif + for (int i = 0; i < height; i++) // update CieImages with new values after sharpening, defringe, contrast by detail level for (int j = 0; j < width; j++) { float interm = fabsf(ncie->sh_p[i][j] / (32768.f)); @@ -1685,7 +1690,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb if (epdEnabled && params->colorappearance.tonecie && algepd) { lab->deleteLab(); - EPDToneMapCIE (ncie, a_w, c_, width, height, minQ, maxQ, Iterates, scale ); + EPDToneMapCIE(ncie, a_w, c_, width, height, minQ, maxQ, Iterates, scale); lab->reallocLab(); } @@ -1769,7 +1774,7 @@ void ImProcFunctions::ciecam_02float(CieImage* ncie, float adap, int pW, int pwb Ciecam02::jch2xyz_ciecam02float(xx, yy, zz, ncie->J_p[i][j], ncie_C_p, ncie->h_p[i][j], xw2, yw2, zw2, - c2, nc2, pow1n, nbbj, ncbj, flj, czj, dj, awj, c16, plum); + c2, nc2, pow1n, nbbj, ncbj, flj, czj, dj, awj, c16, plum); float x = (float)xx * 655.35f; float y = (float)yy * 655.35f; float z = (float)zz * 655.35f; @@ -1894,7 +1899,7 @@ void ImProcFunctions::moyeqt(Imagefloat* working, float &moyS, float &eqty) for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { - const double s = Color::rgb2s(CLIP(working->r (i, j)), CLIP(working->g (i, j)), CLIP(working->b (i, j))); + const double s = Color::rgb2s(CLIP(working->r(i, j)), CLIP(working->g(i, j)), CLIP(working->b(i, j))); moy += s; sqrs += SQR(s); } @@ -1946,12 +1951,12 @@ filmlike_clip(float *r, float *g, float *b) } } -void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, - int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, - const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, - const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, - double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfileApplyState& asIn, - LUTu& histToneCurve, size_t chunkSize, bool measure) +void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, + int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, + const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, + const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, + double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, DCPProfile *dcpProf, const DCPProfileApplyState& asIn, + LUTu& histToneCurve, size_t chunkSize, bool measure) { rgbProc(working, lab, pipetteBuffer, hltonecurve, shtonecurve, tonecurve, sat, rCurve, gCurve, bCurve, satLimit, satLimitOpacity, ctColorCurve, ctOpacityCurve, opautili, clToningcurve, cl2Toningcurve, customToneCurve1, customToneCurve2, customToneCurvebw1, customToneCurvebw2, rrm, ggm, bbm, autor, autog, autob, @@ -1959,12 +1964,12 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } // Process RGB image and convert to LAB space -void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, - int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, - const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, - const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, - double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, - DCPProfile *dcpProf, const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize, bool measure) +void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer *pipetteBuffer, const LUTf& hltonecurve, const LUTf& shtonecurve, const LUTf& tonecurve, + int sat, const LUTf& rCurve, const LUTf& gCurve, const LUTf& bCurve, float satLimit, float satLimitOpacity, + const ColorGradientCurve& ctColorCurve, const OpacityCurve& ctOpacityCurve, bool opautili, const LUTf& clToningcurve, const LUTf& cl2Toningcurve, + const ToneCurve& customToneCurve1, const ToneCurve& customToneCurve2, const ToneCurve& customToneCurvebw1, const ToneCurve& customToneCurvebw2, + double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, + DCPProfile *dcpProf, const DCPProfileApplyState& asIn, LUTu& histToneCurve, size_t chunkSize, bool measure) { std::unique_ptr stop; @@ -1995,8 +2000,8 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } } - TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params->icm.workingProfile); - TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.workingProfile); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix(params->icm.workingProfile); float toxyz[3][3] = { { @@ -2150,13 +2155,13 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer PerceptualToneCurveState ptc1ApplyState, ptc2ApplyState; if (hasToneCurve1 && curveMode == ToneCurveMode::PERCEPTUAL) { - const PerceptualToneCurve& userToneCurve = static_cast (customToneCurve1); - userToneCurve.initApplyState (ptc1ApplyState, params->icm.workingProfile); + const PerceptualToneCurve& userToneCurve = static_cast(customToneCurve1); + userToneCurve.initApplyState(ptc1ApplyState, params->icm.workingProfile); } if (hasToneCurve2 && curveMode2 == ToneCurveMode::PERCEPTUAL) { - const PerceptualToneCurve& userToneCurve = static_cast (customToneCurve2); - userToneCurve.initApplyState (ptc2ApplyState, params->icm.workingProfile); + const PerceptualToneCurve& userToneCurve = static_cast(customToneCurve2); + userToneCurve.initApplyState(ptc2ApplyState, params->icm.workingProfile); } bool hasColorToning = params->colorToning.enabled && bool (ctOpacityCurve) && bool (ctColorCurve) && params->colorToning.method != "LabGrid"; @@ -2351,6 +2356,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } highlightToneCurve(hltonecurve, rtemp, gtemp, btemp, istart, tH, jstart, tW, TS, exp_scale, comp, hlrange); + if (params->toneCurve.black != 0.0) { shadowToneCurve(shtonecurve, rtemp, gtemp, btemp, istart, tH, jstart, tW, TS); } @@ -2402,7 +2408,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer float tmpg[4] ALIGNED16; float tmpb[4] ALIGNED16; - for (; j < tW - 3; j+=4, tj+=4) { + for (; j < tW - 3; j += 4, tj += 4) { //brightness/contrast STVF(tmpr[0], tonecurve(LVF(rtemp[ti * TS + tj]))); STVF(tmpg[0], tonecurve(LVF(gtemp[ti * TS + tj]))); @@ -2683,6 +2689,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer else if (params->colorToning.method == "Splitco") { constexpr float reducac = 0.3f; constexpr int mode = 0; + for (int i = istart, ti = 0; i < tH; i++, ti++) { for (int j = jstart, tj = 0; j < tW; j++, tj++) { const float r = rtemp[ti * TS + tj]; @@ -3113,9 +3120,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer Color::RGB2Lab(&rtemp[ti * TS], >emp[ti * TS], &btemp[ti * TS], &(lab->L[i][jstart]), &(lab->a[i][jstart]), &(lab->b[i][jstart]), toxyz, tW - jstart); } - // if (hasColorToningLabGrid) { - // colorToningLabGrid(lab, jstart, tW, istart, tH, false); - // } + // if (hasColorToningLabGrid) { + // colorToningLabGrid(lab, jstart, tW, istart, tH, false); + // } } else { // black & white // Auto channel mixer needs whole image, so we now copy to tmpImage and close the tiled processing for (int i = istart, ti = 0; i < tH; i++, ti++) { @@ -3494,9 +3501,9 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer for (int i = 0; i < tH; i++) { Color::RGB2Lab(tmpImage->r(i), tmpImage->g(i), tmpImage->b(i), lab->L[i], lab->a[i], lab->b[i], toxyz, tW); - // if (hasColorToningLabGrid) { - // colorToningLabGrid(lab, 0, tW, i, i + 1, false); - // } + // if (hasColorToningLabGrid) { + // colorToningLabGrid(lab, 0, tW, i, i + 1, false); + // } } @@ -3511,7 +3518,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer } if (sCurveEnabled) { - delete sCurve; + delete sCurve; } if (vCurveEnabled) { @@ -3955,7 +3962,7 @@ void ImProcFunctions::toning2col(float r, float g, float b, float &ro, float &go * @param iplow iphigh [0..1] luminance * @param wp wip 3x3 matrix and inverse conversion rgb XYZ **/ -void ImProcFunctions::labtoning (float r, float g, float b, float &ro, float &go, float &bo, int algm, int metchrom, int twoc, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, const LUTf & clToningcurve, const LUTf & cl2Toningcurve, float iplow, float iphigh, double wp[3][3], double wip[3][3] ) +void ImProcFunctions::labtoning(float r, float g, float b, float &ro, float &go, float &bo, int algm, int metchrom, int twoc, float satLimit, float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, const LUTf & clToningcurve, const LUTf & cl2Toningcurve, float iplow, float iphigh, double wp[3][3], double wip[3][3]) { ro = CLIP(r); go = CLIP(g); @@ -4014,7 +4021,7 @@ void ImProcFunctions::labtoning (float r, float g, float b, float &ro, float &go } -void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, const LUTf& curve) +void ImProcFunctions::luminanceCurve(LabImage* lold, LabImage* lnew, const LUTf& curve) { int W = lold->W; @@ -4034,7 +4041,7 @@ void ImProcFunctions::luminanceCurve (LabImage* lold, LabImage* lnew, const LUTf -void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW, LabImage* lold, LabImage* lnew, const LUTf& acurve, const LUTf& bcurve, const LUTf& satcurve, const LUTf& lhskcurve, const LUTf& clcurve, LUTf & curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histLCurve) +void ImProcFunctions::chromiLuminanceCurve(PipetteBuffer *pipetteBuffer, int pW, LabImage* lold, LabImage* lnew, const LUTf& acurve, const LUTf& bcurve, const LUTf& satcurve, const LUTf& lhskcurve, const LUTf& clcurve, LUTf & curve, bool utili, bool autili, bool butili, bool ccutili, bool cclutili, bool clcutili, LUTu &histCCurve, LUTu &histLCurve) { int W = lold->W; int H = lold->H; @@ -4069,7 +4076,8 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW // !params->labCurve.enabled. It is ugly, but it's the smallest code // change that I could find //------------------------------------------------------------------------- - class TempParams { + class TempParams + { const ProcParams **p_; const ProcParams *old_; ProcParams tmp_; @@ -4091,11 +4099,13 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW bool pipette_for_colortoning_labregions = editPipette && params->colorToning.enabled && params->colorToning.method == "LabRegions"; + if (!params->labCurve.enabled && pipette_for_colortoning_labregions) { utili = autili = butili = ccutili = cclutili = clcutili = false; tempparams.reset(new TempParams(¶ms)); curve.makeIdentity(); } + //------------------------------------------------------------------------- @@ -4104,6 +4114,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW // fill pipette buffer with zeros to avoid crashes editWhatever->fill(0.f); } + if (params->blackwhite.enabled && !params->colorToning.enabled) { for (int i = 0; i < lnew->H; ++i) { for (int j = 0; j < lnew->W; ++j) { @@ -4111,6 +4122,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW } } } + return; } @@ -4172,7 +4184,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW // if(params->labCurve.avoidclip ){ // parameter to adapt curve C=f(C) to gamut - if (params->icm.workingProfile == "ProPhoto") { + if (params->icm.workingProfile == "ProPhoto") { adjustr = 1.2f; // 1.2 instead 1.0 because it's very rare to have C>170.. } else if (params->icm.workingProfile == "Adobe RGB") { adjustr = 1.8f; @@ -4203,7 +4215,22 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW const bool clut = clcutili; const double rstprotection = 100. - params->labCurve.rstprotection; // Red and Skin Tones Protection // avoid color shift is disabled when bwToning is activated and enabled if gamut is true in colorappearanace - const bool avoidColorShift = (params->labCurve.avoidcolorshift || (params->colorappearance.gamut && params->colorappearance.enabled)) && !bwToning ; + // const bool avoidColorShift = (params->labCurve.avoidcolorshift || (params->colorappearance.gamut && params->colorappearance.enabled)) && !bwToning ; + //const bool avoidColorS = params->labCurve.avoidcolorshift; + int gamutmuns = 0; + + if (params->labCurve.gamutmunselmethod == "NONE") { + gamutmuns = 0; + } else if (params->labCurve.gamutmunselmethod == "LAB") { + gamutmuns = 1; + } else if (params->labCurve.gamutmunselmethod == "XYZ") { + gamutmuns = 2; + } else if (params->labCurve.gamutmunselmethod == "XYZREL") { + gamutmuns = 3; + } else if (params->labCurve.gamutmunselmethod == "MUN") { + gamutmuns = 4; + } + const float protectRed = (float)settings->protectred; const double protectRedH = settings->protectredh; const float protect_red = rtengine::LIM(protectRed, 20.f, 180.f); //default=60 chroma: one can put more or less if necessary...in 'option' 40...160 @@ -4228,17 +4255,17 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW const float scaleConst = 100.0f / 100.1f; - const bool gamutLch = settings->gamutLch; + //const bool gamutLch = settings->gamutLch; const float amountchroma = (float) settings->amchroma; - TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix (params->icm.workingProfile); + TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix(params->icm.workingProfile); const double wip[3][3] = { {wiprof[0][0], wiprof[0][1], wiprof[0][2]}, {wiprof[1][0], wiprof[1][1], wiprof[1][2]}, {wiprof[2][0], wiprof[2][1], wiprof[2][2]} }; - TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params->icm.workingProfile); + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); const double wp[3][3] = { {wprof[0][0], wprof[0][1], wprof[0][2]}, {wprof[1][0], wprof[1][1], wprof[1][2]}, @@ -4258,12 +4285,12 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW #endif for (int i = 0; i < H; i++) { - if (avoidColorShift) + // if (avoidColorShift) - // only if user activate Lab adjustments - if (autili || butili || ccutili || cclutili || chutili || lhutili || hhutili || clcutili || utili || chromaticity) { - Color::LabGamutMunsell(lold->L[i], lold->a[i], lold->b[i], W, /*corMunsell*/true, /*lumaMuns*/false, params->toneCurve.hrenabled, /*gamut*/true, wip); - } + // only if user activate Lab adjustments + // if (autili || butili || ccutili || cclutili || chutili || lhutili || hhutili || clcutili || utili || chromaticity) { + // Color::LabGamutMunsell(lold->L[i], lold->a[i], lold->b[i], W, /*corMunsell*/true, /*lumaMuns*/false, params->toneCurve.hrenabled, /*gamut*/true, wip); + // } #ifdef __SSE2__ @@ -4277,7 +4304,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW av = LVFU(lold->a[i][k]); bv = LVFU(lold->b[i][k]); STVF(HHBuffer[k], xatan2f(bv, av)); - STVF (CCBuffer[k], vsqrtf (SQRV (av) + SQRV (bv)) / c327d68v); + STVF(CCBuffer[k], vsqrtf(SQRV(av) + SQRV(bv)) / c327d68v); } for (; k < W; k++) { @@ -4431,8 +4458,8 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW float fx = (0.002f * aprov1) + fy; float fz = fy - (0.005f * bprov1); - float x_ = 65535.f * Color::f2xyz (fx) * Color::D50x; - float z_ = 65535.f * Color::f2xyz (fz) * Color::D50z; + float x_ = 65535.f * Color::f2xyz(fx) * Color::D50x; + float z_ = 65535.f * Color::f2xyz(fz) * Color::D50z; float y_ = Lprov1 > Color::epskapf ? 65535.f * fy * fy * fy : 65535.f * Lprov1 / Color::kappaf; float R, G, B; Color::xyz2rgb(x_, y_, z_, R, G, B, wip); @@ -4704,24 +4731,57 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW btmp -= lold->b[i][j]; } - if (avoidColorShift) { - //gamutmap Lch ==> preserve Hue,but a little slower than gamutbdy for high values...and little faster for low values - if (gamutLch) { - float R, G, B; - //gamut control : Lab values are in gamut - Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); - lnew->L[i][j] = Lprov1 * 327.68f; - lnew->a[i][j] = 327.68f * Chprov1 * sincosval.y; - lnew->b[i][j] = 327.68f * Chprov1 * sincosval.x; - } else { - //use gamutbdy - //Luv limiter - float Y, u, v; - Color::Lab2Yuv(lnew->L[i][j], atmp, btmp, Y, u, v); - //Yuv2Lab includes gamut restriction map - Color::Yuv2Lab(Y, u, v, lnew->L[i][j], lnew->a[i][j], lnew->b[i][j], wp); + lnew->L[i][j] = Lprov1 * 327.68f; + lnew->a[i][j] = 327.68f * Chprov1 * sincosval.y; + lnew->b[i][j] = 327.68f * Chprov1 * sincosval.x; + + //gamutmap Lch ==> preserve Hue,but a little slower than gamutbdy for high values...and little faster for low values + if (gamutmuns == 1) { + float R, G, B; + //gamut control : Lab values are in gamut + Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, 0.15f, 0.96f); + lnew->L[i][j] = Lprov1 * 327.68f; + lnew->a[i][j] = 327.68f * Chprov1 * sincosval.y; + lnew->b[i][j] = 327.68f * Chprov1 * sincosval.x; + } + + if (gamutmuns == 2 || gamutmuns == 3) { + + float xg, yg, zg; + Color::Lab2XYZ(lnew->L[i][j], atmp, btmp, xg, yg, zg); + float x0 = xg; + float y0 = yg; + float z0 = zg; + + Color::gamutmap(xg, yg, zg, wp); + + if (gamutmuns == 3) {//0.5f arbitrary coeff + xg = xg + 0.5f * (x0 - xg); + yg = yg + 0.5f * (y0 - yg); + zg = zg + 0.5f * (z0 - zg); } + float Lag, aag2, bbg2; + Color::XYZ2Lab(xg, yg, zg, Lag, aag2, bbg2); + Lprov1 = Lag / 327.68f; + HH = xatan2f(bbg2, aag2); + Chprov1 = std::sqrt(SQR(aag2) + SQR(bbg2)) / 327.68f; + + if (Chprov1 == 0.0f) { + sincosval.y = 1.f; + sincosval.x = 0.0f; + } else { + sincosval.y = aag2 / (Chprov1 * 327.68f); + sincosval.x = bbg2 / (Chprov1 * 327.68f); + } + + lnew->L[i][j] = Lprov1 * 327.68f; + lnew->a[i][j] = 327.68f * Chprov1 * sincosval.y; + lnew->b[i][j] = 327.68f * Chprov1 * sincosval.x; + + } + + if (gamutmuns > 0) { if (utili || autili || butili || ccut || clut || cclutili || chutili || lhutili || hhutili || clcutili || chromaticity) { float correctionHue = 0.f; // Munsell's correction float correctlum = 0.f; @@ -4747,7 +4807,10 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW lnew->a[i][j] = 327.68f * Chprov * sincosval.y; // apply Munsell lnew->b[i][j] = 327.68f * Chprov * sincosval.x; } - } else { + } + + if (gamutmuns == 0) { + // if(Lprov1 > maxlp) maxlp=Lprov1; // if(Lprov1 < minlp) minlp=Lprov1; if (!bwToning) { @@ -4940,11 +5003,12 @@ void ImProcFunctions::EPDToneMapCIE(CieImage *ncie, float a_w, float c_, int Wid if (!params->epd.enabled) { return; } -/* - if (params->wavelet.enabled && params->wavelet.tmrs != 0) { - return; - } -*/ + + /* + if (params->wavelet.enabled && params->wavelet.tmrs != 0) { + return; + } + */ float stren = params->epd.strength; const float edgest = std::min(params->epd.edgeStopping, params->localContrast.enabled ? 3.0 : 4.0); float sca = params->epd.scale; @@ -4954,7 +5018,7 @@ void ImProcFunctions::EPDToneMapCIE(CieImage *ncie, float a_w, float c_, int Wid float *Qpr = ncie->Q_p[0]; if (settings->verbose) { - printf ("minQ=%f maxQ=%f Qpro=%f\n", static_cast(minQ), static_cast(maxQ), static_cast(Qpro)); + printf("minQ=%f maxQ=%f Qpro=%f\n", static_cast(minQ), static_cast(maxQ), static_cast(Qpro)); } if (maxQ > Qpro) { @@ -4993,6 +5057,7 @@ void ImProcFunctions::EPDToneMapCIE(CieImage *ncie, float a_w, float c_, int Wid #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,10) #endif + for (int i = 0; i < Hei; i++) for (int j = 0; j < Wid; j++) { ncie->Q_p[i][j] = (ncie->Q_p[i][j] * Qpro) / gamm; @@ -5043,7 +5108,7 @@ void ImProcFunctions::EPDToneMaplocal(int sp, LabImage *lab, LabImage *tmp1, uns float stren = ((float)params->locallab.spots.at(sp).stren); const float edgest = std::min(params->locallab.spots.at(sp).estop, params->localContrast.enabled ? 3.0 : 4.0); - + float sca = ((float)params->locallab.spots.at(sp).scaltm); float gamm = ((float)params->locallab.spots.at(sp).gamma); float satur = ((float)params->locallab.spots.at(sp).satur) / 100.f; @@ -5064,6 +5129,7 @@ void ImProcFunctions::EPDToneMaplocal(int sp, LabImage *lab, LabImage *tmp1, uns #ifdef _OPENMP #pragma omp parallel for reduction(max:maxL) reduction(min:minL) schedule(dynamic,16) #endif + for (std::size_t i = 0; i < N; i++) { minL = rtengine::min(minL, L[i]); maxL = rtengine::max(maxL, L[i]); @@ -5081,8 +5147,8 @@ void ImProcFunctions::EPDToneMaplocal(int sp, LabImage *lab, LabImage *tmp1, uns #ifdef _OPENMP #pragma omp parallel for #endif - for (std::size_t i = 0; i < N; i++) - { + + for (std::size_t i = 0; i < N; i++) { L[i] = (L[i] - minL) * mult; } @@ -5111,8 +5177,12 @@ void ImProcFunctions::EPDToneMaplocal(int sp, LabImage *lab, LabImage *tmp1, uns //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. float s = (1.0f + 38.7889f) * powf(Compression, 1.5856f) / (1.0f + 38.7889f * powf(Compression, 1.5856f)); float sat = s + 0.3f * s * satur; + //printf("s=%f sat=%f \n", s, sat); - if(sat == 1.f) sat = 1.001f; + if (sat == 1.f) { + sat = 1.001f; + } + #ifdef _OPENMP #pragma omp parallel for // removed schedule(dynamic,10) #endif @@ -5159,6 +5229,7 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) #ifdef _OPENMP #pragma omp parallel for reduction(min:minL) reduction(max:maxL) #endif + for (size_t i = 1; i < N; i++) { minL = std::min(minL, L[i]); maxL = std::max(maxL, L[i]); @@ -5173,6 +5244,7 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) #ifdef _OPENMP #pragma omp parallel for #endif + for (size_t i = 0; i < N; ++i) { L[i] = (L[i] - minL) * (gamm / maxL); } @@ -5186,7 +5258,7 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) Iterates = edgest * 15.f; } - epd.CompressDynamicRange (L, sca / skip, edgest, Compression, DetailBoost, Iterates, rew); + epd.CompressDynamicRange(L, sca / skip, edgest, Compression, DetailBoost, Iterates, rew); //Restore past range, also desaturate a bit per Mantiuk's Color correction for tone mapping. const float s = (1.f + 38.7889f) * std::pow(Compression, 1.5856f) / (1.f + 38.7889f * std::pow(Compression, 1.5856f)); @@ -5195,6 +5267,7 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip) #ifdef _OPENMP #pragma omp parallel for #endif + for (size_t ii = 0; ii < N; ++ii) { a[ii] *= s; b[ii] *= s; @@ -5242,7 +5315,7 @@ void ImProcFunctions::getAutoExp(const LUTu &histogram, int histcompr, double cl int j = 0; - for (; j < min ((int)ave, imax); ++j) { + for (; j < min((int)ave, imax); ++j) { if (count < 8) { octile[count] += histogram[j]; @@ -5335,7 +5408,7 @@ void ImProcFunctions::getAutoExp(const LUTu &histogram, int histcompr, double cl } //compute clipped white point - unsigned int clippable = (int) (static_cast(sum) * clip / 100.0 ); + unsigned int clippable = (int)(static_cast(sum) * clip / 100.0); clipped = 0; int whiteclip = (imax) - 1; @@ -5414,7 +5487,7 @@ void ImProcFunctions::getAutoExp(const LUTu &histogram, int histcompr, double cl contr = (int) 50.0f * (1.1f - ospread); contr = max(0, min(100, contr)); //take gamma into account - double whiteclipg = (int) (CurveFactory::gamma2(whiteclip * static_cast(corr) / 65536.0) * 65536.0); + double whiteclipg = (int)(CurveFactory::gamma2(whiteclip * static_cast(corr) / 65536.0) * 65536.0); float gavg = 0.; @@ -5594,7 +5667,8 @@ void ImProcFunctions::rgb2lab(const Imagefloat &src, LabImage &dst, const Glib:: } void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, float L[], float a[], float b[], const procparams::ColorManagementParams &icm, bool consider_histogram_settings) const -{ // Adapted from ImProcFunctions::lab2rgb +{ + // Adapted from ImProcFunctions::lab2rgb const int src_width = src.getWidth(); const int src_height = src.getHeight(); @@ -5626,6 +5700,7 @@ void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, flo if (icm.outputProfile.empty() || icm.outputProfile == ColorManagementParams::NoICMString) { profile = "sRGB"; } + oprof = ICCStore::getInstance()->getProfile(profile); } @@ -5638,7 +5713,7 @@ void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, flo lcmsMutex->lock(); cmsHPROFILE LabIProf = cmsCreateLab4Profile(nullptr); - cmsHTRANSFORM hTransform = cmsCreateTransform (oprof, TYPE_RGB_8, LabIProf, TYPE_Lab_FLT, icm.outputIntent, flags); + cmsHTRANSFORM hTransform = cmsCreateTransform(oprof, TYPE_RGB_8, LabIProf, TYPE_Lab_FLT, icm.outputIntent, flags); cmsCloseProfile(LabIProf); lcmsMutex->unlock(); @@ -5662,7 +5737,7 @@ void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, flo float* ra = a + (i - y) * w; float* rb = b + (i - y) * w; - cmsDoTransform (hTransform, src.data + ix, outbuffer, w); + cmsDoTransform(hTransform, src.data + ix, outbuffer, w); for (int j = 0; j < w; j++) { rL[j] = outbuffer[iy++] * 327.68f; @@ -5691,6 +5766,7 @@ void ImProcFunctions::rgb2lab(const Image8 &src, int x, int y, int w, int h, flo for (int i = y; i < y2; i++) { int offset = (i - y) * w; + for (int j = x; j < x2; j++) { float X, Y, Z; // lab2rgb uses gamma2curve, which is gammatab_srgb. @@ -5782,7 +5858,7 @@ void ImProcFunctions::colorToningLabGrid(LabImage *lab, int xstart, int xend, in float b_scale = (params->colorToning.labgridBHigh - params->colorToning.labgridBLow) / factor / scaling; float b_base = params->colorToning.labgridBLow / scaling; - #ifdef _OPENMP +#ifdef _OPENMP #pragma omp parallel for if (MultiThread) #endif diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 1be1d0371..36c571291 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -257,7 +257,7 @@ enum class BlurType { int shortcu, bool delt, const float hueref, const float chromaref, const float lumaref, float maxdE, float mindE, float maxdElim, float mindElim, float iterat, float limscope, int scope, bool fftt, float blu_ma, float cont_ma, int indic, float &fab); - void avoidcolshi(const struct local_params& lp, int sp, LabImage * original, LabImage *transformed, int cy, int cx, int sk); + void avoidcolshi(const struct local_params& lp, int sp, LabImage *transformed, LabImage *reserved, int cy, int cx, int sk); void deltaEforMask(float **rdE, int bfw, int bfh, LabImage* bufcolorig, const float hueref, const float chromaref, const float lumaref, float maxdE, float mindE, float maxdElim, float mindElim, float iterat, float limscope, int scope, float balance, float balanceh); diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 62f211ae6..bdc1b6db1 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -12540,12 +12540,31 @@ void ImProcFunctions::clarimerge(const struct local_params& lp, float &mL, float } } -void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImage * original, LabImage *transformed, int cy, int cx, int sk) +void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImage *transformed, LabImage *reserved, int cy, int cx, int sk) { - if (params->locallab.spots.at(sp).avoid && lp.islocal) { + int avoidgamut = 0; + + if (params->locallab.spots.at(sp).avoidgamutMethod == "NONE") { + avoidgamut = 0; + } else if (params->locallab.spots.at(sp).avoidgamutMethod == "LAB") { + avoidgamut = 1; + } else if (params->locallab.spots.at(sp).avoidgamutMethod == "XYZ") { + avoidgamut = 2; + } else if (params->locallab.spots.at(sp).avoidgamutMethod == "XYZREL") { + avoidgamut = 3; + } else if (params->locallab.spots.at(sp).avoidgamutMethod == "MUNS") { + avoidgamut = 4; + } + + if (avoidgamut == 0) { + return; + } + + if (avoidgamut > 0 && lp.islocal) { const float ach = lp.trans / 100.f; bool execmunsell = true; - if(params->locallab.spots.at(sp).expcie && (params->locallab.spots.at(sp).modecam == "all" || params->locallab.spots.at(sp).modecam == "jz" || params->locallab.spots.at(sp).modecam == "cam16")) { + + if (params->locallab.spots.at(sp).expcie && (params->locallab.spots.at(sp).modecam == "all" || params->locallab.spots.at(sp).modecam == "jz" || params->locallab.spots.at(sp).modecam == "cam16")) { execmunsell = false; } @@ -12556,11 +12575,18 @@ void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImag {wiprof[2][0], wiprof[2][1], wiprof[2][2]} }; + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.workingProfile); + const double wp[3][3] = {//improve precision with double + {wprof[0][0], wprof[0][1], wprof[0][2]}, + {wprof[1][0], wprof[1][1], wprof[1][2]}, + {wprof[2][0], wprof[2][1], wprof[2][2]} + }; + const float softr = params->locallab.spots.at(sp).avoidrad;//max softr = 30 - const bool muns = params->locallab.spots.at(sp).avoidmun;//Munsell control with 200 LUT + // const bool muns = params->locallab.spots.at(sp).avoidmun;//Munsell control with 200 LUT //improve precision with mint and maxt const float tr = std::min(2.f, softr); - const float mint = 0.15f - 0.06f * tr;//between 0.15f and 0.03f + const float mint = 0.15f - 0.06f * tr;//between 0.15f and 0.03f const float maxt = 0.98f + 0.008f * tr;//between 0.98f and 0.996f const bool highlight = params->toneCurve.hrenabled; @@ -12581,6 +12607,7 @@ void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImag #ifdef _OPENMP #pragma omp for schedule(dynamic,16) #endif + for (int y = 0; y < transformed->H; y++) { const int loy = cy + y; const bool isZone0 = loy > lp.yc + lp.ly || loy < lp.yc - lp.lyT; // whole line is zone 0 => we can skip a lot of processing @@ -12640,7 +12667,7 @@ void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImag if (lp.shapmet == 0) { calcTransition(lox, loy, ach, lp, zone, localFactor); - } else /*if (lp.shapmet == 1)*/ { + } else { /*if (lp.shapmet == 1)*/ calcTransitionrect(lox, loy, ach, lp, zone, localFactor); } @@ -12675,42 +12702,103 @@ void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImag sincosval.y = aa / (Chprov1 * 327.68f); sincosval.x = bb / (Chprov1 * 327.68f); } + #endif + float lnew = transformed->L[y][x]; + float anew = transformed->a[y][x]; + float bnew = transformed->b[y][x]; + Lprov1 = lnew / 327.68f; + //HH = xatan2f(bnew, anew); - Color::pregamutlab(Lprov1, HH, chr); - Chprov1 = rtengine::min(Chprov1, chr); - if(!muns) { - float R, G, B; + if (avoidgamut == 1) { //Lab correction + + Color::pregamutlab(Lprov1, HH, chr); + Chprov1 = rtengine::min(Chprov1, chr); + + float R, G, B; Color::gamutLchonly(HH, sincosval, Lprov1, Chprov1, R, G, B, wip, highlight, mint, maxt);//replace for best results - } - transformed->L[y][x] = Lprov1 * 327.68f; - transformed->a[y][x] = 327.68f * Chprov1 * sincosval.y; - transformed->b[y][x] = 327.68f * Chprov1 * sincosval.x; + lnew = Lprov1 * 327.68f; + anew = 327.68f * Chprov1 * sincosval.y; + bnew = 327.68f * Chprov1 * sincosval.x; + //HH = xatan2f(bnew, anew); + transformed->a[y][x] = anew; + transformed->b[y][x] = bnew; - if (needHH) { - const float Lprov2 = original->L[y][x] / 327.68f; + } else if (avoidgamut == 2 || avoidgamut == 3) { //XYZ correction + float xg, yg, zg; + const float aag = transformed->a[y][x];//anew + const float bbg = transformed->b[y][x];//bnew + float Lag = transformed->L[y][x]; + + Color::Lab2XYZ(Lag, aag, bbg, xg, yg, zg); + float x0 = xg; + float y0 = yg; + float z0 = zg; + + Color::gamutmap(xg, yg, zg, wp); + + if (avoidgamut == 3) {//0.5f arbitrary coeff + xg = xg + 0.5f * (x0 - xg); + yg = yg + 0.5f * (y0 - yg); + zg = zg + 0.5f * (z0 - zg); + } + + //Color::gamutmap(xg, yg, zg, wp);//Put XYZ in gamut wp + float aag2, bbg2; + Color::XYZ2Lab(xg, yg, zg, Lag, aag2, bbg2); + Lprov1 = Lag / 327.68f; + HH = xatan2f(bbg2, aag2);//rebuild HH in case of...absolute colorimetry + Chprov1 = std::sqrt(SQR(aag2) + SQR(bbg2)) / 327.68f; + + if (Chprov1 == 0.0f) { + sincosval.y = 1.f; + sincosval.x = 0.0f; + } else { + sincosval.y = aag2 / (Chprov1 * 327.68f); + sincosval.x = bbg2 / (Chprov1 * 327.68f); + } + + lnew = Lprov1 * 327.68f; + anew = 327.68f * Chprov1 * sincosval.y; + bnew = 327.68f * Chprov1 * sincosval.x; + transformed->a[y][x] = anew; + transformed->b[y][x] = bnew; + + } + + if (needHH && avoidgamut <= 4) {//Munsell + Lprov1 = lnew / 327.68f; + float Chprov = sqrt(SQR(anew) + SQR(bnew)) / 327.68f; + + const float Lprov2 = reserved->L[y][x] / 327.68f; float correctionHue = 0.f; // Munsell's correction float correctlum = 0.f; - const float memChprov = std::sqrt(SQR(original->a[y][x]) + SQR(original->b[y][x])) / 327.68f; - float Chprov = std::sqrt(SQR(transformed->a[y][x]) + SQR(transformed->b[y][x])) / 327.68f; - if(execmunsell) { + const float memChprov = std::sqrt(SQR(reserved->a[y][x]) + SQR(reserved->b[y][x])) / 327.68f; + + if (execmunsell) { Color::AllMunsellLch(true, Lprov1, Lprov2, HH, Chprov, memChprov, correctionHue, correctlum); } - if (std::fabs(correctionHue) < 0.015f) { - HH += correctlum; // correct only if correct Munsell chroma very small. + if (correctionHue != 0.f || correctlum != 0.f) { + + if (std::fabs(correctionHue) < 0.015f) { + HH += correctlum; // correct only if correct Munsell chroma very small. + } + + sincosval = xsincosf(HH + correctionHue); } - sincosval = xsincosf(HH + correctionHue); - transformed->a[y][x] = 327.68f * Chprov * sincosval.y; // apply Munsell - transformed->b[y][x] = 327.68f * Chprov * sincosval.x; + anew = 327.68f * Chprov * sincosval.y; // apply Munsell + bnew = 327.68f * Chprov * sincosval.x; + transformed->a[y][x] = anew; // apply Munsell + transformed->b[y][x] = bnew; } } } } - //Guidedfilter to reduce artifacts in transitions - if (softr != 0.f) {//soft for L a b because we change color... + //Guidedfilter to reduce artifacts in transitions : case Lab + if (softr != 0.f && avoidgamut == 1) {//soft for L a b because we change color... const float tmpblur = softr < 0.f ? -1.f / softr : 1.f + softr; const int r1 = rtengine::max(6 / sk * tmpblur + 0.5f, 1); const int r2 = rtengine::max(10 / sk * tmpblur + 0.5f, 1); @@ -12734,13 +12822,15 @@ void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImag for (int y = 0; y < bh ; y++) { for (int x = 0; x < bw; x++) { ble[y][x] = transformed->L[y][x] / 32768.f; - guid[y][x] = original->L[y][x] / 32768.f; + guid[y][x] = reserved->L[y][x] / 32768.f; } } + rtengine::guidedFilter(guid, ble, ble, r2, 0.2f * epsil, multiThread); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) if (multiThread) #endif + for (int y = 0; y < bh; y++) { for (int x = 0; x < bw; x++) { transformed->L[y][x] = 32768.f * ble[y][x]; @@ -12757,11 +12847,13 @@ void ImProcFunctions::avoidcolshi(const struct local_params& lp, int sp, LabImag blechro[y][x] = std::sqrt(SQR(transformed->b[y][x]) + SQR(transformed->a[y][x])) / 32768.f; } } + rtengine::guidedFilter(guid, blechro, blechro, r1, epsil, multiThread); #ifdef _OPENMP #pragma omp parallel for schedule(dynamic,16) if (multiThread) #endif + for (int y = 0; y < bh; y++) { for (int x = 0; x < bw; x++) { const float Chprov1 = std::sqrt(SQR(transformed->a[y][x]) + SQR(transformed->b[y][x])); @@ -13286,7 +13378,7 @@ void ImProcFunctions::Lab_Local( struct local_params lp; calcLocalParams(sp, oW, oH, params->locallab, lp, prevDeltaE, llColorMask, llColorMaskinv, llExpMask, llExpMaskinv, llSHMask, llSHMaskinv, llvibMask, lllcMask, llsharMask, llcbMask, llretiMask, llsoftMask, lltmMask, llblMask, lllogMask, ll_Mask, llcieMask, locwavCurveden, locwavdenutili); - avoidcolshi(lp, sp, original, transformed, cy, cx, sk); + //avoidcolshi(lp, sp, transformed, reserved, cy, cx, sk); const float radius = lp.rad / (sk * 1.4); //0 to 70 ==> see skip int levred; @@ -19188,7 +19280,7 @@ void ImProcFunctions::Lab_Local( // Gamut and Munsell control - very important do not deactivated to avoid crash - avoidcolshi(lp, sp, original, transformed, cy, cx, sk); + avoidcolshi(lp, sp, transformed, reserved, cy, cx, sk); } } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index a83419559..13df614dc 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -137,7 +137,7 @@ enum ProcEventCode { EvHLComprThreshold = 107, EvResizeBoundingBox = 108, EvResizeAppliesTo = 109, - EvLAvoidColorShift = 110, + //EvLAvoidColorShift = 110, obsolete_111 = 111, // obsolete EvLRSTProtection = 112, EvDemosaicDCBIter = 113, @@ -617,7 +617,7 @@ enum ProcEventCode { Evlocallabadjblur = 587, Evlocallabbilateral = 588, Evlocallabsensiden = 589, - Evlocallabavoid = 590, + // Evlocallabavoid = 590, Evlocallabsharcontrast = 591, EvLocenacontrast = 592, Evlocallablcradius = 593, @@ -1067,7 +1067,7 @@ enum ProcEventCode { Evlocallabnlgam = 1037, Evlocallabdivgr = 1038, EvLocallabSpotavoidrad = 1039, - EvLocallabSpotavoidmun = 1040, + //EvLocallabSpotavoidmun = 1040, Evlocallabcontthres = 1041, Evlocallabnorm = 1042, Evlocallabreparw = 1043, diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 371731b93..e6bdc9619 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -608,7 +608,7 @@ LCurveParams::LCurveParams() : brightness(0), contrast(0), chromaticity(0), - avoidcolorshift(false), + gamutmunselmethod("MUN"), rstprotection(0), lcredsk(true) { @@ -630,7 +630,7 @@ bool LCurveParams::operator ==(const LCurveParams& other) const && brightness == other.brightness && contrast == other.contrast && chromaticity == other.chromaticity - && avoidcolorshift == other.avoidcolorshift + && gamutmunselmethod == other.gamutmunselmethod && rstprotection == other.rstprotection && lcredsk == other.lcredsk; } @@ -2848,6 +2848,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : structexclu(0), struc(4.0), shapeMethod("IND"), + avoidgamutMethod("MUNS"), loc{150, 150, 150, 150}, centerX(0), centerY(0), @@ -2862,13 +2863,11 @@ LocallabParams::LocallabSpot::LocallabSpot() : balanh(1.0), colorde(5.0), colorscope(30.0), - avoidrad(0.7), + avoidrad(0.), transitweak(1.0), transitgrad(0.0), hishow(false), activ(true), - avoid(false), - avoidmun(false), blwh(false), recurs(false), laplac(true), @@ -4560,6 +4559,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && structexclu == other.structexclu && struc == other.struc && shapeMethod == other.shapeMethod + && avoidgamutMethod == other.avoidgamutMethod && loc == other.loc && centerX == other.centerX && centerY == other.centerY @@ -4579,8 +4579,6 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && transitgrad == other.transitgrad && hishow == other.hishow && activ == other.activ - && avoid == other.avoid - && avoidmun == other.avoidmun && blwh == other.blwh && recurs == other.recurs && laplac == other.laplac @@ -6045,7 +6043,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->labCurve.brightness, "Luminance Curve", "Brightness", labCurve.brightness, keyFile); saveToKeyfile(!pedited || pedited->labCurve.contrast, "Luminance Curve", "Contrast", labCurve.contrast, keyFile); saveToKeyfile(!pedited || pedited->labCurve.chromaticity, "Luminance Curve", "Chromaticity", labCurve.chromaticity, keyFile); - saveToKeyfile(!pedited || pedited->labCurve.avoidcolorshift, "Luminance Curve", "AvoidColorShift", labCurve.avoidcolorshift, keyFile); + saveToKeyfile(!pedited || pedited->labCurve.gamutmunselmethod, "Luminance Curve", "Gamutmunse", labCurve.gamutmunselmethod, keyFile); saveToKeyfile(!pedited || pedited->labCurve.rstprotection, "Luminance Curve", "RedAndSkinTonesProtection", labCurve.rstprotection, keyFile); saveToKeyfile(!pedited || pedited->labCurve.lcredsk, "Luminance Curve", "LCredsk", labCurve.lcredsk, keyFile); saveToKeyfile(!pedited || pedited->labCurve.lcurve, "Luminance Curve", "LCurve", labCurve.lcurve, keyFile); @@ -6347,6 +6345,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || spot_edited->structexclu, "Locallab", "StructExclu_" + index_str, spot.structexclu, keyFile); saveToKeyfile(!pedited || spot_edited->struc, "Locallab", "Struc_" + index_str, spot.struc, keyFile); saveToKeyfile(!pedited || spot_edited->shapeMethod, "Locallab", "ShapeMethod_" + index_str, spot.shapeMethod, keyFile); + saveToKeyfile(!pedited || spot_edited->avoidgamutMethod, "Locallab", "AvoidgamutMethod_" + index_str, spot.avoidgamutMethod, keyFile); saveToKeyfile(!pedited || spot_edited->loc, "Locallab", "Loc_" + index_str, spot.loc, keyFile); saveToKeyfile(!pedited || spot_edited->centerX, "Locallab", "CenterX_" + index_str, spot.centerX, keyFile); saveToKeyfile(!pedited || spot_edited->centerY, "Locallab", "CenterY_" + index_str, spot.centerY, keyFile); @@ -6366,8 +6365,6 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || spot_edited->transitgrad, "Locallab", "Transitgrad_" + index_str, spot.transitgrad, keyFile); saveToKeyfile(!pedited || spot_edited->hishow, "Locallab", "Hishow_" + index_str, spot.hishow, keyFile); saveToKeyfile(!pedited || spot_edited->activ, "Locallab", "Activ_" + index_str, spot.activ, keyFile); - saveToKeyfile(!pedited || spot_edited->avoid, "Locallab", "Avoid_" + index_str, spot.avoid, keyFile); - saveToKeyfile(!pedited || spot_edited->avoidmun, "Locallab", "Avoidmun_" + index_str, spot.avoidmun, keyFile); saveToKeyfile(!pedited || spot_edited->blwh, "Locallab", "Blwh_" + index_str, spot.blwh, keyFile); saveToKeyfile(!pedited || spot_edited->recurs, "Locallab", "Recurs_" + index_str, spot.recurs, keyFile); saveToKeyfile(!pedited || spot_edited->laplac, "Locallab", "Laplac_" + index_str, spot.laplac, keyFile); @@ -7871,7 +7868,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) // if Saturation == 0, should we set BWToning on? assignFromKeyfile(keyFile, "Luminance Curve", "Saturation", pedited, labCurve.chromaticity, pedited->labCurve.chromaticity); // transform AvoidColorClipping into AvoidColorShift - assignFromKeyfile(keyFile, "Luminance Curve", "AvoidColorClipping", pedited, labCurve.avoidcolorshift, pedited->labCurve.avoidcolorshift); +// assignFromKeyfile(keyFile, "Luminance Curve", "AvoidColorClipping", pedited, labCurve.avoidcolorshift, pedited->labCurve.avoidcolorshift); } else { if (keyFile.has_key("Luminance Curve", "Chromaticity")) { labCurve.chromaticity = keyFile.get_integer("Luminance Curve", "Chromaticity"); @@ -7885,7 +7882,6 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) } } - assignFromKeyfile(keyFile, "Luminance Curve", "AvoidColorShift", pedited, labCurve.avoidcolorshift, pedited->labCurve.avoidcolorshift); assignFromKeyfile(keyFile, "Luminance Curve", "RedAndSkinTonesProtection", pedited, labCurve.rstprotection, pedited->labCurve.rstprotection); } @@ -7914,6 +7910,25 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Luminance Curve", "hhCurve", pedited, labCurve.hhcurve, pedited->labCurve.hhcurve); assignFromKeyfile(keyFile, "Luminance Curve", "LcCurve", pedited, labCurve.lccurve, pedited->labCurve.lccurve); assignFromKeyfile(keyFile, "Luminance Curve", "ClCurve", pedited, labCurve.clcurve, pedited->labCurve.clcurve); + if (keyFile.has_key("Luminance Curve", "Gamutmunse")) { + assignFromKeyfile(keyFile, "Luminance Curve", "Gamutmunse", pedited, labCurve.gamutmunselmethod, pedited->labCurve.gamutmunselmethod); + } else { + if (ppVersion < 303) { + if (keyFile.has_key("Luminance Curve", "AvoidColorClipping")) { + labCurve.gamutmunselmethod = + keyFile.get_boolean("Luminance Curve", "AvoidColorClipping") ? "LAB" : "NONE"; + if (pedited) { + pedited->labCurve.gamutmunselmethod = true; + } + } + } else if (keyFile.has_key("Luminance Curve", "AvoidColorShift")) { + labCurve.gamutmunselmethod = + keyFile.get_boolean("Luminance Curve", "AvoidColorShift") ? "LAB" : "NONE"; + if (pedited) { + pedited->labCurve.gamutmunselmethod = true; + } + } + } } if (keyFile.has_group("Sharpening")) { @@ -8423,6 +8438,16 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "StructExclu_" + index_str, pedited, spot.structexclu, spotEdited.structexclu); assignFromKeyfile(keyFile, "Locallab", "Struc_" + index_str, pedited, spot.struc, spotEdited.struc); assignFromKeyfile(keyFile, "Locallab", "ShapeMethod_" + index_str, pedited, spot.shapeMethod, spotEdited.shapeMethod); + if (keyFile.has_key("Locallab", "AvoidgamutMethod_" + index_str)) { + assignFromKeyfile(keyFile, "Locallab", "AvoidgamutMethod_" + index_str, pedited, spot.avoidgamutMethod, spotEdited.avoidgamutMethod); + } else if (keyFile.has_key("Locallab", "Avoid_" + index_str)) { + const bool avoid = keyFile.get_boolean("Locallab", "Avoid_" + index_str); + const bool munsell = keyFile.has_key("Locallab", "Avoidmun_" + index_str) && keyFile.get_boolean("Locallab", "Avoidmun_" + index_str); + spot.avoidgamutMethod = avoid ? (munsell ? "MUNS" : "LAB") : "NONE"; + if (pedited) { + spotEdited.avoidgamutMethod = true; + } + } assignFromKeyfile(keyFile, "Locallab", "Loc_" + index_str, pedited, spot.loc, spotEdited.loc); assignFromKeyfile(keyFile, "Locallab", "CenterX_" + index_str, pedited, spot.centerX, spotEdited.centerX); assignFromKeyfile(keyFile, "Locallab", "CenterY_" + index_str, pedited, spot.centerY, spotEdited.centerY); @@ -8442,8 +8467,6 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "Transitgrad_" + index_str, pedited, spot.transitgrad, spotEdited.transitgrad); assignFromKeyfile(keyFile, "Locallab", "Hishow_" + index_str, pedited, spot.hishow, spotEdited.hishow); assignFromKeyfile(keyFile, "Locallab", "Activ_" + index_str, pedited, spot.activ, spotEdited.activ); - assignFromKeyfile(keyFile, "Locallab", "Avoid_" + index_str, pedited, spot.avoid, spotEdited.avoid); - assignFromKeyfile(keyFile, "Locallab", "Avoidmun_" + index_str, pedited, spot.avoidmun, spotEdited.avoidmun); assignFromKeyfile(keyFile, "Locallab", "Blwh_" + index_str, pedited, spot.blwh, spotEdited.blwh); assignFromKeyfile(keyFile, "Locallab", "Recurs_" + index_str, pedited, spot.recurs, spotEdited.recurs); assignFromKeyfile(keyFile, "Locallab", "Laplac_" + index_str, pedited, spot.laplac, spotEdited.laplac); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 24e1ca036..e86272b0a 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -376,7 +376,7 @@ struct LCurveParams { int brightness; int contrast; int chromaticity; - bool avoidcolorshift; + Glib::ustring gamutmunselmethod; double rstprotection; bool lcredsk; @@ -1019,6 +1019,8 @@ struct LocallabParams { int structexclu; double struc; Glib::ustring shapeMethod; // IND, SYM, INDSL, SYMSL + Glib::ustring avoidgamutMethod; // NONE, LAB, XYZ + std::vector loc; // For ellipse/rectangle: {locX, locXL, locY, locYT} int centerX; int centerY; @@ -1038,8 +1040,6 @@ struct LocallabParams { double transitgrad; bool hishow; bool activ; - bool avoid; - bool avoidmun; bool blwh; bool recurs; bool laplac; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index d45283c38..3916adfbe 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -1185,8 +1185,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { AUTOEXP, //Evlocallabforcebw AUTOEXP, //Evlocallabsigjz AUTOEXP, //Evlocallabsigq - AUTOEXP //Evlocallablogcie - + AUTOEXP //Evlocallablogcie }; diff --git a/rtgui/blackwhite.cc b/rtgui/blackwhite.cc index 7fcc45312..d869903b5 100644 --- a/rtgui/blackwhite.cc +++ b/rtgui/blackwhite.cc @@ -49,7 +49,8 @@ BlackWhite::BlackWhite (): FoldableToolPanel(this, "blackwhite", M("TP_BWMIX_LAB metHBox->set_spacing (2); Gtk::Label* metLabel = Gtk::manage (new Gtk::Label (M("TP_BWMIX_MET") + ":")); metHBox->pack_start (*metLabel, Gtk::PACK_SHRINK); - method = Gtk::manage (new MyComboBoxText ()); + + method = Gtk::manage (new MyComboBoxText ()); method->append (M("TP_BWMIX_MET_DESAT")); method->append (M("TP_BWMIX_MET_LUMEQUAL")); method->append (M("TP_BWMIX_MET_CHANMIX")); diff --git a/rtgui/controlspotpanel.cc b/rtgui/controlspotpanel.cc index 0d57d98bb..60fde12a6 100644 --- a/rtgui/controlspotpanel.cc +++ b/rtgui/controlspotpanel.cc @@ -24,6 +24,7 @@ #include "options.h" #include "../rtengine/procparams.h" #include "rtimage.h" +#include "eventmapper.h" using namespace rtengine; using namespace procparams; @@ -55,6 +56,7 @@ ControlSpotPanel::ControlSpotPanel(): qualityMethod_(Gtk::manage(new MyComboBoxText())), //complexMethod_(Gtk::manage(new MyComboBoxText())), wavMethod_(Gtk::manage(new MyComboBoxText())), + avoidgamutMethod_(Gtk::manage(new MyComboBoxText())), sensiexclu_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SENSIEXCLU"), 0, 100, 1, 12))), structexclu_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_STRUCCOL"), 0, 100, 1, 0))), @@ -76,15 +78,13 @@ ControlSpotPanel::ControlSpotPanel(): balanh_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BALANH"), 0.2, 2.5, 0.1, 1.0, Gtk::manage(new RTImage("rawtherapee-logo-16.png")), Gtk::manage(new RTImage("circle-red-green-small.png"))))), colorde_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_COLORDE"), -15, 15, 2, 5, Gtk::manage(new RTImage("circle-blue-yellow-small.png")), Gtk::manage(new RTImage("circle-gray-green-small.png"))))), colorscope_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_COLORSCOPE"), 0., 100.0, 1., 30.))), - avoidrad_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_AVOIDRAD"), 0., 30.0, 0.1, 0.7))), + avoidrad_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_AVOIDRAD"), 0., 30.0, 0.1, 0.))), scopemask_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_SCOPEMASK"), 0, 100, 1, 60))), denoichmask_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DENOIMASK"), 0., 100., 0.5, 0))), lumask_(Gtk::manage(new Adjuster(M("TP_LOCALLAB_LUMASK"), -50, 30, 1, 10, Gtk::manage(new RTImage("circle-yellow-small.png")), Gtk::manage(new RTImage("circle-gray-small.png")) ))), hishow_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_PREVSHOW")))), activ_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_ACTIVSPOT")))), - avoid_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_AVOID")))), - avoidmun_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_AVOIDMUN")))), blwh_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_BLWH")))), recurs_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_RECURS")))), laplac_(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_LAPLACC")))), @@ -100,6 +100,7 @@ ControlSpotPanel::ControlSpotPanel(): preview_(Gtk::manage(new Gtk::ToggleButton(M("TP_LOCALLAB_PREVIEW")))), ctboxshape(Gtk::manage(new Gtk::Box())), ctboxshapemethod(Gtk::manage(new Gtk::Box())), + ctboxgamut(Gtk::manage(new Gtk::Box())), controlPanelListener(nullptr), lastObject_(-1), @@ -111,6 +112,8 @@ ControlSpotPanel::ControlSpotPanel(): excluFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_EXCLUF")))), maskPrevActive(false) { + auto m = ProcEventMapper::getInstance(); + EvLocallabavoidgamutMethod = m->newEvent(AUTOEXP, "HISTORY_MSG_LOCAL_GAMUTMUNSEL"); const bool showtooltip = options.showtooltip; pack_start(*hishow_); @@ -397,23 +400,30 @@ ControlSpotPanel::ControlSpotPanel(): activConn_ = activ_->signal_toggled().connect( sigc::mem_fun(*this, &ControlSpotPanel::activChanged)); - avoidConn_ = avoid_->signal_toggled().connect( - sigc::mem_fun(*this, &ControlSpotPanel::avoidChanged)); - avoidmunConn_ = avoidmun_->signal_toggled().connect( - sigc::mem_fun(*this, &ControlSpotPanel::avoidmunChanged)); - - Gtk::Frame* const avFrame = Gtk::manage(new Gtk::Frame()); + Gtk::Label* const labelgamut = Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_AVOID") + ":")); + ctboxgamut->pack_start(*labelgamut, Gtk::PACK_SHRINK, 4); + avoidgamutMethod_->append(M("TP_LOCALLAB_GAMUTNON")); + avoidgamutMethod_->append(M("TP_LOCALLAB_GAMUTLABRELA")); + avoidgamutMethod_->append(M("TP_LOCALLAB_GAMUTXYZABSO")); + avoidgamutMethod_->append(M("TP_LOCALLAB_GAMUTXYZRELA")); + avoidgamutMethod_->append(M("TP_LOCALLAB_GAMUTMUNSELL")); + avoidgamutMethod_->set_active(4); + avoidgamutconn_ = avoidgamutMethod_->signal_changed().connect( + sigc::mem_fun( + *this, &ControlSpotPanel::avoidgamutMethodChanged)); + ctboxgamut->pack_start(*avoidgamutMethod_); + if (showtooltip) { + ctboxgamut->set_tooltip_text(M("TP_LOCALLAB_AVOIDCOLORSHIFT_TOOLTIP")); + } + + Gtk::Frame* const avFrame = Gtk::manage(new Gtk::Frame()); ToolParamBlock* const avbox = Gtk::manage(new ToolParamBlock()); avFrame->set_label_align(0.025, 0.5); - avFrame->set_label_widget(*avoid_); + avbox->pack_start(*ctboxgamut); avbox->pack_start(*avoidrad_); - avbox->pack_start(*avoidmun_); avFrame->add(*avbox); specCaseBox->pack_start(*avFrame); - if (showtooltip) { - avoidmun_->set_tooltip_text(M("TP_LOCALLAB_AVOIDMUN_TOOLTIP")); - } blwhConn_ = blwh_->signal_toggled().connect( sigc::mem_fun(*this, &ControlSpotPanel::blwhChanged)); @@ -429,7 +439,6 @@ ControlSpotPanel::ControlSpotPanel(): if (showtooltip) { recurs_->set_tooltip_text(M("TP_LOCALLAB_RECURS_TOOLTIP")); - avoid_->set_tooltip_text(M("TP_LOCALLAB_AVOIDCOLORSHIFT_TOOLTIP")); } specCaseBox->pack_start(*recurs_); @@ -854,8 +863,6 @@ void ControlSpotPanel::load_ControlSpot_param() avoidrad_->setValue((double)row[spots_.avoidrad]); hishow_->set_active(row[spots_.hishow]); activ_->set_active(row[spots_.activ]); - avoid_->set_active(row[spots_.avoid]); - avoidmun_->set_active(row[spots_.avoidmun]); blwh_->set_active(row[spots_.blwh]); recurs_->set_active(row[spots_.recurs]); // laplac_->set_active(row[spots_.laplac]); @@ -868,6 +875,8 @@ void ControlSpotPanel::load_ControlSpot_param() //savrest_->set_active(row[spots_.savrest]); //complexMethod_->set_active(row[spots_.complexMethod]); wavMethod_->set_active(row[spots_.wavMethod]); + avoidgamutMethod_->set_active(row[spots_.avoidgamutMethod]); + } void ControlSpotPanel::controlspotChanged() @@ -1055,6 +1064,34 @@ void ControlSpotPanel::spotMethodChanged() } } +void ControlSpotPanel::avoidgamutMethodChanged() +{ + + // Get selected control spot + const auto s = treeview_->get_selection(); + + if (!s->count_selected_rows()) { + return; + } + const int meth = avoidgamutMethod_->get_active_row_number(); + avoidrad_->show(); + + if(meth == 2 || meth == 3 || meth == 4) { + avoidrad_->hide(); + } + + const auto iter = s->get_selected(); + Gtk::TreeModel::Row row = *iter; + + row[spots_.avoidgamutMethod] = avoidgamutMethod_->get_active_row_number(); + + // Raise event + if (listener) { + listener->panelChanged(EvLocallabavoidgamutMethod, avoidgamutMethod_->get_active_text()); + } + +} + void ControlSpotPanel::shapeMethodChanged() { // printf("shapeMethodChanged\n"); @@ -1217,6 +1254,7 @@ void ControlSpotPanel::updateParamVisibility() // Update Control Spot GUI according to shapeMethod_ combobox state (to be compliant with shapeMethodChanged function) const int method = shapeMethod_->get_active_row_number(); + const int meth = avoidgamutMethod_->get_active_row_number(); if (!batchMode) { if (method == 1 || method == 3) { // Symmetrical cases @@ -1260,6 +1298,12 @@ void ControlSpotPanel::updateParamVisibility() centerY_->show(); } + if(meth == 1) { + avoidrad_->show(); + } else { + avoidrad_->hide(); +} + // Update Control Spot GUI according to spotMethod_ combobox state (to be compliant with spotMethodChanged function) if (multiImage && spotMethod_->get_active_text() == M("GENERAL_UNCHANGED")) { excluFrame->show(); @@ -1588,57 +1632,6 @@ void ControlSpotPanel::hishowChanged() } - -void ControlSpotPanel::avoidChanged() -{ - // printf("avoidChanged\n"); - - // Get selected control spot - const auto s = treeview_->get_selection(); - - if (!s->count_selected_rows()) { - return; - } - - const auto iter = s->get_selected(); - Gtk::TreeModel::Row row = *iter; - row[spots_.avoid] = avoid_->get_active(); - - // Raise event - if (listener) { - if (avoid_->get_active()) { - listener->panelChanged(Evlocallabavoid, M("GENERAL_ENABLED")); - } else { - listener->panelChanged(Evlocallabavoid, M("GENERAL_DISABLED")); - } - } -} - -void ControlSpotPanel::avoidmunChanged() -{ - // printf("avoidmunChanged\n"); - - // Get selected control spot - const auto s = treeview_->get_selection(); - - if (!s->count_selected_rows()) { - return; - } - - const auto iter = s->get_selected(); - Gtk::TreeModel::Row row = *iter; - row[spots_.avoidmun] = avoidmun_->get_active(); - - // Raise event - if (listener) { - if (avoidmun_->get_active()) { - listener->panelChanged(EvLocallabSpotavoidmun, M("GENERAL_ENABLED")); - } else { - listener->panelChanged(EvLocallabSpotavoidmun, M("GENERAL_DISABLED")); - } - } -} - void ControlSpotPanel::activChanged() { // printf("activChanged\n"); @@ -1859,8 +1852,6 @@ void ControlSpotPanel::disableParamlistener(bool cond) avoidrad_->block(cond); hishowconn_.block(cond); activConn_.block(cond); - avoidConn_.block(cond); - avoidmunConn_.block(cond); blwhConn_.block(cond); recursConn_.block(cond); laplacConn_.block(cond); @@ -1872,6 +1863,8 @@ void ControlSpotPanel::disableParamlistener(bool cond) //savrestConn_.block(cond); //complexMethodconn_.block(cond); wavMethodconn_.block(cond); + avoidgamutconn_.block(cond); + } void ControlSpotPanel::setParamEditable(bool cond) @@ -1906,8 +1899,6 @@ void ControlSpotPanel::setParamEditable(bool cond) avoidrad_->set_sensitive(cond); hishow_->set_sensitive(cond); activ_->set_sensitive(cond); - avoid_->set_sensitive(cond); - avoidmun_->set_sensitive(cond); blwh_->set_sensitive(cond); recurs_->set_sensitive(cond); laplac_->set_sensitive(cond); @@ -1920,6 +1911,7 @@ void ControlSpotPanel::setParamEditable(bool cond) //complexMethod_->set_sensitive(cond); wavMethod_->set_sensitive(cond); preview_->set_sensitive(cond); + avoidgamutMethod_->set_sensitive(cond); if (!cond) { // Reset complex parameters visibility to default state @@ -2592,8 +2584,6 @@ ControlSpotPanel::SpotRow* ControlSpotPanel::getSpot(const int index) r->lumask = row[spots_.lumask]; r->hishow = row[spots_.hishow]; r->activ = row[spots_.activ]; - r->avoid = row[spots_.avoid]; - r->avoidmun = row[spots_.avoidmun]; r->blwh = row[spots_.blwh]; r->recurs = row[spots_.recurs]; r->laplac = row[spots_.laplac]; @@ -2601,6 +2591,7 @@ ControlSpotPanel::SpotRow* ControlSpotPanel::getSpot(const int index) r->shortc = row[spots_.shortc]; //r->savrest = row[spots_.savrest]; r->wavMethod = row[spots_.wavMethod]; + r->avoidgamutMethod = row[spots_.avoidgamutMethod]; return r; } @@ -2725,8 +2716,6 @@ void ControlSpotPanel::addControlSpot(SpotRow* newSpot) row[spots_.avoidrad] = newSpot->avoidrad; row[spots_.hishow] = newSpot->hishow; row[spots_.activ] = newSpot->activ; - row[spots_.avoid] = newSpot->avoid; - row[spots_.avoidmun] = newSpot->avoidmun; row[spots_.blwh] = newSpot->blwh; row[spots_.recurs] = newSpot->recurs; row[spots_.laplac] = newSpot->laplac; @@ -2738,6 +2727,7 @@ void ControlSpotPanel::addControlSpot(SpotRow* newSpot) //row[spots_.savrest] = newSpot->savrest; row[spots_.complexMethod] = newSpot->complexMethod; row[spots_.wavMethod] = newSpot->wavMethod; + row[spots_.avoidgamutMethod] = newSpot->avoidgamutMethod; updateParamVisibility(); disableParamlistener(false); @@ -2845,8 +2835,6 @@ ControlSpotPanel::ControlSpots::ControlSpots() add(avoidrad); add(hishow); add(activ); - add(avoid); - add(avoidmun); add(blwh); add(recurs); add(laplac); @@ -2858,6 +2846,7 @@ ControlSpotPanel::ControlSpots::ControlSpots() //add(savrest); add(complexMethod); add(wavMethod); + add(avoidgamutMethod); } //----------------------------------------------------------------------------- diff --git a/rtgui/controlspotpanel.h b/rtgui/controlspotpanel.h index 92406c690..b1e191b0e 100644 --- a/rtgui/controlspotpanel.h +++ b/rtgui/controlspotpanel.h @@ -57,6 +57,7 @@ public: int sensiexclu; int structexclu; int shapeMethod; // 0 = Independent (mouse), 1 = Symmetrical (mouse), 2 = Independent (mouse + sliders), 3 = Symmetrical (mouse + sliders) + int avoidgamutMethod; int locX; int locXL; int locY; @@ -79,8 +80,6 @@ public: double avoidrad; bool hishow; bool activ; - bool avoid; - bool avoidmun; bool blwh; bool recurs; bool laplac; @@ -243,7 +242,8 @@ private: void spotMethodChanged(); void shapeMethodChanged(); void qualityMethodChanged(); - //void complexMethodChanged(); + void avoidgamutMethodChanged(); + //void complexMethodChanged(); void wavMethodChanged(); void updateParamVisibility(); @@ -252,8 +252,6 @@ private: void hishowChanged(); void activChanged(); - void avoidChanged(); - void avoidmunChanged(); void blwhChanged(); void recursChanged(); void laplacChanged(); @@ -293,6 +291,7 @@ private: Gtk::TreeModelColumn sensiexclu; Gtk::TreeModelColumn structexclu; Gtk::TreeModelColumn shapeMethod; // 0 = Independent (mouse), 1 = Symmetrical (mouse), 2 = Independent (mouse + sliders), 3 = Symmetrical (mouse + sliders) + Gtk::TreeModelColumn avoidgamutMethod; Gtk::TreeModelColumn locX; Gtk::TreeModelColumn locXL; Gtk::TreeModelColumn locY; @@ -315,8 +314,6 @@ private: Gtk::TreeModelColumn avoidrad; Gtk::TreeModelColumn hishow; Gtk::TreeModelColumn activ; - Gtk::TreeModelColumn avoid; - Gtk::TreeModelColumn avoidmun; Gtk::TreeModelColumn blwh; Gtk::TreeModelColumn recurs; Gtk::TreeModelColumn laplac; @@ -347,6 +344,7 @@ private: }; ControlSpots spots_; + rtengine::ProcEvent EvLocallabavoidgamutMethod; // Child widgets Gtk::ScrolledWindow* const scrolledwindow_; @@ -381,6 +379,8 @@ private: //sigc::connection complexMethodconn_; MyComboBoxText* const wavMethod_; sigc::connection wavMethodconn_; + MyComboBoxText* const avoidgamutMethod_; + sigc::connection avoidgamutconn_; Adjuster* const sensiexclu_; Adjuster* const structexclu_; @@ -411,10 +411,6 @@ private: sigc::connection hishowconn_; Gtk::CheckButton* const activ_; sigc::connection activConn_; - Gtk::CheckButton* const avoid_; - sigc::connection avoidConn_; - Gtk::CheckButton* const avoidmun_; - sigc::connection avoidmunConn_; Gtk::CheckButton* const blwh_; sigc::connection blwhConn_; Gtk::CheckButton* const recurs_; @@ -438,6 +434,7 @@ private: Gtk::Box* const ctboxshape; Gtk::Box* const ctboxshapemethod; + Gtk::Box* const ctboxgamut; // Internal variables ControlPanelListener* controlPanelListener; diff --git a/rtgui/labcurve.cc b/rtgui/labcurve.cc index d2279f586..e0e0bfb01 100644 --- a/rtgui/labcurve.cc +++ b/rtgui/labcurve.cc @@ -19,6 +19,7 @@ #include #include "labcurve.h" +#include "eventmapper.h" #include "curveeditor.h" #include "curveeditorgroup.h" @@ -32,61 +33,80 @@ using namespace rtengine; using namespace rtengine::procparams; -LCurve::LCurve () : FoldableToolPanel(this, "labcurves", M("TP_LABCURVE_LABEL"), false, true) +LCurve::LCurve() : FoldableToolPanel(this, "labcurves", M("TP_LABCURVE_LABEL"), false, true) { - brightness = Gtk::manage (new Adjuster (M("TP_LABCURVE_BRIGHTNESS"), -100., 100., 1., 0.)); - contrast = Gtk::manage (new Adjuster (M("TP_LABCURVE_CONTRAST"), -100., 100., 1., 0.)); - chromaticity = Gtk::manage (new Adjuster (M("TP_LABCURVE_CHROMATICITY"), -100., 100., 1., 0.)); + auto m = ProcEventMapper::getInstance(); + Evgamutmunsell = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_GAMUTMUNSEL"); + CurveListener::setMulti(true); + brightness = Gtk::manage(new Adjuster(M("TP_LABCURVE_BRIGHTNESS"), -100., 100., 1., 0.)); + contrast = Gtk::manage(new Adjuster(M("TP_LABCURVE_CONTRAST"), -100., 100., 1., 0.)); + chromaticity = Gtk::manage(new Adjuster(M("TP_LABCURVE_CHROMATICITY"), -100., 100., 1., 0.)); chromaticity->set_tooltip_markup(M("TP_LABCURVE_CHROMA_TOOLTIP")); - pack_start (*brightness); - brightness->show (); + pack_start(*brightness); + brightness->show(); - pack_start (*contrast); - contrast->show (); + pack_start(*contrast); + contrast->show(); - pack_start (*chromaticity); - chromaticity->show (); + pack_start(*chromaticity); + chromaticity->show(); - brightness->setAdjusterListener (this); - contrast->setAdjusterListener (this); - chromaticity->setAdjusterListener (this); + brightness->setAdjusterListener(this); + contrast->setAdjusterListener(this); + chromaticity->setAdjusterListener(this); brightness->setLogScale(2, 0, true); contrast->setLogScale(2, 0, true); chromaticity->setLogScale(2, 0, true); //%%%%%%%%%%%%%%%%%% - Gtk::Separator* hsep2 = Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); - hsep2->show (); - pack_start (*hsep2, Gtk::PACK_EXPAND_WIDGET, 4); + Gtk::Separator* hsep2 = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); + hsep2->show(); + pack_start(*hsep2, Gtk::PACK_EXPAND_WIDGET, 4); - avoidcolorshift = Gtk::manage (new Gtk::CheckButton (M("TP_LABCURVE_AVOIDCOLORSHIFT"))); - avoidcolorshift->set_tooltip_text (M("TP_LABCURVE_AVOIDCOLORSHIFT_TOOLTIP")); - pack_start (*avoidcolorshift, Gtk::PACK_SHRINK, 4); - lcredsk = Gtk::manage (new Gtk::CheckButton (M("TP_LABCURVE_LCREDSK"))); - lcredsk->set_tooltip_markup (M("TP_LABCURVE_LCREDSK_TOOLTIP")); - pack_start (*lcredsk); - rstprotection = Gtk::manage ( new Adjuster (M("TP_LABCURVE_RSTPROTECTION"), 0., 100., 0.1, 0.) ); - pack_start (*rstprotection); - rstprotection->show (); - rstprotection->setAdjusterListener (this); - rstprotection->set_tooltip_text (M("TP_LABCURVE_RSTPRO_TOOLTIP")); + Gtk::Box* metHBox = Gtk::manage(new Gtk::Box()); + metHBox->set_spacing(2); + Gtk::Label* metLabel = Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_AVOID") + ":")); + metHBox->pack_start(*metLabel, Gtk::PACK_SHRINK); - acconn = avoidcolorshift->signal_toggled().connect( sigc::mem_fun(*this, &LCurve::avoidcolorshift_toggled) ); - lcconn = lcredsk->signal_toggled().connect( sigc::mem_fun(*this, &LCurve::lcredsk_toggled) ); + gamutmunselmethod = Gtk::manage(new MyComboBoxText()); + gamutmunselmethod->append(M("TP_LOCALLAB_GAMUTNON")); + gamutmunselmethod->append(M("TP_LOCALLAB_GAMUTLABRELA")); + gamutmunselmethod->append(M("TP_LOCALLAB_GAMUTXYZABSO")); + gamutmunselmethod->append(M("TP_LOCALLAB_GAMUTXYZRELA")); + gamutmunselmethod->append(M("TP_LOCALLAB_GAMUTMUNSELL")); + gamutmunselmethod->set_active(4); + gamutmunselmethod->set_tooltip_text(M("TP_LOCALLAB_AVOIDCOLORSHIFT_TOOLTIP")); + metHBox->pack_start(*gamutmunselmethod); + pack_start(*metHBox); + gamutmunselmethodconn = gamutmunselmethod->signal_changed().connect(sigc::mem_fun(*this, &LCurve::gamutmunselChanged)); + + + lcredsk = Gtk::manage(new Gtk::CheckButton(M("TP_LABCURVE_LCREDSK"))); + lcredsk->set_tooltip_markup(M("TP_LABCURVE_LCREDSK_TOOLTIP")); + pack_start(*lcredsk); + + rstprotection = Gtk::manage(new Adjuster(M("TP_LABCURVE_RSTPROTECTION"), 0., 100., 0.1, 0.)); + pack_start(*rstprotection); + rstprotection->show(); + + rstprotection->setAdjusterListener(this); + rstprotection->set_tooltip_text(M("TP_LABCURVE_RSTPRO_TOOLTIP")); + + lcconn = lcredsk->signal_toggled().connect(sigc::mem_fun(*this, &LCurve::lcredsk_toggled)); //%%%%%%%%%%%%%%%%%%% - Gtk::Separator* hsep3 = Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); - hsep3->show (); - pack_start (*hsep3, Gtk::PACK_EXPAND_WIDGET, 4); + Gtk::Separator* hsep3 = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); + hsep3->show(); + pack_start(*hsep3, Gtk::PACK_EXPAND_WIDGET, 4); - curveEditorG = new CurveEditorGroup (options.lastLabCurvesDir); - curveEditorG->setCurveListener (this); + curveEditorG = new CurveEditorGroup(options.lastLabCurvesDir); + curveEditorG->setCurveListener(this); lshape = static_cast(curveEditorG->addCurve(CT_Diagonal, "L*")); lshape->setTooltip(M("TP_LABCURVE_CURVEEDITOR_LL_TOOLTIP")); @@ -216,88 +236,111 @@ LCurve::LCurve () : FoldableToolPanel(this, "labcurves", M("TP_LABCURVE_LABEL"), // This will add the reset button at the end of the curveType buttons curveEditorG->curveListComplete(); - pack_start (*curveEditorG, Gtk::PACK_SHRINK, 4); - Gtk::Separator* hsepdh = Gtk::manage (new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); - hsepdh->show (); - pack_start (*hsepdh, Gtk::PACK_EXPAND_WIDGET, 4); + pack_start(*curveEditorG, Gtk::PACK_SHRINK, 4); + Gtk::Separator* hsepdh = Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_HORIZONTAL)); + hsepdh->show(); + pack_start(*hsepdh, Gtk::PACK_EXPAND_WIDGET, 4); + show_all_children(); } -LCurve::~LCurve () +LCurve::~LCurve() { delete curveEditorG; } -void LCurve::read (const ProcParams* pp, const ParamsEdited* pedited) +void LCurve::read(const ProcParams* pp, const ParamsEdited* pedited) { - disableListener (); + disableListener(); + gamutmunselmethodconn.block(true); + + + brightness->setValue(pp->labCurve.brightness); + contrast->setValue(pp->labCurve.contrast); + chromaticity->setValue(pp->labCurve.chromaticity); + adjusterChanged(chromaticity, pp->labCurve.chromaticity); // To update the GUI sensitiveness + //%%%%%%%%%%%%%%%%%%%%%% + rstprotection->setValue(pp->labCurve.rstprotection); + + + bwtconn.block(true); + lcconn.block(true); + lcredsk->set_active(pp->labCurve.lcredsk); + + bwtconn.block(false); + lcconn.block(false); + + lastLCVal = pp->labCurve.lcredsk; + //%%%%%%%%%%%%%%%%%%%%%% + + lshape->setCurve(pp->labCurve.lcurve); + ashape->setCurve(pp->labCurve.acurve); + bshape->setCurve(pp->labCurve.bcurve); + ccshape->setCurve(pp->labCurve.cccurve); + chshape->setCurve(pp->labCurve.chcurve); + lhshape->setCurve(pp->labCurve.lhcurve); + hhshape->setCurve(pp->labCurve.hhcurve); + lcshape->setCurve(pp->labCurve.lccurve); + clshape->setCurve(pp->labCurve.clcurve); + + if (pedited && !pedited->labCurve.gamutmunselmethod) { + gamutmunselmethod->set_active(4); // "Unchanged" + } else if (pp->labCurve.gamutmunselmethod == "NONE") { + gamutmunselmethod->set_active(0); + } else if (pp->labCurve.gamutmunselmethod == "LAB") { + gamutmunselmethod->set_active(1); + } else if (pp->labCurve.gamutmunselmethod == "XYZ") { + gamutmunselmethod->set_active(2); + } else if (pp->labCurve.gamutmunselmethod == "XYZREL") { + gamutmunselmethod->set_active(3); + } else if (pp->labCurve.gamutmunselmethod == "MUN") { + gamutmunselmethod->set_active(4); + } + + gamutmunselChanged(); if (pedited) { - brightness->setEditedState (pedited->labCurve.brightness ? Edited : UnEdited); - contrast->setEditedState (pedited->labCurve.contrast ? Edited : UnEdited); - chromaticity->setEditedState (pedited->labCurve.chromaticity ? Edited : UnEdited); + brightness->setEditedState(pedited->labCurve.brightness ? Edited : UnEdited); + contrast->setEditedState(pedited->labCurve.contrast ? Edited : UnEdited); + chromaticity->setEditedState(pedited->labCurve.chromaticity ? Edited : UnEdited); //%%%%%%%%%%%%%%%%%%%%%% - rstprotection->setEditedState (pedited->labCurve.rstprotection ? Edited : UnEdited); - avoidcolorshift->set_inconsistent (!pedited->labCurve.avoidcolorshift); - lcredsk->set_inconsistent (!pedited->labCurve.lcredsk); + rstprotection->setEditedState(pedited->labCurve.rstprotection ? Edited : UnEdited); + lcredsk->set_inconsistent(!pedited->labCurve.lcredsk); //%%%%%%%%%%%%%%%%%%%%%% - lshape->setUnChanged (!pedited->labCurve.lcurve); - ashape->setUnChanged (!pedited->labCurve.acurve); - bshape->setUnChanged (!pedited->labCurve.bcurve); - ccshape->setUnChanged (!pedited->labCurve.cccurve); - chshape->setUnChanged (!pedited->labCurve.chcurve); - lhshape->setUnChanged (!pedited->labCurve.lhcurve); - hhshape->setUnChanged (!pedited->labCurve.hhcurve); - lcshape->setUnChanged (!pedited->labCurve.lccurve); - clshape->setUnChanged (!pedited->labCurve.clcurve); + lshape->setUnChanged(!pedited->labCurve.lcurve); + ashape->setUnChanged(!pedited->labCurve.acurve); + bshape->setUnChanged(!pedited->labCurve.bcurve); + ccshape->setUnChanged(!pedited->labCurve.cccurve); + chshape->setUnChanged(!pedited->labCurve.chcurve); + lhshape->setUnChanged(!pedited->labCurve.lhcurve); + hhshape->setUnChanged(!pedited->labCurve.hhcurve); + lcshape->setUnChanged(!pedited->labCurve.lccurve); + clshape->setUnChanged(!pedited->labCurve.clcurve); + + if (!pedited->labCurve.gamutmunselmethod) { + gamutmunselmethod->set_active_text(M("GENERAL_UNCHANGED")); + } set_inconsistent(multiImage && !pedited->labCurve.enabled); } - brightness->setValue (pp->labCurve.brightness); - contrast->setValue (pp->labCurve.contrast); - chromaticity->setValue (pp->labCurve.chromaticity); - adjusterChanged(chromaticity, pp->labCurve.chromaticity); // To update the GUI sensitiveness - //%%%%%%%%%%%%%%%%%%%%%% - rstprotection->setValue (pp->labCurve.rstprotection); + gamutmunselmethodconn.block(false); - bwtconn.block (true); - acconn.block (true); - lcconn.block (true); - avoidcolorshift->set_active (pp->labCurve.avoidcolorshift); - lcredsk->set_active (pp->labCurve.lcredsk); - - bwtconn.block (false); - acconn.block (false); - lcconn.block (false); - - lastACVal = pp->labCurve.avoidcolorshift; - lastLCVal = pp->labCurve.lcredsk; - //%%%%%%%%%%%%%%%%%%%%%% - - lshape->setCurve (pp->labCurve.lcurve); - ashape->setCurve (pp->labCurve.acurve); - bshape->setCurve (pp->labCurve.bcurve); - ccshape->setCurve (pp->labCurve.cccurve); - chshape->setCurve (pp->labCurve.chcurve); - lhshape->setCurve (pp->labCurve.lhcurve); - hhshape->setCurve (pp->labCurve.hhcurve); - lcshape->setCurve (pp->labCurve.lccurve); - clshape->setCurve (pp->labCurve.clcurve); setEnabled(pp->labCurve.enabled); - + queue_draw(); - enableListener (); + enableListener(); } -void LCurve::autoOpenCurve () + +void LCurve::autoOpenCurve() { // Open up the first curve if selected bool active = lshape->openIfNonlinear(); @@ -336,7 +379,7 @@ void LCurve::autoOpenCurve () } -void LCurve::setEditProvider (EditDataProvider *provider) +void LCurve::setEditProvider(EditDataProvider *provider) { lshape->setEditProvider(provider); ccshape->setEditProvider(provider); @@ -351,127 +394,128 @@ void LCurve::setEditProvider (EditDataProvider *provider) } -void LCurve::write (ProcParams* pp, ParamsEdited* pedited) +void LCurve::write(ProcParams* pp, ParamsEdited* pedited) { pp->labCurve.enabled = getEnabled(); - - pp->labCurve.brightness = brightness->getValue (); - pp->labCurve.contrast = (int)contrast->getValue (); - pp->labCurve.chromaticity = (int)chromaticity->getValue (); - //%%%%%%%%%%%%%%%%%%%%%% - pp->labCurve.avoidcolorshift = avoidcolorshift->get_active (); - pp->labCurve.lcredsk = lcredsk->get_active (); - pp->labCurve.rstprotection = rstprotection->getValue (); + pp->labCurve.brightness = brightness->getValue(); + pp->labCurve.contrast = (int)contrast->getValue(); + pp->labCurve.chromaticity = (int)chromaticity->getValue(); + //%%%%%%%%%%%%%%%%%%%%%% + pp->labCurve.lcredsk = lcredsk->get_active(); + + pp->labCurve.rstprotection = rstprotection->getValue(); //%%%%%%%%%%%%%%%%%%%%%% - pp->labCurve.lcurve = lshape->getCurve (); - pp->labCurve.acurve = ashape->getCurve (); - pp->labCurve.bcurve = bshape->getCurve (); - pp->labCurve.cccurve = ccshape->getCurve (); - pp->labCurve.chcurve = chshape->getCurve (); - pp->labCurve.lhcurve = lhshape->getCurve (); - pp->labCurve.hhcurve = hhshape->getCurve (); - pp->labCurve.lccurve = lcshape->getCurve (); - pp->labCurve.clcurve = clshape->getCurve (); + pp->labCurve.lcurve = lshape->getCurve(); + pp->labCurve.acurve = ashape->getCurve(); + pp->labCurve.bcurve = bshape->getCurve(); + pp->labCurve.cccurve = ccshape->getCurve(); + pp->labCurve.chcurve = chshape->getCurve(); + pp->labCurve.lhcurve = lhshape->getCurve(); + pp->labCurve.hhcurve = hhshape->getCurve(); + pp->labCurve.lccurve = lcshape->getCurve(); + pp->labCurve.clcurve = clshape->getCurve(); + + if (pedited) { - pedited->labCurve.brightness = brightness->getEditedState (); - pedited->labCurve.contrast = contrast->getEditedState (); - pedited->labCurve.chromaticity = chromaticity->getEditedState (); + pedited->labCurve.brightness = brightness->getEditedState(); + pedited->labCurve.contrast = contrast->getEditedState(); + pedited->labCurve.chromaticity = chromaticity->getEditedState(); //%%%%%%%%%%%%%%%%%%%%%% - pedited->labCurve.avoidcolorshift = !avoidcolorshift->get_inconsistent(); pedited->labCurve.lcredsk = !lcredsk->get_inconsistent(); - pedited->labCurve.rstprotection = rstprotection->getEditedState (); + pedited->labCurve.rstprotection = rstprotection->getEditedState(); + pedited->labCurve.gamutmunselmethod = gamutmunselmethod->get_active_text() != M("GENERAL_UNCHANGED"); - pedited->labCurve.lcurve = !lshape->isUnChanged (); - pedited->labCurve.acurve = !ashape->isUnChanged (); - pedited->labCurve.bcurve = !bshape->isUnChanged (); - pedited->labCurve.cccurve = !ccshape->isUnChanged (); - pedited->labCurve.chcurve = !chshape->isUnChanged (); - pedited->labCurve.lhcurve = !lhshape->isUnChanged (); - pedited->labCurve.hhcurve = !hhshape->isUnChanged (); - pedited->labCurve.lccurve = !lcshape->isUnChanged (); - pedited->labCurve.clcurve = !clshape->isUnChanged (); + pedited->labCurve.lcurve = !lshape->isUnChanged(); + pedited->labCurve.acurve = !ashape->isUnChanged(); + pedited->labCurve.bcurve = !bshape->isUnChanged(); + pedited->labCurve.cccurve = !ccshape->isUnChanged(); + pedited->labCurve.chcurve = !chshape->isUnChanged(); + pedited->labCurve.lhcurve = !lhshape->isUnChanged(); + pedited->labCurve.hhcurve = !hhshape->isUnChanged(); + pedited->labCurve.lccurve = !lcshape->isUnChanged(); + pedited->labCurve.clcurve = !clshape->isUnChanged(); pedited->labCurve.enabled = !get_inconsistent(); + } + if (gamutmunselmethod->get_active_row_number() == 0) { + pp->labCurve.gamutmunselmethod = "NONE"; + } else if (gamutmunselmethod->get_active_row_number() == 1) { + pp->labCurve.gamutmunselmethod = "LAB"; + } else if (gamutmunselmethod->get_active_row_number() == 2) { + pp->labCurve.gamutmunselmethod = "XYZ"; + } else if (gamutmunselmethod->get_active_row_number() == 3) { + pp->labCurve.gamutmunselmethod = "XYZREL"; + } else if (gamutmunselmethod->get_active_row_number() == 4) { + pp->labCurve.gamutmunselmethod = "MUN"; + } + + + } -void LCurve::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited) +void LCurve::setDefaults(const ProcParams* defParams, const ParamsEdited* pedited) { - brightness->setDefault (defParams->labCurve.brightness); - contrast->setDefault (defParams->labCurve.contrast); - chromaticity->setDefault (defParams->labCurve.chromaticity); - rstprotection->setDefault (defParams->labCurve.rstprotection); + brightness->setDefault(defParams->labCurve.brightness); + contrast->setDefault(defParams->labCurve.contrast); + chromaticity->setDefault(defParams->labCurve.chromaticity); + rstprotection->setDefault(defParams->labCurve.rstprotection); if (pedited) { - brightness->setDefaultEditedState (pedited->labCurve.brightness ? Edited : UnEdited); - contrast->setDefaultEditedState (pedited->labCurve.contrast ? Edited : UnEdited); - chromaticity->setDefaultEditedState (pedited->labCurve.chromaticity ? Edited : UnEdited); - rstprotection->setDefaultEditedState (pedited->labCurve.rstprotection ? Edited : UnEdited); + brightness->setDefaultEditedState(pedited->labCurve.brightness ? Edited : UnEdited); + contrast->setDefaultEditedState(pedited->labCurve.contrast ? Edited : UnEdited); + chromaticity->setDefaultEditedState(pedited->labCurve.chromaticity ? Edited : UnEdited); + rstprotection->setDefaultEditedState(pedited->labCurve.rstprotection ? Edited : UnEdited); } else { - brightness->setDefaultEditedState (Irrelevant); - contrast->setDefaultEditedState (Irrelevant); - chromaticity->setDefaultEditedState (Irrelevant); - rstprotection->setDefaultEditedState (Irrelevant); + brightness->setDefaultEditedState(Irrelevant); + contrast->setDefaultEditedState(Irrelevant); + chromaticity->setDefaultEditedState(Irrelevant); + rstprotection->setDefaultEditedState(Irrelevant); } } //%%%%%%%%%%%%%%%%%%%%%% -//Color shift control changed -void LCurve::avoidcolorshift_toggled () + +void LCurve::gamutmunselChanged() { - if (batchMode) { - if (avoidcolorshift->get_inconsistent()) { - avoidcolorshift->set_inconsistent (false); - acconn.block (true); - avoidcolorshift->set_active (false); - acconn.block (false); - } else if (lastACVal) { - avoidcolorshift->set_inconsistent (true); - } - - lastACVal = avoidcolorshift->get_active (); + if (listener && (multiImage || getEnabled())) { + listener->panelChanged(Evgamutmunsell, gamutmunselmethod->get_active_text()); } - if (listener && getEnabled()) { - if (avoidcolorshift->get_active ()) { - listener->panelChanged (EvLAvoidColorShift, M("GENERAL_ENABLED")); - } else { - listener->panelChanged (EvLAvoidColorShift, M("GENERAL_DISABLED")); - } - } } -void LCurve::lcredsk_toggled () + +void LCurve::lcredsk_toggled() { if (batchMode) { if (lcredsk->get_inconsistent()) { - lcredsk->set_inconsistent (false); - lcconn.block (true); - lcredsk->set_active (false); - lcconn.block (false); + lcredsk->set_inconsistent(false); + lcconn.block(true); + lcredsk->set_active(false); + lcconn.block(false); } else if (lastLCVal) { - lcredsk->set_inconsistent (true); + lcredsk->set_inconsistent(true); } - lastLCVal = lcredsk->get_active (); + lastLCVal = lcredsk->get_active(); } else { lcshape->refresh(); } if (listener && getEnabled()) { - if (lcredsk->get_active ()) { - listener->panelChanged (EvLLCredsk, M("GENERAL_ENABLED")); + if (lcredsk->get_active()) { + listener->panelChanged(EvLLCredsk, M("GENERAL_ENABLED")); } else { - listener->panelChanged (EvLLCredsk, M("GENERAL_DISABLED")); + listener->panelChanged(EvLLCredsk, M("GENERAL_DISABLED")); } } } @@ -484,44 +528,44 @@ void LCurve::lcredsk_toggled () * If more than one curve has been added, the curve listener is automatically * set to 'multi=true', and send a pointer of the modified curve in a parameter */ -void LCurve::curveChanged (CurveEditor* ce) +void LCurve::curveChanged(CurveEditor* ce) { if (listener && getEnabled()) { if (ce == lshape) { - listener->panelChanged (EvLLCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLLCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == ashape) { - listener->panelChanged (EvLaCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLaCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == bshape) { - listener->panelChanged (EvLbCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLbCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == ccshape) { - listener->panelChanged (EvLCCCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLCCCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == chshape) { - listener->panelChanged (EvLCHCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLCHCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == lhshape) { - listener->panelChanged (EvLLHCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLLHCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == hhshape) { - listener->panelChanged (EvLHHCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLHHCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == lcshape) { - listener->panelChanged (EvLLCCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLLCCurve, M("HISTORY_CUSTOMCURVE")); } if (ce == clshape) { - listener->panelChanged (EvLCLCurve, M("HISTORY_CUSTOMCURVE")); + listener->panelChanged(EvLCLCurve, M("HISTORY_CUSTOMCURVE")); } @@ -533,45 +577,43 @@ void LCurve::adjusterChanged(Adjuster* a, double newval) Glib::ustring costr; if (a == brightness) { - costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(2), a->getValue()); + costr = Glib::ustring::format(std::setw(3), std::fixed, std::setprecision(2), a->getValue()); } else if (a == rstprotection) { - costr = Glib::ustring::format (std::setw(3), std::fixed, std::setprecision(1), a->getValue()); + costr = Glib::ustring::format(std::setw(3), std::fixed, std::setprecision(1), a->getValue()); } else { - costr = Glib::ustring::format ((int)a->getValue()); + costr = Glib::ustring::format((int)a->getValue()); } if (a == brightness) { if (listener && getEnabled()) { - listener->panelChanged (EvLBrightness, costr); + listener->panelChanged(EvLBrightness, costr); } } else if (a == contrast) { if (listener && getEnabled()) { - listener->panelChanged (EvLContrast, costr); + listener->panelChanged(EvLContrast, costr); } } else if (a == rstprotection) { if (listener && getEnabled()) { - listener->panelChanged (EvLRSTProtection, costr); + listener->panelChanged(EvLRSTProtection, costr); } } else if (a == chromaticity) { if (multiImage) { //if chromaticity==-100 (lowest value), we enter the B&W mode and avoid color shift and rstprotection has no effect - rstprotection->set_sensitive( true ); - avoidcolorshift->set_sensitive( true ); - lcredsk->set_sensitive( true ); + rstprotection->set_sensitive(true); + lcredsk->set_sensitive(true); } else { //if chromaticity==-100 (lowest value), we enter the B&W mode and avoid color shift and rstprotection has no effect - rstprotection->set_sensitive( int(newval) > -100 ); //no reason for grey rstprotection - avoidcolorshift->set_sensitive( int(newval) > -100 ); - lcredsk->set_sensitive( int(newval) > -100 ); + rstprotection->set_sensitive(int(newval) > -100); //no reason for grey rstprotection + lcredsk->set_sensitive(int(newval) > -100); } if (listener && getEnabled()) { - listener->panelChanged (EvLSaturation, costr); + listener->panelChanged(EvLSaturation, costr); } } } -void LCurve::colorForValue (double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller) +void LCurve::colorForValue(double valX, double valY, enum ColorCaller::ElemType elemType, int callerId, ColorCaller *caller) { float R = 0.f, G = 0.f, B = 0.f; @@ -586,47 +628,54 @@ void LCurve::colorForValue (double valX, double valY, enum ColorCaller::ElemType float value = (1.f - 0.7f) * float(valX) + 0.7f; // whole hue range // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) - Color::hsv2rgb01(float(valY*0.8), float(valX), value, R, G, B); + Color::hsv2rgb01(float(valY * 0.8), float(valX), value, R, G, B); } else if (callerId == 6) { // cc - left bar float value = (1.f - 0.7f) * float(valX) + 0.7f; float hue = (1.14056f - 0.92f) * float(valY) + 0.92f; + if (hue > 1.0f) { hue -= 1.0f; } + // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) Color::hsv2rgb01(hue, float(valX), value, R, G, B); } else if (callerId == 3) { // lc - bottom bar float value = (1.f - 0.7f) * float(valX) + 0.7f; + if (lcredsk->get_active()) { // skin range // -0.1 rad < Hue < 1.6 rad // Y axis / from 0.92 up to 0.14056 float hue = (1.14056f - 0.92f) * float(valY) + 0.92f; + if (hue > 1.0f) { hue -= 1.0f; } + // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) Color::hsv2rgb01(hue, float(valX), value, R, G, B); } else { // whole hue range // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) - Color::hsv2rgb01(float(valY*0.8), float(valX), value, R, G, B); + Color::hsv2rgb01(float(valY * 0.8), float(valX), value, R, G, B); } } else if (callerId == 4) { // LH - bottom bar Color::hsv2rgb01(float(valX), 0.5f, float(valY), R, G, B); } else if (callerId == 5) { // HH - bottom bar float h = float((valY - 0.5) * 0.3 + valX); + if (h > 1.0f) { h -= 1.0f; } else if (h < 0.0f) { h += 1.0f; } + Color::hsv2rgb01(h, 0.5f, 0.5f, R, G, B); } else if (callerId == 7) { // cc and cl - left bar float value = (1.f - 0.7f) * float(valX) + 0.7f; // whole hue range // Y axis / from 0.15 up to 0.75 (arbitrary values; was 0.45 before) - Color::hsv2rgb01(float(valY*0.8), 1.f - float(valX), value, R, G, B); + Color::hsv2rgb01(float(valY * 0.8), 1.f - float(valX), value, R, G, B); } caller->ccRed = double(R); @@ -634,17 +683,19 @@ void LCurve::colorForValue (double valX, double valY, enum ColorCaller::ElemType caller->ccBlue = double(B); } -void LCurve::setBatchMode (bool batchMode) +void LCurve::setBatchMode(bool batchMode) { - ToolPanel::setBatchMode (batchMode); - brightness->showEditedCB (); - contrast->showEditedCB (); - chromaticity->showEditedCB (); - rstprotection->showEditedCB (); - curveEditorG->setBatchMode (batchMode); + ToolPanel::setBatchMode(batchMode); + brightness->showEditedCB(); + contrast->showEditedCB(); + chromaticity->showEditedCB(); + rstprotection->showEditedCB(); + curveEditorG->setBatchMode(batchMode); lcshape->setBottomBarColorProvider(nullptr, -1); lcshape->setLeftBarColorProvider(nullptr, -1); + gamutmunselmethod->append(M("GENERAL_UNCHANGED")); + } @@ -661,13 +712,13 @@ void LCurve::updateCurveBackgroundHistogram( const LUTu& histLRETI ) { - lshape->updateBackgroundHistogram (histLCurve); - ccshape->updateBackgroundHistogram (histCCurve); - lcshape->updateBackgroundHistogram (histCCurve); - clshape->updateBackgroundHistogram (histLCurve); + lshape->updateBackgroundHistogram(histLCurve); + ccshape->updateBackgroundHistogram(histCCurve); + lcshape->updateBackgroundHistogram(histCCurve); + clshape->updateBackgroundHistogram(histLCurve); } -void LCurve::setAdjusterBehavior (bool bradd, bool contradd, bool satadd) +void LCurve::setAdjusterBehavior(bool bradd, bool contradd, bool satadd) { brightness->setAddMode(bradd); @@ -675,7 +726,7 @@ void LCurve::setAdjusterBehavior (bool bradd, bool contradd, bool satadd) chromaticity->setAddMode(satadd); } -void LCurve::trimValues (rtengine::procparams::ProcParams* pp) +void LCurve::trimValues(rtengine::procparams::ProcParams* pp) { brightness->trimValue(pp->labCurve.brightness); @@ -687,11 +738,11 @@ void LCurve::enabledChanged() { if (listener) { if (get_inconsistent()) { - listener->panelChanged (EvLEnabled, M("GENERAL_UNCHANGED")); + listener->panelChanged(EvLEnabled, M("GENERAL_UNCHANGED")); } else if (getEnabled()) { - listener->panelChanged (EvLEnabled, M("GENERAL_ENABLED")); + listener->panelChanged(EvLEnabled, M("GENERAL_ENABLED")); } else { - listener->panelChanged (EvLEnabled, M("GENERAL_DISABLED")); + listener->panelChanged(EvLEnabled, M("GENERAL_DISABLED")); } } } diff --git a/rtgui/labcurve.h b/rtgui/labcurve.h index dfb79ae7a..5d762ea9e 100644 --- a/rtgui/labcurve.h +++ b/rtgui/labcurve.h @@ -59,11 +59,14 @@ protected: DiagonalCurveEditor* cdshape; //%%%%%%%%%%%%%%%% - Gtk::CheckButton* avoidcolorshift; Gtk::CheckButton* lcredsk; + MyComboBoxText* gamutmunselmethod; + sigc::connection gamutmunselmethodconn; + rtengine::ProcEvent Evgamutmunsell; + Adjuster* rstprotection; - sigc::connection bwtconn, acconn, lcconn; + sigc::connection bwtconn, lcconn; bool lastACVal, lastLCVal; //%%%%%%%%%%%%%%%% @@ -84,8 +87,8 @@ public: void curveChanged (CurveEditor* ce) override; void adjusterChanged (Adjuster* a, double newval) override; - void avoidcolorshift_toggled (); void lcredsk_toggled(); + void gamutmunselChanged(); void updateCurveBackgroundHistogram( const LUTu& histToneCurve, diff --git a/rtgui/locallab.cc b/rtgui/locallab.cc index 4fb61c1c6..90312b22b 100644 --- a/rtgui/locallab.cc +++ b/rtgui/locallab.cc @@ -277,6 +277,18 @@ void Locallab::read(const rtengine::procparams::ProcParams* pp, const ParamsEdit } else { r->shapeMethod = 3; } + + if (pp->locallab.spots.at(i).avoidgamutMethod == "NONE") { + r->avoidgamutMethod = 0; + } else if (pp->locallab.spots.at(i).avoidgamutMethod == "LAB") { + r->avoidgamutMethod = 1; + } else if (pp->locallab.spots.at(i).avoidgamutMethod == "XYZ") { + r->avoidgamutMethod= 2; + } else if (pp->locallab.spots.at(i).avoidgamutMethod == "XYZREL") { + r->avoidgamutMethod= 3; + } else if (pp->locallab.spots.at(i).avoidgamutMethod == "MUNS") { + r->avoidgamutMethod= 4; + } r->locX = pp->locallab.spots.at(i).loc.at(0); r->locXL = pp->locallab.spots.at(i).loc.at(1); @@ -306,8 +318,6 @@ void Locallab::read(const rtengine::procparams::ProcParams* pp, const ParamsEdit r->avoidrad = pp->locallab.spots.at(i).avoidrad; r->hishow = pp->locallab.spots.at(i).hishow; r->activ = pp->locallab.spots.at(i).activ; - r->avoid = pp->locallab.spots.at(i).avoid; - r->avoidmun = pp->locallab.spots.at(i).avoidmun; r->blwh = pp->locallab.spots.at(i).blwh; r->recurs = pp->locallab.spots.at(i).recurs; r->laplac = true; //pp->locallab.spots.at(i).laplac; @@ -441,6 +451,18 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited r->shapeMethod = 3; } + if (newSpot->avoidgamutMethod == "NONE") { + r->avoidgamutMethod = 0; + } else if (newSpot->avoidgamutMethod == "LAB") { + r->avoidgamutMethod = 1; + } else if (newSpot->avoidgamutMethod == "XYZ") { + r->avoidgamutMethod = 2; + } else if (newSpot->avoidgamutMethod == "XYZREL") { + r->avoidgamutMethod = 3; + } else if (newSpot->avoidgamutMethod == "MUNS") { + r->avoidgamutMethod = 4; + } + // Calculate spot size and center position according to preview area if (provider && !batchMode) { provider->getImageSize(imW, imH); @@ -488,8 +510,6 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited r->avoidrad = newSpot->avoidrad; r->hishow = newSpot->hishow; r->activ = newSpot->activ; - r->avoid = newSpot->avoid; - r->avoidmun = newSpot->avoidmun; r->blwh = newSpot->blwh; r->recurs = newSpot->recurs; r->laplac = newSpot->laplac; @@ -742,6 +762,18 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited r->shapeMethod = 3; } //printf("n0=%f n1=%f n2=%f n3=%f\n", (double) newSpot->loc.at(0), (double) newSpot->loc.at(1), (double) newSpot->loc.at(2), (double) newSpot->loc.at(3)); + if (newSpot->avoidgamutMethod == "NONE") { + r->avoidgamutMethod = 0; + } else if (newSpot->avoidgamutMethod == "LAB") { + r->avoidgamutMethod = 1; + } else if (newSpot->avoidgamutMethod== "XYZ") { + r->avoidgamutMethod = 2; + } else if (newSpot->avoidgamutMethod== "XYZREL") { + r->avoidgamutMethod = 3; + } else if (newSpot->avoidgamutMethod== "MUNS") { + r->avoidgamutMethod = 4; + } + //printf("n0=%f n1=%f n2=%f n3=%f\n", (double) newSpot->loc.at(0), (double) newSpot->loc.at(1), (double) newSpot->loc.at(2), (double) newSpot->loc.at(3)); // Calculate spot size and center position according to preview area if (provider && !batchMode) { @@ -799,8 +831,6 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited r->colorscope = newSpot->colorscope; r->avoidrad = newSpot->avoidrad; r->activ = newSpot->activ; - r->avoid = newSpot->avoid; - r->avoidmun = newSpot->avoidmun; r->blwh = newSpot->blwh; r->recurs = newSpot->recurs; r->laplac = newSpot->laplac; @@ -927,6 +957,18 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited pp->locallab.spots.at(pp->locallab.selspot).shapeMethod = "SYMSL"; } + if (r->avoidgamutMethod == 0) { + pp->locallab.spots.at(pp->locallab.selspot).avoidgamutMethod = "NONE"; + } else if (r->avoidgamutMethod == 1) { + pp->locallab.spots.at(pp->locallab.selspot).avoidgamutMethod = "LAB"; + } else if (r->avoidgamutMethod == 2) { + pp->locallab.spots.at(pp->locallab.selspot).avoidgamutMethod = "XYZ"; + } else if (r->avoidgamutMethod == 3) { + pp->locallab.spots.at(pp->locallab.selspot).avoidgamutMethod = "XYZREL"; + } else if (r->avoidgamutMethod == 4) { + pp->locallab.spots.at(pp->locallab.selspot).avoidgamutMethod = "MUNS"; + } + pp->locallab.spots.at(pp->locallab.selspot).loc.at(0) = r->locX; pp->locallab.spots.at(pp->locallab.selspot).loc.at(1) = r->locXL; pp->locallab.spots.at(pp->locallab.selspot).loc.at(2) = r->locY; @@ -955,8 +997,6 @@ void Locallab::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited pp->locallab.spots.at(pp->locallab.selspot).avoidrad = r->avoidrad; pp->locallab.spots.at(pp->locallab.selspot).hishow = r->hishow; pp->locallab.spots.at(pp->locallab.selspot).activ = r->activ; - pp->locallab.spots.at(pp->locallab.selspot).avoid = r->avoid; - pp->locallab.spots.at(pp->locallab.selspot).avoidmun = r->avoidmun; pp->locallab.spots.at(pp->locallab.selspot).blwh = r->blwh; pp->locallab.spots.at(pp->locallab.selspot).recurs = r->recurs; pp->locallab.spots.at(pp->locallab.selspot).laplac = r->laplac; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index acdda4e8a..7d641d753 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -104,7 +104,7 @@ void ParamsEdited::set(bool v) labCurve.brightness = v; labCurve.contrast = v; labCurve.chromaticity = v; - labCurve.avoidcolorshift = v; + labCurve.gamutmunselmethod = v; labCurve.rstprotection = v; labCurve.lcredsk = v; localContrast.enabled = v; @@ -804,7 +804,7 @@ void ParamsEdited::initFrom(const std::vector& labCurve.brightness = labCurve.brightness && p.labCurve.brightness == other.labCurve.brightness; labCurve.contrast = labCurve.contrast && p.labCurve.contrast == other.labCurve.contrast; labCurve.chromaticity = labCurve.chromaticity && p.labCurve.chromaticity == other.labCurve.chromaticity; - labCurve.avoidcolorshift = labCurve.avoidcolorshift && p.labCurve.avoidcolorshift == other.labCurve.avoidcolorshift; + labCurve.gamutmunselmethod = labCurve.gamutmunselmethod && p.labCurve.gamutmunselmethod == other.labCurve.gamutmunselmethod; labCurve.rstprotection = labCurve.rstprotection && p.labCurve.rstprotection == other.labCurve.rstprotection; labCurve.lcredsk = labCurve.lcredsk && p.labCurve.lcredsk == other.labCurve.lcredsk; @@ -908,7 +908,6 @@ void ParamsEdited::initFrom(const std::vector& vibrance.avoidcolorshift = vibrance.avoidcolorshift && p.vibrance.avoidcolorshift == other.vibrance.avoidcolorshift; vibrance.pastsattog = vibrance.pastsattog && p.vibrance.pastsattog == other.vibrance.pastsattog; vibrance.skintonescurve = vibrance.skintonescurve && p.vibrance.skintonescurve == other.vibrance.skintonescurve; - colorappearance.enabled = colorappearance.enabled && p.colorappearance.enabled == other.colorappearance.enabled; colorappearance.degree = colorappearance.degree && p.colorappearance.degree == other.colorappearance.degree; colorappearance.autodegree = colorappearance.autodegree && p.colorappearance.autodegree == other.colorappearance.autodegree; @@ -1090,6 +1089,7 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).structexclu = locallab.spots.at(j).structexclu && pSpot.structexclu == otherSpot.structexclu; locallab.spots.at(j).struc = locallab.spots.at(j).struc && pSpot.struc == otherSpot.struc; locallab.spots.at(j).shapeMethod = locallab.spots.at(j).shapeMethod && pSpot.shapeMethod == otherSpot.shapeMethod; + locallab.spots.at(j).avoidgamutMethod = locallab.spots.at(j).avoidgamutMethod && pSpot.avoidgamutMethod == otherSpot.avoidgamutMethod; locallab.spots.at(j).loc = locallab.spots.at(j).loc && pSpot.loc == otherSpot.loc; locallab.spots.at(j).centerX = locallab.spots.at(j).centerX && pSpot.centerX == otherSpot.centerX; locallab.spots.at(j).centerY = locallab.spots.at(j).centerY && pSpot.centerY == otherSpot.centerY; @@ -1109,8 +1109,6 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).transitgrad = locallab.spots.at(j).transitgrad && pSpot.transitgrad == otherSpot.transitgrad; locallab.spots.at(j).hishow = locallab.spots.at(j).hishow && pSpot.hishow == otherSpot.hishow; locallab.spots.at(j).activ = locallab.spots.at(j).activ && pSpot.activ == otherSpot.activ; - locallab.spots.at(j).avoid = locallab.spots.at(j).avoid && pSpot.avoid == otherSpot.avoid; - locallab.spots.at(j).avoidmun = locallab.spots.at(j).avoidmun && pSpot.avoidmun == otherSpot.avoidmun; locallab.spots.at(j).blwh = locallab.spots.at(j).blwh && pSpot.blwh == otherSpot.blwh; locallab.spots.at(j).recurs = locallab.spots.at(j).recurs && pSpot.recurs == otherSpot.recurs; locallab.spots.at(j).laplac = locallab.spots.at(j).laplac && pSpot.laplac == otherSpot.laplac; @@ -2392,8 +2390,8 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.labCurve.chromaticity = dontforceSet && options.baBehav[ADDSET_LC_CHROMATICITY] ? toEdit.labCurve.chromaticity + mods.labCurve.chromaticity : mods.labCurve.chromaticity; } - if (labCurve.avoidcolorshift) { - toEdit.labCurve.avoidcolorshift = mods.labCurve.avoidcolorshift; + if (labCurve.gamutmunselmethod) { + toEdit.labCurve.gamutmunselmethod = mods.labCurve.gamutmunselmethod; } if (labCurve.rstprotection) { @@ -3434,6 +3432,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).shapeMethod = mods.locallab.spots.at(i).shapeMethod; } + if (locallab.spots.at(i).avoidgamutMethod) { + toEdit.locallab.spots.at(i).avoidgamutMethod = mods.locallab.spots.at(i).avoidgamutMethod; + } + if (locallab.spots.at(i).loc) { toEdit.locallab.spots.at(i).loc = mods.locallab.spots.at(i).loc; } @@ -3510,14 +3512,6 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).activ = mods.locallab.spots.at(i).activ; } - if (locallab.spots.at(i).avoid) { - toEdit.locallab.spots.at(i).avoid = mods.locallab.spots.at(i).avoid; - } - - if (locallab.spots.at(i).avoidmun) { - toEdit.locallab.spots.at(i).avoidmun = mods.locallab.spots.at(i).avoidmun; - } - if (locallab.spots.at(i).blwh) { toEdit.locallab.spots.at(i).blwh = mods.locallab.spots.at(i).blwh; } @@ -7412,6 +7406,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : structexclu(v), struc(v), shapeMethod(v), + avoidgamutMethod(v), loc(v), centerX(v), centerY(v), @@ -7431,8 +7426,6 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : transitgrad(v), hishow(v), activ(v), - avoid(v), - avoidmun(v), blwh(v), recurs(v), laplac(v), @@ -8104,6 +8097,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) structexclu = v; struc = v; shapeMethod = v; + avoidgamutMethod = v; loc = v; centerX = v; centerY = v; @@ -8123,8 +8117,6 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) transitgrad = v; hishow = v; activ = v; - avoid = v; - avoidmun = v; blwh = v; recurs = v; laplac = v; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 56d71cfa3..616e6d261 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -109,7 +109,7 @@ struct LCurveParamsEdited { bool brightness; bool contrast; bool chromaticity; - bool avoidcolorshift; + bool gamutmunselmethod; bool rstprotection; bool lcurve; bool acurve; @@ -402,6 +402,7 @@ public: bool structexclu; bool struc; bool shapeMethod; + bool avoidgamutMethod; bool loc; bool centerX; bool centerY; @@ -421,8 +422,6 @@ public: bool transitgrad; bool hishow; bool activ; - bool avoid; - bool avoidmun; bool blwh; bool recurs; bool laplac; From ba11a9355ac76342368ba122b252fe372b328128 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Tue, 31 Jan 2023 23:42:36 -0800 Subject: [PATCH 104/134] mac: fixes lensfun logic Fixes use of the v1 lensfun interface for v0.3.3, v0.3.4-RC1, etc. --- tools/osx/macosx_bundle.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index d0cbf4d6b..26b8b4d08 100644 --- a/tools/osx/macosx_bundle.sh +++ b/tools/osx/macosx_bundle.sh @@ -191,13 +191,15 @@ lensfunversion=$(pkg-config --modversion lensfun | cut -f3 -d'.') if [ $lensfunversion = 95 ] then ditto ${LOCAL_PREFIX}/share/lensfun/version_2/* "${RESOURCES}/share/lensfun" + # Copy liblensfun to Frameworks + ditto ${LOCAL_PREFIX}/lib/liblensfun.2.dylib "${CONTENTS}/Frameworks/liblensfun.2.dylib" + else ditto ${LOCAL_PREFIX}/share/lensfun/version_1/* "${RESOURCES}/share/lensfun" + # Copy liblensfun to Frameworks + ditto ${LOCAL_PREFIX}/lib/liblensfun.1.dylib "${CONTENTS}/Frameworks/liblensfun.1.dylib" fi -# Copy liblensfun to Frameworks -ditto ${LOCAL_PREFIX}/lib/liblensfun.2.dylib "${CONTENTS}/Frameworks/liblensfun.2.dylib" - # Copy libomp to Frameworks ditto ${LOCAL_PREFIX}/lib/libomp.dylib "${CONTENTS}/Frameworks" From a3adbce04b91f2cbb892d810df92805b216db4d2 Mon Sep 17 00:00:00 2001 From: "U-PCSPECIALIST01\\jdesm" Date: Mon, 6 Feb 2023 19:00:14 +0100 Subject: [PATCH 105/134] Support for Nikon Z9 --- rtengine/camconst.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rtengine/camconst.json b/rtengine/camconst.json index 7a143e850..07f08d9a6 100644 --- a/rtengine/camconst.json +++ b/rtengine/camconst.json @@ -1973,6 +1973,11 @@ Camera constants: "dcraw_matrix" : [13705, -6004, -1401, -5464, 13568, 2062, -940, 1706, 7618] // DNG }, + { // Quality C + "make_model" : "NIKON Z 9", + "dcraw_matrix" : [13389, -6049, -1441, -4544, 12757, 1969, 229, 498, 7390] //DNG + }, + { // Quality C, only color matrix and PDAF lines info "make_model" : "Nikon Z 6", "dcraw_matrix" : [8210, -2534, -683, -5355, 13338, 2212, -1143, 1928, 6464], // DNG v13.2 From e5d46032ffbe8b21946019203260ab1aefe9c483 Mon Sep 17 00:00:00 2001 From: Desmis Date: Thu, 9 Feb 2023 07:14:20 +0100 Subject: [PATCH 106/134] Add "Inpaint opposed" to Highlight reconstruction and improved Itcwb (#6635) * Essai HL * Try Inpaint opposed * Code improvment * Add file * Improvment to process inpaint opposed and color propagation * Clean code * Change Blend to Coloropp in Profile pp3 * Enable BENCHFUN hilite_recon * Clean rtengine cmakelist * Comment unused code * Neutralise unused code * Change bad Exposure in Pop2Lab.pp3 * Try to fix bug when Inpaint Opposed is used and White balance disabled * Changes to refreshmap * Change to improccoordinator M_RETINEX * Clean unused commented code * Force Inpaint-opposed in rawimagesouce if wb change * Suppressed message in console * Change events and limits to 1 the number of calls to inpaint-opposed * Comment code * Add gain theshold to inpaint opposed * fixed typo in procparams.cc * Change in option.cc itcwb_sort to true * Change itcw sorted in options and rawimagesource.cc * Change sampling read datas Itcwb * Allow or not purple in WB itcwb * Added option icwb.nopurple to bypass settings * Added code comment Itcwb * optimize Itcwb between green and student * Formated code used by Itcwb with Astylert.bat * Change color_match - thanks to Lawrence37 * Remove wrong text --- rtdata/languages/default | 3 + .../Auto-Matched Curve - ISO High.pp3 | 2 +- .../profiles/Auto-Matched Curve - ISO Low.pp3 | 2 +- .../Auto-Matched Curve - ISO Medium.pp3 | 2 +- .../Film Negative - Black and White.pp3 | 2 +- rtdata/profiles/Film Negative.pp3 | 2 +- rtdata/profiles/Pop/Pop 1.pp3 | 2 +- rtdata/profiles/Pop/Pop 2 Lab.pp3 | 2 +- rtdata/profiles/Pop/Pop 3 Skin.pp3 | 2 +- rtdata/profiles/Pop/Pop 4 Black-and-White.pp3 | 2 +- .../Standard Film Curve - ISO High.pp3 | 2 +- .../Standard Film Curve - ISO Low.pp3 | 2 +- .../Standard Film Curve - ISO Medium.pp3 | 2 +- rtengine/clutstore.cc | 2 +- rtengine/colortemp.cc | 91 +- rtengine/colortemp.h | 14 +- rtengine/dcrop.cc | 12 +- rtengine/filmnegativeproc.cc | 2 +- rtengine/hilite_recon.cc | 373 ++++++- rtengine/iimage.h | 2 +- rtengine/imagesource.h | 9 +- rtengine/improccoordinator.cc | 29 +- rtengine/iplocallab.cc | 2 +- rtengine/linalgebra.h | 275 ++++++ rtengine/perspectivecorrection.cc | 2 +- rtengine/previewimage.cc | 2 +- rtengine/procparams.cc | 7 +- rtengine/procparams.h | 1 + rtengine/rawimagesource.cc | 927 +++++++++++------- rtengine/rawimagesource.h | 14 +- rtengine/refreshmap.cc | 2 +- rtengine/rtthumbnail.cc | 2 +- rtengine/settings.h | 4 +- rtengine/simpleprocess.cc | 8 +- rtengine/spot.cc | 4 +- rtengine/stdimagesource.cc | 22 +- rtengine/stdimagesource.h | 8 +- rtgui/options.cc | 22 +- rtgui/paramsedited.cc | 6 + rtgui/paramsedited.h | 1 + rtgui/tonecurve.cc | 80 +- rtgui/tonecurve.h | 2 + 42 files changed, 1455 insertions(+), 497 deletions(-) create mode 100644 rtengine/linalgebra.h diff --git a/rtdata/languages/default b/rtdata/languages/default index 68fda352b..84b28c955 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1417,6 +1417,7 @@ HISTORY_MSG_FILMNEGATIVE_VALUES;Film negative values HISTORY_MSG_GAMUTMUNSEL;Gamut-Munsell HISTORY_MSG_HISTMATCHING;Auto-matched tone curve HISTORY_MSG_HLBL;Color propagation - blur +HISTORY_MSG_HLTH;Inpaint opposed - gain threshold HISTORY_MSG_ICL_LABGRIDCIEXY;Cie xy HISTORY_MSG_ICM_AINTENT;Abstract profile intent HISTORY_MSG_ICM_BLUX;Primaries Blue X @@ -2518,8 +2519,10 @@ TP_GRADIENT_STRENGTH_TOOLTIP;Filter strength in stops. TP_HLREC_BLEND;Blend TP_HLREC_CIELAB;CIELab Blending TP_HLREC_COLOR;Color Propagation +TP_HLREC_COLOROPP;Inpaint Opposed TP_HLREC_ENA_TOOLTIP;Could be activated by Auto Levels. TP_HLREC_HLBLUR;Blur +TP_HLREC_HLTH;Gain threshold TP_HLREC_LABEL;Highlight reconstruction TP_HLREC_LUMINANCE;Luminance Recovery TP_HLREC_METHOD;Method: diff --git a/rtdata/profiles/Auto-Matched Curve - ISO High.pp3 b/rtdata/profiles/Auto-Matched Curve - ISO High.pp3 index 99f0af8fe..16c9a71f5 100644 --- a/rtdata/profiles/Auto-Matched Curve - ISO High.pp3 +++ b/rtdata/profiles/Auto-Matched Curve - ISO High.pp3 @@ -4,7 +4,7 @@ HistogramMatching=true [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Directional Pyramid Denoising] Enabled=true diff --git a/rtdata/profiles/Auto-Matched Curve - ISO Low.pp3 b/rtdata/profiles/Auto-Matched Curve - ISO Low.pp3 index c94077b21..e6c7fb96c 100644 --- a/rtdata/profiles/Auto-Matched Curve - ISO Low.pp3 +++ b/rtdata/profiles/Auto-Matched Curve - ISO Low.pp3 @@ -4,7 +4,7 @@ HistogramMatching=true [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [LensProfile] LcMode=lfauto diff --git a/rtdata/profiles/Auto-Matched Curve - ISO Medium.pp3 b/rtdata/profiles/Auto-Matched Curve - ISO Medium.pp3 index f9196bb30..ffb5587b9 100644 --- a/rtdata/profiles/Auto-Matched Curve - ISO Medium.pp3 +++ b/rtdata/profiles/Auto-Matched Curve - ISO Medium.pp3 @@ -4,7 +4,7 @@ HistogramMatching=true [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Directional Pyramid Denoising] Enabled=true diff --git a/rtdata/profiles/Film Negative - Black and White.pp3 b/rtdata/profiles/Film Negative - Black and White.pp3 index ad2a38e1e..3bebe7e3c 100644 --- a/rtdata/profiles/Film Negative - Black and White.pp3 +++ b/rtdata/profiles/Film Negative - Black and White.pp3 @@ -11,7 +11,7 @@ Curve2=1;0;0;0.0397505754145333;0.020171771436200074;0.54669745433149319;0.69419 [HLRecovery] Enabled=false -Method=Blend +Method=Coloropp [Black & White] Enabled=true diff --git a/rtdata/profiles/Film Negative.pp3 b/rtdata/profiles/Film Negative.pp3 index 0ecac1d33..e76c61866 100644 --- a/rtdata/profiles/Film Negative.pp3 +++ b/rtdata/profiles/Film Negative.pp3 @@ -11,7 +11,7 @@ Curve2=1;0;0;0.0397505754145333;0.020171771436200074;0.54669745433149319;0.69419 [HLRecovery] Enabled=false -Method=Blend +Method=Coloropp [Crop] FixedRatio=false diff --git a/rtdata/profiles/Pop/Pop 1.pp3 b/rtdata/profiles/Pop/Pop 1.pp3 index 2152a268b..cbdf4ab5b 100644 --- a/rtdata/profiles/Pop/Pop 1.pp3 +++ b/rtdata/profiles/Pop/Pop 1.pp3 @@ -19,7 +19,7 @@ Curve2=0; [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Luminance Curve] Enabled=true diff --git a/rtdata/profiles/Pop/Pop 2 Lab.pp3 b/rtdata/profiles/Pop/Pop 2 Lab.pp3 index 796aeb5ba..f4c01fd1b 100644 --- a/rtdata/profiles/Pop/Pop 2 Lab.pp3 +++ b/rtdata/profiles/Pop/Pop 2 Lab.pp3 @@ -19,7 +19,7 @@ Curve2=0; [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Luminance Curve] Enabled=true diff --git a/rtdata/profiles/Pop/Pop 3 Skin.pp3 b/rtdata/profiles/Pop/Pop 3 Skin.pp3 index 650b2e189..ebce37b58 100644 --- a/rtdata/profiles/Pop/Pop 3 Skin.pp3 +++ b/rtdata/profiles/Pop/Pop 3 Skin.pp3 @@ -19,7 +19,7 @@ Curve2=0; [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Luminance Curve] Enabled=true diff --git a/rtdata/profiles/Pop/Pop 4 Black-and-White.pp3 b/rtdata/profiles/Pop/Pop 4 Black-and-White.pp3 index 9faa32a0a..1e3527ceb 100644 --- a/rtdata/profiles/Pop/Pop 4 Black-and-White.pp3 +++ b/rtdata/profiles/Pop/Pop 4 Black-and-White.pp3 @@ -19,7 +19,7 @@ Curve2=0; [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Black & White] Enabled=true diff --git a/rtdata/profiles/Standard Film Curve - ISO High.pp3 b/rtdata/profiles/Standard Film Curve - ISO High.pp3 index 4dd3a9b1d..42bbed6d3 100644 --- a/rtdata/profiles/Standard Film Curve - ISO High.pp3 +++ b/rtdata/profiles/Standard Film Curve - ISO High.pp3 @@ -6,7 +6,7 @@ Curve=1;0;0;0.11;0.089999999999999997;0.32000000000000001;0.42999999999999999;0. [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Directional Pyramid Denoising] Enabled=true diff --git a/rtdata/profiles/Standard Film Curve - ISO Low.pp3 b/rtdata/profiles/Standard Film Curve - ISO Low.pp3 index 45fcca730..342b1c8d3 100644 --- a/rtdata/profiles/Standard Film Curve - ISO Low.pp3 +++ b/rtdata/profiles/Standard Film Curve - ISO Low.pp3 @@ -6,7 +6,7 @@ Curve=1;0;0;0.11;0.089999999999999997;0.32000000000000001;0.42999999999999999;0. [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [LensProfile] LcMode=lfauto diff --git a/rtdata/profiles/Standard Film Curve - ISO Medium.pp3 b/rtdata/profiles/Standard Film Curve - ISO Medium.pp3 index 4aff630f5..f3b292094 100644 --- a/rtdata/profiles/Standard Film Curve - ISO Medium.pp3 +++ b/rtdata/profiles/Standard Film Curve - ISO Medium.pp3 @@ -6,7 +6,7 @@ Curve=1;0;0;0.11;0.089999999999999997;0.32000000000000001;0.42999999999999999;0. [HLRecovery] Enabled=true -Method=Blend +Method=Coloropp [Directional Pyramid Denoising] Enabled=true diff --git a/rtengine/clutstore.cc b/rtengine/clutstore.cc index e3bd9c988..4c70ad951 100644 --- a/rtengine/clutstore.cc +++ b/rtengine/clutstore.cc @@ -57,7 +57,7 @@ bool loadFile( rtengine::procparams::ColorManagementParams icm; icm.workingProfile = working_color_space; - img_src.getImage(curr_wb, TR_NONE, img_float.get(), pp, rtengine::procparams::ToneCurveParams(), rtengine::procparams::RAWParams()); + img_src.getImage(curr_wb, TR_NONE, img_float.get(), pp, rtengine::procparams::ToneCurveParams(), rtengine::procparams::RAWParams(), 0); if (!working_color_space.empty()) { img_src.convertColorSpace(img_float.get(), icm, curr_wb); diff --git a/rtengine/colortemp.cc b/rtengine/colortemp.cc index a4dd8a4d1..4ba47b25a 100644 --- a/rtengine/colortemp.cc +++ b/rtengine/colortemp.cc @@ -33,7 +33,7 @@ namespace rtengine { -static double cie_colour_match_jd2[97][3] = {//350nm to 830nm 5 nm J.Desmis 2° Standard Observer. +static const color_match_type cie_colour_match_jd2 = {//350nm to 830nm 5 nm J.Desmis 2° Standard Observer. {0.0000000, 0.000000, 0.000000}, {0.0000000, 0.000000, 0.000000}, {0.0001299, 0.0003917, 0.0006061}, {0.0002321, 0.000006965, 0.001086}, {0.0004149, 0.00001239, 0.001946}, {0.0007416, 0.00002202, 0.003846}, {0.001368, 0.000039, 0.006450001}, {0.002236, 0.000064, 0.01054999}, {0.004243, 0.000120, 0.02005001}, @@ -70,7 +70,7 @@ static double cie_colour_match_jd2[97][3] = {//350nm to 830nm 5 nm J.Desmis 2 }; -static const double cie_colour_match_jd[97][3] = {//350nm to 830nm 5 nm J.Desmis 10° Standard Observer. +static const color_match_type cie_colour_match_jd = {//350nm to 830nm 5 nm J.Desmis 10° Standard Observer. {0.000000000000, 0.000000000000, 0.000000000000}, {0.000000000000, 0.000000000000, 0.000000000000}, {0.000000122200, 0.000000013398, 0.000000535027}, @@ -2963,15 +2963,16 @@ void ColorTemp::temp2mulxyz (double temp, const std::string &method, double &Xxy // 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; if (iterator != spectMap.end()) { - spectrum_to_xyz_preset(iterator->second, x, y, z); + spectrum_to_xyz_preset(iterator->second, x, y, z, color_match); } else { // otherwise we use the Temp+Green generic solution if (temp <= INITIALBLACKBODY) { // if temperature is between 2000K and 4000K we use blackbody, because there will be no Daylight reference below 4000K... // of course, the previous version of RT used the "magical" but wrong formula of U.Fuchs (Ufraw). - spectrum_to_xyz_blackbody(temp, x, y, z); + spectrum_to_xyz_blackbody(temp, x, y, z, color_match); } else { // from 4000K up to 25000K: using the D illuminant (daylight) which is standard double x_D, y_D; @@ -2990,7 +2991,7 @@ void ColorTemp::temp2mulxyz (double temp, const std::string &method, double &Xxy double interm = 0.0241 + 0.2562 * x_D - 0.734 * y_D; double m1 = (-1.3515 - 1.7703 * x_D + 5.9114 * y_D) / interm; double m2 = (0.03 - 31.4424 * x_D + 30.0717 * y_D) / interm; - spectrum_to_xyz_daylight(m1, m2, x, y, z); + spectrum_to_xyz_daylight(m1, m2, x, y, z, color_match); } } @@ -3169,17 +3170,19 @@ 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; + 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]); + spectrum_to_color_xyz_preset(spec_color[i], spect_illum[illum + 3], XchkLamp[i], YchkLamp[i], ZchkLamp[i], color_match); } //calculate XYZ for each color : for Blackbody and Daylight at tempw if(tempw <= INITIALBLACKBODY) { for(int i = 0; i < N_c; i++) { - spectrum_to_color_xyz_blackbody(spec_color[i], tempw, Xchk[i], Ychk[i], Zchk[i]); + spectrum_to_color_xyz_blackbody(spec_color[i], tempw, Xchk[i], Ychk[i], Zchk[i], color_match); } - spectrum_to_xyz_blackbody(tempw, x, y, z);//for white point + spectrum_to_xyz_blackbody(tempw, x, y, z, color_match);//for white point } else { // after 6600K (arbitrary) I use daylight...because ...but there is no lamp... double m11, m22, x_DD, y_DD, interm2; @@ -3197,10 +3200,10 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul, m22 = (0.03 - 31.4424 * x_DD + 30.0717 * y_DD) / interm2; for(int i = 0; i < N_c; i++) { - spectrum_to_color_xyz_daylight(spec_color[i], m11, m22, Xchk[i], Ychk[i], Zchk[i]); + spectrum_to_color_xyz_daylight(spec_color[i], m11, m22, Xchk[i], Ychk[i], Zchk[i], color_match); } - spectrum_to_xyz_daylight(m11, m22, x, y, z); + spectrum_to_xyz_daylight(m11, m22, x, y, z, color_match); } if (settings->verbose) { @@ -3394,16 +3397,16 @@ I have increase precision used by J.Walker and pass to 350nm to 830nm And also add 10° standard observer */ -void ColorTemp::spectrum_to_xyz_daylight(double _m1, double _m2, double &x, double &y, double &z) +void ColorTemp::spectrum_to_xyz_daylight(double _m1, double _m2, double &x, double &y, double &z, const color_match_type &color_match) { int i; double lambda, X = 0, Y = 0, Z = 0, XYZ; for (i = 0, lambda = 350.; lambda < 830.1; i++, lambda += 5.) { double Me = daylight_spect(lambda, _m1, _m2); - X += Me * cie_colour_match_jd2[i][0]; - Y += Me * cie_colour_match_jd2[i][1]; - Z += Me * cie_colour_match_jd2[i][2]; + X += Me * color_match[i][0]; + Y += Me * color_match[i][1]; + Z += Me * color_match[i][2]; } XYZ = (X + Y + Z); @@ -3412,16 +3415,16 @@ void ColorTemp::spectrum_to_xyz_daylight(double _m1, double _m2, double &x, doub z = Z / XYZ; } -void ColorTemp::spectrum_to_xyz_blackbody(double _temp, double &x, double &y, double &z) +void ColorTemp::spectrum_to_xyz_blackbody(double _temp, double &x, double &y, double &z, const color_match_type &color_match) { int i; double lambda, X = 0, Y = 0, Z = 0, XYZ; for (i = 0, lambda = 350.; lambda < 830.1; i++, lambda += 5.) { double Me = blackbody_spect(lambda, _temp); - X += Me * cie_colour_match_jd2[i][0]; - Y += Me * cie_colour_match_jd2[i][1]; - Z += Me * cie_colour_match_jd2[i][2]; + X += Me * color_match[i][0]; + Y += Me * color_match[i][1]; + Z += Me * color_match[i][2]; } XYZ = (X + Y + Z); @@ -3430,7 +3433,7 @@ void ColorTemp::spectrum_to_xyz_blackbody(double _temp, double &x, double &y, do z = Z / XYZ; } -void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, double &y, double &z) +void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, double &y, double &z, const color_match_type &color_match) { int i; double lambda, X = 0, Y = 0, Z = 0, XYZ; @@ -3454,9 +3457,9 @@ void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, dou */ for (i = 0, lambda = 350.; lambda < 830.1; i++, lambda += 5.) { double Me = get_spectral_color(lambda, spec_intens); - X += Me * cie_colour_match_jd2[i][0]; - Y += Me * cie_colour_match_jd2[i][1]; - Z += Me * cie_colour_match_jd2[i][2]; + X += Me * color_match[i][0]; + Y += Me * color_match[i][1]; + Z += Me * color_match[i][2]; } XYZ = (X + Y + Z); @@ -3466,7 +3469,7 @@ void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, dou } //calculate XYZ from spectrum data (color) and illuminant : J.Desmis December 2011 -void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const double* spec_intens, double &xx, double &yy, double &zz) +void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const double* spec_intens, double &xx, double &yy, double &zz, const color_match_type &color_match) { int i; double lambda, X = 0, Y = 0, Z = 0, Yo = 0; @@ -3478,9 +3481,9 @@ void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const dou Me = get_spectral_color(lambda, spec_color); Mc = get_spectral_color(lambda, spec_intens); - X += Mc * cie_colour_match_jd2[i][0] * Me; - Y += Mc * cie_colour_match_jd2[i][1] * Me; - Z += Mc * cie_colour_match_jd2[i][2] * Me; + X += Mc * color_match[i][0] * Me; + Y += Mc * color_match[i][1] * Me; + Z += Mc * color_match[i][2] * Me; } for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5) { @@ -3488,7 +3491,7 @@ void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const dou double Ms; Ms = get_spectral_color(lambda, spec_intens); - Yo += cie_colour_match_jd2[i][1] * Ms; + Yo += color_match[i][1] * Ms; } xx = X / Yo; @@ -3497,7 +3500,7 @@ void ColorTemp::spectrum_to_color_xyz_preset(const double* spec_color, const dou } //calculate XYZ from spectrum data (color) and illuminant : J.Desmis december 2011 -void ColorTemp::spectrum_to_color_xyz_daylight(const double* spec_color, double _m1, double _m2, double &xx, double &yy, double &zz) +void ColorTemp::spectrum_to_color_xyz_daylight(const double* spec_color, double _m1, double _m2, double &xx, double &yy, double &zz, const color_match_type &color_match) { int i; double lambda, X = 0, Y = 0, Z = 0; @@ -3505,9 +3508,9 @@ void ColorTemp::spectrum_to_color_xyz_daylight(const double* spec_color, double for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5) { const double Me = spec_color[i]; const double Mc = daylight_spect(lambda, _m1, _m2); - X += Mc * cie_colour_match_jd2[i][0] * Me; - Y += Mc * cie_colour_match_jd2[i][1] * Me; - Z += Mc * cie_colour_match_jd2[i][2] * Me; + X += Mc * color_match[i][0] * Me; + Y += Mc * color_match[i][1] * Me; + Z += Mc * color_match[i][2] * Me; } xx = X / Y; @@ -3516,7 +3519,7 @@ void ColorTemp::spectrum_to_color_xyz_daylight(const double* spec_color, double } //calculate XYZ from spectrum data (color) and illuminant : J.Desmis december 2011 -void ColorTemp::spectrum_to_color_xyz_blackbody(const double* spec_color, double _temp, double &xx, double &yy, double &zz) +void ColorTemp::spectrum_to_color_xyz_blackbody(const double* spec_color, double _temp, double &xx, double &yy, double &zz, const color_match_type &color_match) { int i; double lambda, X = 0, Y = 0, Z = 0; @@ -3524,9 +3527,9 @@ void ColorTemp::spectrum_to_color_xyz_blackbody(const double* spec_color, double for (i = 0, lambda = 350; lambda < 830.1; i++, lambda += 5) { const double Me = spec_color[i]; const double Mc = blackbody_spect(lambda, _temp); - X += Mc * cie_colour_match_jd2[i][0] * Me; - Y += Mc * cie_colour_match_jd2[i][1] * Me; - Z += Mc * cie_colour_match_jd2[i][2] * Me; + X += Mc * color_match[i][0] * Me; + Y += Mc * color_match[i][1] * Me; + Z += Mc * color_match[i][2] * Me; } xx = X / Y; @@ -3762,27 +3765,21 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float } if (settings->verbose) { - if (settings->itcwb_stdobserver10 == false) { + 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"); } } - if (settings->itcwb_stdobserver10 == true) { - for (int i = 0; i < 97; i++) { - cie_colour_match_jd2[i][0] = cie_colour_match_jd[i][0]; - cie_colour_match_jd2[i][1] = cie_colour_match_jd[i][1];; - cie_colour_match_jd2[i][2] = cie_colour_match_jd[i][2]; - } - } + const color_match_type &color_match = (settings->itcwb_stdobserver10 == true) ? cie_colour_match_jd : cie_colour_match_jd2; if (separated) { const double tempw = Txyz[repref].Tem; if (tempw <= INITIALBLACKBODY) { for (int i = 0; i < N_c; i++) { - spectrum_to_color_xyz_blackbody(spec_colorforxcyc[i], tempw, TX[i], TY[i], TZ[i]); + spectrum_to_color_xyz_blackbody(spec_colorforxcyc[i], tempw, TX[i], TY[i], TZ[i], color_match); } } else { double m11, m22, x_DD, y_DD, interm2; @@ -3801,7 +3798,7 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float m22 = (0.03 - 31.4424 * x_DD + 30.0717 * y_DD) / interm2; for (int i = 0; i < N_c; i++) { - spectrum_to_color_xyz_daylight(spec_colorforxcyc[i], m11, m22, TX[i], TY[i], TZ[i]); + spectrum_to_color_xyz_daylight(spec_colorforxcyc[i], m11, m22, TX[i], TY[i], TZ[i], color_match); } } } else { @@ -3810,7 +3807,7 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float if (tempw <= INITIALBLACKBODY) { for (int i = 0; i < N_c; i++) { - spectrum_to_color_xyz_blackbody(spec_colorforxcyc[i], tempw, Refxyz[i].Xref, Refxyz[i].Yref, Refxyz[i].Zref); + spectrum_to_color_xyz_blackbody(spec_colorforxcyc[i], tempw, Refxyz[i].Xref, Refxyz[i].Yref, Refxyz[i].Zref, color_match); } } else { double x_DD; @@ -3829,7 +3826,7 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float const double m22 = (0.03 - 31.4424 * x_DD + 30.0717 * y_DD) / interm2; for (int i = 0; i < N_c; i++) { - spectrum_to_color_xyz_daylight(spec_colorforxcyc[i], m11, m22, Refxyz[i].Xref, Refxyz[i].Yref, Refxyz[i].Zref); + spectrum_to_color_xyz_daylight(spec_colorforxcyc[i], m11, m22, Refxyz[i].Xref, Refxyz[i].Yref, Refxyz[i].Zref, color_match); } } diff --git a/rtengine/colortemp.h b/rtengine/colortemp.h index 89c324490..78091f51d 100644 --- a/rtengine/colortemp.h +++ b/rtengine/colortemp.h @@ -26,6 +26,8 @@ namespace rtengine { +using color_match_type = double [97][3]; + constexpr double MINTEMP = 1500.0; constexpr double MAXTEMP = 60000.0; constexpr double MINGREEN = 0.02; @@ -375,13 +377,13 @@ public: static const double JDC468_greym13_325_spect[97]; static const double JDC468_greyf26_156_spect[97]; */ - static void spectrum_to_xyz_daylight (double _m1, double _m2, double &x, double &y, double &z); - static void spectrum_to_xyz_blackbody (double _temp, double &x, double &y, double &z); - static void spectrum_to_xyz_preset (const double* spec_intens, double &x, double &y, double &z); + static void spectrum_to_xyz_daylight (double _m1, double _m2, double &x, double &y, double &z, const color_match_type &color_match); + static void spectrum_to_xyz_blackbody (double _temp, double &x, double &y, double &z, const color_match_type &color_match); + static void spectrum_to_xyz_preset (const double* spec_intens, double &x, double &y, double &z, const color_match_type &color_match); - static void spectrum_to_color_xyz_daylight (const double* spec_color, double _m1, double _m2, double &xx, double &yy, double &zz); - static void spectrum_to_color_xyz_blackbody (const double* spec_color, double _temp, double &xx, double &yy, double &zz); - static void spectrum_to_color_xyz_preset (const double* spec_color, const double* spec_intens, double &xx, double &yy, double &zz); + static void spectrum_to_color_xyz_daylight (const double* spec_color, double _m1, double _m2, double &xx, double &yy, double &zz, const color_match_type &color_match); + static void spectrum_to_color_xyz_blackbody (const double* spec_color, double _temp, double &xx, double &yy, double &zz, const color_match_type &color_match); + static void spectrum_to_color_xyz_preset (const double* spec_color, const double* spec_intens, double &xx, double &yy, double &zz, const color_match_type &color_match); }; } diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index f4ac49fc4..8ddaa5f75 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -228,18 +228,18 @@ void Crop::update(int todo) if (settings->leveldnautsimpl == 1) { if (params.dirpyrDenoise.Cmethod == "MAN" || params.dirpyrDenoise.Cmethod == "PON") { PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); + parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0); } } else { if (params.dirpyrDenoise.C2method == "MANU") { PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); + parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0); } } if ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "PRE") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "PREV")) { PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); + parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0); if ((!isDetailWindow) && parent->adnListener && skip == 1 && params.dirpyrDenoise.enabled) { float lowdenoise = 1.f; @@ -451,7 +451,7 @@ void Crop::update(int todo) for (int wcr = 0; wcr <= 2; wcr++) { for (int hcr = 0; hcr <= 2; hcr++) { PreviewProps ppP(coordW[wcr], coordH[hcr], crW, crH, 1); - parent->imgsrc->getImage(parent->currWB, tr, origCropPart, ppP, params.toneCurve, params.raw); + parent->imgsrc->getImage(parent->currWB, tr, origCropPart, ppP, params.toneCurve, params.raw, 0); // we only need image reduced to 1/4 here for (int ii = 0; ii < crH; ii += 2) { @@ -613,7 +613,7 @@ void Crop::update(int todo) // if (params.dirpyrDenoise.Cmethod=="AUT" || params.dirpyrDenoise.Cmethod=="PON") {//reinit origCrop after Auto if ((settings->leveldnautsimpl == 1 && params.dirpyrDenoise.Cmethod == "AUT") || (settings->leveldnautsimpl == 0 && params.dirpyrDenoise.C2method == "AUTO")) { //reinit origCrop after Auto PreviewProps pp(trafx, trafy, trafw * skip, trafh * skip, skip); - parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw); + parent->imgsrc->getImage(parent->currWB, tr, origCrop, pp, params.toneCurve, params.raw, 0); } if ((todo & M_SPOT) && params.spot.enabled && !params.spot.entries.empty()) { @@ -749,7 +749,7 @@ void Crop::update(int todo) fattalCrop.reset(f); PreviewProps pp(0, 0, parent->fw, parent->fh, skip); int tr = getCoarseBitMask(params.coarse); - parent->imgsrc->getImage(parent->currWB, tr, f, pp, params.toneCurve, params.raw); + parent->imgsrc->getImage(parent->currWB, tr, f, pp, params.toneCurve, params.raw, 0); parent->imgsrc->convertColorSpace(f, params.icm, parent->currWB); if (params.dirpyrDenoise.enabled || params.filmNegative.enabled || params.spot.enabled) { diff --git a/rtengine/filmnegativeproc.cc b/rtengine/filmnegativeproc.cc index ae1813db9..c33dc4a9a 100644 --- a/rtengine/filmnegativeproc.cc +++ b/rtengine/filmnegativeproc.cc @@ -84,7 +84,7 @@ void getSpotAvgMax(ImageSource *imgsrc, ColorTemp currWB, const std::unique_ptr< } rtengine::Imagefloat spotImg(spotSize, spotSize); - imgsrc->getImage(currWB, tr, &spotImg, pp, params->toneCurve, params->raw); + imgsrc->getImage(currWB, tr, &spotImg, pp, params->toneCurve, params->raw, 0); auto avgMax = [spotSize, &spotImg](RGB & avg, RGB & max) -> void { avg = {}; diff --git a/rtengine/hilite_recon.cc b/rtengine/hilite_recon.cc index a45e5d345..07d1a7b7b 100644 --- a/rtengine/hilite_recon.cc +++ b/rtengine/hilite_recon.cc @@ -32,14 +32,15 @@ #include "opthelper.h" #include "rawimagesource.h" #include "rt_math.h" -//#define BENCHMARK -//#include "StopWatch.h" +#define BENCHMARK +#include "StopWatch.h" #include "guidedfilter.h" #include "settings.h" #include "gauss.h" #include "rescale.h" #include "iccstore.h" #include "color.h" +#include "linalgebra.h" namespace { @@ -301,7 +302,7 @@ using namespace procparams; void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue, int blur) { - // BENCHFUN + BENCHFUN double progress = 0.0; if (plistener) { @@ -1226,5 +1227,371 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue }// end of HLReconstruction + +//----------------------------------------------------------------------------- +// "inpaint opposed" algorithm taken from darktable +// +// (Very effective, very simple, very neat) +// +// Kudos to the original authors (@jenshannoschwalm from dt, in collaboration +// with @garagecoder and @Iain from gmic). +// +// Copyright and description of the original code follows +// +/* + Copyright (C) 2022 darktable developers. + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +*/ + +/* The refavg values are calculated in raw-RGB-cube3 space + We calculate all color channels in the 3x3 photosite area, this can be understaood as a "superpixel", + the "asking" location is in the centre. + As this works for bayer and xtrans sensors we don't have a fixed ratio but calculate the average + for every color channel first. + refavg for one of red, green or blue is defined as means of both other color channels (opposing). + + The basic idea / observation for the _process_opposed algorithm is, the refavg is a good estimate + for any clipped color channel in the vast majority of images, working mostly fine both for small specular + highlighted spots and large areas. + + The correction via some sort of global chrominance further helps to correct color casts. + The chrominace data are taken from the areas morphologically very close to clipped data. + Failures of the algorithm (color casts) are in most cases related to + a) very large differences between optimal white balance coefficients vs what we have as D65 in the darktable pipeline + b) complicated lightings so the gradients are not well related + c) a wrong whitepoint setting in the rawprepare module. + d) the maths might not be best +*/ +//----------------------------------------------------------------------------- + +namespace { + +constexpr int HL_BORDER = 8; +constexpr float HL_POWERF = 3.0f; + +// void border_fill_zero(int *d, int width, int height) +// { +// for (int i = 0; i < HL_BORDER * width; i++) { +// d[i] = 0; +// } +// for (int i = (height - HL_BORDER - 1) * width; i < width*height; i++) { +// d[i] = 0; +// } +// for (int row = HL_BORDER; row < height - HL_BORDER; row++) { +// int *p1 = d + row*width; +// int *p2 = d + (row+1)*width - HL_BORDER; +// for(int i = 0; i < HL_BORDER; i++) { +// p1[i] = p2[i] = 0; +// } +// } +// } + + +int test_dilate(const int *img, int i, int w1) +{ + int retval = 0; + retval = img[i-w1-1] | img[i-w1] | img[i-w1+1] | + img[i-1] | img[i] | img[i+1] | + img[i+w1-1] | img[i+w1] | img[i+w1+1]; + if (retval) { + return retval; + } + + const size_t w2 = 2*w1; + retval = img[i-w2-1] | img[i-w2] | img[i-w2+1] | + img[i-w1-2] | img[i-w1+2] | + img[i-2] | img[i+2] | + img[i+w1-2] | img[i+w1+2] | + img[i+w2-1] | img[i+w2] | img[i+w2+1]; + if (retval) { + return retval; + } + + const size_t w3 = 3*w1; + retval = img[i-w3-2] | img[i-w3-1] | img[i-w3] | img[i-w3+1] | img[i-w3+2] | + img[i-w2-3] | img[i-w2-2] | img[i-w2+2] | img[i-w2+3] | + img[i-w1-3] | img[i-w1+3] | + img[i-3] | img[i+3] | + img[i+w1-3] | img[i+w1+3] | + img[i+w2-3] | img[i+w2-2] | img[i+w2+2] | img[i+w2+3] | + img[i+w3-2] | img[i+w3-1] | img[i+w3] | img[i+w3+1] | img[i+w3+2]; + return retval; +} + + +void dilating(const int *img, int *o, int w1, int height) +{ +#ifdef _OPENMP +# pragma omp parallel for +#endif + for (int row = HL_BORDER; row < height - HL_BORDER; row++) { + for (int col = HL_BORDER, i = row*w1 + col; col < w1 - HL_BORDER; col++, i++) { + o[i] = test_dilate(img, i, w1); + } + } +} + +} // namespace + +void RawImageSource::highlight_recovery_opposed(float scale_mul[3], const ColorTemp &wb, float gainth) +{ + BENCHFUN + + if (settings->verbose) { + std::cout << "Applying Highlight Recovery: Inpaint opposed" << std::endl; + } + + if (plistener) { + plistener->setProgressStr("PROGRESSBAR_HLREC"); + plistener->setProgress(0); + } + + double rr, gg, bb; + wb.getMultipliers(rr, gg, bb); + wbMul2Camera(rr, gg, bb); + + float gain = 1.2f * gainth; + + float clipval = 0.987f / gain; + const float scalecoeffs[3] = { + scale_mul[0] * float(rr) / 65535.f, + scale_mul[1] * float(gg) / 65535.f, + scale_mul[2] * float(bb) / 65535.f, + }; + const float clips[3] = { + clipval * float(rr), + clipval * float(gg), + clipval * float(bb) + }; + const float clipdark[3] = { + 0.03f * clips[0], + 0.125f * clips[1], + 0.03f * clips[2] + }; + + bool anyclipped = false; + float **chan[3] = { red, green, blue }; + + const float clipscale[3] = { + clips[0] / scalecoeffs[0], + clips[1] / scalecoeffs[1], + clips[2] / scalecoeffs[2] + }; + + int x1 = W, y1 = H, x2 = 0, y2 = 0; + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + for (int c = 0; c < 3; ++c) { + if (chan[c][y][x] >= clipscale[c]) { + anyclipped = true; + x1 = std::min(x, x1); + x2 = std::max(x, x2); + y1 = std::min(y, y1); + y2 = std::max(y, y2); + } + } + } + } + + if (!anyclipped) { + if (plistener) { + plistener->setProgress(1.0); + } + return; + } + + x1 = std::max(x1-1, 0); + x2 = std::min(x2+1, W-1); + y1 = std::max(y1-1, 0); + y2 = std::min(y2+1, H-1); + + const int cW = x2 - x1 + 1; + const int cH = y2 - y1 + 1; + +#ifdef _OPENMP +# pragma omp parallel for +#endif + for (int y = 0; y < cH; ++y) { + const int yy = y + y1; + for (int x = 0; x < cW; ++x) { + const int xx = x + x1; + for (int c = 0; c < 3; ++c) { + chan[c][yy][xx] *= scalecoeffs[c]; + } + } + } + + if (plistener) { + plistener->setProgress(0.1); + } + + multi_array2D tmp(cW, cH); + + const int pwidth = cW + 2 * HL_BORDER; + const int pheight = cH + 2 * HL_BORDER; + const int p_size = pwidth * pheight; + AlignedBuffer mask_vec(4 * p_size); + int *mask_buffer = mask_vec.data; + + const auto mask_val = + [&](int c, int y, int x) -> int & + { + return mask_buffer[c * p_size + (HL_BORDER + y) * pwidth + x + HL_BORDER]; + }; + + const auto set_refavg = + [&](int y, int x) -> bool + { + const int yy = y + y1; + const int xx = x + x1; + bool found = false; + for (int c = 0; c < 3 && !found; ++c) { + if (chan[c][yy][xx] >= clips[c]) { + found = true; + } + } + if (!found) { + return false; + } + + float mean[3] = { 0.0f, 0.0f, 0.0f }; + for (int dy = -1; dy < 2; dy++) { + for (int dx = -1; dx < 2; dx++) { + for (int c = 0; c < 3; ++c) { + mean[c] += std::max(0.0f, chan[c][yy+dy][xx+dx]); + } + } + } + for (int c = 0; c < 3; ++c) { + mean[c] = pow_F(mean[c] / 9.0f, 1.0f / HL_POWERF); + } + + const float croot_refavg[3] = { + 0.5f * (mean[1] + mean[2]), + 0.5f * (mean[0] + mean[2]), + 0.5f * (mean[0] + mean[1]) + }; + + for (int c = 0; c < 3; ++c) { + if (chan[c][yy][xx] >= clips[c]) { + tmp[c][y][x] = pow_F(croot_refavg[c], HL_POWERF); + mask_val(c, y, x) = 1; + } + } + return true; + }; + +#ifdef _OPENMP +# pragma omp parallel for +#endif + for (int y = 0; y < cH; ++y) { + const int yy = y + y1; + for (int x = 0; x < cW; ++x) { + const int xx = x + x1; + for (int c = 0; c < 3; ++c) { + tmp[c][y][x] = std::max(0.f, chan[c][yy][xx]); + } + + if ((x > 0) && (x < cW - 1) && (y > 0) && (y < cH - 1)) { + set_refavg(y, x); + } + } + } + + if (plistener) { + plistener->setProgress(0.3); + } + + for (size_t i = 0; i < 3; i++) { + int *mask = mask_buffer + i * p_size; + int *tmp = mask_buffer + 3 * p_size; + //border_fill_zero(mask, pwidth, pheight); + dilating(mask, tmp, pwidth, pheight); + memcpy(mask, tmp, p_size * sizeof(int)); + } + + float cr_sum[3] = { 0.f, 0.f, 0.f }; + int cr_cnt[3] = { 0, 0, 0 }; + +#ifdef _OPENMP +# pragma omp parallel for reduction(+ : cr_sum, cr_cnt) +#endif + for (int y = 1; y < cH-1; ++y) { + const int yy = y + y1; + for (int x = 1; x < cW-1; ++x) { + const int xx = x + x1; + for (int c = 0; c < 3; ++c) { + const float inval = std::max(0.0f, chan[c][yy][xx]); + if (mask_val(c, y, x) && (inval > clipdark[c]) && (inval < clips[c])) { + cr_sum[c] += inval - tmp[c][y][x]; + ++cr_cnt[c]; + } + } + } + } + + if (plistener) { + plistener->setProgress(0.6); + } + + float chrominance[3] = { + cr_sum[0] / std::max(1.f, float(cr_cnt[0])), + cr_sum[1] / std::max(1.f, float(cr_cnt[1])), + cr_sum[2] / std::max(1.f, float(cr_cnt[2])) + }; + +#ifdef _OPENMP +# pragma omp parallel for +#endif + for (int y = 0; y < cH; ++y) { + const int yy = y + y1; + for (int x = 0; x < cW; ++x) { + const int xx = x + x1; + for (int c = 0; c < 3; ++c) { + const float inval = std::max(0.0f, chan[c][yy][xx]); + if (inval >= clips[c]) { + chan[c][yy][xx] = std::max(inval, tmp[c][y][x] + chrominance[c]); + } + } + } + } + + if (plistener) { + plistener->setProgress(0.9); + } + +#ifdef _OPENMP +# pragma omp parallel for +#endif + for (int y = 0; y < cH; ++y) { + const int yy = y + y1; + for (int x = 0; x < cW; ++x) { + const int xx = x + x1; + for (int c = 0; c < 3; ++c) { + chan[c][yy][xx] /= scalecoeffs[c]; + } + } + } + + if (plistener) { + plistener->setProgress(1.0); + } +} + + + + } diff --git a/rtengine/iimage.h b/rtengine/iimage.h index 2c75a0d59..a544b454a 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -111,7 +111,7 @@ public: { rm = gm = bm = 1.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) + 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) { rm = gm = bm = 1.0; } diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index a8ea8f851..d6d22c269 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -109,7 +109,7 @@ public: virtual void getWBMults (const ColorTemp &ctemp, const procparams::RAWParams &raw, std::array& scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const = 0; // use right after demosaicing image, add coarse transformation and put the result in the provided Imagefloat* - virtual void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hlp, const procparams::RAWParams &raw) = 0; + virtual void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hlp, const procparams::RAWParams &raw, int opposed) = 0; virtual eSensorType getSensorType () const = 0; virtual bool isMono () const = 0; // true is ready to provide the AutoWB, i.e. when the image has been demosaiced for RawImageSource @@ -117,10 +117,10 @@ public: virtual void convertColorSpace (Imagefloat* image, const procparams::ColorManagementParams &cmp, const ColorTemp &wb) = 0; // DIRTY HACK: this method is derived in rawimagesource and strimagesource, but (...,RAWParams raw) will be used ONLY for raw images 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) = 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 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) = 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 double getDefGain () const @@ -195,6 +195,9 @@ public: } virtual void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) = 0; virtual void captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold, double &radius) = 0; + virtual void wbMul2Camera(double &rm, double &gm, double &bm) = 0; + virtual void wbCamera2Mul(double &rm, double &gm, double &bm) = 0; + }; } diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index ec5ffc8ef..cc2d75b3d 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1,6 +1,6 @@ /* * This file is part of RawTherapee. - * + * * Copyright (c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify @@ -409,11 +409,13 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if (imageTypeListener) { imageTypeListener->imageTypeChanged(imgsrc->isRAW(), imgsrc->getSensorType() == ST_BAYER, imgsrc->getSensorType() == ST_FUJI_XTRANS, imgsrc->isMono(), imgsrc->isGainMapSupported()); } - + bool iscolor = (params->toneCurve.method == "Color");// || params->toneCurve.method == "Coloropp"); if ((todo & M_RAW) || (!highDetailRawComputed && highDetailNeeded) - || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified()) - || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) { + // || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified()) + // || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) { + || (params->toneCurve.hrenabled && !iscolor && imgsrc->isRGBSourceModified()) + || (!params->toneCurve.hrenabled && iscolor && imgsrc->isRGBSourceModified())) { if (settings->verbose) { if (imgsrc->getSensorType() == ST_BAYER) { @@ -466,8 +468,10 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) if ((todo & M_RAW) || (!highDetailRawComputed && highDetailNeeded) - || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified()) - || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) { + // || (params->toneCurve.hrenabled && params->toneCurve.method != "Color" && imgsrc->isRGBSourceModified()) + // || (!params->toneCurve.hrenabled && params->toneCurve.method == "Color" && imgsrc->isRGBSourceModified())) { + || (params->toneCurve.hrenabled && !iscolor && imgsrc->isRGBSourceModified()) + || (!params->toneCurve.hrenabled && iscolor && imgsrc->isRGBSourceModified())) { if (highDetailNeeded) { highDetailRawComputed = true; } else { @@ -510,8 +514,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } if (todo & (M_INIT | M_LINDENOISE | M_HDR)) { MyMutex::MyLock initLock(minit); // Also used in crop window - - imgsrc->HLRecovery_Global(params->toneCurve); // this handles Color HLRecovery + // imgsrc->HLRecovery_Global(params->toneCurve); // this handles Color HLRecovery if (settings->verbose) { @@ -538,7 +541,7 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) printf("tempref=%f greref=%f\n", tempref, greenref); } - imgsrc->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc, studgood, 0, 0, fh, fw, 0, 0, fh, fw, rm, gm, bm, params->wb, params->icm, params->raw); + 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 (params->wb.method == "autitcgreen") { params->wb.temperature = tempitc; @@ -617,8 +620,8 @@ 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); - - imgsrc->getImage(currWB, tr, orig_prev, pp, params->toneCurve, params->raw); + 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()) { spotsDone = true; @@ -2462,7 +2465,7 @@ bool ImProcCoordinator::getAutoWB(double& temp, double& green, double equal, dou double greenitc = 1.; float studgood = 1000.f; double tempref, greenref; - imgsrc->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc, studgood, 0, 0, fh, fw, 0, 0, fh, fw, rm, gm, bm, params->wb, params->icm, params->raw); + 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); @@ -2649,7 +2652,7 @@ void ImProcCoordinator::saveInputICCReference(const Glib::ustring& fname, bool a currWB = ColorTemp(); // = no white balance } - imgsrc->getImage(currWB, tr, im, pp, ppar.toneCurve, ppar.raw); + imgsrc->getImage(currWB, tr, im, pp, ppar.toneCurve, ppar.raw, 0); ImProcFunctions ipf(&ppar, true); if (ipf.needsTransform(fW, fH, imgsrc->getRotateDegree(), imgsrc->getMetaData())) { diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index bdc1b6db1..811e941e4 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -2128,7 +2128,7 @@ void ImProcFunctions::getAutoLogloc(int sp, ImageSource *imgsrc, float *sourceg, Imagefloat img(int(fw / SCALE + 0.5), int(fh / SCALE + 0.5)); const ProcParams neutral; - imgsrc->getImage(imgsrc->getWB(), TR_NONE, &img, pp, params->toneCurve, neutral.raw); + imgsrc->getImage(imgsrc->getWB(), TR_NONE, &img, pp, params->toneCurve, neutral.raw, 0); imgsrc->convertColorSpace(&img, params->icm, imgsrc->getWB()); float minVal = RT_INFINITY; float maxVal = -RT_INFINITY; diff --git a/rtengine/linalgebra.h b/rtengine/linalgebra.h new file mode 100644 index 000000000..32e44e147 --- /dev/null +++ b/rtengine/linalgebra.h @@ -0,0 +1,275 @@ +/* -*- C++ -*- + * This file is part of ART + * + * Copyright (c) 2022 Alberto Griggio + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +#pragma once +#include + +namespace rtengine { + +template +class Vec3 { +public: + Vec3() { data_[0] = data_[1] = data_[2] = T(); } + Vec3(T a, T b, T c) { data_[0] = a; data_[1] = b; data_[2] = c; } + + template + Vec3(T2 const a[3]) { data_[0] = a[0]; data_[1] = a[1]; data_[2] = a[2]; } + + Vec3 &operator=(const Vec3 &a) = default; + + template + Vec3 &operator=(T2 const a[3]) + { + data_[0] = a[0]; data_[1] = a[1]; data_[2] = a[2]; + return *this; + } + + T operator[](int i) const { return data_[i]; } + T &operator[](int i) { return data_[i]; } + operator const T *() const { return data_; } + operator T *() { return data_; } + +private: + T data_[3]; +}; + +typedef Vec3 Vec3f; + + +template +class Mat33 { +public: + Mat33() + { + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + data_[i][j] = T(); + } + } + } + + Mat33(T a00, T a01, T a02, + T a10, T a11, T a12, + T a20, T a21, T a22) + { + data_[0][0] = a00; data_[0][1] = a01; data_[0][2] = a02; + data_[1][0] = a10; data_[1][1] = a11; data_[1][2] = a12; + data_[2][0] = a20; data_[2][1] = a21; data_[2][2] = a22; + } + + template + Mat33(const T2 m[3][3]) + { + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + data_[i][j] = m[i][j]; + } + } + } + + Mat33 &operator=(const Mat33 &m) = default; + + template + Mat33 &operator=(const T2 m[3][3]) + { + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + data_[i][j] = m[i][j]; + } + } + return *this; + } + + T const *operator[](int i) const { return data_[i]; } + T *operator[](int i) { return data_[i]; } + typedef const T(*Data)[3]; + operator Data() const { return data_; } + +private: + T data_[3][3]; +}; + + +typedef Mat33 Mat33f; + + +template +Mat33 identity() +{ + return Mat33(1, 0, 0, 0, 1, 0, 0, 0, 1); +} + + +template +Mat33 diagonal(T a, T b, T c) +{ + return Mat33(a, 0, 0, 0, b, 0, 0, 0, c); +} + + +template +Mat33 transpose(T const m[3][3]) +{ + return Mat33(m[0][0], m[1][0], m[2][0], + m[0][1], m[1][1], m[2][1], + m[0][2], m[1][2], m[2][2]); +} + +template +Mat33 transpose(const Mat33 &m) +{ + return transpose(static_cast::Data>(m)); +} + + +template +bool inverse(T const m[3][3], Mat33 &out) +{ + const T res00 = m[1][1] * m[2][2] - m[2][1] * m[1][2]; + const T res10 = m[2][0] * m[1][2] - m[1][0] * m[2][2]; + const T res20 = m[1][0] * m[2][1] - m[2][0] * m[1][1]; + + const T det = m[0][0] * res00 + m[0][1] * res10 + m[0][2] * res20; + + if (std::abs(det) >= 1.0e-10) { + out[0][0] = res00 / det; + out[0][1] = (m[2][1] * m[0][2] - m[0][1] * m[2][2]) / det; + out[0][2] = (m[0][1] * m[1][2] - m[1][1] * m[0][2]) / det; + out[1][0] = res10 / det; + out[1][1] = (m[0][0] * m[2][2] - m[2][0] * m[0][2]) / det; + out[1][2] = (m[1][0] * m[0][2] - m[0][0] * m[1][2]) / det; + out[2][0] = res20 / det; + out[2][1] = (m[2][0] * m[0][1] - m[0][0] * m[2][1]) / det; + out[2][2] = (m[0][0] * m[1][1] - m[1][0] * m[0][1]) / det; + return true; + } else { + return false; + } +} + +template +Mat33 inverse(const Mat33 &m) +{ + Mat33 res; + inverse(static_cast::Data>(m), res); + return res; +} + +template +Mat33 inverse(T const m[3][3]) +{ + Mat33 res; + inverse(m, res); + return res; +} + +template +bool inverse(const Mat33 &m, Mat33 &out) +{ + return inverse(static_cast::Data>(m), out); +} + + +template +Mat33 dot_product(T const a[3][3], T const b[3][3]) +{ + Mat33 res; + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + res[i][j] = 0; + + for (int k = 0; k < 3; ++k) { + res[i][j] += a[i][k] * b[k][j]; + } + } + } + + return res; +} + +template +Mat33 dot_product(const Mat33 &a, T const b[3][3]) +{ + return dot_product(static_cast::Data>(a), b); +} + +template +Mat33 dot_product(T const a[3][3], const Mat33 &b) +{ + return dot_product(a, static_cast::Data>(b)); +} + +template +Mat33 dot_product(const Mat33 &a, const Mat33 &b) +{ + return dot_product(static_cast::Data>(a), static_cast::Data>(b)); +} + + +template +Vec3 dot_product(T const a[3][3], T const b[3]) +{ + Vec3 res; + + for (int i = 0; i < 3; ++i) { + res[i] = 0; + for (int k = 0; k < 3; ++k) { + res[i] += a[i][k] * b[k]; + } + } + + return res; +} + + +template +Vec3 dot_product(const Mat33 &a, T const b[3]) +{ + return dot_product(static_cast::Data>(a), b); +} + +template +Vec3 dot_product(T const a[3][3], const Vec3 &b) +{ + return dot_product(a, static_cast(b)); +} + +template +Vec3 dot_product(const Mat33 &a, const Vec3 &b) +{ + return dot_product(static_cast::Data>(a), static_cast(b)); +} + + +template +Mat33 operator*(const Mat33 &m, T v) +{ + return Mat33(m[0][0] * v, m[0][1] * v, m[0][2] * v, + m[1][0] * v, m[1][1] * v, m[1][2] * v, + m[2][0] * v, m[2][1] * v, m[2][2] * v); +} + +template +Vec3 operator*(const Vec3 &a, T v) +{ + return Vec3(a[0] * v, a[1] * v, a[2] * v); +} + +} // namespace rtengine diff --git a/rtengine/perspectivecorrection.cc b/rtengine/perspectivecorrection.cc index 7a56ef5a8..f4428faf2 100644 --- a/rtengine/perspectivecorrection.cc +++ b/rtengine/perspectivecorrection.cc @@ -297,7 +297,7 @@ PerspectiveCorrection::Params PerspectiveCorrection::autocompute(ImageSource *sr neutral.raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST); neutral.raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST); neutral.icm.outputProfile = ColorManagementParams::NoICMString; - src->getImage(src->getWB(), tr, img.get(), pp, neutral.toneCurve, neutral.raw); + src->getImage(src->getWB(), tr, img.get(), pp, neutral.toneCurve, neutral.raw, 0); src->convertColorSpace(img.get(), pparams->icm, src->getWB()); neutral.commonTrans.autofill = false; // Ensures crop factor is correct. diff --git a/rtengine/previewimage.cc b/rtengine/previewimage.cc index de1603f1c..1afe72c92 100644 --- a/rtengine/previewimage.cc +++ b/rtengine/previewimage.cc @@ -121,7 +121,7 @@ PreviewImage::PreviewImage (const Glib::ustring &fname, const Glib::ustring &ext double contrastThresholdDummy = 0.0; rawImage.demosaic(params.raw, false, contrastThresholdDummy); Imagefloat image(fw, fh); - rawImage.getImage (wb, TR_NONE, &image, pp, params.toneCurve, params.raw); + rawImage.getImage (wb, TR_NONE, &image, pp, params.toneCurve, params.raw, 0); rtengine::Image8 output(fw, fh); rawImage.convertColorSpace(&image, params.icm, wb); #ifdef _OPENMP diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index e6bdc9619..9323bd9e7 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -373,7 +373,7 @@ ToneCurveParams::ToneCurveParams() : autoexp(false), clip(0.02), hrenabled(false), - method("Blend"), + method("Coloropp"), expcomp(0), curve{ DCT_Linear @@ -390,6 +390,7 @@ ToneCurveParams::ToneCurveParams() : shcompr(50), hlcompr(0), hlbl(0), + hlth(1.0), hlcomprthresh(0), histmatching(false), fromHistMatching(false), @@ -416,6 +417,7 @@ bool ToneCurveParams::isPanningRelatedChange(const ToneCurveParams& other) const && shcompr == other.shcompr && hlcompr == other.hlcompr && hlbl == other.hlbl + && hlth == other.hlth && hlcomprthresh == other.hlcomprthresh && histmatching == other.histmatching && clampOOG == other.clampOOG); @@ -440,6 +442,7 @@ bool ToneCurveParams::operator ==(const ToneCurveParams& other) const && shcompr == other.shcompr && hlcompr == other.hlcompr && hlbl == other.hlbl + && hlth == other.hlth && hlcomprthresh == other.hlcomprthresh && histmatching == other.histmatching && fromHistMatching == other.fromHistMatching @@ -5912,6 +5915,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->toneCurve.hrenabled, "HLRecovery", "Enabled", toneCurve.hrenabled, keyFile); saveToKeyfile(!pedited || pedited->toneCurve.method, "HLRecovery", "Method", toneCurve.method, keyFile); saveToKeyfile(!pedited || pedited->toneCurve.hlbl, "HLRecovery", "Hlbl", toneCurve.hlbl, keyFile); + saveToKeyfile(!pedited || pedited->toneCurve.hlth, "HLRecovery", "Hlth", toneCurve.hlth, keyFile); const std::map tc_mapping = { {ToneCurveMode::STD, "Standard"}, @@ -7697,6 +7701,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "HLRecovery", "Enabled", pedited, toneCurve.hrenabled, pedited->toneCurve.hrenabled); assignFromKeyfile(keyFile, "HLRecovery", "Method", pedited, toneCurve.method, pedited->toneCurve.method); assignFromKeyfile(keyFile, "HLRecovery", "Hlbl", pedited, toneCurve.hlbl, pedited->toneCurve.hlbl); + assignFromKeyfile(keyFile, "HLRecovery", "Hlth", pedited, toneCurve.hlth, pedited->toneCurve.hlth); } if (keyFile.has_group("Channel Mixer")) { diff --git a/rtengine/procparams.h b/rtengine/procparams.h index e86272b0a..33d95a619 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -299,6 +299,7 @@ struct ToneCurveParams { int shcompr; int hlcompr; // Highlight Recovery's compression int hlbl; // Highlight Recovery's compression + double hlth; // Highlight Recovery's threshold int hlcomprthresh; // Highlight Recovery's threshold bool histmatching; // histogram matching bool fromHistMatching; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 550c59e9c..7ff9c4d0f 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -468,6 +468,7 @@ RawImageSource::RawImageSource () { embProfile = nullptr; rgbSourceModified = false; + for (int i = 0; i < 4; ++i) { psRedBrightness[i] = psGreenBrightness[i] = psBlueBrightness[i] = 1.f; } @@ -639,6 +640,57 @@ float calculate_scale_mul(float scale_mul[4], const float pre_mul_[4], const flo return gain; } +void RawImageSource::wbMul2Camera(double &rm, double &gm, double &bm) +{ + double r = rm; + double g = gm; + double b = bm; + + auto imatrices = getImageMatrices(); + + if (imatrices) { + double rr = imatrices->cam_rgb[0][0] * r + imatrices->cam_rgb[0][1] * g + imatrices->cam_rgb[0][2] * b; + double gg = imatrices->cam_rgb[1][0] * r + imatrices->cam_rgb[1][1] * g + imatrices->cam_rgb[1][2] * b; + double bb = imatrices->cam_rgb[2][0] * r + imatrices->cam_rgb[2][1] * g + imatrices->cam_rgb[2][2] * b; + r = rr; + g = gg; + b = bb; + } + + rm = ri->get_pre_mul(0) / r; + gm = ri->get_pre_mul(1) / g; + bm = ri->get_pre_mul(2) / b; + + rm /= gm; + bm /= gm; + gm = 1.0; +} + + +void RawImageSource::wbCamera2Mul(double &rm, double &gm, double &bm) +{ + auto imatrices = getImageMatrices(); + + double r = ri->get_pre_mul(0) / rm; + double g = ri->get_pre_mul(1) / gm; + double b = ri->get_pre_mul(2) / bm; + + if (imatrices) { + double rr = imatrices->rgb_cam[0][0] * r + imatrices->rgb_cam[0][1] * g + imatrices->rgb_cam[0][2] * b; + double gg = imatrices->rgb_cam[1][0] * r + imatrices->rgb_cam[1][1] * g + imatrices->rgb_cam[1][2] * b; + double bb = imatrices->rgb_cam[2][0] * r + imatrices->rgb_cam[2][1] * g + imatrices->rgb_cam[2][2] * b; + r = rr; + g = gg; + b = bb; + } + + rm = r / g; + bm = b / g; + gm = 1.0; +} + + + void RawImageSource::getWBMults (const ColorTemp &ctemp, const RAWParams &raw, std::array& out_scale_mul, float &autoGainComp, float &rm, float &gm, float &bm) const { @@ -689,10 +741,9 @@ void RawImageSource::getWBMults (const ColorTemp &ctemp, const RAWParams &raw, s autoGainComp = camInitialGain / initialGain; } -void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw) -{ +void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw, int opposed) +{// added int opposed to force getimage to use inpaint-opposed if enable, only once MyMutex::MyLock lock(getImageMutex); - tran = defTransform (tran); // compute channel multipliers @@ -705,7 +756,9 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima gm = ri->get_pre_mul(1); bm = ri->get_pre_mul(2); } else { - ctemp.getMultipliers (r, g, b); + // ctemp.getMultipliers (r, g, b); + r = g = b = 1; + wbCamera2Mul(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; @@ -790,22 +843,52 @@ void RawImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* ima int maxx = this->W, maxy = this->H, skip = pp.getSkip(); - // raw clip levels after white balance + 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 (!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); + } + rgbSourceModified = true; + } + } + + // now apply the wb coefficients + if (ctemp.getTemp() >= 0) { + double r, g, b; + ctemp.getMultipliers(r, g, b); + wbMul2Camera(r, g, b); + + rm *= r; + gm *= g; + bm *= b; + } hlmax[0] = clmax[0] * rm; hlmax[1] = clmax[1] * gm; hlmax[2] = clmax[2] * bm; - const bool doClip = (chmax[0] >= clmax[0] || chmax[1] >= clmax[1] || chmax[2] >= clmax[2]) && !hrp.hrenabled && hrp.clampOOG; + const float expcomp = std::pow(2, ri->getBaselineExposure()); + rm *= expcomp; + gm *= expcomp; + bm *= expcomp; float area = skip * skip; rm /= area; gm /= area; bm /= area; - bool doHr = (hrp.hrenabled && hrp.method != "Color"); - const float expcomp = std::pow(2, ri->getBaselineExposure()); - rm *= expcomp; - gm *= expcomp; - bm *= expcomp; + #ifdef _OPENMP #pragma omp parallel if(!d1x) // omp disabled for D1x to avoid race conditions (see Issue 1088 http://code.google.com/p/rawtherapee/issues/detail?id=1088) @@ -1697,7 +1780,6 @@ void RawImageSource::demosaic(const RAWParams &raw, bool autoContrast, double &c rgbSourceModified = false; - if (cache) { if (!redCache) { redCache = new array2D(W, H); @@ -2396,7 +2478,6 @@ void RawImageSource::retinex(const ColorManagementParams& cmp, const RetinexPara } rgbSourceModified = false; // tricky handling for Color propagation - t5.set(); if (settings->verbose) { @@ -2442,16 +2523,17 @@ void RawImageSource::flush() void RawImageSource::HLRecovery_Global(const ToneCurveParams &hrp) { - if (hrp.hrenabled && hrp.method == "Color") { - if (!rgbSourceModified) { - if (settings->verbose) { - printf ("Applying Highlight Recovery: Color propagation...\n"); - } - - HLRecovery_inpaint (red, green, blue, hrp.hlbl); - rgbSourceModified = true; - } - } + // if (hrp.hrenabled && hrp.method == "Color") { + // if (!rgbSourceModified) { + // if (settings->verbose) { + // printf ("Applying Highlight Recovery: Color propagation...\n"); + // } +// + // HLRecovery_inpaint (red, green, blue, hrp.hlbl); +// +// rgbSourceModified = true; + // } +// } } @@ -3460,6 +3542,7 @@ bool RawImageSource::findInputProfile(Glib::ustring inProfile, cmsHPROFILE embed // very effective to reduce (or remove) the magenta, but with levels of grey ! void RawImageSource::HLRecovery_blend(float* rin, float* gin, float* bin, int width, float maxval, float* hlmax) { + constexpr int ColorCount = 3; // Transform matrixes rgb>lab and back @@ -3684,6 +3767,7 @@ void RawImageSource::HLRecovery_CIELab (float* rin, float* gin, float* bin, floa void RawImageSource::hlRecovery (const std::string &method, float* red, float* green, float* blue, int width, float* hlmax) { +// BENCHFUN if (method == "Luminance") { HLRecovery_Luminance (red, green, blue, red, green, blue, width, 65535.0); @@ -3953,12 +4037,12 @@ void RawImageSource::getRowStartEnd (int x, int &start, int &end) } } - -static void histoxyY(int bfhitc, int bfwitc, const array2D & xc, const array2D & yc, const array2D & Yc, LUTf &xxx, LUTf &yyy, LUTf &YYY, LUTu &histxy) +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 190 colors - //this "choice" are guided by generally colors who are in nature skin, sky, etc. in those cases "steps" are small + // calculate histogram x y in a range of 236 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 + // purp enable or not purple color in xyY - approximation... #ifdef _OPENMP #pragma omp parallel #endif @@ -3971,434 +4055,528 @@ static void histoxyY(int bfhitc, int bfwitc, const array2D & xc, const ar yyythr.clear(); LUTf YYYthr(YYY.getSize()); YYYthr.clear(); + // bool purp = false; #ifdef _OPENMP #pragma omp for schedule(dynamic, 4) nowait #endif - for (int y = 0; y < bfhitc ; y++) { + + 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) { + } else if (yc[y][x] < 0.25f) { nh = 1; - //blue - } else if (yc[y][x] < 0.4f) { + } else if (yc[y][x] < 0.3f) { nh = 2; - + //blue + } else if (yc[y][x] < 0.35f) { + nh = 3; + } else if (yc[y][x] < 0.4f) { + nh = 4; + } else if (yc[y][x] < 0.45f) { + nh = 5; } else if (yc[y][x] < 0.5f) { //blue green - nh = 3; + nh = 6; + } else if (yc[y][x] < 0.55f) { + nh = 7; } else if (yc[y][x] < 0.6f) { - nh = 4; + nh = 8; + } else if (yc[y][x] < 0.7f) { + nh = 9; } else if (yc[y][x] < 0.82f) { //green - nh = 5; + nh = 10; } } 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 = 12; + } else if (yc[y][x] < 0.3f) { nh = 13; - } else if (yc[y][x] < 0.29f) { + } else if (yc[y][x] < 0.35f) { 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; + nh = 15; } else if (yc[y][x] < 0.45f) { - nh = 18; + nh = 16; } else if (yc[y][x] < 0.5f) { - nh = 19; + nh = 17; + } else if (yc[y][x] < 0.55f) { + nh = 18; } else if (yc[y][x] < 0.6f) { + nh = 19; + } else if (yc[y][x] < 0.67f) { 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 + } else if (xc[y][x] < 0.28f && yc[y][x] > 0.1f) {//blue sky and other if (yc[y][x] < 0.2f) { nh = 22; - } else if (yc[y][x] < 0.24f) { + } else if (yc[y][x] < 0.23f) { nh = 23; - } else if (yc[y][x] < 0.29f) { + } else if (yc[y][x] < 0.25f) { nh = 24; - } else if (yc[y][x] < 0.32f) { + } else if (yc[y][x] < 0.27f) { nh = 25; - } else if (yc[y][x] < 0.36f) { + } else if (yc[y][x] < 0.29f) { nh = 26; - } else if (yc[y][x] < 0.4f) { + } else if (yc[y][x] < 0.31f) { nh = 27; - } else if (yc[y][x] < 0.5f) { + } else if (yc[y][x] < 0.33f) { nh = 28; - } else if (yc[y][x] < 0.7f) { + } else if (yc[y][x] < 0.35f) { nh = 29; + } else if (yc[y][x] < 0.37f) { + nh = 30; + } else if (yc[y][x] < 0.4f) { + nh = 31; + } else if (yc[y][x] < 0.45f) { + nh = 32; + } else if (yc[y][x] < 0.5f) { + nh = 33; + } else if (yc[y][x] < 0.55f) { + nh = 34; + } else if (yc[y][x] < 0.6f) { + nh = 35; + } else if (yc[y][x] < 0.67f) { + nh = 36; + } else if (yc[y][x] < 0.75f) { + nh = 37; + } + } else if (xc[y][x] < 0.31f && yc[y][x] > 0.1f) {//near neutral others + if (yc[y][x] < 0.2f) { + nh = 38; + } else if (yc[y][x] < 0.22f) { + nh = 39; + } else if (yc[y][x] < 0.24f) { + nh = 40; + } else if (yc[y][x] < 0.26f) { + nh = 41; + } else if (yc[y][x] < 0.29f) { + nh = 42; + } else if (yc[y][x] < 0.32f) { + nh = 43; + } else if (yc[y][x] < 0.36f) { + nh = 44; + } else if (yc[y][x] < 0.4f) { + nh = 45; + } else if (yc[y][x] < 0.45f) { + nh = 46; + } else if (yc[y][x] < 0.5f) { + nh = 47; + } else if (yc[y][x] < 0.6f) { + nh = 48; + } else if (yc[y][x] < 0.7f) { + nh = 49; } } else if (xc[y][x] < 0.325f && yc[y][x] > 0.1f) {//neutral 34 if (yc[y][x] < 0.2f) { - nh = 30; + nh = 50; + } else if (yc[y][x] < 0.22f) { + nh = 51; } else if (yc[y][x] < 0.24f) { - nh = 31; + nh = 52; } else if (yc[y][x] < 0.29f) { - nh = 32; + nh = 53; } else if (yc[y][x] < 0.32f) { - nh = 33; + nh = 54; } else if (yc[y][x] < 0.33f) { - nh = 34; + nh = 55; } else if (yc[y][x] < 0.335f) { - nh = 35; + nh = 56; } else if (yc[y][x] < 0.34f) { - nh = 36; + nh = 57; } else if (yc[y][x] < 0.35f) { - nh = 37; + nh = 58; } else if (yc[y][x] < 0.37f) { - nh = 38; + nh = 59; } else if (yc[y][x] < 0.4f) { - nh = 39; + nh = 60; } else if (yc[y][x] < 0.45f) { - nh = 40; + nh = 61; } else if (yc[y][x] < 0.5f) { - nh = 41; + nh = 62; } else if (yc[y][x] < 0.55f) { - nh = 42; + nh = 63; + } else if (yc[y][x] < 0.6f) { + nh = 64; + } else if (yc[y][x] < 0.65f) { + nh = 65; } else if (yc[y][x] < 0.7f) { - nh = 43; + nh = 66; } } else if (xc[y][x] < 0.335f && yc[y][x] > 0.1f) {//neutral if (yc[y][x] < 0.2f) { - nh = 44; + nh = 67; + } else if (yc[y][x] < 0.22f) { + nh = 68; } else if (yc[y][x] < 0.24f) { - nh = 45; + nh = 69; + } else if (yc[y][x] < 0.27f) { + nh = 70; } else if (yc[y][x] < 0.29f) { - nh = 46; + nh = 71; } else if (yc[y][x] < 0.32f) { - nh = 47; + nh = 72; } else if (yc[y][x] < 0.33f) { - nh = 48; + nh = 73; } else if (yc[y][x] < 0.335f) { - nh = 49; + nh = 74; } else if (yc[y][x] < 0.34f) { - nh = 50; + nh = 75; } else if (yc[y][x] < 0.345f) { - nh = 51; + nh = 76; } else if (yc[y][x] < 0.35f) { - nh = 52; + nh = 77; } else if (yc[y][x] < 0.355f) { - nh = 53; + nh = 78; } else if (yc[y][x] < 0.36f) { - nh = 54; + nh = 79; } else if (yc[y][x] < 0.37f) { - nh = 55; + nh = 80; } else if (yc[y][x] < 0.38f) { - nh = 56; + nh = 81; } else if (yc[y][x] < 0.4f) { - nh = 57; + nh = 82; } else if (yc[y][x] < 0.45f) { - nh = 58; + nh = 83; } else if (yc[y][x] < 0.5f) { - nh = 59; + nh = 84; } else if (yc[y][x] < 0.55f) { - nh = 60; + nh = 85; + } else if (yc[y][x] < 0.6f) { + nh = 86; + } else if (yc[y][x] < 0.65f) { + nh = 87; } else if (yc[y][x] < 0.7f) { - nh = 61; + nh = 88; } } else if (xc[y][x] < 0.340f && yc[y][x] > 0.1f) {//neutral if (yc[y][x] < 0.2f) { - nh = 62; + nh = 89; + } else if (yc[y][x] < 0.22f) { + nh = 90; } else if (yc[y][x] < 0.24f) { - nh = 63; + nh = 91; } else if (yc[y][x] < 0.29f) { - nh = 64; + nh = 92; } else if (yc[y][x] < 0.32f) { - nh = 65; + nh = 93; } else if (yc[y][x] < 0.325f) { - nh = 66; + nh = 94; } else if (yc[y][x] < 0.33f) { - nh = 67; + nh = 95; } else if (yc[y][x] < 0.335f) { - nh = 68; + nh = 96; } else if (yc[y][x] < 0.34f) { - nh = 69; + nh = 97; } else if (yc[y][x] < 0.345f) { - nh = 70; + nh = 98; } else if (yc[y][x] < 0.35f) { - nh = 71; + nh = 99; } else if (yc[y][x] < 0.355f) { - nh = 72; + nh = 100; } else if (yc[y][x] < 0.36f) { - nh = 73; + nh = 101; } else if (yc[y][x] < 0.37f) { - nh = 74; + nh = 102; } else if (yc[y][x] < 0.38f) { - nh = 75; + nh = 103; } else if (yc[y][x] < 0.4f) { - nh = 76; + nh = 104; } else if (yc[y][x] < 0.45f) { - nh = 77; + nh = 105; } else if (yc[y][x] < 0.5f) { - nh = 78; + nh = 106; } else if (yc[y][x] < 0.55f) { - nh = 79; + nh = 107; + } else if (yc[y][x] < 0.6f) { + nh = 108; + } else if (yc[y][x] < 0.65f) { + nh = 109; } else if (yc[y][x] < 0.7f) { - nh = 80; + nh = 110; } } else if (xc[y][x] < 0.345f && yc[y][x] > 0.1f) {//neutral 37 if (yc[y][x] < 0.2f) { - nh = 81; + nh = 111; + } else if (yc[y][x] < 0.22f) { + nh = 112; } else if (yc[y][x] < 0.24f) { - nh = 82; + nh = 113; + } else if (yc[y][x] < 0.26f) { + nh = 114; } else if (yc[y][x] < 0.29f) { - nh = 83; + nh = 115; } else if (yc[y][x] < 0.32f) { - nh = 84; + nh = 116; } else if (yc[y][x] < 0.33f) { - nh = 85; + nh = 117; } else if (yc[y][x] < 0.335f) { - nh = 86; + nh = 118; } else if (yc[y][x] < 0.34f) { - nh = 87; + nh = 119; } else if (yc[y][x] < 0.345f) { - nh = 88; + nh = 120; } else if (yc[y][x] < 0.35f) { - nh = 89; + nh = 121; } else if (yc[y][x] < 0.355f) { - nh = 90; + nh = 122; } else if (yc[y][x] < 0.36f) { - nh = 91; + nh = 123; } else if (yc[y][x] < 0.37f) { - nh = 92; + nh = 124; } else if (yc[y][x] < 0.38f) { - nh = 93; + nh = 125; } else if (yc[y][x] < 0.39f) { - nh = 94; + nh = 126; } else if (yc[y][x] < 0.4f) { - nh = 95; + nh = 127; } else if (yc[y][x] < 0.42f) { - nh = 96; + nh = 128; } else if (yc[y][x] < 0.45f) { - nh = 97; + nh = 129; } else if (yc[y][x] < 0.48f) { - nh = 98; + nh = 130; } else if (yc[y][x] < 0.5f) { - nh = 99; + nh = 131; } else if (yc[y][x] < 0.55f) { - nh = 100; + nh = 132; } else if (yc[y][x] < 0.65f) { - nh = 101; + nh = 133; } } else if (xc[y][x] < 0.355f && yc[y][x] > 0.1f) {//neutral 37 if (yc[y][x] < 0.2f) { - nh = 102; + nh = 134; + } else if (yc[y][x] < 0.22f) { + nh = 135; } else if (yc[y][x] < 0.24f) { - nh = 103; + nh = 136; + } else if (yc[y][x] < 0.26f) { + nh = 137; } else if (yc[y][x] < 0.29f) { - nh = 104; + nh = 138; } else if (yc[y][x] < 0.32f) { - nh = 105; + nh = 139; } else if (yc[y][x] < 0.33f) { - nh = 106; + nh = 140; } else if (yc[y][x] < 0.335f) { - nh = 107; + nh = 141; } else if (yc[y][x] < 0.34f) { - nh = 108; + nh = 142; } else if (yc[y][x] < 0.345f) { - nh = 109; + nh = 143; } else if (yc[y][x] < 0.35f) { - nh = 110; + nh = 144; } else if (yc[y][x] < 0.355f) { - nh = 111; + nh = 145; } else if (yc[y][x] < 0.36f) { - nh = 112; + nh = 146; } else if (yc[y][x] < 0.37f) { - nh = 113; + nh = 147; } else if (yc[y][x] < 0.38f) { - nh = 114; + nh = 148; } else if (yc[y][x] < 0.39f) { - nh = 115; + nh = 149; } else if (yc[y][x] < 0.4f) { - nh = 116; + nh = 150; } else if (yc[y][x] < 0.42f) { - nh = 117; + nh = 151; } else if (yc[y][x] < 0.45f) { - nh = 118; + nh = 152; } else if (yc[y][x] < 0.48f) { - nh = 119; + nh = 153; } else if (yc[y][x] < 0.5f) { - nh = 120; + nh = 154; } else if (yc[y][x] < 0.55f) { - nh = 121; + nh = 155; + } else if (yc[y][x] < 0.6f) { + nh = 156; } else if (yc[y][x] < 0.65f) { - nh = 122; + nh = 157; } } else if (xc[y][x] < 0.365f && yc[y][x] > 0.15f) { //0.4 if (yc[y][x] < 0.2f) { - nh = 123; + nh = 158; + } else if (yc[y][x] < 0.22f) { + nh = 159; } else if (yc[y][x] < 0.24f) { - nh = 124; + nh = 160; + } else if (yc[y][x] < 0.26f) { + nh = 161; } else if (yc[y][x] < 0.29f) { - nh = 125; + nh = 162; } else if (yc[y][x] < 0.32f) { - nh = 126; + nh = 163; } else if (yc[y][x] < 0.33f) { - nh = 127; + nh = 164; } else if (yc[y][x] < 0.34f) { - nh = 128; + nh = 165; } else if (yc[y][x] < 0.35f) { - nh = 129; + nh = 166; } else if (yc[y][x] < 0.36f) { - nh = 130; + nh = 167; } else if (yc[y][x] < 0.37f) { - nh = 131; + nh = 168; } else if (yc[y][x] < 0.38f) { - nh = 132; + nh = 169; } else if (yc[y][x] < 0.39f) { - nh = 133; + nh = 170; } else if (yc[y][x] < 0.4f) { - nh = 134; + nh = 171; } else if (yc[y][x] < 0.42f) { - nh = 135; + nh = 172; } else if (yc[y][x] < 0.45f) { - nh = 136; + nh = 173; } else if (yc[y][x] < 0.5f) { - nh = 137; + nh = 174; } else if (yc[y][x] < 0.55f) { - nh = 138; + nh = 175; } else if (yc[y][x] < 0.63f) { - nh = 139; + nh = 176; } } 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) { + if (yc[y][x] < 0.2f && purp) {//no take into account if purp = false nh = 177; - } else if (yc[y][x] < 0.4f) { + } else if (yc[y][x] < 0.22f && purp) { nh = 178; - } else if (yc[y][x] < 0.45f) { + } else if (yc[y][x] < 0.24f && purp) { nh = 179; - } else if (yc[y][x] < 0.5f) { + } else if (yc[y][x] < 0.26f && purp) { nh = 180; - } - } else if (xc[y][x] < 0.595f && yc[y][x] > 0.15f) { - if (yc[y][x] < 0.22f) { + } else if (yc[y][x] < 0.29f && purp) { nh = 181; - } else if (yc[y][x] < 0.25f) { + } else if (yc[y][x] < 0.32f) { nh = 182; - } else if (yc[y][x] < 0.3f) { + } else if (yc[y][x] < 0.34f) { nh = 183; - } else if (yc[y][x] < 0.35f) { + } else if (yc[y][x] < 0.37f) { nh = 184; } else if (yc[y][x] < 0.4f) { nh = 185; } else if (yc[y][x] < 0.45f) { nh = 186; + } else if (yc[y][x] < 0.5f) { + nh = 187; + } else if (yc[y][x] < 0.55f) { + nh = 188; + } else if (yc[y][x] < 0.6f) { + nh = 189; + } + } else if (xc[y][x] < 0.445f && yc[y][x] > 0.15f) {//45 + if (yc[y][x] < 0.2f && purp) { + nh = 190; + } else if (yc[y][x] < 0.22f && purp) { + nh = 191; + } else if (yc[y][x] < 0.24f && purp) { + nh = 192; + } else if (yc[y][x] < 0.26f && purp) { + nh = 193; + } else if (yc[y][x] < 0.29f && purp) { + nh = 194; + } else if (yc[y][x] < 0.32f && purp) { + nh = 195; + } else if (yc[y][x] < 0.34f && purp) { + nh = 196; + } else if (yc[y][x] < 0.37f) { + nh = 197; + } else if (yc[y][x] < 0.4f) { + nh = 198; + } else if (yc[y][x] < 0.45f) { + nh = 199; + } else if (yc[y][x] < 0.5f) { + nh = 200; + } else if (yc[y][x] < 0.55f) { + nh = 201; + } else if (yc[y][x] < 0.58f) { + nh = 202; + } + } else if (xc[y][x] < 0.495f && yc[y][x] > 0.15f) { + if (yc[y][x] < 0.2f && purp) { + nh = 203; + } else if (yc[y][x] < 0.22f && purp) { + nh = 204; + } else if (yc[y][x] < 0.24f && purp) { + nh = 205; + } else if (yc[y][x] < 0.26f && purp) { + nh = 206; + } else if (yc[y][x] < 0.29f && purp) { + nh = 207; + } else if (yc[y][x] < 0.32f && purp) { + nh = 208; + } else if (yc[y][x] < 0.34f && purp) { + nh = 209; + } else if (yc[y][x] < 0.37f) { + nh = 210; + } else if (yc[y][x] < 0.4f) { + nh = 211; + } else if (yc[y][x] < 0.45f) { + nh = 212; + } else if (yc[y][x] < 0.5f) { + nh = 213; + } else if (yc[y][x] < 0.55f) { + nh = 214; + } + } else if (xc[y][x] < 0.545f && yc[y][x] > 0.15f) { + if (yc[y][x] < 0.2f && purp) { + nh = 215; + } else if (yc[y][x] < 0.22f && purp) { + nh = 216; + } else if (yc[y][x] < 0.24f && purp) { + nh = 217; + } else if (yc[y][x] < 0.26f && purp) { + nh = 218; + } else if (yc[y][x] < 0.29f && purp) { + nh = 219; + } else if (yc[y][x] < 0.32f && purp) { + nh = 220; + } else if (yc[y][x] < 0.34f && purp) { + nh = 221; + } else if (yc[y][x] < 0.37f) { + nh = 222; + } else if (yc[y][x] < 0.4f) { + nh = 223; + } else if (yc[y][x] < 0.45f) { + nh = 224; + } else if (yc[y][x] < 0.5f) { + nh = 225; + } + } else if (xc[y][x] < 0.595f && yc[y][x] > 0.15f) { + if (yc[y][x] < 0.22f) { + nh = 226; + } else if (yc[y][x] < 0.25f) { + nh = 227; + } else if (yc[y][x] < 0.3f) { + nh = 228; + } else if (yc[y][x] < 0.35f) { + nh = 229; + } else if (yc[y][x] < 0.4f) { + nh = 230; + } else if (yc[y][x] < 0.45f) { + nh = 231; } } else if (xc[y][x] < 0.65f && yc[y][x] > 0.12f) { if (yc[y][x] < 0.25f) { - nh = 187; + nh = 232; } else if (yc[y][x] < 0.3f) { - nh = 188; + nh = 233; } else if (yc[y][x] < 0.35f) { - nh = 189; + nh = 234; } else if (yc[y][x] < 0.45f) { - nh = 190; + nh = 235; } } else if (xc[y][x] < 0.75f && yc[y][x] > 0.1f) { - nh = 191; + nh = 236; //191 } + if (nh >= 0) { histxythr[nh]++; xxxthr[nh] += xc[y][x]; @@ -4407,6 +4585,7 @@ static void histoxyY(int bfhitc, int bfwitc, const array2D & xc, const ar } } } + #ifdef _OPENMP #pragma omp critical #endif @@ -4431,24 +4610,28 @@ float static studentXY(const array2D & YYcurr, const array2D & ref somcurrY += YYcurr[i][tt]; //sum observations first group } + somcurrY *= 100.f; for (int i = 0; i < Nc; i++) { somreffY += reffYY[i][tt]; //sum observations second group } + somreffY *= 100.f; for (int i = 0; i < sizcurr; i++) { somcurr2Y += SQR(YYcurr[i][tt]); //sum sqr observations first group } + somcurr2Y *= SQR(100.f); for (int i = 0; i < Nc; i++) { somreff2Y += SQR(reffYY[i][tt]); //sum sqr observations second group } + somreff2Y *= SQR(100.f); const float somsqueccurrY = somcurr2Y - SQR(somcurrY) / sizcurr; @@ -4465,19 +4648,22 @@ float static studentXY(const array2D & YYcurr, const array2D & ref //student coeeficient } -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) + + + +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 + Copyright (c) Jacques Desmis 6 - 2018 jdesmis@gmail.com, update 1 - 2023 Copyright (c) Ingo Weyrich 3 - 2020 (heckflosse67@gmx.de) - This algorithm try to find temperature correlation between 20 to 201 color between 201 spectral color and about 20 to 55 color found in the image between 192, 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. + 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. I have test many many algorithms to find the first one that work :) Probably (sure) there are improvement to do... I have create a table temperature with temp and white point with 118 values between 2000K and 12000K we can obviously change these values, more...with different steps - I have create a table for tint (green)with 134 values between 0.4 to 4. + I have create a table for tint (green)with 134 values between 0.4 to 4. I have create or recuparate and transformed 201 spectral colors from Colorchecker24, others color and my 468 colors target, or from web flowers, etc. with a step of 5nm, I think it is large enough. I think this value of 201 is now complete: I tested correlation with 60, 90, 100, 120, 155...better student increase with number of color, but now it seems stabilized Of course we can increase this number :) @@ -4520,17 +4706,18 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double You can change parameters in option.cc Itcwb_thres : 34 by default ==> number of color used in final algorithm - between 10 and max 55 - Itcwb_sort : false by default, can improve algorithm if true, ==> sort value in something near chroma order, instead of histogram number + 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 : false - if true force algorithm "extra" ("extra" is used when camera wbsettings are wrong) to all images + 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_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 : 5 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 : 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... */ -// BENCHFUN - + BENCHFUN + TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix("sRGB"); const float wp[3][3] = { {static_cast(wprof[0][0]), static_cast(wprof[0][1]), static_cast(wprof[0][2])}, @@ -4570,7 +4757,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {0.590, 1.f}, {0.600, 1.f}, {0.610, 1.f}, - {0.620, 1.f}, + {0.620, 1.f},//extended range {0.630, 1.f}, {0.640, 1.f}, {0.650, 1.f}, @@ -4579,7 +4766,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}, + {0.714, 1.f},//usual range {0.727, 1.f}, {0.741, 1.f}, {0.755, 1.f}, @@ -4610,7 +4797,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {0.971, 1.f}, {0.980, 1.f}, {0.990, 1.f}, - {1.000, 1.f},//55 + {1.000, 1.f},//55 reference {1.010, 1.f}, {1.020, 1.f}, {1.030, 1.f}, @@ -4641,14 +4828,14 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {1.325, 1.f}, {1.350, 1.f}, {1.375, 1.f}, - {1.400, 1.f}, + {1.400, 1.f},//usual range {1.425, 1.f}, {1.450, 1.f}, {1.475, 1.f}, {1.500, 1.f}, {1.525, 1.f}, {1.550, 1.f}, - {1.575, 1.f}, + {1.575, 1.f},//extended range {1.600, 1.f}, {1.633, 1.f}, {1.666, 1.f}, @@ -4697,7 +4884,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double int end; } RangeGreen; - constexpr RangeGreen Rangestandard = {24, 86}; + constexpr RangeGreen Rangestandard = {24, 86};//usual green range constexpr RangeGreen Rangeextended = {15, 93}; const RangeGreen Rangemax = {0, N_g}; @@ -4778,7 +4965,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double {4927., 0.965414, 0.809229}, {4952., 0.964908, 0.814366}, {4977., 0.964415, 0.819412}, - {5002., 0.963934, 0.824438}, + {5002., 0.963934, 0.824438},//57 reference {5027., 0.963465, 0.829444}, {5052., 0.963008, 0.834429}, {5077., 0.962563, 0.839395}, @@ -4857,10 +5044,10 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double float gmm[N_t]; float bmm[N_t]; - constexpr int siza = 192;//size of histogram + constexpr int siza = 237; //192 untill 01/2023 size of histogram - //tempref and greenref are camera wb values. - // I used them by default to select good spectral values !! + // 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); int repref = 0; @@ -4874,7 +5061,8 @@ 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)); + || (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; @@ -4924,19 +5112,27 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } ; LUTu histxy(siza); //number of values for each pair xy + histxy.clear(); LUTf xxx(siza);//for color references calculated ==> max in images "like histogram" + xxx.clear(); + LUTf yyy(siza); + yyy.clear(); + LUTf YYY(siza);//not used directly, but necessary to keep good range + YYY.clear(); bool separated = true; + int w = -1; array2D reff_spect_yy_camera(N_t, 2 * Nc + 2); + array2D reff_spect_xx_camera(N_t, 2 * Nc + 2); //here we select the good spectral color inside the 113 values @@ -4965,6 +5161,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double #ifdef _OPENMP #pragma omp parallel for #endif + for (int y = 0; y < bfh ; ++y) { for (int x = 0; x < bfw ; ++x) { const float RR = rmm[rep] * redloc[y][x]; @@ -4973,6 +5170,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double Color::rgbxyY(RR, GG, BB, xc[y][x], yc[y][x], Yc[y][x], wp); } } + //histogram xy depend of temp...but in most cases D45 ..D65.. //calculate for this image the mean values for each family of color, near histogram x y (number) //xy vary from x 0..0.77 y 0..0.82 @@ -4982,8 +5180,14 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double // step about 0.02 x 0.32 0.34 y= 0.34 0.36 skin -- sky x 0.24 0.30 y 0.28 0.32 //big step about 0.2 - histoxyY(bfhitc, bfwitc, xc, yc, Yc, xxx, yyy, YYY, histxy); - //return histogram x and y for each temp and in a range of 158 colors (siza) + 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...) + 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) } // free some memory @@ -5014,15 +5218,19 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double int n4 = 0; int n15 = 0; int n30 = 0; + //part to improve //determined the number of colors who be used after for (int nh = 0; nh < siza; nh++) { if (Wbhis[nh].histnum < 30) { n30++; //keep only existing color but avoid to small + if (Wbhis[nh].histnum < 15) { n15++; //keep only existing color but avoid to small + if (Wbhis[nh].histnum < 4) { n4++; //keep only existing color but avoid to small + if (Wbhis[nh].histnum < 1) { n1++; //keep only existing color but avoid to small } @@ -5047,7 +5255,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); + const int sizcu4 = rtengine::min(sizcu30, 55);// + + if (settings->verbose) { + printf("ntr=%i sizcurr2ref=%i sizcu30=%i sizcu4=%i\n", ntr, sizcurr2ref, sizcu30, sizcu4); + } chrom wbchro[sizcu4]; const float swpr = Txyz[repref].XX + Txyz[repref].ZZ + 1.f; @@ -5062,6 +5274,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } float estimchrom = 0.f; + //estimate chromaticity for references for (int nh = 0; nh < sizcu4; ++nh) { const float chxy = std::sqrt(SQR(xx_curref[nh][repref] - xwpr) + SQR(yy_curref[nh][repref] - ywpr)); @@ -5075,10 +5288,12 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } estimchrom /= sizcu4; - if (settings->verbose) { + + if (settings->verbose) { printf("estimchrom=%f\n", estimchrom); } - if (settings->itcwb_sort) { //sort in ascending with chroma values + + if (settings->itcwb_sorted) { //sort in ascending with chroma values std::sort(wbchro, wbchro + sizcu4, wbchro[0]); } @@ -5105,7 +5320,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double 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 for (int i = 0; i < w; ++i) { - float mindeltaE = 100000.f; + float mindeltaE = 100000.f;//we can change this value... int kN = 0; for (int j = 0; j < Nc ; j++) { @@ -5192,7 +5407,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } } - if (extra) {//always used because I made this choice, brings better results + if (extra) {//always used if extra = true because I made this choice, brings better results struct Tempgreen { float student; int tempref; @@ -5206,14 +5421,15 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double for (int i = 0; i < N_g; ++i) {//init variables with Tgstud[i].student = 1000.f;//max value to initialize - Tgstud[i].tempref = 57;//5002K - Tgstud[i].greenref = 55;// 1.f + 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); const int scantempbeg = rtengine::max(goodref - (dgoodref + 1), 1); const int scantempend = rtengine::min(goodref + dgoodref, N_t - 1); + for (int gr = Rangegreenused.begin; gr < Rangegreenused.end; ++gr) { float minstudgr = 100000.f; int goodrefgr = 1; @@ -5249,6 +5465,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double const float BB = bmm[tt] * B_curref_reduc[i][repref]; Color::rgbxyY(RR, GG, BB, xxyycurr_reduc[2 * i][tt], xxyycurr_reduc[2 * i + 1][tt], unused, wp); } + //recalculate xy spectral now with good range of temp and green for (int j = 0; j < Nc ; ++j) { @@ -5257,6 +5474,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double } int kkg = -1; + for (int i = 0; i < Nc ; ++i) { if (good_spectral[i]) { kkg++; @@ -5264,6 +5482,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double reff_spect_xxyy[2 * kkg + 1][tt] = reff_spect_xxyy_prov[2 * i + 1][tt]; } } + //now we have good spectral data //calculate student correlation const float abstudgr = std::fabs(studentXY(xxyycurr_reduc, reff_spect_xxyy, 2 * w, 2 * kkg, tt)); @@ -5272,6 +5491,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double minstudgr = abstudgr; goodrefgr = tt; } + //found the values Tgstud[gr].tempref = goodrefgr; Tgstud[gr].greenref = gr; @@ -5282,48 +5502,35 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double std::sort(Tgstud, Tgstud + N_g, Tgstud[0]); - //now search the value of green the nearest of 1 with a good student value - // I take the 3 first values - //I admit a symetrie in green coefiicient for rgb multiplier...probably not exactly true - //perhaps we can used a Snedecor test ? but why...at least we have confidence interval > 90% - int greengood; - int greengoodprov; - int goodrefprov; - float studprov; - const int goodref0 = Tgstud[0].tempref; - const int greengood0 = Tgstud[0].greenref - 55;//55 green = 1 - const float stud0 = Tgstud[0].student; - const int goodref1 = Tgstud[1].tempref; - const float stud1 = Tgstud[1].student; - const int greengood1 = Tgstud[1].greenref - 55; - const int goodref2 = Tgstud[2].tempref; - const int greengood2 = Tgstud[2].greenref - 55; - const float stud2 = Tgstud[2].student; + // now search the value of green the nearest of 1 with a good student value, I think it is a good choice, perhaps no... + // I take the 5 first values + // I admit a symetrie in green coefiicient for rgb multiplier...probably not exactly true + // perhaps we can used a Snedecor test ? but why...at least we have confidence interval > 90% + int greengood = 55; - if (std::fabs(greengood2) < std::fabs(greengood1)) { - greengoodprov = greengood2; - goodrefprov = goodref2; - studprov = stud2; - } else { - greengoodprov = greengood1; - goodrefprov = goodref1; - studprov = stud1; + int maxkgood = 5;//we can change ...to test 3, 4, 5. High values perhaps less good student, but it is a compromise... + int mingood = std::min(std::fabs(Tgstud[0].greenref - 55), std::fabs(Tgstud[1].greenref - 55)); + for (int k = 2; k < maxkgood; ++k) { + mingood = std::min(std::fabs(mingood), std::fabs(Tgstud[k].greenref - 55)); } - if (std::fabs(greengoodprov) < std::fabs(greengood0)) { - goodref = goodrefprov; - greengood = greengoodprov + 55; - studgood = studprov; + for (int k = 0; k < maxkgood ; ++k) { + if (mingood == fabs(Tgstud[k].greenref - 55)) { + greengood = Tgstud[k].greenref ; + goodref = Tgstud[k].tempref; + studgood = Tgstud[k].student;; + } + } - } else { - goodref = goodref0; - greengood = greengood0 + 55; - studgood = stud0; + if (settings->verbose) { + printf("Student_0=%f Student_k= %f\n", Tgstud[0].student, Tgstud[maxkgood - 1].student); + printf("mingood=%i greeng=%i goodref=%i stud=%f\n", mingood, greengood, goodref, (double) studgood); } tempitc = Txyz[goodref].Tem; greenitc = gree[greengood].green; + if (estimchrom < 0.025f) { float ac = -2.40f * estimchrom + 0.06f;//small empirical correction, maximum 0.06 if chroma=0 for all image, currently for very low chroma +0.02 greenitc += ac; @@ -5337,13 +5544,14 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double if (!extra) { tempitc = Txyz[goodref].Tem; } + //now we have temp green and student if (settings->verbose) { printf("ITCWB tempitc=%f gritc=%f stud=%f \n", tempitc, greenitc, studgood); } } -void RawImageSource::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 WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const ColorManagementParams & cmp, const RAWParams & raw) +void RawImageSource::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 WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const ColorManagementParams & cmp, const RAWParams & raw, const ToneCurveParams &hrp) { // BENCHFUN //auto white balance @@ -5364,8 +5572,7 @@ void RawImageSource::WBauto(double & tempref, double & greenref, array2D } tempitc = 5000.; - - ItcWB(extra, tempref, greenref, tempitc, greenitc, studgood, redloc, greenloc, blueloc, bfw, bfh, avg_rm, avg_gm, avg_bm, cmp, raw, wbpar); + ItcWB(extra, tempref, greenref, tempitc, greenitc, studgood, redloc, greenloc, blueloc, bfw, bfh, avg_rm, avg_gm, avg_bm, cmp, raw, wbpar, hrp); } } @@ -5373,15 +5580,18 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int { // BENCHFUN //used by auto WB local to calculate red, green, blue in local region + int precision = 5; + if (settings->itcwb_precis == 5) { precision = 5; } else if (settings->itcwb_precis < 5) { - precision = 3; + 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); @@ -5404,6 +5614,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int #ifdef _OPENMP #pragma omp parallel for reduction(+:avgL, nn) #endif + for (int i = 0; i < H; i ++) { for (int j = 0; j < W; j++) { const float LL = 0.299f * red[i][j] + 0.587f * green[i][j] + 0.114f * blue[i][j]; @@ -5411,6 +5622,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int nn++; } } + avgL /= nn; double vari = 0.f; @@ -5419,6 +5631,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int #ifdef _OPENMP #pragma omp parallel for reduction(+:vari, mm) #endif + for (int i = 0; i < H; i++) for (int j = 0; j < W; j++) { const float LL = 0.299f * red[i][j] + 0.587f * green[i][j] + 0.114f * blue[i][j]; @@ -5432,8 +5645,10 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int #ifdef _OPENMP #pragma omp parallel for #endif + for (int i = 0; i < bfh; ++i) { const int ii = i * precision; + if (ii < H) { for (int j = 0, jj = 0; j < bfw; ++j, jj += precision) { redloc[i][j] = red[ii][jj] * multip; @@ -5444,7 +5659,7 @@ void RawImageSource::getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int } } -void RawImageSource::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 WBParams & wbpar, const ColorManagementParams & cmp, const RAWParams & raw) +void RawImageSource::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 WBParams & wbpar, const ColorManagementParams & cmp, const RAWParams & raw, const ToneCurveParams &hrp) { // BENCHFUN constexpr double clipHigh = 64000.0; @@ -5459,6 +5674,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref double avg_b = 0; int rn = 0, gn = 0, bn = 0; double avg_rm, avg_gm, avg_bm; + if (wbpar.method == "autold") { if (fuji) { for (int i = 32; i < H - 32; i++) { @@ -5468,7 +5684,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref for (int j = start; j < end; j++) { if (ri->getSensorType() != ST_BAYER) { - double dr = CLIP(initialGain * (rawData[i][3 * j] )); + double dr = CLIP(initialGain * (rawData[i][3 * j])); double dg = CLIP(initialGain * (rawData[i][3 * j + 1])); double db = CLIP(initialGain * (rawData[i][3 * j + 2])); @@ -5507,18 +5723,18 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref if (ri->getSensorType() == ST_FUJI_XTRANS) { const double compval = clipHigh / initialGain; #ifdef _OPENMP - #pragma omp parallel + #pragma omp parallel #endif { double avg_c[3] = {0.0}; int cn[3] = {0}; #ifdef _OPENMP - #pragma omp for schedule(dynamic,16) nowait + #pragma omp for schedule(dynamic,16) nowait #endif for (int i = 32; i < H - 32; i++) { for (int j = 32; j < W - 32; j++) { - // each loop read 1 rgb triplet value + // each loop read 1 rgb triplet value double d = rawData[i][j]; if (d > compval) { @@ -5532,7 +5748,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref } #ifdef _OPENMP - #pragma omp critical + #pragma omp critical #endif { avg_r += avg_c[0]; @@ -5549,9 +5765,9 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref } else { for (int i = 32; i < H - 32; i++) for (int j = 32; j < W - 32; j++) { - // each loop read 1 rgb triplet value + // each loop read 1 rgb triplet value - double dr = CLIP(initialGain * (rawData[i][3 * j] )); + double dr = CLIP(initialGain * (rawData[i][3 * j])); double dg = CLIP(initialGain * (rawData[i][3 * j + 1])); double db = CLIP(initialGain * (rawData[i][3 * j + 2])); @@ -5569,7 +5785,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref bn = rn; } } else { - //determine GRBG coset; (ey,ex) is the offset of the R subarray + //determine GRBG coset; (ey,ex) is the offset of the R subarray int ey, ex; if (ri->ISGREEN(0, 0)) { //first pixel is G @@ -5592,12 +5808,12 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref const double compval = clipHigh / initialGain; #ifdef _OPENMP - #pragma omp parallel for reduction(+:avg_r,avg_g,avg_b,rn,gn,bn) schedule(dynamic,8) + #pragma omp parallel for reduction(+:avg_r,avg_g,avg_b,rn,gn,bn) schedule(dynamic,8) #endif for (int i = 32; i < H - 32; i += 2) for (int j = 32; j < W - 32; j += 2) { - //average each Bayer quartet component individually if non-clipped + //average each Bayer quartet component individually if non-clipped double d[2][2]; d[0][0] = rawData[i][j]; d[0][1] = rawData[i][j + 1]; @@ -5636,17 +5852,18 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref if (wbpar.method == "autitcgreen") { bool twotimes = false; int precision = 5; + if (settings->itcwb_precis == 5) { precision = 5; } else if (settings->itcwb_precis < 5) { - precision = 3; + 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); - WBauto(tempref, greenref, redloc, greenloc, blueloc, bfw, bfh, avg_rm, avg_gm, avg_bm, tempitc, greenitc, studgood, twotimes, wbpar, begx, begy, yEn, xEn, cx, cy, cmp, raw); + WBauto(tempref, greenref, redloc, greenloc, blueloc, bfw, bfh, avg_rm, avg_gm, avg_bm, tempitc, greenitc, studgood, twotimes, wbpar, begx, begy, yEn, xEn, cx, cy, cmp, raw, hrp); } redloc(0, 0); @@ -5654,7 +5871,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref blueloc(0, 0); if (settings->verbose) { - printf ("AVG: %g %g %g\n", avg_r / std::max(1, rn), avg_g / std::max(1, gn), avg_b / std::max(1, bn)); + printf("AVG: %g %g %g\n", avg_r / std::max(1, rn), avg_g / std::max(1, gn), avg_b / std::max(1, bn)); } if (wbpar.method == "autitcgreen") { @@ -5673,7 +5890,7 @@ void RawImageSource::getAutoWBMultipliersitc(double & tempref, double & greenref } -void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm) +void RawImageSource::getAutoWBMultipliers(double &rm, double &gm, double &bm) { // BENCHFUN constexpr double clipHigh = 64000.0; @@ -5710,7 +5927,7 @@ void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm) for (int j = start; j < end; j++) { if (ri->getSensorType() != ST_BAYER) { - double dr = CLIP(initialGain * (rawData[i][3 * j] )); + double dr = CLIP(initialGain * (rawData[i][3 * j])); double dg = CLIP(initialGain * (rawData[i][3 * j + 1])); double db = CLIP(initialGain * (rawData[i][3 * j + 2])); @@ -5793,7 +6010,7 @@ void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm) for (int j = 32; j < W - 32; j++) { // each loop read 1 rgb triplet value - double dr = CLIP(initialGain * (rawData[i][3 * j] )); + double dr = CLIP(initialGain * (rawData[i][3 * j])); double dg = CLIP(initialGain * (rawData[i][3 * j + 1])); double db = CLIP(initialGain * (rawData[i][3 * j + 2])); @@ -5875,7 +6092,7 @@ void RawImageSource::getAutoWBMultipliers (double &rm, double &gm, double &bm) } if (settings->verbose) { - printf ("AVG: %g %g %g\n", avg_r / std::max(1, rn), avg_g / std::max(1, gn), avg_b / std::max(1, bn)); + printf("AVG: %g %g %g\n", avg_r / std::max(1, rn), avg_g / std::max(1, gn), avg_b / std::max(1, bn)); } // return ColorTemp (pow(avg_r/rn, 1.0/6.0)*img_r, pow(avg_g/gn, 1.0/6.0)*img_g, pow(avg_b/bn, 1.0/6.0)*img_b); diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index d7549fe71..fabea5ffc 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -112,7 +112,7 @@ protected: void hlRecovery(const std::string &method, float* red, float* green, float* blue, int width, float* hlmax); void transformRect(const PreviewProps &pp, int tran, int &sx1, int &sy1, int &width, int &height, int &fw); void transformPosition(int x, int y, int tran, int& tx, int& ty); - void 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 procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::WBParams & wbpar); + void 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 procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw, const procparams::WBParams & wbpar, const procparams::ToneCurveParams &hrp); unsigned FC(int row, int col) const; inline void getRowStartEnd (int x, int &start, int &end); @@ -141,12 +141,12 @@ public: void processFlatField(const procparams::RAWParams &raw, const RawImage *riFlatFile, array2D &rawData, const float black[4]); void copyOriginalPixels(const procparams::RAWParams &raw, RawImage *ri, const RawImage *riDark, RawImage *riFlatFile, array2D &rawData ); void scaleColors (int winx, int winy, int winw, int winh, const procparams::RAWParams &raw, array2D &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) 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) 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; void getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) 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) override; + void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw, int opposed) override; eSensorType getSensorType () const override; bool isMono () const override; ColorTemp getWB () const override @@ -199,7 +199,8 @@ public: void MSR(float** luminance, float **originalLuminance, float **exLuminance, const LUTf& mapcurve, bool mapcontlutili, int width, int height, const procparams::RetinexParams &deh, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax); void HLRecovery_inpaint (float** red, float** green, float** blue, int blur); - static void HLRecovery_Luminance (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval); + void highlight_recovery_opposed(float scale_mul[3], const ColorTemp &wb, float gainth); + static void HLRecovery_Luminance (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval); static void HLRecovery_CIELab (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval, double cam[3][3], double icam[3][3]); static void HLRecovery_blend (float* rin, float* gin, float* bin, int width, float maxval, float* hlmax); static void init (); @@ -308,6 +309,9 @@ protected: void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) override; void captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold, double &radius) override; void applyDngGainMap(const float black[4], const std::vector &gainMaps); +public: + void wbMul2Camera(double &rm, double &gm, double &bm) override; + void wbCamera2Mul(double &rm, double &gm, double &bm) override; }; } diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 3916adfbe..eb4a3f888 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -94,7 +94,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { HDR, // EvCACorr, ALLNORAW, // EvHREnabled, 0, // EvHRAmount : obsolete, - ALLNORAW, // EvHRMethod, + ALLNORAW|M_RAW, // EvHRMethod, DEMOSAIC, // EvWProfile, OUTPUTPROFILE, // EvOProfile, ALLNORAW, // EvIProfile, diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 86f1c1372..84c33a734 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -349,7 +349,7 @@ Image8 *load_inspector_mode(const Glib::ustring &fname, RawMetaDataLocation &rml PreviewProps pp(0, 0, w, h, 1); Imagefloat tmp(w, h); - src.getImage(src.getWB(), TR_NONE, &tmp, pp, neutral.toneCurve, neutral.raw); + src.getImage(src.getWB(), TR_NONE, &tmp, pp, neutral.toneCurve, neutral.raw, 0); src.convertColorSpace(&tmp, neutral.icm, src.getWB()); Image8 *img = new Image8(w, h); diff --git a/rtengine/settings.h b/rtengine/settings.h index 1c8c73630..6e787a112 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -44,6 +44,7 @@ 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 @@ -94,7 +95,7 @@ public: // bool showtooltip; int itcwb_thres; - bool itcwb_sort; + bool itcwb_sorted; int itcwb_greenrange; int itcwb_greendeltatemp; bool itcwb_forceextra; @@ -102,6 +103,7 @@ public: int itcwb_delta; bool itcwb_stdobserver10; int itcwb_precis; + bool itcwb_nopurple; //wavelet levels double edghi; double edglo; diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index c542cf726..5de3b08b0 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -261,7 +261,7 @@ private: pl->setProgress(0.40); } - imgsrc->HLRecovery_Global(params.toneCurve); + // imgsrc->HLRecovery_Global(params.toneCurve); if (pl) { @@ -372,7 +372,7 @@ private: int beg_tileW = wcr * tileWskip + tileWskip / 2.f - crW / 2.f; int beg_tileH = hcr * tileHskip + tileHskip / 2.f - crH / 2.f; PreviewProps ppP(beg_tileW, beg_tileH, crW, crH, skipP); - imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw); + imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw, 0); //baseImg->getStdImage(currWB, tr, origCropPart, ppP, true, params.toneCurve); // we only need image reduced to 1/4 here @@ -596,7 +596,7 @@ private: for (int wcr = 0; wcr <= 2; wcr++) { for (int hcr = 0; hcr <= 2; hcr++) { PreviewProps ppP(coordW[wcr], coordH[hcr], crW, crH, 1); - imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw); + imgsrc->getImage(currWB, tr, origCropPart, ppP, params.toneCurve, params.raw, 0); //baseImg->getStdImage(currWB, tr, origCropPart, ppP, true, params.toneCurve); @@ -756,7 +756,7 @@ private: } baseImg = new Imagefloat(fw, fh); - imgsrc->getImage(currWB, tr, baseImg, pp, params.toneCurve, params.raw); + imgsrc->getImage(currWB, tr, baseImg, pp, params.toneCurve, params.raw, 1); if (pl) { pl->setProgress(0.50); diff --git a/rtengine/spot.cc b/rtengine/spot.cc index 5ed090712..09186a399 100644 --- a/rtengine/spot.cc +++ b/rtengine/spot.cc @@ -459,7 +459,7 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s } } - imgsrc->getImage(currWB, tr, srcSpotBox->getImage(), spp, params->toneCurve, params->raw); + imgsrc->getImage(currWB, tr, srcSpotBox->getImage(), spp, params->toneCurve, params->raw, 0); if (cmp) { imgsrc->convertColorSpace(srcImage, *cmp, currWB); } @@ -479,7 +479,7 @@ void ImProcFunctions::removeSpots (Imagefloat* img, ImageSource* imgsrc, const s dstImage->b(y, x) = 60000.f; } } - imgsrc->getImage(currWB, tr, dstSpotBox->getImage(), spp, params->toneCurve, params->raw); + imgsrc->getImage(currWB, tr, dstSpotBox->getImage(), spp, params->toneCurve, params->raw, 0); if (cmp) { imgsrc->convertColorSpace(dstImage, *cmp, currWB); } diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index 8cb8fa792..a3f2502f0 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -193,7 +193,7 @@ int StdImageSource::load (const Glib::ustring &fname) return 0; } -void StdImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw) +void StdImageSource::getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const ToneCurveParams &hrp, const RAWParams &raw, int opposed) { // the code will use OpenMP as of now. @@ -311,11 +311,11 @@ void StdImageSource::getAutoExpHistogram (LUTu & histogram, int& histcompr) } } -void StdImageSource::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 WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const ColorManagementParams &cmp, const RAWParams &raw) +void StdImageSource::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 WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const ColorManagementParams &cmp, const RAWParams &raw, const ToneCurveParams &hrp) { } -void StdImageSource::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 WBParams & wbpar, const ColorManagementParams &cmp, const RAWParams &raw) +void StdImageSource::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 WBParams & wbpar, const ColorManagementParams &cmp, const RAWParams &raw, const ToneCurveParams &hrp) { if (redAWBMul != -1.) { rm = redAWBMul; @@ -324,7 +324,7 @@ void StdImageSource::getAutoWBMultipliersitc(double &tempref, double &greenref, return; } - img->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc,studgood, begx, begy, yEn, xEn, cx, cy, bf_h, bf_w, rm, gm, bm, params->wb, params->icm, params->raw); + img->getAutoWBMultipliersitc(tempref, greenref, tempitc, greenitc,studgood, begx, begy, yEn, xEn, cx, cy, bf_h, bf_w, rm, gm, bm, params->wb, params->icm, params->raw, params->toneCurve); redAWBMul = rm; greenAWBMul = gm; @@ -367,6 +367,20 @@ void StdImageSource::flush() { img->allocate(0, 0); }; +void StdImageSource::wbMul2Camera(double &rm, double &gm, double &bm) +{ + rm = 1.0 / rm; + gm = 1.0 / gm; + bm = 1.0 / bm; +} + + +void StdImageSource::wbCamera2Mul(double &rm, double &gm, double &bm) +{ + rm = 1.0 / rm; + gm = 1.0 / gm; + bm = 1.0 / bm; +} } diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index f83c58a04..90c4be654 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -58,7 +58,7 @@ public: int load (const Glib::ustring &fname) 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) 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 {}; ColorTemp getWB () const override { @@ -66,8 +66,8 @@ public: } 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; - 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) 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) 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; eSensorType getSensorType() const override {return ST_NONE;} bool isMono() const override {return false;} @@ -123,6 +123,8 @@ public: void getRawValues(int x, int y, int rotate, int &R, int &G, int &B) override { R = G = B = 0;} + void wbMul2Camera(double &rm, double &gm, double &bm) override; + void wbCamera2Mul(double &rm, double &gm, double &bm) override; void flush () override; void captureSharpening(const procparams::CaptureSharpeningParams &sharpeningParams, bool showMask, double &conrastThreshold, double &radius) override {}; diff --git a/rtgui/options.cc b/rtgui/options.cc index 3ce97567c..66b9e92a1 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -594,6 +594,7 @@ 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,14 +624,15 @@ void Options::setDefaults() rtSettings.fftwsigma = true; //choice between sigma^2 or empirical formula rtSettings.itcwb_thres = 34;//between 10 to 55 - rtSettings.itcwb_sort = false; + 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 = 5;//3 or 5 or 9 + rtSettings.itcwb_precis = 3;//3 or 5 or 9 + rtSettings.itcwb_nopurple = true; // end locallab //wavelet @@ -1760,6 +1762,10 @@ 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"); } @@ -1795,14 +1801,18 @@ void Options::readFromFile(Glib::ustring fname) rtSettings.itcwb_thres = keyFile.get_integer("Color Management", "Itcwb_thres"); } - if (keyFile.has_key("Color Management", "Itcwb_sort")) { - rtSettings.itcwb_sort = keyFile.get_boolean("Color Management", "Itcwb_sort"); + 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"); } @@ -2563,6 +2573,7 @@ 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); @@ -2596,10 +2607,11 @@ void Options::saveToFile(Glib::ustring fname) 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_sort", rtSettings.itcwb_sort); + 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); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 7d641d753..abd4e8608 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -48,6 +48,7 @@ void ParamsEdited::set(bool v) toneCurve.shcompr = v; toneCurve.hlcompr = v; toneCurve.hlbl = v; + toneCurve.hlth = v; toneCurve.hlcomprthresh = v; toneCurve.autoexp = v; toneCurve.clip = v; @@ -749,6 +750,7 @@ void ParamsEdited::initFrom(const std::vector& toneCurve.shcompr = toneCurve.shcompr && p.toneCurve.shcompr == other.toneCurve.shcompr; toneCurve.hlcompr = toneCurve.hlcompr && p.toneCurve.hlcompr == other.toneCurve.hlcompr; toneCurve.hlbl = toneCurve.hlbl && p.toneCurve.hlbl == other.toneCurve.hlbl; + toneCurve.hlth = toneCurve.hlth && p.toneCurve.hlth == other.toneCurve.hlth; toneCurve.hlcomprthresh = toneCurve.hlcomprthresh && p.toneCurve.hlcomprthresh == other.toneCurve.hlcomprthresh; toneCurve.autoexp = toneCurve.autoexp && p.toneCurve.autoexp == other.toneCurve.autoexp; toneCurve.clip = toneCurve.clip && p.toneCurve.clip == other.toneCurve.clip; @@ -2192,6 +2194,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.toneCurve.hlbl = mods.toneCurve.hlbl; } + if (toneCurve.hlth) { + toEdit.toneCurve.hlth = mods.toneCurve.hlth; + } + if (toneCurve.histmatching) { toEdit.toneCurve.histmatching = mods.toneCurve.histmatching; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 616e6d261..66db8346f 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -52,6 +52,7 @@ struct ToneCurveParamsEdited { bool shcompr; bool hlcompr; bool hlbl; + bool hlth; bool hlcomprthresh; bool autoexp; bool clip; diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc index c39bd3bda..bf81c6f22 100644 --- a/rtgui/tonecurve.cc +++ b/rtgui/tonecurve.cc @@ -42,6 +42,7 @@ ToneCurve::ToneCurve() : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOSURE_LABEL EvHistMatchingBatch = m->newEvent(M_VOID, "HISTORY_MSG_HISTMATCHING"); EvClampOOG = m->newEvent(DARKFRAME, "HISTORY_MSG_CLAMPOOG"); EvHLbl = m->newEvent(DEMOSAIC, "HISTORY_MSG_HLBL"); + EvHLth = m->newEvent(DEMOSAIC, "HISTORY_MSG_HLTH"); CurveListener::setMulti(true); @@ -97,13 +98,14 @@ ToneCurve::ToneCurve() : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOSURE_LABEL method = Gtk::manage (new MyComboBoxText ()); method->append (M("TP_HLREC_LUMINANCE")); method->append (M("TP_HLREC_CIELAB")); - method->append (M("TP_HLREC_COLOR")); method->append (M("TP_HLREC_BLEND")); + method->append (M("TP_HLREC_COLOR")); + method->append (M("TP_HLREC_COLOROPP")); Gtk::Box *hrVBox; hrVBox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); hrVBox->set_spacing(2); - method->set_active(0); + method->set_active(4); Gtk::Frame* const hrFrame = Gtk::manage(new Gtk::Frame()); hrFrame->set_label_align(0.025, 0.5); hrFrame->set_label_widget(*hrenabled); @@ -113,9 +115,11 @@ ToneCurve::ToneCurve() : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOSURE_LABEL hlrbox->pack_start (*lab, Gtk::PACK_SHRINK); hlrbox->pack_start (*method); hlbl = Gtk::manage(new Adjuster(M("TP_HLREC_HLBLUR"), 0, 4, 1, 0)); + hlth = Gtk::manage(new Adjuster(M("TP_HLREC_HLTH"), 0.25, 1.75, 0.01, 1.)); hrVBox->pack_start(*hlrbox, Gtk::PACK_SHRINK); hrVBox->pack_start(*hlbl); + hrVBox->pack_start(*hlth); hrFrame->add(*hrVBox); pack_start(*hrFrame); @@ -223,6 +227,7 @@ ToneCurve::ToneCurve() : FoldableToolPanel(this, TOOL_NAME, M("TP_EXPOSURE_LABEL black->setAdjusterListener(this); hlcompr->setAdjusterListener(this); hlbl->setAdjusterListener(this); + hlth->setAdjusterListener(this); hlcomprthresh->setAdjusterListener(this); shcompr->setAdjusterListener(this); contrast->setAdjusterListener(this); @@ -254,6 +259,7 @@ void ToneCurve::read(const ProcParams* pp, const ParamsEdited* pedited) black->setValue(pp->toneCurve.black); hlcompr->setValue(pp->toneCurve.hlcompr); hlbl->setValue(pp->toneCurve.hlbl); + hlth->setValue(pp->toneCurve.hlth); hlcomprthresh->setValue(pp->toneCurve.hlcomprthresh); shcompr->setValue(pp->toneCurve.shcompr); @@ -283,6 +289,7 @@ void ToneCurve::read(const ProcParams* pp, const ParamsEdited* pedited) black->setEditedState(pedited->toneCurve.black ? Edited : UnEdited); hlcompr->setEditedState(pedited->toneCurve.hlcompr ? Edited : UnEdited); hlbl->setEditedState(pedited->toneCurve.hlbl ? Edited : UnEdited); + hlth->setEditedState(pedited->toneCurve.hlth ? Edited : UnEdited); hlcomprthresh->setEditedState(pedited->toneCurve.hlcomprthresh ? Edited : UnEdited); shcompr->setEditedState(pedited->toneCurve.shcompr ? Edited : UnEdited); brightness->setEditedState(pedited->toneCurve.brightness ? Edited : UnEdited); @@ -310,16 +317,18 @@ void ToneCurve::read(const ProcParams* pp, const ParamsEdited* pedited) hrenabled->set_active(pp->toneCurve.hrenabled); enaconn.block(false); - if (pedited && !pedited->toneCurve.method) { - method->set_active(4); - } else if (pp->toneCurve.method == "Luminance") { + if (pedited && !pedited->toneCurve.method) { + method->set_active(5); + } else if (pp->toneCurve.method == "Luminance") { method->set_active(0); } else if (pp->toneCurve.method == "CIELab blending") { method->set_active(1); - } else if (pp->toneCurve.method == "Color") { - method->set_active(2); } else if (pp->toneCurve.method == "Blend") { + method->set_active(2); + } else if (pp->toneCurve.method == "Color") { method->set_active(3); + } else if (pp->toneCurve.method == "Coloropp") { + method->set_active(4); } hrenabledChanged(); @@ -354,6 +363,7 @@ void ToneCurve::write(ProcParams* pp, ParamsEdited* pedited) pp->toneCurve.black = black->getValue(); pp->toneCurve.hlcompr = hlcompr->getValue(); pp->toneCurve.hlbl = hlbl->getValue(); + pp->toneCurve.hlth = hlth->getValue(); pp->toneCurve.hlcomprthresh = hlcomprthresh->getValue(); pp->toneCurve.shcompr = shcompr->getValue(); pp->toneCurve.brightness = brightness->getValue(); @@ -403,6 +413,7 @@ void ToneCurve::write(ProcParams* pp, ParamsEdited* pedited) pedited->toneCurve.black = black->getEditedState(); pedited->toneCurve.hlcompr = hlcompr->getEditedState(); pedited->toneCurve.hlbl = hlbl->getEditedState(); + pedited->toneCurve.hlth = hlth->getEditedState(); pedited->toneCurve.hlcomprthresh = hlcomprthresh->getEditedState(); pedited->toneCurve.shcompr = shcompr->getEditedState(); pedited->toneCurve.brightness = brightness->getEditedState(); @@ -414,7 +425,7 @@ void ToneCurve::write(ProcParams* pp, ParamsEdited* pedited) pedited->toneCurve.curve2 = !shape2->isUnChanged(); pedited->toneCurve.curveMode = toneCurveMode->get_active_row_number() != 6; pedited->toneCurve.curveMode2 = toneCurveMode2->get_active_row_number() != 6; - pedited->toneCurve.method = method->get_active_row_number() != 4; + pedited->toneCurve.method = method->get_active_row_number() != 5; pedited->toneCurve.hrenabled = !hrenabled->get_inconsistent(); pedited->toneCurve.histmatching = !histmatching->get_inconsistent(); pedited->toneCurve.fromHistMatching = true; @@ -428,9 +439,11 @@ void ToneCurve::write(ProcParams* pp, ParamsEdited* pedited) } else if (method->get_active_row_number() == 1) { pp->toneCurve.method = "CIELab blending"; } else if (method->get_active_row_number() == 2) { - pp->toneCurve.method = "Color"; - } else if (method->get_active_row_number() == 3) { pp->toneCurve.method = "Blend"; + } else if (method->get_active_row_number() == 3) { + pp->toneCurve.method = "Color"; + } else if (method->get_active_row_number() == 4) { + pp->toneCurve.method = "Coloropp"; } } @@ -454,15 +467,21 @@ void ToneCurve::hrenabledChanged() if (hrenabled->get_active()) { hlrbox->show(); hlrbox->set_sensitive(true); - if (method->get_active_row_number() == 2) { + if (method->get_active_row_number() == 3) { hlbl->show(); + hlth->hide(); + } else if (method->get_active_row_number() == 4){ + hlbl->hide(); + hlth->show(); } else { hlbl->hide(); - } + hlth->hide(); + } } else { hlrbox->show(); hlrbox->set_sensitive(false); hlbl->hide(); + hlth->hide(); } } @@ -487,11 +506,16 @@ void ToneCurve::hrenabledChanged() void ToneCurve::methodChanged() { - if (method->get_active_row_number() == 2) { + if (method->get_active_row_number() == 3) { hlbl->show(); - } else { + hlth->hide(); + } else if (method->get_active_row_number() == 4){ hlbl->hide(); - } + hlth->show(); + } else { + hlbl->hide(); + hlth->hide(); + } if (listener) { setHistmatching(false); if (hrenabled->get_active()) { @@ -513,6 +537,7 @@ void ToneCurve::setRaw(bool raw) disableListener(); method->set_sensitive(raw); hlbl->set_sensitive(raw); + hlth->set_sensitive(raw); hrenabled->set_sensitive(raw); histmatching->set_sensitive(raw); enableListener(); @@ -526,6 +551,7 @@ void ToneCurve::setDefaults(const ProcParams* defParams, const ParamsEdited* ped black->setDefault(defParams->toneCurve.black); hlcompr->setDefault(defParams->toneCurve.hlcompr); hlbl->setDefault(defParams->toneCurve.hlbl); + hlth->setDefault(defParams->toneCurve.hlth); hlcomprthresh->setDefault(defParams->toneCurve.hlcomprthresh); shcompr->setDefault(defParams->toneCurve.shcompr); contrast->setDefault(defParams->toneCurve.contrast); @@ -536,6 +562,7 @@ void ToneCurve::setDefaults(const ProcParams* defParams, const ParamsEdited* ped black->setDefaultEditedState(pedited->toneCurve.black ? Edited : UnEdited); hlcompr->setDefaultEditedState(pedited->toneCurve.hlcompr ? Edited : UnEdited); hlbl->setDefaultEditedState(pedited->toneCurve.hlbl ? Edited : UnEdited); + hlth->setDefaultEditedState(pedited->toneCurve.hlth ? Edited : UnEdited); hlcomprthresh->setDefaultEditedState(pedited->toneCurve.hlcomprthresh ? Edited : UnEdited); shcompr->setDefaultEditedState(pedited->toneCurve.shcompr ? Edited : UnEdited); brightness->setDefaultEditedState(pedited->toneCurve.brightness ? Edited : UnEdited); @@ -546,6 +573,7 @@ void ToneCurve::setDefaults(const ProcParams* defParams, const ParamsEdited* ped black->setDefaultEditedState(Irrelevant); hlcompr->setDefaultEditedState(Irrelevant); hlbl->setDefaultEditedState(Irrelevant); + hlth->setDefaultEditedState(Irrelevant); hlcomprthresh->setDefaultEditedState(Irrelevant); shcompr->setDefaultEditedState(Irrelevant); brightness->setDefaultEditedState(Irrelevant); @@ -660,6 +688,8 @@ void ToneCurve::adjusterChanged(Adjuster* a, double newval) listener->panelChanged(EvSaturation, costr); } else if (a == hlbl) { listener->panelChanged(EvHLbl, costr); + } else if (a == hlth) { + listener->panelChanged(EvHLth, costr); } else if (a == hlcompr) { listener->panelChanged(EvHLCompr, costr); @@ -695,6 +725,7 @@ void ToneCurve::neutral_pressed() expcomp->setValue(0); hlcompr->setValue(0); hlbl->setValue(0); + hlth->setValue(1.0); hlcomprthresh->setValue(0); brightness->setValue(0); black->setValue(0); @@ -707,6 +738,7 @@ void ToneCurve::neutral_pressed() hlrbox->show(); hlrbox->set_sensitive(false); hlbl->hide(); + hlth->hide(); } if (!black->getAddMode() && !batchMode) { @@ -841,6 +873,7 @@ void ToneCurve::waitForAutoExp() hrenabled->set_sensitive(false); method->set_sensitive(false); hlbl->set_sensitive(false); + hlth->set_sensitive(false); histmatching->set_sensitive(false); } @@ -853,6 +886,7 @@ void ToneCurve::enableAll() black->setEnabled(true); hlcompr->setEnabled(true); hlbl->setEnabled(true); + hlth->setEnabled(true); hlcomprthresh->setEnabled(true); shcompr->setEnabled(true); contrast->setEnabled(true); @@ -864,6 +898,7 @@ void ToneCurve::enableAll() hrenabled->set_sensitive(true); method->set_sensitive(true); hlbl->set_sensitive(true); + hlth->set_sensitive(true); histmatching->set_sensitive(true); } @@ -883,6 +918,7 @@ void ToneCurve::setBatchMode(bool batchMode) black->showEditedCB(); hlcompr->showEditedCB(); hlbl->showEditedCB(); + hlth->showEditedCB(); hlcomprthresh->showEditedCB(); shcompr->showEditedCB(); brightness->showEditedCB(); @@ -996,16 +1032,22 @@ void ToneCurve::autoExpChanged(double expcomp, int bright, int contr, int black, if (nextHLRecons) { hlrbox->show(); hlrbox->set_sensitive(true); - if (method->get_active_row_number() == 2) { + if (method->get_active_row_number() == 3) { hlbl->show(); - } else { + hlth->hide(); + } else if (method->get_active_row_number() == 4){ hlbl->hide(); - } + hlth->show(); + } else { + hlbl->hide(); + hlth->hide(); + } } else if (!batchMode) { hlrbox->show(); hlrbox->set_sensitive(false); hlbl->hide(); - } + hlth->hide(); + } if (!this->black->getAddMode() && !batchMode) { shcompr->set_sensitive(static_cast(this->black->getValue())); //at black=0 shcompr value has no effect diff --git a/rtgui/tonecurve.h b/rtgui/tonecurve.h index 7ba2178ac..7f0f1ef69 100644 --- a/rtgui/tonecurve.h +++ b/rtgui/tonecurve.h @@ -48,6 +48,7 @@ protected: sigc::connection enaconn; bool lasthrEnabled; Adjuster* hlbl; + Adjuster* hlth; Gtk::Box* abox; Gtk::Box* hlrbox; @@ -82,6 +83,7 @@ protected: rtengine::ProcEvent EvHistMatchingBatch; rtengine::ProcEvent EvClampOOG; rtengine::ProcEvent EvHLbl; + rtengine::ProcEvent EvHLth; // used temporarily in eventing double nextExpcomp; From 8047aded3ba4756233be0d4e833e535bdd6293f0 Mon Sep 17 00:00:00 2001 From: "U-PCSPECIALIST01\\jdesm" Date: Thu, 9 Feb 2023 16:15:42 +0100 Subject: [PATCH 107/134] remove BENCHFUN for inpaint-opposed color-propagation Itcwb --- rtengine/hilite_recon.cc | 4 ++-- rtengine/rawimagesource.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rtengine/hilite_recon.cc b/rtengine/hilite_recon.cc index 07d1a7b7b..f573ff015 100644 --- a/rtengine/hilite_recon.cc +++ b/rtengine/hilite_recon.cc @@ -302,7 +302,7 @@ using namespace procparams; void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue, int blur) { - BENCHFUN + //BENCHFUN double progress = 0.0; if (plistener) { @@ -1347,7 +1347,7 @@ void dilating(const int *img, int *o, int w1, int height) void RawImageSource::highlight_recovery_opposed(float scale_mul[3], const ColorTemp &wb, float gainth) { - BENCHFUN + //BENCHFUN if (settings->verbose) { std::cout << "Applying Highlight Recovery: Inpaint opposed" << std::endl; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 7ff9c4d0f..75757d325 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -4716,7 +4716,7 @@ void RawImageSource::ItcWB(bool extra, double &tempref, double &greenref, double 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_nopurple : true default - allow to bypass highlight recovery and inpait opposed when need flowers and not purple due to highlights... */ - BENCHFUN + // BENCHFUN TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix("sRGB"); const float wp[3][3] = { From d5aae723b8adc74d12fd548a5f3bdb0838d94309 Mon Sep 17 00:00:00 2001 From: "U-PCSPECIALIST01\\jdesm" Date: Thu, 16 Feb 2023 11:10:18 +0100 Subject: [PATCH 108/134] Fixed the same Observer for general and Itcwb --- rtengine/colortemp.cc | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/rtengine/colortemp.cc b/rtengine/colortemp.cc index 4ba47b25a..f6e980f2a 100644 --- a/rtengine/colortemp.cc +++ b/rtengine/colortemp.cc @@ -3764,15 +3764,17 @@ void ColorTemp::tempxy(bool separated, int repref, float **Tx, float **Ty, float Refxyz[i].Zref = 0.f; } - if (settings->verbose) { +/* if (settings->verbose) { + 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->itcwb_stdobserver10 == true) ? cie_colour_match_jd : cie_colour_match_jd2; + } +*/ + 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; if (separated) { const double tempw = Txyz[repref].Tem; From 01441ccb4b1ea76105cf9173e608e25e6de09229 Mon Sep 17 00:00:00 2001 From: Matei George-Daniel Date: Sat, 18 Feb 2023 02:55:15 +0200 Subject: [PATCH 109/134] initialize pointer variable with null --- rtengine/improccoordinator.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index cc2d75b3d..9437f1a75 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -163,6 +163,7 @@ ImProcCoordinator::ImProcCoordinator() : imageTypeListener(nullptr), filmNegListener(nullptr), actListener(nullptr), + primListener(nullptr), adnListener(nullptr), awavListener(nullptr), dehaListener(nullptr), From 23408bfcb3117404af376d24bad07e011e8f0fb2 Mon Sep 17 00:00:00 2001 From: "U-PCSPECIALIST01\\jdesm" Date: Thu, 23 Feb 2023 09:18:48 +0100 Subject: [PATCH 110/134] Local adjustments denoise - Removes the need to have luminance denoise curve activates to activate Nlmeans --- rtengine/iplocallab.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 811e941e4..243f3595d 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -8165,7 +8165,7 @@ void ImProcFunctions::calc_ref(int sp, LabImage * original, LabImage * transform deltasobelL = new LabImage(spotSi, spotSi); bool isdenoise = false; - if ((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.wavcurvedenoi || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f) && lp.denoiena) { + if ((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.wavcurvedenoi || lp.nlstr > 0 || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f) && lp.denoiena) { isdenoise = true; } @@ -10891,7 +10891,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl // const int hspot = ye - ys; // const int wspot = xe - xs; - if (((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.nlstr > 0 || lp.wavcurvedenoi || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f + if (((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.nlstr > 0 || lp.wavcurvedenoi || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f || execmaskden || aut == 1 || aut == 2) && lp.denoiena && lp.quamet != 3) || execdenoi) { // sk == 1 ?? StopWatch Stop1("locallab Denoise called"); @@ -13025,7 +13025,6 @@ void ImProcFunctions::NLMeans(float **img, int strength, int detail_thresh, int if(scale > 5.f) {//avoid to small values - leads to crash - but enough to evaluate noise return; } - BENCHFUN const int W = bfw; const int H = bfh; @@ -13666,7 +13665,7 @@ void ImProcFunctions::Lab_Local( //Prepare mask for Blur and noise and Denoise bool denoiz = false; - if ((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.noiselc > 0.f || lp.wavcurvedenoi || lp.noisecf > 0.f || lp.noisecc > 0.f || lp.bilat > 0.f) && lp.denoiena) { + if ((lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.noiselc > 0.f || lp.wavcurvedenoi || lp.nlstr > 0 || lp.noisecf > 0.f || lp.noisecc > 0.f || lp.bilat > 0.f) && lp.denoiena) { denoiz = true; } @@ -14410,7 +14409,7 @@ void ImProcFunctions::Lab_Local( } //local denoise - if (lp.activspot && lp.denoiena && (lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.wavcurvedenoi || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f )) {//disable denoise if not used + if (lp.activspot && lp.denoiena && (lp.noiself > 0.f || lp.noiself0 > 0.f || lp.noiself2 > 0.f || lp.wavcurvedenoi ||lp.nlstr > 0 || lp.noiselc > 0.f || lp.noisecf > 0.f || lp.noisecc > 0.f )) {//disable denoise if not used float slidL[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; float slida[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; float slidb[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}; From fe69ebff6abbb7d5756f909b3d6abf246215cd4c Mon Sep 17 00:00:00 2001 From: Benitoite Date: Sun, 26 Feb 2023 23:13:24 -0800 Subject: [PATCH 111/134] macOS CI pass architecture to cmake for arch variable set by https://github.com/Beep6581/RawTherapee/blob/dev/tools/osx/macosx_bundle.sh#L102 --- .github/workflows/macos.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 11ae28aa4..576440714 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -48,6 +48,7 @@ jobs: -DCACHE_NAME_SUFFIX="${RAW_THERAPEE_MAJOR}.${RAW_THERAPEE_MINOR}-${REF}" \ -DPROC_TARGET_NUMBER="1" \ -DPROC_LABEL="generic processor" \ + -DCMAKE_OSX_ARCHITECTURES=$(uname -m) \ -DWITH_LTO="OFF" \ -DLENSFUNDBDIR="/Applications/RawTherapee.app/Contents/Resources/share/lensfun" \ -DCMAKE_C_COMPILER=clang \ From 0838d77fb94d4297e911ac975b6348115d93067d Mon Sep 17 00:00:00 2001 From: Benitoite Date: Sun, 26 Feb 2023 23:26:50 -0800 Subject: [PATCH 112/134] macOS CI: libomp ruby file is a formula Uses the --formula flag to tell brew the ruby file is a formula so it doesn't issue a red non-fatal error message. --- .github/workflows/macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 576440714..e466787db 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -64,7 +64,7 @@ jobs: -DCMAKE_RANLIB=/usr/bin/ranlib \ -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 \ .. - curl -L https://github.com/Homebrew/homebrew-core/raw/679923b4eb48a8dc7ecc1f05d06063cd79b3fc00/Formula/libomp.rb -o libomp.rb && brew install libomp.rb + curl -L https://github.com/Homebrew/homebrew-core/raw/679923b4eb48a8dc7ecc1f05d06063cd79b3fc00/Formula/libomp.rb -o libomp.rb && brew install --formula libomp.rb zsh -c 'echo "Configured in $(printf "%0.2f" $(($[$(date +%s)-$(cat configstamp)]/$((60.))))) minutes"' - name: Compile RawTherapee run: | From 69397aea097e8cd5f9c65add70925483d12be1ee Mon Sep 17 00:00:00 2001 From: Benitoite Date: Sun, 26 Feb 2023 23:32:20 -0800 Subject: [PATCH 113/134] macOS CI: update two actions to @v3 updates actions for node12->16 requirements. --- .github/workflows/macos.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index e466787db..4a258354a 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -14,7 +14,7 @@ jobs: build: runs-on: macos-11 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install dependencies run: | date -u @@ -92,7 +92,7 @@ jobs: "ARTIFACT_FILE: ${ARTIFACT_FILE}" \ "PUBLISH_NAME: ${PUBLISH_NAME}" exit - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 with: name: ${{env.ARTIFACT_FILE}} path: ${{env.ARTIFACT_PATH}} From c55bc5103fc50bc2499ebc2a7933bbd8eb4b1495 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Mon, 27 Feb 2023 12:49:26 -0800 Subject: [PATCH 114/134] macOS: mute tput warnings tput warns you when running with no attached terminal; eg. GitHub CI. Redirects warnings to /dev/null --- tools/osx/macosx_bundle.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index 26b8b4d08..9de3a7a5f 100644 --- a/tools/osx/macosx_bundle.sh +++ b/tools/osx/macosx_bundle.sh @@ -9,11 +9,11 @@ # - GTK_PREFIX # Formatting -fNormal="$(tput sgr0)" -fBold="$(tput bold)" +fNormal="$(tput sgr0)" >/dev/null 2>&1 +fBold="$(tput bold)" >/dev/null 2>&1 # Colors depend upon the user's terminal emulator color scheme - what is readable for you may be not readable for someone else. -fMagenta="$(tput setaf 5)" -fRed="$(tput setaf 1)" +fMagenta="$(tput setaf 5)" >/dev/null 2>&1 +fRed="$(tput setaf 1)" >/dev/null 2>&1 function msg { printf "\\n${fBold}-- %s${fNormal}\\n" "${@}" From 4d794d6bbb0c4cd258187a14971021c78f75a596 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Mon, 27 Feb 2023 17:50:10 -0800 Subject: [PATCH 115/134] macOS: set the 'latest' artifact Uses a generically-named nightly instead of name-tagged with commit hash. --- .github/workflows/macos.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 4a258354a..7d3e0cbfd 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -62,7 +62,8 @@ jobs: -DOpenMP_libomp_LIBRARY=/usr/local/lib/libomp.dylib \ -DCMAKE_AR=/usr/bin/ar \ -DCMAKE_RANLIB=/usr/bin/ranlib \ - -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \ + -DOSX_NIGHTLY=ON \ .. curl -L https://github.com/Homebrew/homebrew-core/raw/679923b4eb48a8dc7ecc1f05d06063cd79b3fc00/Formula/libomp.rb -o libomp.rb && brew install --formula libomp.rb zsh -c 'echo "Configured in $(printf "%0.2f" $(($[$(date +%s)-$(cat configstamp)]/$((60.))))) minutes"' @@ -78,7 +79,7 @@ jobs: zsh date +%s > build/bundlestamp && date -u && cd build export REF=${GITHUB_REF##*/} && export LOCAL_PREFIX=/usr && sudo make macosx_bundle - export ARTIFACT=(RawTherapee*.zip) + export ARTIFACT=(RawTherapee*latest.zip) echo "=== artifact: ${ARTIFACT}" # defining environment variables for next step as per # https://github.com/actions/starter-workflows/issues/68 From d89ed3b5957140f797cb2700b9bc6810aa4dd2e2 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Mon, 27 Feb 2023 19:46:25 -0800 Subject: [PATCH 116/134] mac: remove obsolete patch --- tools/osx/libiconv_1.16_rt.patch | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 tools/osx/libiconv_1.16_rt.patch diff --git a/tools/osx/libiconv_1.16_rt.patch b/tools/osx/libiconv_1.16_rt.patch deleted file mode 100644 index 470f7780c..000000000 --- a/tools/osx/libiconv_1.16_rt.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff --git a/lib/iconv.c b/lib/iconv.c -index b7a04f8..41c5896 100644 ---- a/lib/iconv.c -+++ b/lib/iconv.c -@@ -610,5 +610,26 @@ strong_alias (libiconv_open, iconv_open) - strong_alias (libiconv, iconv) - strong_alias (libiconv_close, iconv_close) - #endif -+ -+#undef iconv_open -+#undef iconv -+#undef iconv_close -+ -+LIBICONV_DLL_EXPORTED iconv_t iconv_open (const char* tocode, const char* fromcode) -+{ -+ return libiconv_open(tocode, fromcode); -+} -+ -+LIBICONV_DLL_EXPORTED size_t iconv (iconv_t icd, -+ ICONV_CONST char * * inbuf, size_t *inbytesleft, -+ char * * outbuf, size_t *outbytesleft) -+{ -+ return libiconv(icd, inbuf, inbytesleft, outbuf, outbytesleft); -+} -+ -+LIBICONV_DLL_EXPORTED int iconv_close (iconv_t icd) -+{ -+ return libiconv_close(icd); -+} - - #endif From 0d6733973865983d5c4c30333291dd820324e683 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Mon, 27 Feb 2023 20:59:45 -0800 Subject: [PATCH 117/134] macOS: altool --notarize -> notarytool Updates notary script to use `xcrun notarytool` per Apple deprecation notices. --- tools/osx/macosx_bundle.sh | 45 ++------------------------------------ 1 file changed, 2 insertions(+), 43 deletions(-) diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index 9de3a7a5f..87b318bf0 100644 --- a/tools/osx/macosx_bundle.sh +++ b/tools/osx/macosx_bundle.sh @@ -370,27 +370,7 @@ if [[ -n $NOTARY ]]; then msg "Notarizing the application:" ditto -c -k --sequesterRsrc --keepParent "${APP}" "${APP}.zip" echo "Uploading..." - uuid=`xcrun altool --notarize-app --primary-bundle-id "com.rawtherapee.RawTherapee" ${NOTARY} --file "${APP}.zip" 2>&1 | grep 'RequestUUID' | awk '{ print $3 }'` - echo "Result= $uuid" # Display identifier string - sleep 15 - while : - do - fullstatus=`xcrun altool --notarization-info "$uuid" ${NOTARY} 2>&1` # get the status - status1=`echo "$fullstatus" | grep 'Status\:' | awk '{ print $2 }'` - if [[ $status1 = "success" ]]; then - xcrun stapler staple *app # staple the ticket - xcrun stapler validate -v *app - echo "Notarization success" - break - elif [[ $status1 = "in" ]]; then - echo "Notarization still in progress, sleeping for 15 seconds and trying again" - sleep 15 - else - echo "Notarization failed fullstatus below" - echo "$fullstatus" - exit 1 - fi - done + sudo xcrun notarytool submit "${APP}.zip" ${NOTARY} --wait fi function CreateDmg { @@ -452,28 +432,7 @@ function CreateDmg { msg "Notarizing the dmg:" zip "${dmg_name}.dmg.zip" "${dmg_name}.dmg" echo "Uploading..." - uuid=$(xcrun altool --notarize-app --primary-bundle-id "com.rawtherapee" ${NOTARY} --file "${dmg_name}.dmg.zip" 2>&1 | grep 'RequestUUID' | awk '{ print $3 }') - echo "dmg Result= ${uuid}" # Display identifier string - sleep 15 - while : - do - fullstatus=`xcrun altool --notarization-info "$uuid" ${NOTARY} 2>&1` # get the status - status1=`echo "$fullstatus" | grep 'Status\:' | awk '{ print $2 }'` - if [[ $status1 = "success" ]]; then - xcrun stapler staple "${dmg_name}.dmg" # staple the ticket - xcrun stapler validate -v "${dmg_name}.dmg" - echo "dmg Notarization success" - rm *dmg.zip - break - elif [[ $status1 = "in" ]]; then - echo "dmg Notarization still in progress, sleeping for 15 seconds and trying again" - sleep 15 - else - echo "dmg Notarization failed fullstatus below" - echo "$fullstatus" - exit 1 - fi - done + sudo xcrun notarytool submit "${dmg_name}.dmg.zip" ${NOTARY} --wait fi # Zip disk image for redistribution From 74d6762f790e2a5d46d7788e05d4f267ffced820 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Mon, 27 Feb 2023 21:04:46 -0800 Subject: [PATCH 118/134] macOS: show new notarytool format of notary string --- tools/osx/macosx_bundle.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index 87b318bf0..1bfe6986d 100644 --- a/tools/osx/macosx_bundle.sh +++ b/tools/osx/macosx_bundle.sh @@ -135,8 +135,8 @@ EXPATLIB="$(cmake .. -LA -N | grep pkgcfg_lib_EXPAT_expat)"; pkgcfg_lib_EXPAT_ex #Out: Developer ID Application: Doctor Who (1234567890) CODESIGNID="$(cmake .. -L -N | grep CODESIGNID)"; CODESIGNID="${CODESIGNID#*=}" -#In: NOTARY:STRING=--username drwho@bbc.com --password abcd-efgh-hijk-lmno -#Out: --username drwho@bbc.com --password abcd-efgh-hijk-lmno +#In: NOTARY:STRING="--apple-id drwho@bbc.com --password abcd-efgh-hijk-lmno --team-id ABCDE12345" +#Out: --apple-id drwho@bbc.com --password abcd-efgh-hijk-lmno --team-id ABCDE12345 NOTARY="$(cmake .. -L -N | grep NOTARY)"; NOTARY="${NOTARY#*=}" # In: FANCY_DMG:BOOL=ON From 3fe30277bf2022f785453d0a5593d5adfee131d6 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Mon, 27 Feb 2023 21:14:10 -0800 Subject: [PATCH 119/134] macOS: fixes a few packaging warnings and tries not forcing a non-system z or expat into Frameworks. --- tools/osx/macosx_bundle.sh | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index 1bfe6986d..a43a1814c 100644 --- a/tools/osx/macosx_bundle.sh +++ b/tools/osx/macosx_bundle.sh @@ -201,7 +201,7 @@ else fi # Copy libomp to Frameworks -ditto ${LOCAL_PREFIX}/lib/libomp.dylib "${CONTENTS}/Frameworks" +cp ${LOCAL_PREFIX}/lib/libomp.dylib "${CONTENTS}/Frameworks" msg "Copying dependencies from ${GTK_PREFIX}." CheckLink "${EXECUTABLE}" 2>&1 @@ -209,24 +209,20 @@ CheckLink "${EXECUTABLE}" 2>&1 # dylib install names ModifyInstallNames 2>&1 -# Copy libjpeg-turbo ("62") into the app bundle -ditto ${LOCAL_PREFIX}/lib/libjpeg.62.dylib "${CONTENTS}/Frameworks/libjpeg.62.dylib" +## Copy libexpat into the app bundle (which is keg-only) +## if [[ -d /usr/local/Cellar/expat ]]; then ditto /usr/local/Cellar/expat/*/lib/libexpat.1.dylib "${CONTENTS}/Frameworks"; else cp "${EXPATLIB}" "${CONTENTS}/Frameworks/libexpat.1.dylib"; fi -# Copy libexpat into the app bundle (which is keg-only) -if [[ -d /usr/local/Cellar/expat ]]; then ditto /usr/local/Cellar/expat/*/lib/libexpat.1.dylib "${CONTENTS}/Frameworks"; else ditto "${EXPATLIB}" "${CONTENTS}/Frameworks/libexpat.1.dylib"; fi +## Copy libz into the app bundle +## cp ${LOCAL_PREFIX}/lib/libz.1.dylib "${CONTENTS}/Frameworks" -# Copy libz into the app bundle -ditto ${LOCAL_PREFIX}/lib/libz.1.dylib "${CONTENTS}/Frameworks" - -# Copy libpng12 & 16 to the app bundle -ditto ${LOCAL_PREFIX}/lib/libpng16.16.dylib "${CONTENTS}/Frameworks/libpng16.16.dylib" -ditto ${LOCAL_PREFIX}/lib/libpng12.0.dylib "${CONTENTS}/Frameworks/libpng12.0.dylib" +# Copy libpng16 to the app bundle +cp ${LOCAL_PREFIX}/lib/libpng16.16.dylib "${CONTENTS}/Frameworks/libpng16.16.dylib" # Copy libtiff 5 into the app bundle -ditto ${LOCAL_PREFIX}/lib/libtiff.5.dylib "${CONTENTS}/Frameworks/libtiff.5.dylib" +cp ${LOCAL_PREFIX}/lib/libtiff.5.dylib "${CONTENTS}/Frameworks/libtiff.5.dylib" # Copy libomp to Frameworks -ditto ${LOCAL_PREFIX}/lib/libomp.dylib "${CONTENTS}/Frameworks" +cp ${LOCAL_PREFIX}/lib/libomp.dylib "${CONTENTS}/Frameworks" # Prepare GTK+3 installation msg "Copying configuration files from ${GTK_PREFIX}:" @@ -240,7 +236,7 @@ find -E "${LIB}" -type f -regex '.*\.(a|la|cache)$' | while read -r; do rm "${RE # Make Frameworks folder flat msg "Flattening the Frameworks folder" cp -RL "${LIB}"/gdk-pixbuf-2.0/2*/loaders/* "${LIB}" -cp "${LIB}"/gtk-3.0/3*/immodules/*.{dylib,so} "${LIB}" +cp "${LIB}"/gtk-3.0/3*/immodules/*.{dylib,so} "${LIB}" >/dev/null 2>&1 rm -r "${LIB}"/gtk-3.0 rm -r "${LIB}"/gdk-pixbuf-2.0 From a07c38f4054957c7f43b70708ae6feaa6d2020aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Wed, 1 Mar 2023 12:47:55 +0100 Subject: [PATCH 120/134] Support for saving TIFFs as BigTIFF (#6690) --- rtdata/languages/default | 1 + rtengine/iimage.h | 8 +++++- rtengine/image16.h | 2 +- rtengine/image8.h | 10 +++++-- rtengine/imagefloat.h | 10 +++++-- rtengine/imageio.cc | 61 +++++++++++++++++++++++++++------------- rtengine/imageio.h | 8 +++++- rtgui/batchqueue.cc | 11 +++++++- rtgui/batchqueueentry.cc | 3 ++ rtgui/editorpanel.cc | 6 ++-- rtgui/options.cc | 6 ++++ rtgui/options.h | 4 +++ rtgui/saveformatpanel.cc | 12 ++++++++ rtgui/saveformatpanel.h | 1 + 14 files changed, 113 insertions(+), 30 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 84b28c955..bda477f14 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2061,6 +2061,7 @@ SAMPLEFORMAT_16;16-bit floating-point SAMPLEFORMAT_32;24-bit floating-point SAMPLEFORMAT_64;32-bit floating-point SAVEDLG_AUTOSUFFIX;Automatically add a suffix if the file already exists +SAVEDLG_BIGTIFF;BigTIFF SAVEDLG_FILEFORMAT;File format SAVEDLG_FILEFORMAT_FLOAT; floating-point SAVEDLG_FORCEFORMATOPTS;Force saving options diff --git a/rtengine/iimage.h b/rtengine/iimage.h index a544b454a..cdb7dd6eb 100644 --- a/rtengine/iimage.h +++ b/rtengine/iimage.h @@ -1882,7 +1882,13 @@ public: * @param bps can be 8 or 16 depending on the bits per pixels the output file will have * @param isFloat is true for saving float images. Will be ignored by file format not supporting float data @return the error code, 0 if none */ - virtual int saveAsTIFF (const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const = 0; + virtual int saveAsTIFF ( + const Glib::ustring &fname, + int bps = -1, + bool isFloat = false, + bool uncompressed = false, + bool big = false + ) const = 0; /** @brief Sets the progress listener if you want to follow the progress of the image saving operations (optional). * @param pl is the pointer to the class implementing the ProgressListener interface */ virtual void setSaveProgressListener (ProgressListener* pl) = 0; diff --git a/rtengine/image16.h b/rtengine/image16.h index 25b777832..273ae63a1 100644 --- a/rtengine/image16.h +++ b/rtengine/image16.h @@ -81,7 +81,7 @@ public: return saveJPEG(fname, quality, subSamp); } - int saveAsTIFF(const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const override + int saveAsTIFF(const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false, bool big = false) const override { return saveTIFF(fname, bps, isFloat, uncompressed); } diff --git a/rtengine/image8.h b/rtengine/image8.h index 76a580bb6..416dc9143 100644 --- a/rtengine/image8.h +++ b/rtengine/image8.h @@ -79,9 +79,15 @@ public: return saveJPEG (fname, quality, subSamp); } - int saveAsTIFF (const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const override + int saveAsTIFF ( + const Glib::ustring &fname, + int bps = -1, + bool isFloat = false, + bool uncompressed = false, + bool big = false + ) const override { - return saveTIFF (fname, bps, isFloat, uncompressed); + return saveTIFF (fname, bps, isFloat, uncompressed, big); } void setSaveProgressListener (ProgressListener* pl) override diff --git a/rtengine/imagefloat.h b/rtengine/imagefloat.h index fc3ba318d..d69df9325 100644 --- a/rtengine/imagefloat.h +++ b/rtengine/imagefloat.h @@ -82,9 +82,15 @@ public: { return saveJPEG (fname, quality, subSamp); } - int saveAsTIFF (const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const override + int saveAsTIFF ( + const Glib::ustring &fname, + int bps = -1, + bool isFloat = false, + bool uncompressed = false, + bool big = false + ) const override { - return saveTIFF (fname, bps, isFloat, uncompressed); + return saveTIFF (fname, bps, isFloat, uncompressed, big); } void setSaveProgressListener (ProgressListener* pl) override { diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index ce44d1ff4..573a391aa 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -17,21 +17,17 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include -#include -#include -#include #include #include -#include -#include #include -#include "rt_math.h" -#include "procparams.h" -#include "utils.h" -#include "../rtgui/options.h" -#include "../rtgui/version.h" -#include "../rtexif/rtexif.h" +#include + +#include +#include +#include +#include +#include +#include #ifdef WIN32 #include @@ -39,12 +35,20 @@ #include #endif +#include "color.h" +#include "iccjpeg.h" #include "imageio.h" #include "iptcpairs.h" -#include "iccjpeg.h" -#include "color.h" - #include "jpeg.h" +#include "procparams.h" +#include "rt_math.h" +#include "utils.h" + +#include "../rtgui/options.h" +#include "../rtgui/version.h" + +#include "../rtexif/rtexif.h" + using namespace std; using namespace rtengine; @@ -1328,7 +1332,13 @@ int ImageIO::saveJPEG (const Glib::ustring &fname, int quality, int subSamp) con return IMIO_SUCCESS; } -int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool uncompressed) const +int ImageIO::saveTIFF ( + const Glib::ustring &fname, + int bps, + bool isFloat, + bool uncompressed, + bool big +) const { if (getWidth() < 1 || getHeight() < 1) { return IMIO_HEADERERROR; @@ -1345,15 +1355,28 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u int lineWidth = width * 3 * bps / 8; unsigned char* linebuffer = new unsigned char[lineWidth]; + std::string mode = "w"; + // little hack to get libTiff to use proper byte order (see TIFFClienOpen()): - const char *mode = !exifRoot ? "w" : (exifRoot->getOrder() == rtexif::INTEL ? "wl" : "wb"); + if (exifRoot) { + if (exifRoot->getOrder() == rtexif::INTEL) { + mode += 'l'; + } else { + mode += 'b'; + } + } + + if (big) { + mode += '8'; + } + #ifdef WIN32 FILE *file = g_fopen_withBinaryAndLock (fname); int fileno = _fileno(file); int osfileno = _get_osfhandle(fileno); - TIFF* out = TIFFFdOpen (osfileno, fname.c_str(), mode); + TIFF* out = TIFFFdOpen (osfileno, fname.c_str(), mode.c_str()); #else - TIFF* out = TIFFOpen(fname.c_str(), mode); + TIFF* out = TIFFOpen(fname.c_str(), mode.c_str()); int fileno = TIFFFileno (out); #endif diff --git a/rtengine/imageio.h b/rtengine/imageio.h index 566fef13b..e900feccd 100644 --- a/rtengine/imageio.h +++ b/rtengine/imageio.h @@ -113,7 +113,13 @@ public: int savePNG (const Glib::ustring &fname, int bps = -1) const; int saveJPEG (const Glib::ustring &fname, int quality = 100, int subSamp = 3) const; - int saveTIFF (const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const; + int saveTIFF ( + const Glib::ustring &fname, + int bps = -1, + bool isFloat = false, + bool uncompressed = false, + bool big = false + ) const; cmsHPROFILE getEmbeddedProfile () const; void getEmbeddedProfileData (int& length, unsigned char*& pdata) const; diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 19da96fb5..4e25475f0 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -264,6 +264,7 @@ bool BatchQueue::saveBatchQueue () << saveFormat.tiffBits << '|' << (saveFormat.tiffFloat ? 1 : 0) << '|' << saveFormat.tiffUncompressed << '|' << saveFormat.saveParams << '|' << entry->forceFormatOpts << '|' << entry->fast_pipeline << '|' + << saveFormat.bigTiff << '|' << std::endl; } } @@ -331,6 +332,7 @@ bool BatchQueue::loadBatchQueue () const auto saveParams = nextIntOr (options.saveFormat.saveParams); const auto forceFormatOpts = nextIntOr (options.forceFormatOpts); const auto fast = nextIntOr(false); + const auto bigTiff = nextIntOr (options.saveFormat.bigTiff); rtengine::procparams::ProcParams pparams; @@ -370,6 +372,7 @@ bool BatchQueue::loadBatchQueue () saveFormat.tiffBits = tiffBits; saveFormat.tiffFloat = tiffFloat == 1; saveFormat.tiffUncompressed = tiffUncompressed != 0; + saveFormat.bigTiff = bigTiff != 0; saveFormat.saveParams = saveParams != 0; entry->forceFormatOpts = forceFormatOpts != 0; } else { @@ -693,7 +696,13 @@ rtengine::ProcessingJob* BatchQueue::imageReady(rtengine::IImagefloat* img) int err = 0; if (saveFormat.format == "tif") { - err = img->saveAsTIFF (fname, saveFormat.tiffBits, saveFormat.tiffFloat, saveFormat.tiffUncompressed); + err = img->saveAsTIFF ( + fname, + saveFormat.tiffBits, + saveFormat.tiffFloat, + saveFormat.tiffUncompressed, + saveFormat.bigTiff + ); } else if (saveFormat.format == "png") { err = img->saveAsPNG (fname, saveFormat.pngBits); } else if (saveFormat.format == "jpg") { diff --git a/rtgui/batchqueueentry.cc b/rtgui/batchqueueentry.cc index 9fe4dd605..7499fb63b 100644 --- a/rtgui/batchqueueentry.cc +++ b/rtgui/batchqueueentry.cc @@ -201,6 +201,9 @@ std::tuple BatchQueueEntry::getToolTip (int x, int y) const if (saveFormat.tiffUncompressed) { tooltip += Glib::ustring::compose("\n%1", M("SAVEDLG_TIFFUNCOMPRESSED")); } + if (saveFormat.bigTiff) { + tooltip += Glib::ustring::compose("\n%1", M("SAVEDLG_BIGTIFF")); + } } } } diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 95808d4b0..ffe13fea3 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2013,7 +2013,7 @@ bool EditorPanel::idle_saveImage (ProgressConnector *pc, img->setSaveProgressListener (parent->getProgressListener()); if (sf.format == "tif") - ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fname, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed), + ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fname, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed, sf.bigTiff), sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams)); else if (sf.format == "png") ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsPNG), fname, sf.pngBits), @@ -2270,7 +2270,7 @@ bool EditorPanel::saveImmediately (const Glib::ustring &filename, const SaveForm if (gimpPlugin) { err = img->saveAsTIFF (filename, 32, true, true); } else if (sf.format == "tif") { - err = img->saveAsTIFF (filename, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed); + err = img->saveAsTIFF (filename, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed, sf.bigTiff); } else if (sf.format == "png") { err = img->saveAsPNG (filename, sf.pngBits); } else if (sf.format == "jpg") { @@ -2380,7 +2380,7 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector *p ProgressConnector *ld = new ProgressConnector(); img->setSaveProgressListener (parent->getProgressListener()); - ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fileName, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed), + ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fileName, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed, sf.bigTiff), sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_sentToGimp), ld, img, fileName)); } else { Glib::ustring msg_ = Glib::ustring (" Error during image processing\n"); diff --git a/rtgui/options.cc b/rtgui/options.cc index 66b9e92a1..e230dcf8a 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -313,6 +313,7 @@ void Options::setDefaults() saveFormat.tiffBits = 16; saveFormat.tiffFloat = false; saveFormat.tiffUncompressed = true; + saveFormat.bigTiff = false; saveFormat.saveParams = true; saveFormatBatch.format = "jpg"; @@ -1046,6 +1047,10 @@ void Options::readFromFile(Glib::ustring fname) saveFormat.tiffUncompressed = keyFile.get_boolean("Output", "TiffUncompressed"); } + if (keyFile.has_key("Output", "BigTiff")) { + saveFormat.bigTiff = keyFile.get_boolean("Output", "BigTiff"); + } + if (keyFile.has_key("Output", "SaveProcParams")) { saveFormat.saveParams = keyFile.get_boolean("Output", "SaveProcParams"); } @@ -2447,6 +2452,7 @@ void Options::saveToFile(Glib::ustring fname) keyFile.set_integer("Output", "TiffBps", saveFormat.tiffBits); keyFile.set_boolean("Output", "TiffFloat", saveFormat.tiffFloat); keyFile.set_boolean("Output", "TiffUncompressed", saveFormat.tiffUncompressed); + keyFile.set_boolean("Output", "BigTiff", saveFormat.bigTiff); keyFile.set_boolean("Output", "SaveProcParams", saveFormat.saveParams); keyFile.set_string("Output", "FormatBatch", saveFormatBatch.format); diff --git a/rtgui/options.h b/rtgui/options.h index 286c64df0..5fb4e4f8b 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -72,6 +72,7 @@ struct SaveFormat { int _tiff_bits, bool _tiff_float, bool _tiff_uncompressed, + bool _big_tiff, bool _save_params ) : format(_format), @@ -81,6 +82,7 @@ struct SaveFormat { tiffBits(_tiff_bits), tiffFloat(_tiff_float), tiffUncompressed(_tiff_uncompressed), + bigTiff(_big_tiff), saveParams(_save_params) { } @@ -98,6 +100,7 @@ struct SaveFormat { _tiff_bits, _tiff_float, true, + false, true ) { @@ -114,6 +117,7 @@ struct SaveFormat { int tiffBits; bool tiffFloat; bool tiffUncompressed; + bool bigTiff; bool saveParams; }; diff --git a/rtgui/saveformatpanel.cc b/rtgui/saveformatpanel.cc index 00f6e7b2b..773ee9105 100644 --- a/rtgui/saveformatpanel.cc +++ b/rtgui/saveformatpanel.cc @@ -100,6 +100,11 @@ SaveFormatPanel::SaveFormatPanel () : listener (nullptr) tiffUncompressed->signal_toggled().connect( sigc::mem_fun(*this, &SaveFormatPanel::formatChanged)); tiffUncompressed->show_all(); + bigTiff = new Gtk::CheckButton (M("SAVEDLG_BIGTIFF")); + setExpandAlignProperties(bigTiff, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); + bigTiff->signal_toggled().connect( sigc::mem_fun(*this, &SaveFormatPanel::formatChanged)); + bigTiff->show_all(); + // --------------------- MAIN BOX @@ -114,12 +119,14 @@ SaveFormatPanel::SaveFormatPanel () : listener (nullptr) attach (*hb1, 0, 0, 1, 1); attach (*jpegOpts, 0, 1, 1, 1); attach (*tiffUncompressed, 0, 2, 1, 1); + attach (*bigTiff, 0, 3, 1, 1); attach (*savesPP, 0, 4, 1, 2); } SaveFormatPanel::~SaveFormatPanel () { delete jpegQual; delete tiffUncompressed; + delete bigTiff; } void SaveFormatPanel::init (SaveFormat &sf) @@ -158,6 +165,7 @@ void SaveFormatPanel::init (SaveFormat &sf) jpegQual->setValue(sf.jpegQuality); savesPP->set_active(sf.saveParams); tiffUncompressed->set_active(sf.tiffUncompressed); + bigTiff->set_active(sf.bigTiff); listener = tmp; } @@ -175,6 +183,7 @@ SaveFormat SaveFormatPanel::getFormat () sf.jpegQuality = jpegQual->getValue(); sf.jpegSubSamp = jpegSubSamp->get_active_row_number() + 1; sf.tiffUncompressed = tiffUncompressed->get_active(); + sf.bigTiff = bigTiff->get_active(); sf.saveParams = savesPP->get_active(); return sf; @@ -193,12 +202,15 @@ void SaveFormatPanel::formatChanged () if (fr == "jpg") { jpegOpts->show_all(); tiffUncompressed->hide(); + bigTiff->hide(); } else if (fr == "png") { jpegOpts->hide(); tiffUncompressed->hide(); + bigTiff->hide(); } else if (fr == "tif") { jpegOpts->hide(); tiffUncompressed->show_all(); + bigTiff->show_all(); } if (listener) { diff --git a/rtgui/saveformatpanel.h b/rtgui/saveformatpanel.h index af9baa58a..9d9f6266e 100644 --- a/rtgui/saveformatpanel.h +++ b/rtgui/saveformatpanel.h @@ -39,6 +39,7 @@ class SaveFormatPanel : public Gtk::Grid, public AdjusterListener, public rtengi protected: Adjuster* jpegQual; Gtk::CheckButton* tiffUncompressed; + Gtk::CheckButton* bigTiff; MyComboBoxText* format; MyComboBoxText* jpegSubSamp; Gtk::Grid* formatOpts; From 8f6d4f31c53cbb51e7aff0dce0763bdb34384b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Thu, 2 Mar 2023 09:17:01 +0100 Subject: [PATCH 121/134] Consistently use `Gtk::manage()` in `SaveFormatPanel` --- rtgui/saveformatpanel.cc | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/rtgui/saveformatpanel.cc b/rtgui/saveformatpanel.cc index 773ee9105..d9b04e8fe 100644 --- a/rtgui/saveformatpanel.cc +++ b/rtgui/saveformatpanel.cc @@ -71,7 +71,7 @@ SaveFormatPanel::SaveFormatPanel () : listener (nullptr) jpegOpts->set_row_spacing(5); setExpandAlignProperties(jpegOpts, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); - jpegQual = new Adjuster (M("SAVEDLG_JPEGQUAL"), 0, 100, 1, 100); + jpegQual = Gtk::manage (new Adjuster (M("SAVEDLG_JPEGQUAL"), 0, 100, 1, 100) ); setExpandAlignProperties(jpegQual, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); jpegQual->setAdjusterListener (this); @@ -95,12 +95,12 @@ SaveFormatPanel::SaveFormatPanel () : listener (nullptr) // --------------------- TIFF OPTIONS - tiffUncompressed = new Gtk::CheckButton (M("SAVEDLG_TIFFUNCOMPRESSED")); + tiffUncompressed = Gtk::manage (new Gtk::CheckButton (M("SAVEDLG_TIFFUNCOMPRESSED")) ); setExpandAlignProperties(tiffUncompressed, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); tiffUncompressed->signal_toggled().connect( sigc::mem_fun(*this, &SaveFormatPanel::formatChanged)); tiffUncompressed->show_all(); - bigTiff = new Gtk::CheckButton (M("SAVEDLG_BIGTIFF")); + bigTiff = Gtk::manage (new Gtk::CheckButton (M("SAVEDLG_BIGTIFF")) ); setExpandAlignProperties(bigTiff, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER); bigTiff->signal_toggled().connect( sigc::mem_fun(*this, &SaveFormatPanel::formatChanged)); bigTiff->show_all(); @@ -122,12 +122,8 @@ SaveFormatPanel::SaveFormatPanel () : listener (nullptr) attach (*bigTiff, 0, 3, 1, 1); attach (*savesPP, 0, 4, 1, 2); } -SaveFormatPanel::~SaveFormatPanel () -{ - delete jpegQual; - delete tiffUncompressed; - delete bigTiff; -} + +SaveFormatPanel::~SaveFormatPanel () = default; void SaveFormatPanel::init (SaveFormat &sf) { From 8587fe068db6854b7ebd3c17ec26de49cf9bd1ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Fri, 3 Mar 2023 08:57:08 +0100 Subject: [PATCH 122/134] Don't perform EXIF hack on BigTIFF --- rtdata/languages/default | 2 +- rtengine/imageio.cc | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index bda477f14..10d0a89c3 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2061,7 +2061,7 @@ SAMPLEFORMAT_16;16-bit floating-point SAMPLEFORMAT_32;24-bit floating-point SAMPLEFORMAT_64;32-bit floating-point SAVEDLG_AUTOSUFFIX;Automatically add a suffix if the file already exists -SAVEDLG_BIGTIFF;BigTIFF +SAVEDLG_BIGTIFF;BigTIFF (no metadata support) SAVEDLG_FILEFORMAT;File format SAVEDLG_FILEFORMAT_FLOAT; floating-point SAVEDLG_FORCEFORMATOPTS;Force saving options diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 573a391aa..7b3513051 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -1392,7 +1392,7 @@ int ImageIO::saveTIFF ( bool applyExifPatch = false; - if (exifRoot) { + if (exifRoot && !big) { rtexif::TagDirectory* cl = (const_cast (exifRoot))->clone (nullptr); // ------------------ remove some unknown top level tags which produce warnings when opening a tiff (might be useless) ----------------- @@ -1475,10 +1475,11 @@ int ImageIO::saveTIFF ( } #if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ - bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::MOTOROLA; + bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::MOTOROLA; #else - bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::INTEL; + bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::INTEL; #endif + if (iptcdata) { rtexif::Tag iptcTag(nullptr, rtexif::lookupAttrib (rtexif::ifdAttribs, "IPTCData")); iptcTag.initLongArray((char*)iptcdata, iptclen); From e2311cc3daf12891d0f5479b8099575466e7ed83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Fri, 3 Mar 2023 09:17:12 +0100 Subject: [PATCH 123/134] Some minor improvements to `ImageIO::saveTIFF()` --- rtengine/imageio.cc | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc index 7b3513051..ad230bb7d 100644 --- a/rtengine/imageio.cc +++ b/rtengine/imageio.cc @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -1352,8 +1354,8 @@ int ImageIO::saveTIFF ( bps = getBPS (); } - int lineWidth = width * 3 * bps / 8; - unsigned char* linebuffer = new unsigned char[lineWidth]; + int lineWidth = width * 3 * (bps / 8); + std::vector linebuffer(lineWidth); std::string mode = "w"; @@ -1381,7 +1383,6 @@ int ImageIO::saveTIFF ( #endif if (!out) { - delete [] linebuffer; return IMIO_CANNOTWRITEFILE; } @@ -1485,15 +1486,9 @@ int ImageIO::saveTIFF ( iptcTag.initLongArray((char*)iptcdata, iptclen); if (needsReverse) { unsigned char *ptr = iptcTag.getValue(); - for (int a = 0; a < iptcTag.getCount(); ++a) { - unsigned char cc; - cc = ptr[3]; - ptr[3] = ptr[0]; - ptr[0] = cc; - cc = ptr[2]; - ptr[2] = ptr[1]; - ptr[1] = cc; - ptr += 4; + for (int a = 0; a < iptcTag.getCount(); ++a, ptr += 4) { + std::swap(ptr[0], ptr[3]); + std::swap(ptr[1], ptr[2]); } } TIFFSetField (out, TIFFTAG_RICHTIFFIPTC, iptcTag.getCount(), (long*)iptcTag.getValue()); @@ -1533,32 +1528,25 @@ int ImageIO::saveTIFF ( } for (int row = 0; row < height; row++) { - getScanline (row, linebuffer, bps, isFloat); + getScanline (row, linebuffer.data(), bps, isFloat); if (bps == 16) { if(needsReverse && !uncompressed && isFloat) { for(int i = 0; i < lineWidth; i += 2) { - char temp = linebuffer[i]; - linebuffer[i] = linebuffer[i + 1]; - linebuffer[i + 1] = temp; + std::swap(linebuffer[i], linebuffer[i + 1]); } } } else if (bps == 32) { if(needsReverse && !uncompressed) { for(int i = 0; i < lineWidth; i += 4) { - char temp = linebuffer[i]; - linebuffer[i] = linebuffer[i + 3]; - linebuffer[i + 3] = temp; - temp = linebuffer[i + 1]; - linebuffer[i + 1] = linebuffer[i + 2]; - linebuffer[i + 2] = temp; + std::swap(linebuffer[i], linebuffer[i + 3]); + std::swap(linebuffer[i + 1], linebuffer[i + 2]); } } } - if (TIFFWriteScanline (out, linebuffer, row, 0) < 0) { + if (TIFFWriteScanline (out, linebuffer.data(), row, 0) < 0) { TIFFClose (out); - delete [] linebuffer; return IMIO_CANNOTWRITEFILE; } @@ -1608,8 +1596,6 @@ int ImageIO::saveTIFF ( fclose (file); #endif - delete [] linebuffer; - if (pl) { pl->setProgressStr ("PROGRESSBAR_READY"); pl->setProgress (1.0); From f2b0301be281c621ae036268d9bf02da1b74ad8c Mon Sep 17 00:00:00 2001 From: Beep6581 Date: Fri, 3 Mar 2023 14:30:34 +0100 Subject: [PATCH 124/134] Update README.md The RawTherapee logo shown in GitHub now depends on the user's GitHub color scheme - black text when light, white text when dark. --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 21f219a83..64f4d08aa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ -![RawTherapee logo](https://raw.githubusercontent.com/Beep6581/RawTherapee/dev/rtdata/images/rt-logo-text-black.svg) + + + + RawTherapee logo + ![RawTherapee screenshot](http://rawtherapee.com/images/carousel/100_rt59_provence_local_maskxxx.jpg) From 92f0a11dc7100fa53dfb1146156925dda8c3a318 Mon Sep 17 00:00:00 2001 From: Lawrence37 <45837045+Lawrence37@users.noreply.github.com> Date: Mon, 6 Mar 2023 23:11:58 -0800 Subject: [PATCH 125/134] Add missing fftw libraries for Windows build (#6702) Add missing fftw library for Windows build --- .github/workflows/windows.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index ab81edec6..40c74f5e2 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -94,6 +94,8 @@ jobs: - name: Bundle dependencies run: | + echo "Listing shared library dependencies." + ldd "./build/${{matrix.build_type}}/rawtherapee.exe" echo "Getting workspace path." export BUILD_DIR="$(pwd)/build/${{matrix.build_type}}" echo "Build directory is '$BUILD_DIR'." @@ -120,6 +122,7 @@ jobs: "libexpat-1.dll" \ libffi-*.dll \ "libfftw3f-3.dll" \ + "libfftw3f_omp-3.dll" \ "libfontconfig-1.dll" \ "libfreetype-6.dll" \ "libfribidi-0.dll" \ From 4cff5ef35b4e7801387b72521d256672802d370c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Wed, 8 Mar 2023 08:18:38 +0100 Subject: [PATCH 126/134] Fix `settings.ini` formatting (closes #6697) --- .github/workflows/windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 40c74f5e2..49fdf5999 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -206,7 +206,7 @@ jobs: echo "Creating GTK settings.ini." mkdir -p "$BUILD_DIR/share/gtk-3.0/" - echo '[Settings] gtk-button-images=1' > "$BUILD_DIR/share/gtk-3.0/settings.ini" + echo -e '[Settings]\ngtk-button-images=1' > "$BUILD_DIR/share/gtk-3.0/settings.ini" - name: Create installer if: ${{matrix.build_type == 'release' && (github.ref_type == 'tag' || github.ref_name == 'dev')}} From 38ab9af4fc72239ef4132e4f7ca18b67f3e30bd2 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Wed, 8 Mar 2023 01:05:38 -0800 Subject: [PATCH 127/134] Mac: option for CI artifact naming --- CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 30e646fd8..92888424c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,9 @@ option(OSX_DEV_BUILD "Generate macOS development builds" OFF) # On macOS, optionally generate the final zip artifact file without version in the name for nightly upload purposes. option(OSX_NIGHTLY "Generate a generically-named zip" OFF) +# On macOS, optionally generate RawTherapee__macOS_.zip for the CI +option(OSX_CONTINUOUS "Generate a generically-named zip for CI" OFF) + # Generate a universal macOS build option(OSX_UNIVERSAL "Generate a universal app" OFF) @@ -94,14 +97,13 @@ option(OSX_UNIVERSAL "Generate a universal app" OFF) if(OSX_UNIVERSAL) if(NOT "${OSX_UNIVERSAL_URL}") if(CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") - set(OSX_UNIVERSAL_URL "https://kd6kxr.keybase.pub/RawTherapee_macOS_x86_64_latest.zip" CACHE STRING "URL of x86_64 app for lipo") + set(OSX_UNIVERSAL_URL "file:///rawtherapee/latest/RawTherapee_macOS_x86_64_latest.zip" CACHE STRING "URL of x86_64 app for lipo") else() - set(OSX_UNIVERSAL_URL "https://kd6kxr.keybase.pub/RawTherapee_macOS_arm64_latest.zip" CACHE STRING "URL of arm64 app for lipo") + set(OSX_UNIVERSAL_URL "file:///rawtherapee/latest/RawTherapee_macOS_arm64_latest.zip" CACHE STRING "URL of arm64 app for lipo") endif() endif() endif() - # By default we don't use a specific processor target, so PROC_TARGET_NUMBER is # set to 0. Specify other values to optimize for specific processor architecture # as listed in ProcessorTargets.cmake: From a79888c1af937e3f1f5d465ed8ffe637a8f0d992 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Wed, 8 Mar 2023 01:08:26 -0800 Subject: [PATCH 128/134] Mac: CI artifact naming --- tools/osx/macosx_bundle.sh | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index a43a1814c..f06ce8aa9 100644 --- a/tools/osx/macosx_bundle.sh +++ b/tools/osx/macosx_bundle.sh @@ -120,8 +120,8 @@ minimum_macos_version=${MINIMUM_SYSTEM_VERSION} #Out: /opt LOCAL_PREFIX="$(cmake .. -L -N | grep LOCAL_PREFIX)"; LOCAL_PREFIX="${LOCAL_PREFIX#*=}" -#In: OSX_UNIVERSAL_URL=https:// etc. -#Out: https:// etc. +#In: OSX_UNIVERSAL_URL=file:/// etc. +#Out: file:/// etc. UNIVERSAL_URL="$(cmake .. -L -N | grep OSX_UNIVERSAL_URL)"; UNIVERSAL_URL="${UNIVERSAL_URL#*=}" if [[ -n $UNIVERSAL_URL ]]; then echo "Universal app is ON. The URL is ${UNIVERSAL_URL}" @@ -153,6 +153,13 @@ if [[ -n $NIGHTLY ]]; then echo "Nightly/generically-named zip is ON." fi +# In: OSX_CONTINUOUS:BOOL=ON +# Out: ON +OSX_CONTINUOUS="$(cmake .. -L -N | grep OSX_CONTINUOUS)"; NIGHTLY="${OSX_CONTINUOUS#*=}" && CONTINUOUS="${OSX_CONTINUOUS#*=}" +if [[ -n $CONTINUOUS ]]; then + echo "Continuous/generically-named zip is ON." +fi + APP="${PROJECT_NAME}.app" CONTENTS="${APP}/Contents" RESOURCES="${CONTENTS}/Resources" @@ -434,12 +441,16 @@ function CreateDmg { # Zip disk image for redistribution msg "Zipping disk image for redistribution:" mkdir "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}_folder" - ditto {"${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}.dmg","rawtherapee-cli","${PROJECT_SOURCE_DATA_DIR}/INSTALL.txt"} "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}_folder" + cp {"${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}.dmg","${PROJECT_NAME}.app/Contents/Frameworks/rawtherapee-cli","${PROJECT_SOURCE_DATA_DIR}/INSTALL.readme.rtf"} "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}_folder" zip -r "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}.zip" "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}_folder/" if [[ -n $NIGHTLY ]]; then cp "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}.zip" "${PROJECT_NAME}_macOS_${arch}_latest.zip" fi + if [[ -n $CONTINUOUS ]]; then + mv "${PROJECT_NAME}_macOS_${arch}_latest.zip" "${PROJECT_NAME}_$(git status|head -1|awk -v N=$3 '{print $3}')_macOS_${arch}_${CMAKE_BUILD_TYPE}.zip" + fi } + CreateDmg msg "Finishing build:" echo "Script complete." From 53b4edd01d6f35c7d500fadfa7bb28bf66369393 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Wed, 8 Mar 2023 01:11:22 -0800 Subject: [PATCH 129/134] Mac: removes arch from CI name --- tools/osx/macosx_bundle.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index f06ce8aa9..8125f45ee 100644 --- a/tools/osx/macosx_bundle.sh +++ b/tools/osx/macosx_bundle.sh @@ -447,7 +447,7 @@ function CreateDmg { cp "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}.zip" "${PROJECT_NAME}_macOS_${arch}_latest.zip" fi if [[ -n $CONTINUOUS ]]; then - mv "${PROJECT_NAME}_macOS_${arch}_latest.zip" "${PROJECT_NAME}_$(git status|head -1|awk -v N=$3 '{print $3}')_macOS_${arch}_${CMAKE_BUILD_TYPE}.zip" + mv "${PROJECT_NAME}_macOS_${arch}_latest.zip" "${PROJECT_NAME}_$(git status|head -1|awk -v N=$3 '{print $3}')_macOS_${CMAKE_BUILD_TYPE}.zip" fi } From 60ac617bcf65b20a011cdae593ebf8d409060eff Mon Sep 17 00:00:00 2001 From: Benitoite Date: Wed, 8 Mar 2023 01:42:51 -0800 Subject: [PATCH 130/134] Mac: set the CI artifact name --- .github/workflows/macos.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 7d3e0cbfd..3348d48b9 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -63,7 +63,7 @@ jobs: -DCMAKE_AR=/usr/bin/ar \ -DCMAKE_RANLIB=/usr/bin/ranlib \ -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \ - -DOSX_NIGHTLY=ON \ + -DOSX_CONTINUOUS=ON \ .. curl -L https://github.com/Homebrew/homebrew-core/raw/679923b4eb48a8dc7ecc1f05d06063cd79b3fc00/Formula/libomp.rb -o libomp.rb && brew install --formula libomp.rb zsh -c 'echo "Configured in $(printf "%0.2f" $(($[$(date +%s)-$(cat configstamp)]/$((60.))))) minutes"' @@ -79,7 +79,7 @@ jobs: zsh date +%s > build/bundlestamp && date -u && cd build export REF=${GITHUB_REF##*/} && export LOCAL_PREFIX=/usr && sudo make macosx_bundle - export ARTIFACT=(RawTherapee*latest.zip) + export ARTIFACT=(RawTherapee*${CMAKE_BUILD_TYPE}.zip) echo "=== artifact: ${ARTIFACT}" # defining environment variables for next step as per # https://github.com/actions/starter-workflows/issues/68 From 3e11f0bcf874071a65eba0cac28161afe6b90d23 Mon Sep 17 00:00:00 2001 From: Benitoite Date: Wed, 8 Mar 2023 10:02:52 -0800 Subject: [PATCH 131/134] Mac: use the symbolic ref for branch --- tools/osx/macosx_bundle.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index 8125f45ee..51c055ee8 100644 --- a/tools/osx/macosx_bundle.sh +++ b/tools/osx/macosx_bundle.sh @@ -447,7 +447,7 @@ function CreateDmg { cp "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}.zip" "${PROJECT_NAME}_macOS_${arch}_latest.zip" fi if [[ -n $CONTINUOUS ]]; then - mv "${PROJECT_NAME}_macOS_${arch}_latest.zip" "${PROJECT_NAME}_$(git status|head -1|awk -v N=$3 '{print $3}')_macOS_${CMAKE_BUILD_TYPE}.zip" + mv "${PROJECT_NAME}_macOS_${arch}_latest.zip" "${PROJECT_NAME}_$(git symbolic-ref --short -q HEAD)_macOS_${CMAKE_BUILD_TYPE}.zip" fi } From ec19698dc4347318c54fd7e0f6c7d352c3a8629d Mon Sep 17 00:00:00 2001 From: Benitoite Date: Wed, 8 Mar 2023 11:42:47 -0800 Subject: [PATCH 132/134] Mac: use git branch --show-current --- tools/osx/macosx_bundle.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index 51c055ee8..ace34d70f 100644 --- a/tools/osx/macosx_bundle.sh +++ b/tools/osx/macosx_bundle.sh @@ -447,7 +447,7 @@ function CreateDmg { cp "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}.zip" "${PROJECT_NAME}_macOS_${arch}_latest.zip" fi if [[ -n $CONTINUOUS ]]; then - mv "${PROJECT_NAME}_macOS_${arch}_latest.zip" "${PROJECT_NAME}_$(git symbolic-ref --short -q HEAD)_macOS_${CMAKE_BUILD_TYPE}.zip" + mv "${PROJECT_NAME}_macOS_${arch}_latest.zip" "${PROJECT_NAME}_$(git branch --show-current)_macOS_${CMAKE_BUILD_TYPE}.zip" fi } From f92dca3e590b65c4feee50b3aa0755811aa1d29f Mon Sep 17 00:00:00 2001 From: Benitoite Date: Wed, 8 Mar 2023 15:07:57 -0800 Subject: [PATCH 133/134] Mac: handle detached HEAD --- tools/osx/macosx_bundle.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index ace34d70f..6b91654a3 100644 --- a/tools/osx/macosx_bundle.sh +++ b/tools/osx/macosx_bundle.sh @@ -447,7 +447,11 @@ function CreateDmg { cp "${PROJECT_NAME}_macOS_${MINIMUM_SYSTEM_VERSION}_${arch}_${PROJECT_FULL_VERSION}.zip" "${PROJECT_NAME}_macOS_${arch}_latest.zip" fi if [[ -n $CONTINUOUS ]]; then - mv "${PROJECT_NAME}_macOS_${arch}_latest.zip" "${PROJECT_NAME}_$(git branch --show-current)_macOS_${CMAKE_BUILD_TYPE}.zip" + BRANCH=$(git branch --show-current) + if test -z "${BRANCH}" + BRANCH=$(git rev-parse --short HEAD) + fi + mv "${PROJECT_NAME}_macOS_${arch}_latest.zip" "${PROJECT_NAME}_${BRANCH}_macOS_${CMAKE_BUILD_TYPE}.zip" fi } From ee2ebabb78533da17abaeb3872ce910bc05e950f Mon Sep 17 00:00:00 2001 From: Benitoite Date: Wed, 8 Mar 2023 15:57:07 -0800 Subject: [PATCH 134/134] =?UTF-8?q?Mac:=20add=20missing=20=E2=80=98then?= =?UTF-8?q?=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/osx/macosx_bundle.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/osx/macosx_bundle.sh b/tools/osx/macosx_bundle.sh index 6b91654a3..ca381ec14 100644 --- a/tools/osx/macosx_bundle.sh +++ b/tools/osx/macosx_bundle.sh @@ -448,7 +448,7 @@ function CreateDmg { fi if [[ -n $CONTINUOUS ]]; then BRANCH=$(git branch --show-current) - if test -z "${BRANCH}" + if test -z "${BRANCH}"; then BRANCH=$(git rev-parse --short HEAD) fi mv "${PROJECT_NAME}_macOS_${arch}_latest.zip" "${PROJECT_NAME}_${BRANCH}_macOS_${CMAKE_BUILD_TYPE}.zip"