merge with dev

This commit is contained in:
Desmis
2017-03-12 16:53:50 +01:00
70 changed files with 2305 additions and 488 deletions

View File

@@ -30,7 +30,8 @@ set (BASESOURCEFILES
darkframe.cc flatfield.cc rawcacorrection.cc rawexposure.cc wavelet.cc
dirpyrequalizer.cc hsvequalizer.cc defringe.cc
popupcommon.cc popupbutton.cc popuptogglebutton.cc sharpenedge.cc sharpenmicro.cc colorappearance.cc locallab.cc
filmsimulation.cc prsharpening.cc)
filmsimulation.cc prsharpening.cc
dynamicprofile.cc dynamicprofilepanel.cc)
include_directories (BEFORE "${CMAKE_CURRENT_BINARY_DIR}")

255
rtgui/dynamicprofile.cc Normal file
View File

@@ -0,0 +1,255 @@
/* -*- C++ -*-
* This file is part of RawTherapee.
*
* Copyright (c) 2017 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 <http://www.gnu.org/licenses/>.
*/
#include "dynamicprofile.h"
#include "profilestore.h"
#include <stdlib.h>
#include <glibmm/regex.h>
using namespace rtengine;
using namespace rtengine::procparams;
namespace {
const int ISO_MAX = 512000;
const double FNUMBER_MAX = 100.0;
const double FOCALLEN_MAX = 10000.0;
const double SHUTTERSPEED_MAX = 1000.0;
const double EXPCOMP_MIN = -20.0;
const double EXPCOMP_MAX = 20.0;
} // namespace
bool DynamicProfileRule::Optional::operator()(const Glib::ustring &val) const
{
if (!enabled) {
return true;
}
if (value.find("re:") == 0) {
// this is a regexp
return Glib::Regex::match_simple(value.substr(3), val,
Glib::REGEX_CASELESS);
} else {
// normal string comparison
return value.casefold() == val.casefold();
}
}
DynamicProfileRule::DynamicProfileRule():
serial_number(0),
iso(0, ISO_MAX),
fnumber(0, FNUMBER_MAX),
focallen(0, FOCALLEN_MAX),
shutterspeed(0, SHUTTERSPEED_MAX),
expcomp(EXPCOMP_MIN, EXPCOMP_MAX)
{
}
bool DynamicProfileRule::operator<(const DynamicProfileRule &other) const
{
return serial_number < other.serial_number;
}
bool DynamicProfileRule::matches(const rtengine::ImageMetaData *im) const
{
return (iso(im->getISOSpeed())
&& fnumber(im->getFNumber())
&& focallen(im->getFocalLen())
&& shutterspeed(im->getShutterSpeed())
&& expcomp(im->getExpComp())
&& camera(im->getCamera())
&& lens(im->getLens()));
}
namespace {
void get_int_range(DynamicProfileRule::Range<int> &dest,
const Glib::KeyFile &kf, const Glib::ustring &group,
const Glib::ustring &key)
{
try {
int min = kf.get_integer(group, key + "_min");
int max = kf.get_integer(group, key + "_max");
if (min <= max) {
dest.min = min;
dest.max = max;
}
} catch (Glib::KeyFileError &e) {
}
}
void get_double_range(DynamicProfileRule::Range<double> &dest,
const Glib::KeyFile &kf, const Glib::ustring &group,
const Glib::ustring &key)
{
try {
double min = kf.get_double(group, key + "_min");
double max = kf.get_double(group, key + "_max");
if (min <= max) {
dest.min = min;
dest.max = max;
}
} catch (Glib::KeyFileError &e) {
}
}
void get_optional(DynamicProfileRule::Optional &dest,
const Glib::KeyFile &kf, const Glib::ustring &group,
const Glib::ustring &key)
{
try {
bool e = kf.get_boolean(group, key + "_enabled");
if (e) {
Glib::ustring s = kf.get_string(group, key + "_value");
dest.enabled = e;
dest.value = s;
}
} catch (Glib::KeyFileError &) {
}
}
void set_int_range(Glib::KeyFile &kf, const Glib::ustring &group,
const Glib::ustring &key,
const DynamicProfileRule::Range<int> &val)
{
kf.set_integer(group, key + "_min", val.min);
kf.set_integer(group, key + "_max", val.max);
}
void set_double_range(Glib::KeyFile &kf, const Glib::ustring &group,
const Glib::ustring &key,
const DynamicProfileRule::Range<double> &val)
{
kf.set_double(group, key + "_min", val.min);
kf.set_double(group, key + "_max", val.max);
}
void set_optional(Glib::KeyFile &kf, const Glib::ustring &group,
const Glib::ustring &key,
const DynamicProfileRule::Optional &val)
{
kf.set_boolean(group, key + "_enabled", val.enabled);
kf.set_string(group, key + "_value", val.value);
}
} // namespace
bool loadDynamicProfileRules(std::vector<DynamicProfileRule> &out)
{
out.clear();
Glib::KeyFile kf;
try {
if (!kf.load_from_file(
Glib::build_filename(Options::rtdir, "dynamicprofile.cfg"))) {
return false;
}
} catch (Glib::Error &e) {
return false;
}
if (options.rtSettings.verbose) {
printf("loading dynamic profiles...\n");
}
auto groups = kf.get_groups();
for (auto group : groups) {
// groups are of the form "rule N", where N is a positive integer
if (group.find("rule ") != 0) {
return false;
}
std::istringstream buf(group.c_str() + 5);
int serial = 0;
if (!(buf >> serial) || !buf.eof()) {
return false;
}
if (options.rtSettings.verbose) {
printf(" loading rule %d\n", serial);
}
out.emplace_back(DynamicProfileRule());
DynamicProfileRule &rule = out.back();
rule.serial_number = serial;
get_int_range(rule.iso, kf, group, "iso");
get_double_range(rule.fnumber, kf, group, "fnumber");
get_double_range(rule.focallen, kf, group, "focallen");
get_double_range(rule.shutterspeed, kf, group, "shutterspeed");
get_double_range(rule.expcomp, kf, group, "expcomp");
get_optional(rule.camera, kf, group, "camera");
get_optional(rule.lens, kf, group, "lens");
try {
rule.profilepath = kf.get_string(group, "profilepath");
} catch (Glib::KeyFileError &) {
out.pop_back();
}
}
std::sort(out.begin(), out.end());
return true;
}
bool storeDynamicProfileRules(const std::vector<DynamicProfileRule> &rules)
{
if (options.rtSettings.verbose) {
printf("saving dynamic profiles...\n");
}
Glib::KeyFile kf;
for (auto &rule : rules) {
std::ostringstream buf;
buf << "rule " << rule.serial_number;
Glib::ustring group = buf.str();
set_int_range(kf, group, "iso", rule.iso);
set_double_range(kf, group, "fnumber", rule.fnumber);
set_double_range(kf, group, "focallen", rule.focallen);
set_double_range(kf, group, "shutterspeed", rule.shutterspeed);
set_double_range(kf, group, "expcomp", rule.expcomp);
set_optional(kf, group, "camera", rule.camera);
set_optional(kf, group, "lens", rule.lens);
kf.set_string(group, "profilepath", rule.profilepath);
}
return kf.save_to_file(
Glib::build_filename(Options::rtdir, "dynamicprofile.cfg"));
}
PartialProfile *loadDynamicProfile(const ImageMetaData *im)
{
PartialProfile *ret = new PartialProfile(true, true);
for (auto &rule : profileStore.getDynamicProfileRules()) {
if (rule.matches(im)) {
if (options.rtSettings.verbose) {
printf("found matching profile %s\n",
rule.profilepath.c_str());
}
const PartialProfile *p =
profileStore.getProfile(rule.profilepath);
if (p != nullptr) {
p->applyTo(ret->pparams);
} else {
printf("ERROR loading matching profile from: %s\n",
rule.profilepath.c_str());
}
}
}
return ret;
}

74
rtgui/dynamicprofile.h Normal file
View File

@@ -0,0 +1,74 @@
/* -*- C++ -*-
* This file is part of RawTherapee.
*
* Copyright (c) 2017 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _DYNAMICPROFILE_H_
#define _DYNAMICPROFILE_H_
#include <glibmm.h>
#include <vector>
#include "options.h"
class DynamicProfileRule {
public:
template <class T>
struct Range {
T min;
T max;
explicit Range(T l=T(), T u=T()): min(l), max(u) {}
bool operator()(T val) const
{
return val >= min && val <= max;
}
};
struct Optional {
Glib::ustring value;
bool enabled;
explicit Optional(const Glib::ustring v="", bool e=false):
value(v), enabled(e) {}
bool operator()(const Glib::ustring &val) const;
};
DynamicProfileRule();
bool matches(const rtengine::ImageMetaData *im) const;
bool operator<(const DynamicProfileRule &other) const;
int serial_number;
Range<int> iso;
Range<double> fnumber;
Range<double> focallen;
Range<double> shutterspeed;
Range<double> expcomp;
Optional camera;
Optional lens;
Glib::ustring profilepath;
};
bool loadDynamicProfileRules(std::vector<DynamicProfileRule> &out);
bool storeDynamicProfileRules(
const std::vector<DynamicProfileRule> &rules);
rtengine::procparams::PartialProfile *loadDynamicProfile(
const rtengine::ImageMetaData *im);
#endif // _DYNAMICPROFILE_H_

View File

@@ -0,0 +1,533 @@
/* -*- C++ -*-
* This file is part of RawTherapee.
*
* Copyright (c) 2017 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 <http://www.gnu.org/licenses/>.
*/
#include "dynamicprofilepanel.h"
#include "multilangmgr.h"
#include "profilestore.h"
#include "../rtengine/rtengine.h"
#include <sstream>
#include <iomanip>
//-----------------------------------------------------------------------------
// DynamicProfilePanel::EditDialog
//-----------------------------------------------------------------------------
DynamicProfilePanel::EditDialog::EditDialog(const Glib::ustring &title,
Gtk::Window &parent):
Gtk::Dialog(title, parent)
{
profilepath_ = Gtk::manage(new ProfileStoreComboBox());
Gtk::HBox *hb = Gtk::manage(new Gtk::HBox());
hb->pack_start(*Gtk::manage(new Gtk::Label(M("DYNPROFILEEDITOR_PROFILE"))),
false, false, 4);
hb->pack_start(*profilepath_, true, true, 2);
get_content_area()->pack_start(*hb, Gtk::PACK_SHRINK, 4);
add_optional(M("EXIFFILTER_CAMERA"), has_camera_, camera_);
add_optional(M("EXIFFILTER_LENS"), has_lens_, lens_);
add_range(M("EXIFFILTER_ISO"), iso_min_, iso_max_);
add_range(M("EXIFFILTER_APERTURE"), fnumber_min_, fnumber_max_);
add_range(M("EXIFFILTER_FOCALLEN"), focallen_min_, focallen_max_);
add_range(M("EXIFFILTER_SHUTTER"), shutterspeed_min_, shutterspeed_max_);
add_range(M("EXIFFILTER_EXPOSURECOMPENSATION"), expcomp_min_, expcomp_max_);
add_button(M("GENERAL_OK"), 1);
add_button(M("GENERAL_CANCEL"), 2);
set_ranges();
show_all_children();
}
void DynamicProfilePanel::EditDialog::set_rule(
const DynamicProfileRule &rule)
{
iso_min_->set_value(rule.iso.min);
iso_max_->set_value(rule.iso.max);
fnumber_min_->set_value(rule.fnumber.min);
fnumber_max_->set_value(rule.fnumber.max);
focallen_min_->set_value(rule.focallen.min);
focallen_max_->set_value(rule.focallen.max);
shutterspeed_min_->set_value(rule.shutterspeed.min);
shutterspeed_max_->set_value(rule.shutterspeed.max);
expcomp_min_->set_value(rule.expcomp.min);
expcomp_max_->set_value(rule.expcomp.max);
has_camera_->set_active(rule.camera.enabled);
camera_->set_text(rule.camera.value);
has_lens_->set_active(rule.lens.enabled);
lens_->set_text(rule.lens.value);
profilepath_->updateProfileList();
if (!profilepath_->setActiveRowFromFullPath(rule.profilepath)) {
profilepath_->setInternalEntry();
}
}
DynamicProfileRule DynamicProfilePanel::EditDialog::get_rule()
{
DynamicProfileRule ret;
ret.iso.min = iso_min_->get_value_as_int();
ret.iso.max = iso_max_->get_value_as_int();
ret.fnumber.min = fnumber_min_->get_value();
ret.fnumber.max = fnumber_max_->get_value();
ret.focallen.min = focallen_min_->get_value();
ret.focallen.max = focallen_max_->get_value();
ret.shutterspeed.min = shutterspeed_min_->get_value();
ret.shutterspeed.max = shutterspeed_max_->get_value();
ret.expcomp.min = expcomp_min_->get_value();
ret.expcomp.max = expcomp_max_->get_value();
ret.camera.enabled = has_camera_->get_active();
ret.camera.value = camera_->get_text();
ret.lens.enabled = has_lens_->get_active();
ret.lens.value = lens_->get_text();
ret.profilepath = profilepath_->getFullPathFromActiveRow();
return ret;
}
void DynamicProfilePanel::EditDialog::set_ranges()
{
DynamicProfileRule default_rule;
iso_min_->set_digits(0);
iso_max_->set_digits(0);
iso_min_->set_increments(1, 10);
iso_max_->set_increments(1, 10);
iso_min_->set_range(default_rule.iso.min, default_rule.iso.max);
iso_max_->set_range(default_rule.iso.min, default_rule.iso.max);
iso_min_->set_value(default_rule.iso.min);
iso_max_->set_value(default_rule.iso.max);
#define DOIT_(name) \
name ## _min_->set_digits(1); \
name ## _max_->set_digits(1); \
name ## _min_->set_increments(0.1, 1); \
name ## _max_->set_increments(0.1, 1); \
name ## _min_->set_range(default_rule. name .min, \
default_rule. name .max); \
name ## _max_->set_range(default_rule. name .min, \
default_rule. name .max); \
name ## _min_->set_value(default_rule. name .min); \
name ## _max_->set_value(default_rule. name .max)
DOIT_(fnumber);
DOIT_(focallen);
DOIT_(shutterspeed);
DOIT_(expcomp);
#undef DOIT_
shutterspeed_min_->set_digits(4);
shutterspeed_max_->set_digits(4);
profilepath_->setInternalEntry();
}
void DynamicProfilePanel::EditDialog::add_range(const Glib::ustring &name,
Gtk::SpinButton *&from, Gtk::SpinButton *&to)
{
Gtk::HBox *hb = Gtk::manage(new Gtk::HBox());
hb->pack_start(*Gtk::manage(new Gtk::Label(name)), false, false, 4);
from = Gtk::manage(new Gtk::SpinButton());
to = Gtk::manage(new Gtk::SpinButton());
from->set_numeric(true);
to->set_numeric(true);
hb->pack_start(*from, true, true, 2);
hb->pack_start(*Gtk::manage(new Gtk::Label(" - ")),
false, false, 4);
hb->pack_start(*to, true, true, 2);
get_content_area()->pack_start(*hb, Gtk::PACK_SHRINK, 4);
}
void DynamicProfilePanel::EditDialog::add_optional(const Glib::ustring &name,
Gtk::CheckButton *&check, Gtk::Entry *&field)
{
check = Gtk::manage (new Gtk::CheckButton(name));
Gtk::HBox *hb = Gtk::manage(new Gtk::HBox());
hb->pack_start(*check, Gtk::PACK_SHRINK, 4);
field = Gtk::manage(new Gtk::Entry());
hb->pack_start(*field, true, true, 2);
get_content_area()->pack_start(*hb, Gtk::PACK_SHRINK, 4);
field->set_tooltip_text(M("DYNPROFILEEDITOR_ENTRY_TOOLTIP"));
}
//-----------------------------------------------------------------------------
// DynamicProfilePanel
//-----------------------------------------------------------------------------
DynamicProfilePanel::DynamicProfilePanel():
vbox_(Gtk::ORIENTATION_VERTICAL),
button_up_(M("DYNPROFILEEDITOR_MOVE_UP")),
button_down_(M("DYNPROFILEEDITOR_MOVE_DOWN")),
button_new_(M("DYNPROFILEEDITOR_NEW")),
button_edit_(M("DYNPROFILEEDITOR_EDIT")),
button_delete_(M("DYNPROFILEEDITOR_DELETE"))
{
add(vbox_);
treeview_.set_grid_lines(Gtk::TREE_VIEW_GRID_LINES_VERTICAL);
scrolledwindow_.add(treeview_);
scrolledwindow_.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
vbox_.pack_start(scrolledwindow_);
vbox_.pack_start(buttonbox_, Gtk::PACK_SHRINK);
buttonbox_.pack_start(button_new_, Gtk::PACK_SHRINK);
buttonbox_.pack_start(button_edit_, Gtk::PACK_SHRINK);
buttonbox_.pack_start(button_delete_, Gtk::PACK_SHRINK);
buttonbox_.pack_start(button_up_, Gtk::PACK_SHRINK);
buttonbox_.pack_start(button_down_, Gtk::PACK_SHRINK);
buttonbox_.set_border_width(5);
buttonbox_.set_layout(Gtk::BUTTONBOX_END);
button_up_.signal_clicked().connect(
sigc::mem_fun(*this, &DynamicProfilePanel::on_button_up));
button_down_.signal_clicked().connect(
sigc::mem_fun(*this, &DynamicProfilePanel::on_button_down));
button_new_.signal_clicked().connect(
sigc::mem_fun(*this, &DynamicProfilePanel::on_button_new));
button_edit_.signal_clicked().connect(
sigc::mem_fun(*this, &DynamicProfilePanel::on_button_edit));
button_delete_.signal_clicked().connect(
sigc::mem_fun(*this, &DynamicProfilePanel::on_button_delete));
treemodel_ = Gtk::ListStore::create(columns_);
treeview_.set_model(treemodel_);
auto cell = Gtk::manage(new Gtk::CellRendererText());
int cols_count = treeview_.append_column(
M("DYNPROFILEEDITOR_PROFILE"), *cell);
auto col = treeview_.get_column(cols_count - 1);
if (col) {
col->set_cell_data_func(
*cell, sigc::mem_fun(
*this, &DynamicProfilePanel::render_profilepath));
}
cell = Gtk::manage(new Gtk::CellRendererText());
cols_count = treeview_.append_column(
M("EXIFFILTER_CAMERA"), *cell);
col = treeview_.get_column(cols_count - 1);
if (col) {
col->set_cell_data_func(
*cell, sigc::mem_fun(
*this, &DynamicProfilePanel::render_camera));
}
cell = Gtk::manage(new Gtk::CellRendererText());
cols_count = treeview_.append_column(M("EXIFFILTER_LENS"), *cell);
col = treeview_.get_column(cols_count - 1);
if (col) {
col->set_cell_data_func(
*cell, sigc::mem_fun(
*this, &DynamicProfilePanel::render_lens));
}
cell = Gtk::manage(new Gtk::CellRendererText());
cols_count = treeview_.append_column(M("EXIFFILTER_ISO"), *cell);
col = treeview_.get_column(cols_count - 1);
if (col) {
col->set_cell_data_func(
*cell, sigc::mem_fun(
*this, &DynamicProfilePanel::render_iso));
}
cell = Gtk::manage(new Gtk::CellRendererText());
cols_count = treeview_.append_column(M("EXIFFILTER_APERTURE"), *cell);
col = treeview_.get_column(cols_count - 1);
if (col) {
col->set_cell_data_func(
*cell, sigc::mem_fun(
*this, &DynamicProfilePanel::render_fnumber));
}
cell = Gtk::manage(new Gtk::CellRendererText());
cols_count = treeview_.append_column(M("EXIFFILTER_FOCALLEN"), *cell);
col = treeview_.get_column(cols_count - 1);
if (col) {
col->set_cell_data_func(
*cell, sigc::mem_fun(
*this, &DynamicProfilePanel::render_focallen));
}
cell = Gtk::manage(new Gtk::CellRendererText());
cols_count = treeview_.append_column(M("EXIFFILTER_SHUTTER"), *cell);
col = treeview_.get_column(cols_count - 1);
if (col) {
col->set_cell_data_func(
*cell, sigc::mem_fun(
*this, &DynamicProfilePanel::render_shutterspeed));
}
cell = Gtk::manage(new Gtk::CellRendererText());
cols_count = treeview_.append_column(
M("EXIFFILTER_EXPOSURECOMPENSATION"), *cell);
col = treeview_.get_column(cols_count - 1);
if (col) {
col->set_cell_data_func(
*cell, sigc::mem_fun(
*this, &DynamicProfilePanel::render_expcomp));
}
show_all_children();
for (auto &r : profileStore.getDynamicProfileRules()) {
add_rule(r);
}
}
void DynamicProfilePanel::update_rule(Gtk::TreeModel::Row row,
const DynamicProfileRule &rule)
{
row[columns_.iso] = rule.iso;
row[columns_.fnumber] = rule.fnumber;
row[columns_.focallen] = rule.focallen;
row[columns_.shutterspeed] = rule.shutterspeed;
row[columns_.expcomp] = rule.expcomp;
row[columns_.camera] = rule.camera;
row[columns_.lens] = rule.lens;
row[columns_.profilepath] = rule.profilepath;
}
void DynamicProfilePanel::add_rule(const DynamicProfileRule &rule)
{
auto row = *(treemodel_->append());
update_rule(row, rule);
}
DynamicProfileRule DynamicProfilePanel::to_rule(Gtk::TreeModel::Row row,
int serial)
{
DynamicProfileRule ret;
ret.serial_number = serial;
ret.iso = row[columns_.iso];
ret.fnumber = row[columns_.fnumber];
ret.focallen = row[columns_.focallen];
ret.shutterspeed = row[columns_.shutterspeed];
ret.expcomp = row[columns_.expcomp];
ret.camera = row[columns_.camera];
ret.lens = row[columns_.lens];
ret.profilepath = row[columns_.profilepath];
return ret;
}
void DynamicProfilePanel::render_profilepath(
Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter)
{
auto row = *iter;
Gtk::CellRendererText *ct = static_cast<Gtk::CellRendererText *>(cell);
auto value = row[columns_.profilepath];
auto pse = profileStore.findEntryFromFullPath(value);
if (pse != nullptr) {
ct->property_text() = pse->label;
} else {
ct->property_text() = value;
}
}
#define RENDER_RANGE_(tp, name, tostr) \
auto row = *iter; \
Gtk::CellRendererText *ct = static_cast<Gtk::CellRendererText *>(cell); \
DynamicProfileRule::Range<tp> r = row[columns_. name]; \
DynamicProfileRule dflt; \
if (r.min > dflt.name.min || r.max < dflt.name.max) { \
auto value = tostr(r.min) + " - " + tostr(r.max); \
ct->property_text() = value; \
} else { \
ct->property_text() = ""; \
}
namespace {
template <class V>
Glib::ustring to_str(V n, int precision=1)
{
std::ostringstream buf;
buf << std::setprecision(precision) << std::fixed << n;
return buf.str();
}
} // namespace
void DynamicProfilePanel::render_iso(
Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter)
{
RENDER_RANGE_(int, iso, to_str);
}
void DynamicProfilePanel::render_fnumber(
Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter)
{
RENDER_RANGE_(double, fnumber,
[](double f)
{ return std::string("f/") +
rtengine::ImageMetaData::apertureToString(f); });
}
void DynamicProfilePanel::render_focallen(
Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter)
{
RENDER_RANGE_(double, focallen, to_str);
}
void DynamicProfilePanel::render_shutterspeed(
Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter)
{
RENDER_RANGE_(double, shutterspeed,
rtengine::ImageMetaData::shutterToString);
}
void DynamicProfilePanel::render_expcomp(
Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter)
{
RENDER_RANGE_(double, expcomp, to_str);
}
#undef RENDER_RANGE_
#define RENDER_OPTIONAL_(name) \
auto row = *iter; \
Gtk::CellRendererText *ct = static_cast<Gtk::CellRendererText *>(cell); \
DynamicProfileRule::Optional o = row[columns_. name]; \
if (o.enabled) { \
ct->property_text() = o.value; \
} else { \
ct->property_text() = ""; \
}
void DynamicProfilePanel::render_camera(
Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter)
{
RENDER_OPTIONAL_(camera);
}
void DynamicProfilePanel::render_lens(
Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter)
{
RENDER_OPTIONAL_(lens);
}
#undef RENDER_OPTIONAL_
void DynamicProfilePanel::on_button_up()
{
auto s = treeview_.get_selection();
if (!s->count_selected_rows()) {
return;
}
auto it = s->get_selected();
if (it != treemodel_->children().begin()) {
auto it2 = it;
--it2;
treemodel_->iter_swap(it, it2);
}
}
void DynamicProfilePanel::on_button_down()
{
auto s = treeview_.get_selection();
if (!s->count_selected_rows()) {
return;
}
auto it = s->get_selected();
auto it2 = it;
++it2;
if (it2 != treemodel_->children().end()) {
treemodel_->iter_swap(it, it2);
}
}
void DynamicProfilePanel::on_button_delete()
{
auto s = treeview_.get_selection();
if (!s->count_selected_rows()) {
return;
}
auto it = s->get_selected();
treemodel_->erase(it);
}
void DynamicProfilePanel::on_button_new()
{
EditDialog d(M("DYNPROFILEEDITOR_NEW_RULE"),
static_cast<Gtk::Window &>(*get_toplevel()));
int status = d.run();
if (status == 1) {
DynamicProfileRule rule = d.get_rule();
add_rule(rule);
}
}
void DynamicProfilePanel::on_button_edit()
{
auto s = treeview_.get_selection();
if (!s->count_selected_rows()) {
return;
}
EditDialog d(M("DYNPROFILEEDITOR_EDIT_RULE"),
static_cast<Gtk::Window &>(*get_toplevel()));
auto it = s->get_selected();
Gtk::TreeModel::Row row = *(s->get_selected());
d.set_rule(to_rule(row));
int status = d.run();
if (status == 1) {
update_rule(row, d.get_rule());
}
}
void DynamicProfilePanel::save()
{
std::vector<DynamicProfileRule> rules;
int serial = 1;
for (auto row : treemodel_->children()) {
rules.emplace_back(to_rule(row, serial++));
}
if (!storeDynamicProfileRules(rules)) {
printf("Error in saving dynamic profile rules\n");
} else {
profileStore.setDynamicProfileRules(rules);
if (options.rtSettings.verbose) {
printf("Saved %d dynamic profile rules\n", int(rules.size()));
}
}
}

140
rtgui/dynamicprofilepanel.h Normal file
View File

@@ -0,0 +1,140 @@
/* -*- C++ -*-
* This file is part of RawTherapee.
*
* Copyright (c) 2017 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _DYNAMICPROFILEPANEL_H_
#define _DYNAMICPROFILEPANEL_H_
#include <gtkmm.h>
#include "dynamicprofile.h"
#include "profilestore.h"
class DynamicProfilePanel: public Gtk::VBox {
public:
DynamicProfilePanel();
void save();
private:
void update_rule(Gtk::TreeModel::Row row,
const DynamicProfileRule &rule);
void add_rule(const DynamicProfileRule &rule);
DynamicProfileRule to_rule(Gtk::TreeModel::Row row, int serial=0);
void on_button_quit();
void on_button_up();
void on_button_down();
void on_button_new();
void on_button_edit();
void on_button_delete();
class DynamicProfileColumns: public Gtk::TreeModel::ColumnRecord {
public:
DynamicProfileColumns()
{
add(iso);
add(fnumber);
add(focallen);
add(shutterspeed);
add(expcomp);
add(camera);
add(lens);
add(profilepath);
}
Gtk::TreeModelColumn<DynamicProfileRule::Range<int>> iso;
Gtk::TreeModelColumn<DynamicProfileRule::Range<double>> fnumber;
Gtk::TreeModelColumn<DynamicProfileRule::Range<double>> focallen;
Gtk::TreeModelColumn<DynamicProfileRule::Range<double>> shutterspeed;
Gtk::TreeModelColumn<DynamicProfileRule::Range<double>> expcomp;
Gtk::TreeModelColumn<DynamicProfileRule::Optional> camera;
Gtk::TreeModelColumn<DynamicProfileRule::Optional> lens;
Gtk::TreeModelColumn<Glib::ustring> profilepath;
};
// cell renderers
void render_iso(Gtk::CellRenderer* cell,
const Gtk::TreeModel::iterator& iter);
void render_fnumber(Gtk::CellRenderer* cell,
const Gtk::TreeModel::iterator& iter);
void render_focallen(Gtk::CellRenderer* cell,
const Gtk::TreeModel::iterator& iter);
void render_shutterspeed(Gtk::CellRenderer* cell,
const Gtk::TreeModel::iterator& iter);
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_profilepath(Gtk::CellRenderer* cell,
const Gtk::TreeModel::iterator& iter);
class EditDialog: public Gtk::Dialog {
public:
EditDialog(const Glib::ustring &title, Gtk::Window &parent);
void set_rule(const DynamicProfileRule &rule);
DynamicProfileRule get_rule();
private:
void set_ranges();
void add_range(const Glib::ustring &name,
Gtk::SpinButton *&from, Gtk::SpinButton *&to);
void add_optional(const Glib::ustring &name,
Gtk::CheckButton *&check, Gtk::Entry *&field);
Gtk::SpinButton *iso_min_;
Gtk::SpinButton *iso_max_;
Gtk::SpinButton *fnumber_min_;
Gtk::SpinButton *fnumber_max_;
Gtk::SpinButton *focallen_min_;
Gtk::SpinButton *focallen_max_;
Gtk::SpinButton *shutterspeed_min_;
Gtk::SpinButton *shutterspeed_max_;
Gtk::SpinButton *expcomp_min_;
Gtk::SpinButton *expcomp_max_;
Gtk::CheckButton *has_camera_;
Gtk::Entry *camera_;
Gtk::CheckButton *has_lens_;
Gtk::Entry *lens_;
ProfileStoreComboBox *profilepath_;
};
DynamicProfileColumns columns_;
//Child widgets:
Gtk::Box vbox_;
Gtk::ScrolledWindow scrolledwindow_;
Gtk::TreeView treeview_;
Glib::RefPtr<Gtk::ListStore> treemodel_;
Gtk::ButtonBox buttonbox_;
Gtk::Button button_up_;
Gtk::Button button_down_;
Gtk::Button button_new_;
Gtk::Button button_edit_;
Gtk::Button button_delete_;
};
#endif // _DYNAMICPROFILEPANEL_H_

View File

@@ -37,6 +37,7 @@
#include "rtimage.h"
#include "version.h"
#include "extprog.h"
#include "dynamicprofile.h"
#ifndef WIN32
#include <glibmm/fileutils.h>
@@ -182,7 +183,7 @@ int main (int argc, char **argv)
bool consoleOpened = false;
// suppression of annoying error boxes
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
if (argc > 1 || options.rtSettings.verbose) {
if (options.rtSettings.verbose || ( !Glib::file_test (fname_to_utf8 (argv[1]), Glib::FILE_TEST_EXISTS ) && !Glib::file_test (fname_to_utf8 (argv[1]), Glib::FILE_TEST_IS_DIR))) {
@@ -208,8 +209,8 @@ int main (int argc, char **argv)
SetConsoleCtrlHandler ( NULL, true );
// Set title of console
char consoletitle[128];
sprintf(consoletitle, "RawTherapee %s Console", RTVERSION);
SetConsoleTitle(consoletitle);
sprintf (consoletitle, "RawTherapee %s Console", RTVERSION);
SetConsoleTitle (consoletitle);
// increase size of screen buffer
COORD c;
c.X = 200;
@@ -717,7 +718,7 @@ int processLineParams ( int argc, char **argv )
rawParams = new rtengine::procparams::PartialProfile (true, true);
Glib::ustring profPath = options.findProfilePath (options.defProfRaw);
if (options.is_defProfRawMissing() || profPath.empty() || rawParams->load (profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename (profPath, options.defProfRaw.substr (5) + paramFileExtension))) {
if (options.is_defProfRawMissing() || profPath.empty() || (profPath != DEFPROFILE_DYNAMIC && rawParams->load (profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename (profPath, options.defProfRaw.substr (5) + paramFileExtension)))) {
std::cerr << "Error: default raw processing profile not found" << std::endl;
rawParams->deleteInstance();
delete rawParams;
@@ -728,7 +729,7 @@ int processLineParams ( int argc, char **argv )
imgParams = new rtengine::procparams::PartialProfile (true);
profPath = options.findProfilePath (options.defProfImg);
if (options.is_defProfImgMissing() || profPath.empty() || imgParams->load (profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename (profPath, options.defProfImg.substr (5) + paramFileExtension))) {
if (options.is_defProfImgMissing() || profPath.empty() || (profPath != DEFPROFILE_DYNAMIC && imgParams->load (profPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename (profPath, options.defProfImg.substr (5) + paramFileExtension)))) {
std::cerr << "Error: default non-raw processing profile not found" << std::endl;
imgParams->deleteInstance();
delete imgParams;
@@ -800,9 +801,21 @@ int processLineParams ( int argc, char **argv )
if (useDefault) {
if (isRaw) {
if (options.defProfRaw == DEFPROFILE_DYNAMIC) {
rawParams->deleteInstance();
delete rawParams;
rawParams = loadDynamicProfile (ii->getMetaData());
}
std::cout << " Merging default raw processing profile" << std::endl;
rawParams->applyTo (&currentParams);
} else {
if (options.defProfImg == DEFPROFILE_DYNAMIC) {
imgParams->deleteInstance();
delete imgParams;
imgParams = loadDynamicProfile (ii->getMetaData());
}
std::cout << " Merging default non-raw processing profile" << std::endl;
imgParams->applyTo (&currentParams);
}

View File

@@ -245,6 +245,10 @@ Glib::ustring Options::findProfilePath (Glib::ustring &profName)
return profName;
}
if (profName == DEFPROFILE_DYNAMIC) {
return profName;
}
Glib::ustring p = profName.substr (0, 4);
if (p == "${U}") {

View File

@@ -39,11 +39,22 @@
#define DEFPROFILE_IMG "Neutral"
// Profile name to use for internal values' profile
#define DEFPROFILE_INTERNAL "Neutral"
// Special name for the Dynamic profile
#define DEFPROFILE_DYNAMIC "Dynamic"
class SaveFormat
{
struct SaveFormat {
SaveFormat() :
format ("jpg"),
pngBits (8),
pngCompression (6),
jpegQuality (90),
jpegSubSamp (2),
tiffBits (8),
tiffUncompressed (true),
saveParams (true)
{
}
public:
Glib::ustring format;
int pngBits;
int pngCompression;
@@ -52,7 +63,6 @@ public:
int tiffBits;
bool tiffUncompressed;
bool saveParams;
SaveFormat () : format ("jpg"), pngBits (8), pngCompression (6), jpegQuality (90), jpegSubSamp (2), tiffBits (8), tiffUncompressed (true), saveParams (true) {};
};
enum ThFileType {FT_Invalid = -1, FT_None = 0, FT_Raw = 1, FT_Jpeg = 2, FT_Tiff = 3, FT_Png = 4, FT_Custom = 5, FT_Tiff16 = 6, FT_Png16 = 7, FT_Custom16 = 8};

View File

@@ -82,6 +82,7 @@ Preferences::Preferences (RTWindow *rtwindow)
nb->append_page (*getGeneralPanel(), M ("PREFERENCES_TAB_GENERAL"));
nb->append_page (*getProcParamsPanel(), M ("PREFERENCES_TAB_IMPROC"));
nb->append_page (*getDynProfilePanel(), M ("PREFERENCES_TAB_DYNAMICPROFILE"));
nb->append_page (*getFileBrowserPanel(), M ("PREFERENCES_TAB_BROWSER"));
nb->append_page (*getColorManagementPanel(), M ("PREFERENCES_TAB_COLORMGR"));
nb->append_page (*getBatchProcPanel(), M ("PREFERENCES_BATCH_PROCESSING"));
@@ -247,11 +248,11 @@ Gtk::Widget* Preferences::getBatchProcPanel ()
appendBehavList (mi, M ("TP_DIRPYRDENOISE_PASSES"), ADDSET_DIRPYRDN_PASSES, true);
mi = behModel->append ();
mi->set_value (behavColumns.label, M("TP_WBALANCE_LABEL"));
appendBehavList (mi, M("TP_WBALANCE_TEMPERATURE"), ADDSET_WB_TEMPERATURE, true);
appendBehavList (mi, M("TP_WBALANCE_GREEN"), ADDSET_WB_GREEN, true);
appendBehavList (mi, M("TP_WBALANCE_EQBLUERED"), ADDSET_WB_EQUAL, true);
appendBehavList (mi, M("TP_WBALANCE_TEMPBIAS"), ADDSET_WB_TEMPBIAS, true);
mi->set_value (behavColumns.label, M ("TP_WBALANCE_LABEL"));
appendBehavList (mi, M ("TP_WBALANCE_TEMPERATURE"), ADDSET_WB_TEMPERATURE, true);
appendBehavList (mi, M ("TP_WBALANCE_GREEN"), ADDSET_WB_GREEN, true);
appendBehavList (mi, M ("TP_WBALANCE_EQBLUERED"), ADDSET_WB_EQUAL, true);
appendBehavList (mi, M ("TP_WBALANCE_TEMPBIAS"), ADDSET_WB_TEMPBIAS, true);
mi = behModel->append ();
mi->set_value (behavColumns.label, M ("TP_COLORAPP_LABEL"));
@@ -440,6 +441,14 @@ void Preferences::behSetRadioToggled (const Glib::ustring& path)
iter->set_value (behavColumns.badd, false);
}
Gtk::Widget *Preferences::getDynProfilePanel()
{
dynProfilePanel = Gtk::manage (new DynamicProfilePanel());
return dynProfilePanel;
}
Gtk::Widget* Preferences::getProcParamsPanel ()
{
@@ -449,11 +458,13 @@ Gtk::Widget* Preferences::getProcParamsPanel ()
Gtk::VBox* vbpp = Gtk::manage (new Gtk::VBox ());
Gtk::Label* drlab = Gtk::manage (new Gtk::Label (M ("PREFERENCES_FORRAW") + ":", Gtk::ALIGN_START));
rprofiles = Gtk::manage (new ProfileStoreComboBox ());
rprofiles->addRow (profileStore.getInternalDynamicPSE());
setExpandAlignProperties (rprofiles, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
rprofiles->set_size_request (50, -1);
rpconn = rprofiles->signal_changed().connect ( sigc::mem_fun (*this, &Preferences::forRAWComboChanged) );
Gtk::Label* drimg = Gtk::manage (new Gtk::Label (M ("PREFERENCES_FORIMAGE") + ":", Gtk::ALIGN_START));
iprofiles = Gtk::manage (new ProfileStoreComboBox ());
iprofiles->addRow (profileStore.getInternalDynamicPSE());
iprofiles->set_size_request (50, -1);
setExpandAlignProperties (iprofiles, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL);
ipconn = iprofiles->signal_changed().connect ( sigc::mem_fun (*this, &Preferences::forImageComboChanged) );
@@ -2106,6 +2117,7 @@ void Preferences::okPressed ()
options.copyFrom (&moptions);
options.filterOutParsedExtensions();
Options::save ();
dynProfilePanel->save();
hide ();
}
@@ -2269,6 +2281,8 @@ void Preferences::updateProfileList()
{
rprofiles->updateProfileList();
iprofiles->updateProfileList();
rprofiles->addRow (profileStore.getInternalDynamicPSE());
iprofiles->addRow (profileStore.getInternalDynamicPSE());
}
void Preferences::restoreValue()

View File

@@ -24,6 +24,7 @@
#include "options.h"
#include <vector>
#include "rtwindow.h"
#include "dynamicprofilepanel.h"
class Preferences : public Gtk::Dialog, public ProfileStoreListener
{
@@ -204,6 +205,8 @@ class Preferences : public Gtk::Dialog, public ProfileStoreListener
Gtk::CheckButton* ckbHideTPVScrollbar;
Gtk::CheckButton* ckbUseIconNoText;
DynamicProfilePanel *dynProfilePanel;
Glib::ustring storedValueRaw;
Glib::ustring storedValueImg;
@@ -242,6 +245,7 @@ class Preferences : public Gtk::Dialog, public ProfileStoreListener
Gtk::Widget* getBatchProcPanel ();
Gtk::Widget* getPerformancePanel ();
Gtk::Widget* getSoundPanel ();
Gtk::Widget* getDynProfilePanel ();
public:
explicit Preferences (RTWindow *rtwindow);

View File

@@ -20,13 +20,14 @@
#include "options.h"
#include "toolpanel.h"
#include "guiutils.h"
#include "dynamicprofile.h"
ProfileStore profileStore;
using namespace rtengine;
using namespace rtengine::procparams;
ProfileStore::ProfileStore () : parseMutex(nullptr), storeState(STORESTATE_NOTINITIALIZED), internalDefaultProfile(nullptr), internalDefaultEntry(nullptr)
ProfileStore::ProfileStore () : parseMutex(nullptr), storeState(STORESTATE_NOTINITIALIZED), internalDefaultProfile(nullptr), internalDefaultEntry(nullptr), internalDynamicEntry(nullptr), dynamicRules(new std::vector<DynamicProfileRule>())
{
internalDefaultProfile = new AutoPartialProfile();
internalDefaultProfile->set(true);
@@ -42,6 +43,7 @@ bool ProfileStore::init ()
storeState = STORESTATE_BEINGINITIALIZED;
parseMutex = new MyMutex();
_parseProfiles ();
loadDynamicProfileRules(*dynamicRules);
storeState = STORESTATE_INITIALIZED;
}
@@ -63,6 +65,8 @@ ProfileStore::~ProfileStore ()
partProfiles.clear ();
clearFileList();
delete internalDefaultProfile;
delete internalDefaultEntry;
delete internalDynamicEntry;
lock.release();
delete parseMutex;
parseMutex = nullptr;
@@ -140,6 +144,10 @@ void ProfileStore::_parseProfiles ()
entries.push_back(internalDefaultEntry);
partProfiles[internalDefaultEntry] = internalDefaultProfile;
if (!internalDynamicEntry) {
internalDynamicEntry = new ProfileStoreEntry(Glib::ustring("(") + M("PROFILEPANEL_PDYNAMIC") + Glib::ustring(")"), PSET_FILE, 0, 0);
// do not add it to the entries. This is here only for the preferences dialog
}
// Check if the default profiles has been found.
if (findEntryFromFullPathU(options.defProfRaw) == nullptr) {
@@ -273,7 +281,7 @@ const ProfileStoreEntry* ProfileStore::findEntryFromFullPathU(Glib::ustring path
return nullptr;
}
if (path == DEFPROFILE_INTERNAL) {
if (path == DEFPROFILE_INTERNAL || path == DEFPROFILE_DYNAMIC) {
return internalDefaultEntry;
}
@@ -499,6 +507,20 @@ void ProfileStore::dumpFolderList()
printf("\n");
}
const std::vector<DynamicProfileRule> &ProfileStore::getDynamicProfileRules() const
{
return *dynamicRules;
}
void ProfileStore::setDynamicProfileRules(const std::vector<DynamicProfileRule> &r)
{
*dynamicRules = r;
}
ProfileStoreEntry::ProfileStoreEntry() : label(""), type(PSET_FOLDER), parentFolderId(0), folderId(0) {}
ProfileStoreEntry::ProfileStoreEntry(Glib::ustring label, PSEType type, unsigned short parentFolder, unsigned short folder) : label(label), type(type), parentFolderId(parentFolder), folderId(folder) {}
@@ -570,12 +592,12 @@ void ProfileStoreComboBox::refreshProfileList_ (Gtk::TreeModel::Row *parentRow,
// creating and assigning the custom Label object
newSubMenu[methodColumns.label] = entry->label;
newSubMenu[methodColumns.profileStoreEntry] = entry;
#if GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION == 18
// HACK: Workaround for bug in Gtk+ 3.18...
Gtk::TreeModel::Row menuHeader = *(refTreeModel->append(newSubMenu->children()));
menuHeader[methodColumns.label] = entry->label;
menuHeader[methodColumns.label] = "-";
menuHeader[methodColumns.profileStoreEntry] = entry;
#endif
refreshProfileList_ (&newSubMenu, entry->folderId, false, entryList);
} else {
refreshProfileList_ (parentRow, entry->folderId, true, entryList);
@@ -603,7 +625,6 @@ void ProfileStoreComboBox::refreshProfileList_ (Gtk::TreeModel::Row *parentRow,
*/
void ProfileStoreComboBox::updateProfileList ()
{
// clear items
clear();
refTreeModel.clear();
@@ -710,6 +731,11 @@ Gtk::TreeIter ProfileStoreComboBox::findRowFromFullPath (Glib::ustring path)
return row;
}
if (path == DEFPROFILE_DYNAMIC) {
row = findRowFromEntry(profileStore.getInternalDynamicPSE());
return row;
}
// removing the filename
Glib::ustring fName = Glib::path_get_basename(path);
@@ -758,6 +784,10 @@ Glib::ustring ProfileStoreComboBox::getFullPathFromActiveRow()
return Glib::ustring(DEFPROFILE_INTERNAL);
}
if (currEntry == profileStore.getInternalDynamicPSE()) {
return Glib::ustring(DEFPROFILE_DYNAMIC);
}
path = Glib::build_filename(profileStore.getPathFromId(currEntry->parentFolderId), currEntry->label);
}

View File

@@ -31,6 +31,9 @@
#include "guiutils.h"
// forward decl
class DynamicProfileRule;
/** @brief This will implement callback functions for the ProfileStore
*
*/
@@ -144,6 +147,7 @@ private:
StoreState storeState;
rtengine::procparams::AutoPartialProfile *internalDefaultProfile;
ProfileStoreEntry *internalDefaultEntry;
ProfileStoreEntry *internalDynamicEntry;
/** Alphabetically ordered list of folder and files through Gtk::Label sub-class;
* ready to be used in Menu and Combobox
@@ -160,6 +164,9 @@ private:
/** List of the client of this store */
std::list<ProfileStoreListener*> listeners;
/** cache for dynamic profile rules */
std::unique_ptr<std::vector<DynamicProfileRule>> dynamicRules;
/** @brief Method to recursively parse a profile folder with a level depth arbitrarily limited to 3
*
* @param realPath current full path of the scanned directory ; e.g.: ~/MyProfiles/
@@ -198,6 +205,14 @@ public:
return internalDefaultEntry;
}
const ProfileStoreEntry* getInternalDynamicPSE()
{
return internalDynamicEntry;
}
const std::vector<DynamicProfileRule> &getDynamicProfileRules() const;
void setDynamicProfileRules(const std::vector<DynamicProfileRule> &r);
void addListener(ProfileStoreListener *listener);
void removeListener(ProfileStoreListener *listener);

View File

@@ -21,6 +21,8 @@
#include "guiutils.h"
#include "rtimage.h"
#include "../rtengine/utils.h"
extern Options options;
SaveAsDialog::SaveAsDialog (const Glib::ustring &initialDir, Gtk::Window* parent)
@@ -217,41 +219,57 @@ SaveFormat SaveAsDialog::getFormat ()
void SaveAsDialog::okPressed ()
{
fname = fchooser->get_filename();
// checking if the filename field is empty. The user have to click Cancel if he don't want to specify a filename
// NB: There seem to be a bug in Gtkmm2.22 / FileChooserWidget : if you suppress the filename entry and
// click on a folder in the list, the filename field is empty but get_filename will return the folder's path :/
if (!fname.length() || Glib::file_test (fname, Glib::FILE_TEST_IS_DIR)) {
Glib::ustring msg_ = Glib::ustring("<b>") + M("MAIN_MSG_EMPTYFILENAME") + "</b>";
Gtk::MessageDialog msgd (*this, msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
msgd.run ();
if (Glib::file_test(fname, Glib::FILE_TEST_IS_DIR)) {
fname = fchooser->get_current_name();
}
// Checking if the filename field is empty. The user have to click Cancel if he don't want to specify a filename
if (fname.empty()) {
Gtk::MessageDialog(
*this,
Glib::ustring("<b>")
+ M("MAIN_MSG_EMPTYFILENAME")
+ "</b>",
true,
Gtk::MESSAGE_WARNING,
Gtk::BUTTONS_OK,
true
).run();
return;
}
// resolve extension ambiguities
SaveFormat sf = formatOpts->getFormat ();
Glib::ustring extLower = getExtension (fname).lowercase ();
bool extIsEmpty = (extLower == "");
bool extIsJpeg = (extLower == "jpg" || extLower == "jpeg" || extLower == "jpe");
bool extIsTiff = (extLower == "tif" || extLower == "tiff");
bool extIsPng = (extLower == "png");
if (getExtension(fname).empty()) {
// Extension is either empty or unfamiliar
fname += '.' + formatOpts->getFormat().format;
} else if (
!rtengine::hasJpegExtension(fname)
&& !rtengine::hasTiffExtension(fname)
&& !rtengine::hasPngExtension(fname)
) {
// Create dialog to warn user that the filename may have two extensions on the end
Gtk::MessageDialog msgd(
*this,
Glib::ustring("<b>")
+ M("GENERAL_WARNING")
+ ": "
+ M("SAVEDLG_WARNFILENAME")
+ " \""
+ Glib::path_get_basename (fname)
+ '.'
+ formatOpts->getFormat().format
+ "\"</b>",
true,
Gtk::MESSAGE_WARNING,
Gtk::BUTTONS_OK_CANCEL,
true
);
if (extIsEmpty || !(extIsJpeg || extIsTiff || extIsPng)) {
// extension is either empty or unfamiliar.
fname += Glib::ustring (".") + sf.format;
} else if ( !(sf.format == "jpg" && extIsJpeg)
&& !(sf.format == "tif" && extIsTiff)
&& !(sf.format == "png" && extIsPng ) ) {
// create dialog to warn user that the filename may have two extensions on the end.
Glib::ustring msg_ = Glib::ustring ("<b>") + M("GENERAL_WARNING") + ": "
+ M("SAVEDLG_WARNFILENAME") + " \"" + Glib::path_get_basename (fname)
+ "." + sf.format + "\"</b>";
Gtk::MessageDialog msgd (*this, msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK_CANCEL, true);
if (msgd.run () == Gtk::RESPONSE_OK) {
fname += Glib::ustring (".") + sf.format;
if (msgd.run() == Gtk::RESPONSE_OK) {
fname += "." + formatOpts->getFormat().format;
} else {
return;
}

View File

@@ -30,6 +30,7 @@
#include "profilestore.h"
#include "batchqueue.h"
#include "extprog.h"
#include "dynamicprofile.h"
using namespace rtengine::procparams;
@@ -216,8 +217,31 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu
const CacheImageData* cfs = getCacheImageData();
Glib::ustring defaultPparamsPath = options.findProfilePath(defProf);
const bool create = (!hasProcParams() || forceCPB);
if (!options.CPBPath.empty() && !defaultPparamsPath.empty() && (!hasProcParams() || forceCPB) && cfs && cfs->exifValid) {
const Glib::ustring outFName =
(options.paramsLoadLocation == PLL_Input) ?
fname + paramFileExtension :
getCacheFileName("profiles", paramFileExtension);
if (defProf == DEFPROFILE_DYNAMIC && create && cfs && cfs->exifValid) {
rtengine::ImageMetaData* imageMetaData;
if (getType() == FT_Raw) {
rtengine::RawMetaDataLocation metaData = rtengine::Thumbnail::loadMetaDataFromRaw(fname);
imageMetaData = rtengine::ImageMetaData::fromFile (fname, &metaData);
} else {
imageMetaData = rtengine::ImageMetaData::fromFile (fname, nullptr);
}
PartialProfile *pp = loadDynamicProfile(imageMetaData);
int err = pp->pparams->save(outFName);
pp->deleteInstance();
delete pp;
if (!err) {
loadProcParams();
}
}
if (!options.CPBPath.empty() && !defaultPparamsPath.empty() && create && cfs && cfs->exifValid) {
// First generate the communication file, with general values and EXIF metadata
rtengine::ImageMetaData* imageMetaData;
@@ -233,14 +257,6 @@ rtengine::procparams::ProcParams* Thumbnail::createProcParamsForUpdate(bool retu
const rtexif::TagDirectory* exifDir = nullptr;
if (imageMetaData && (exifDir = imageMetaData->getExifData())) {
Glib::ustring outFName;
if (options.paramsLoadLocation == PLL_Input) {
outFName = fname + paramFileExtension;
} else {
outFName = getCacheFileName("profiles", paramFileExtension);
}
exifDir->CPBDump(tmpFileName, fname, outFName,
defaultPparamsPath == DEFPROFILE_INTERNAL ? DEFPROFILE_INTERNAL : Glib::build_filename(defaultPparamsPath, Glib::path_get_basename(defProf) + paramFileExtension),
cfs,