1 /*
2 * This file is part of RawTherapee.
3 *
4 * Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
5 *
6 * RawTherapee is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * RawTherapee is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <map>
21 #include <iterator>
22 #include <iostream>
23
24 #include <locale.h>
25
26 #include <glib/gstdio.h>
27
28 #include <giomm.h>
29 #include <sstream>
30 #include <fstream>
31
32 #include "curves.h"
33 #include "procparams.h"
34 #include "rtengine.h"
35 #include "metadata.h"
36 #include "halffloat.h"
37 #include "base64.h"
38
39 #include "../rtgui/multilangmgr.h"
40 #include "../rtgui/options.h"
41 #include "../rtgui/paramsedited.h"
42 #include "../rtgui/ppversion.h"
43 #include "../rtgui/version.h"
44
45 using namespace std;
46
47 namespace rtengine { namespace procparams {
48
49 namespace {
50
compress(const std::string & src)51 std::vector<uint8_t> compress(const std::string &src)
52 {
53 auto s = Gio::MemoryOutputStream::create(nullptr, 0, g_realloc, g_free);
54 auto c = Gio::ZlibCompressor::create(Gio::ZLIB_COMPRESSOR_FORMAT_RAW, -1);
55 std::vector<uint8_t> res;
56 {
57 auto stream = Gio::ConverterOutputStream::create(s, c);
58 stream->set_close_base_stream(true);
59 gsize n;
60 if (!stream->write_all(src, n)) {
61 return res;
62 }
63 }
64 char *data = static_cast<char *>(s->get_data());
65 for (size_t i = 0, n = s->get_data_size(); i < n; ++i) {
66 res.push_back(data[i]);
67 }
68 return res;
69 }
70
71
decompress(const std::vector<uint8_t> & src)72 std::string decompress(const std::vector<uint8_t> &src)
73 {
74 auto s = Gio::MemoryOutputStream::create(nullptr, 0, g_realloc, g_free);
75 auto c = Gio::ZlibDecompressor::create(Gio::ZLIB_COMPRESSOR_FORMAT_RAW);
76 std::vector<char> res;
77 {
78 auto stream = Gio::ConverterOutputStream::create(s, c);
79 stream->set_close_base_stream(true);
80 constexpr gsize chunk = 512;
81 size_t i = 0;
82 while (i < src.size()) {
83 gsize count = std::min(src.size() - i, chunk);
84 auto n = stream->write(&(src[i]), count);
85 if (n < 0) {
86 return "";
87 } else if (n == 0) {
88 break;
89 }
90 i += n;
91 }
92 // gsize n;
93 // if (!stream->write_all(&(src[0]), src.size(), n)) {
94 // return "";
95 // }
96 }
97 char *data = static_cast<char *>(s->get_data());
98 for (size_t i = 0, n = s->get_data_size(); i < n; ++i) {
99 res.push_back(data[i]);
100 }
101 res.push_back(0);
102 return std::string(&(res[0]));
103 }
104
105 class ConversionError: public std::exception {
what() const106 const char *what() const noexcept { return "base64 error"; }
107 };
108
to_xmp(const Glib::ustring & data)109 std::string to_xmp(const Glib::ustring &data)
110 {
111 auto res = compress(data.raw());
112 return base64encode(res);
113 }
114
115
from_xmp(const std::string & data)116 Glib::ustring from_xmp(const std::string &data)
117 {
118 try {
119 auto buf = base64decode(data);
120 return decompress(buf);
121 } catch (std::exception &e) {
122 throw ConversionError();
123 }
124 }
125
unpack_list(const std::string & data)126 std::vector<double> unpack_list(const std::string &data)
127 {
128 std::vector<double> ret;
129 if (data.empty()) {
130 return ret;
131 }
132 std::vector<uint8_t> buf;
133 try {
134 buf = base64decode(data);
135 } catch (std::exception &exc) {
136 throw ConversionError();
137 }
138 Exiv2::byte *p = reinterpret_cast<Exiv2::byte *>(&(buf[0]));
139 for (size_t i = 0; i < buf.size(); i += sizeof(uint16_t)) {
140 uint16_t v = Exiv2::getUShort(p + i, Exiv2::littleEndian);
141 float f = DNG_HalfToFloat(v);
142 ret.push_back(f);
143 }
144 return ret;
145 }
146
147
pack_list(const std::vector<double> & data)148 std::string pack_list(const std::vector<double> &data)
149 {
150 if (data.empty()) {
151 return "";
152 }
153 std::vector<uint8_t> bytes(data.size() * sizeof(uint16_t));
154 auto p = &(bytes[0]);
155 size_t off = 0;
156 for (auto f : data) {
157 uint16_t v = DNG_FloatToHalf(f);
158 long o = Exiv2::us2Data(p + off, v, Exiv2::littleEndian);
159 off += o;
160 }
161 return base64encode(bytes);
162 }
163
164 } // namespace
165
166
167 const short SpotParams::minRadius = 2;
168 const short SpotParams::maxRadius = 200;
169
170 //-----------------------------------------------------------------------------
171 // KeyFile
172 //-----------------------------------------------------------------------------
173
has_group(const Glib::ustring & grp) const174 bool KeyFile::has_group(const Glib::ustring &grp) const
175 {
176 return kf_.has_group(GRP(grp));
177 }
178
179
has_key(const Glib::ustring & grp,const Glib::ustring & key) const180 bool KeyFile::has_key(const Glib::ustring &grp, const Glib::ustring &key) const
181 {
182 return kf_.has_key(GRP(grp), key);
183 }
184
185
get_keys(const Glib::ustring & grp) const186 Glib::ArrayHandle<Glib::ustring> KeyFile::get_keys(const Glib::ustring &grp) const
187 {
188 return kf_.get_keys(GRP(grp));
189 }
190
191
get_string(const Glib::ustring & grp,const Glib::ustring & key) const192 Glib::ustring KeyFile::get_string(const Glib::ustring &grp, const Glib::ustring &key) const
193 {
194 return kf_.get_string(GRP(grp), key);
195 }
196
197
get_integer(const Glib::ustring & grp,const Glib::ustring & key) const198 int KeyFile::get_integer(const Glib::ustring &grp, const Glib::ustring &key) const
199 {
200 return kf_.get_integer(GRP(grp), key);
201 }
202
203
get_double(const Glib::ustring & grp,const Glib::ustring & key) const204 double KeyFile::get_double(const Glib::ustring &grp, const Glib::ustring &key) const
205 {
206 return kf_.get_double(GRP(grp), key);
207 }
208
209
get_boolean(const Glib::ustring & grp,const Glib::ustring & key) const210 bool KeyFile::get_boolean(const Glib::ustring &grp, const Glib::ustring &key) const
211 {
212 return kf_.get_boolean(GRP(grp), key);
213 }
214
215
get_string_list(const Glib::ustring & grp,const Glib::ustring & key) const216 Glib::ArrayHandle<Glib::ustring> KeyFile::get_string_list(const Glib::ustring &grp, const Glib::ustring &key) const
217 {
218 return kf_.get_string_list(GRP(grp), key);
219 }
220
221
get_integer_list(const Glib::ustring & grp,const Glib::ustring & key) const222 Glib::ArrayHandle<int> KeyFile::get_integer_list(const Glib::ustring &grp, const Glib::ustring &key) const
223 {
224 return kf_.get_integer_list(GRP(grp), key);
225 }
226
227
get_double_list(const Glib::ustring & grp,const Glib::ustring & key) const228 Glib::ArrayHandle<double> KeyFile::get_double_list(const Glib::ustring &grp, const Glib::ustring &key) const
229 {
230 return kf_.get_double_list(GRP(grp), key);
231 }
232
233
set_string(const Glib::ustring & grp,const Glib::ustring & key,const Glib::ustring & string)234 void KeyFile::set_string(const Glib::ustring &grp, const Glib::ustring &key, const Glib::ustring &string)
235 {
236 kf_.set_string(GRP(grp), key, string);
237 }
238
239
set_boolean(const Glib::ustring & grp,const Glib::ustring & key,bool value)240 void KeyFile::set_boolean(const Glib::ustring &grp, const Glib::ustring &key, bool value)
241 {
242 kf_.set_boolean(GRP(grp), key, value);
243 }
244
245
set_integer(const Glib::ustring & grp,const Glib::ustring & key,int value)246 void KeyFile::set_integer(const Glib::ustring &grp, const Glib::ustring &key, int value)
247 {
248 kf_.set_integer(GRP(grp), key, value);
249 }
250
251
set_double(const Glib::ustring & grp,const Glib::ustring & key,double value)252 void KeyFile::set_double(const Glib::ustring &grp, const Glib::ustring &key, double value)
253 {
254 kf_.set_double(GRP(grp), key, value);
255 }
256
257
set_string_list(const Glib::ustring & grp,const Glib::ustring & key,const Glib::ArrayHandle<Glib::ustring> & list)258 void KeyFile::set_string_list(const Glib::ustring &grp, const Glib::ustring &key, const Glib::ArrayHandle<Glib::ustring> &list)
259 {
260 kf_.set_string_list(GRP(grp), key, list);
261 }
262
263
set_integer_list(const Glib::ustring & grp,const Glib::ustring & key,const Glib::ArrayHandle<int> & list)264 void KeyFile::set_integer_list(const Glib::ustring &grp, const Glib::ustring &key, const Glib::ArrayHandle<int> &list)
265 {
266 kf_.set_integer_list(GRP(grp), key, list);
267 }
268
269
set_double_list(const Glib::ustring & grp,const Glib::ustring & key,const Glib::ArrayHandle<double> & list)270 void KeyFile::set_double_list(const Glib::ustring &grp, const Glib::ustring &key, const Glib::ArrayHandle<double> &list)
271 {
272 kf_.set_double_list(GRP(grp), key, list);
273 }
274
275
load_from_file(const Glib::ustring & fn)276 bool KeyFile::load_from_file(const Glib::ustring &fn)
277 {
278 filename_ = fn;
279 return kf_.load_from_file(fn);
280 }
281
282
load_from_data(const Glib::ustring & data)283 bool KeyFile::load_from_data(const Glib::ustring &data)
284 {
285 return kf_.load_from_data(data);
286 }
287
288
to_data()289 Glib::ustring KeyFile::to_data()
290 {
291 return kf_.to_data();
292 }
293
294
295 namespace {
296
expandRelativePath(const Glib::ustring & procparams_fname,const Glib::ustring & prefix,Glib::ustring embedded_fname)297 Glib::ustring expandRelativePath(const Glib::ustring &procparams_fname, const Glib::ustring &prefix, Glib::ustring embedded_fname)
298 {
299 if (embedded_fname == "" || !Glib::path_is_absolute(procparams_fname)) {
300 return embedded_fname;
301 }
302
303 if (prefix != "") {
304 if (embedded_fname.length() < prefix.length() || embedded_fname.substr(0, prefix.length()) != prefix) {
305 return embedded_fname;
306 }
307
308 embedded_fname = embedded_fname.substr(prefix.length());
309 }
310
311 if (Glib::path_is_absolute(embedded_fname)) {
312 return prefix + embedded_fname;
313 }
314
315 Glib::ustring absPath = prefix + Glib::path_get_dirname(procparams_fname) + G_DIR_SEPARATOR_S + embedded_fname;
316 return absPath;
317 }
318
319
getFromKeyfile(const KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,int & value)320 void getFromKeyfile(
321 const KeyFile& keyfile,
322 const Glib::ustring& group_name,
323 const Glib::ustring& key,
324 int& value
325 )
326 {
327 value = keyfile.get_integer(group_name, key);
328 }
329
getFromKeyfile(const KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,double & value)330 void getFromKeyfile(
331 const KeyFile& keyfile,
332 const Glib::ustring& group_name,
333 const Glib::ustring& key,
334 double& value
335 )
336 {
337 value = keyfile.get_double(group_name, key);
338 }
339
getFromKeyfile(const KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,bool & value)340 void getFromKeyfile(
341 const KeyFile& keyfile,
342 const Glib::ustring& group_name,
343 const Glib::ustring& key,
344 bool& value
345 )
346 {
347 try {
348 value = keyfile.get_boolean(group_name, key);
349 } catch (Glib::KeyFileError &e) {
350 int v = keyfile.get_integer(group_name, key);
351 value = v;
352 }
353 }
354
getFromKeyfile(const KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,Glib::ustring & value)355 void getFromKeyfile(
356 const KeyFile& keyfile,
357 const Glib::ustring& group_name,
358 const Glib::ustring& key,
359 Glib::ustring& value
360 )
361 {
362 value = keyfile.get_string(group_name, key);
363 }
364
getFromKeyfile(const KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,std::vector<double> & value)365 void getFromKeyfile(
366 const KeyFile& keyfile,
367 const Glib::ustring& group_name,
368 const Glib::ustring& key,
369 std::vector<double>& value
370 )
371 {
372 value = keyfile.get_double_list(group_name, key);
373 rtengine::sanitizeCurve(value);
374 }
375
getFromKeyfile(const KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,std::vector<float> & value)376 void getFromKeyfile(
377 const KeyFile& keyfile,
378 const Glib::ustring& group_name,
379 const Glib::ustring& key,
380 std::vector<float>& value
381 )
382 {
383 std::vector<double> tmpval = keyfile.get_double_list(group_name, key);
384 value.assign(tmpval.begin(), tmpval.end());
385 }
386
getFromKeyfile(const KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,std::vector<std::string> & value)387 void getFromKeyfile(
388 const KeyFile& keyfile,
389 const Glib::ustring& group_name,
390 const Glib::ustring& key,
391 std::vector<std::string>& value
392 )
393 {
394 auto tmpval = keyfile.get_string_list(group_name, key);
395 value.assign(tmpval.begin(), tmpval.end());
396 }
397
398 template<typename T>
assignFromKeyfile(const KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,T & value)399 bool assignFromKeyfile(const KeyFile& keyfile, const Glib::ustring& group_name, const Glib::ustring& key, T &value)
400 {
401 try {
402 if (keyfile.has_key(group_name, key)) {
403 getFromKeyfile(keyfile, group_name, key, value);
404
405 return true;
406 }
407 } catch (Glib::KeyFileError &exc) {
408 auto pl = keyfile.progressListener();
409 if (pl) {
410 pl->error(Glib::ustring::compose("WARNING: %1: %2", keyfile.filename(), exc.what()));
411 return false;
412 } else {
413 throw exc;
414 }
415 }
416
417 return false;
418 }
419
420 template<typename T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
assignFromKeyfile(const KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,const std::map<std::string,T> & mapping,T & value)421 bool assignFromKeyfile(const KeyFile& keyfile, const Glib::ustring& group_name, const Glib::ustring& key, const std::map<std::string, T>& mapping, T& value)
422 {
423 try {
424 if (keyfile.has_key(group_name, key)) {
425 Glib::ustring v;
426 getFromKeyfile(keyfile, group_name, key, v);
427
428 const typename std::map<std::string, T>::const_iterator m = mapping.find(v);
429
430 if (m != mapping.end()) {
431 value = m->second;
432 } else {
433 return false;
434 }
435
436 return true;
437 }
438 } catch (Glib::KeyFileError &exc) {
439 auto pl = keyfile.progressListener();
440 if (pl) {
441 pl->error(Glib::ustring::compose("WARNING: %1: %2", keyfile.filename(), exc.what()));
442 return false;
443 } else {
444 throw exc;
445 }
446 }
447
448 return false;
449 }
450
putToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,int value,KeyFile & keyfile)451 void putToKeyfile(
452 const Glib::ustring& group_name,
453 const Glib::ustring& key,
454 int value,
455 KeyFile& keyfile
456 )
457 {
458 keyfile.set_integer(group_name, key, value);
459 }
460
putToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,double value,KeyFile & keyfile)461 void putToKeyfile(
462 const Glib::ustring& group_name,
463 const Glib::ustring& key,
464 double value,
465 KeyFile& keyfile
466 )
467 {
468 keyfile.set_double(group_name, key, value);
469 }
470
putToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,bool value,KeyFile & keyfile)471 void putToKeyfile(
472 const Glib::ustring& group_name,
473 const Glib::ustring& key,
474 bool value,
475 KeyFile& keyfile
476 )
477 {
478 keyfile.set_boolean(group_name, key, value);
479 }
480
putToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,const Glib::ustring & value,KeyFile & keyfile)481 void putToKeyfile(
482 const Glib::ustring& group_name,
483 const Glib::ustring& key,
484 const Glib::ustring& value,
485 KeyFile& keyfile
486 )
487 {
488 keyfile.set_string(group_name, key, value);
489 }
490
putToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,const std::vector<int> & value,KeyFile & keyfile)491 void putToKeyfile(
492 const Glib::ustring& group_name,
493 const Glib::ustring& key,
494 const std::vector<int>& value,
495 KeyFile& keyfile
496 )
497 {
498 const Glib::ArrayHandle<int> list = value;
499 keyfile.set_integer_list(group_name, key, list);
500 }
501
putToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,const std::vector<double> & value,KeyFile & keyfile)502 void putToKeyfile(
503 const Glib::ustring& group_name,
504 const Glib::ustring& key,
505 const std::vector<double>& value,
506 KeyFile& keyfile
507 )
508 {
509 const Glib::ArrayHandle<double> list = value;
510 keyfile.set_double_list(group_name, key, list);
511 }
512
putToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,const std::vector<std::string> & value,KeyFile & keyfile)513 void putToKeyfile(
514 const Glib::ustring& group_name,
515 const Glib::ustring& key,
516 const std::vector<std::string>& value,
517 KeyFile& keyfile
518 )
519 {
520 const Glib::ArrayHandle<Glib::ustring> list = value;
521 keyfile.set_string_list(group_name, key, list);
522 }
523
524 template<typename T>
saveToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,const T & value,KeyFile & keyfile)525 bool saveToKeyfile(
526 const Glib::ustring& group_name,
527 const Glib::ustring& key,
528 const T& value,
529 KeyFile& keyfile
530 )
531 {
532 putToKeyfile(group_name, key, value, keyfile);
533 return true;
534 }
535
536 template<typename T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
saveToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,const std::map<T,const char * > & mapping,const T & value,KeyFile & keyfile)537 bool saveToKeyfile(
538 const Glib::ustring& group_name,
539 const Glib::ustring& key,
540 const std::map<T, const char*>& mapping,
541 const T& value,
542 KeyFile& keyfile
543 )
544 {
545 const typename std::map<T, const char*>::const_iterator m = mapping.find(value);
546
547 if (m != mapping.end()) {
548 keyfile.set_string(group_name, key, m->second);
549 return true;
550 }
551
552 return false;
553 }
554
555
filenameToUri(const Glib::ustring & fname,const Glib::ustring & basedir)556 Glib::ustring filenameToUri(const Glib::ustring &fname, const Glib::ustring &basedir)
557 {
558 if (fname.empty()) {
559 return fname;
560 }
561
562 const auto stripif =
563 [](std::string &p, const Glib::ustring &d) -> bool
564 {
565 std::string dd = Glib::filename_from_utf8(d + G_DIR_SEPARATOR_S);
566 if (p.substr(0, dd.length()) == dd) {
567 p = std::string(G_DIR_SEPARATOR_S) + p.substr(dd.length());
568 return true;
569 }
570 return false;
571 };
572
573 try {
574 auto fn = Glib::filename_from_utf8(fname);
575 if (Glib::path_is_absolute(fname)) {
576 if (stripif(fn, argv0)) {
577 return Glib::filename_to_uri(fn, "S");
578 } else if (stripif(fn, options.rtdir)) {
579 return Glib::filename_to_uri(fn, "U");
580 } else if (Glib::path_get_dirname(fname) == basedir) {
581 fn = Glib::filename_to_utf8(Glib::path_get_basename(fname));
582 return Glib::filename_to_uri(fn, "B");
583 } else {
584 return Glib::filename_to_uri(fn);
585 }
586 } else {
587 return Glib::filename_to_uri(Glib::ustring(G_DIR_SEPARATOR_S) + fn, "R");
588 }
589 } catch (Glib::ConvertError &) {
590 return fname;
591 }
592 }
593
594
filenameFromUri(const Glib::ustring & uri,const Glib::ustring & basedir)595 Glib::ustring filenameFromUri(const Glib::ustring &uri, const Glib::ustring &basedir)
596 {
597 if (uri.empty()) {
598 return uri;
599 }
600
601 try {
602 // Glib::filename_from_uri seems to have troubles on windows (leads to
603 // crashes), so we use the C function directly
604 gchar *h = nullptr;
605 gchar *fn = g_filename_from_uri(uri.c_str(), &h, nullptr);
606 if (!fn) {
607 return uri;
608 }
609 std::string f(fn);
610 g_free(fn);
611 if (h) {
612 std::string hn(h);
613 g_free(h);
614 f = f.substr(1);
615 if (hn == "U") {
616 f = Glib::build_filename(Glib::filename_from_utf8(options.rtdir), f);
617 } else if (hn == "S") {
618 f = Glib::build_filename(Glib::filename_from_utf8(argv0), f);
619 } else if (hn == "B") {
620 f = Glib::build_filename(Glib::filename_from_utf8(basedir), f);
621 } else if (hn != "R") {
622 return uri;
623 }
624 }
625 Glib::ustring ret = Glib::filename_to_utf8(f);
626 return ret;
627 } catch (Glib::ConvertError &e) {
628 return uri;
629 }
630 }
631
632 } // namespace
633
634
635
Shape()636 AreaMask::Shape::Shape():
637 mode(ADD),
638 feather(0.),
639 blur(0.)
640 {
641 }
642
Rectangle()643 AreaMask::Rectangle::Rectangle():
644 x(0.),
645 y(0.),
646 width(100.),
647 height(100.),
648 angle(0.),
649 roundness(0.)
650 {
651 }
652
653
Gradient()654 AreaMask::Gradient::Gradient():
655 x(0.),
656 y(0.),
657 strengthStart(100.),
658 strengthEnd(0.),
659 angle(0.)
660 {
661 feather = 25.;
662 }
663
664
clone() const665 std::unique_ptr<AreaMask::Shape> AreaMask::Rectangle::clone() const
666 {
667 return std::unique_ptr<Shape>(new Rectangle(*this));
668 }
669
670
Knot()671 AreaMask::Polygon::Knot::Knot():
672 x(0.),
673 y(0.),
674 roundness(0.)
675 {
676 }
677
setPos(CoordD & pos)678 void AreaMask::Polygon::Knot::setPos(CoordD &pos)
679 {
680 x = pos.x;
681 y = pos.y;
682 }
683
684
clone() const685 std::unique_ptr<AreaMask::Shape> AreaMask::Polygon::clone() const
686 {
687 return std::unique_ptr<Shape>(new Polygon(*this));
688 }
689
clone() const690 std::unique_ptr<AreaMask::Shape> AreaMask::Gradient::clone() const
691 {
692 return std::unique_ptr<Shape>(new Gradient(*this));
693 }
694
operator ==(const Shape & other) const695 bool AreaMask::Shape::operator==(const Shape &other) const
696 {
697 return mode == other.mode
698 && feather == other.feather
699 && blur == other.blur;
700 }
701
702
operator !=(const Shape & other) const703 bool AreaMask::Shape::operator!=(const Shape &other) const
704 {
705 return !(*this == other);
706 }
707
708
operator ==(const Knot & other) const709 bool AreaMask::Polygon::Knot::operator==(const Knot &other) const
710 {
711 return
712 x == other.x
713 && y == other.y
714 && roundness == other.roundness;
715 }
716
717
toImgSpace(double v,int imSize)718 int AreaMask::Shape::toImgSpace(double v, int imSize)
719 {
720 double s2 = imSize / 2.;
721 return s2 + v / 100. * s2;
722 }
723
724
toParamRange(int v,int imSize)725 double AreaMask::Shape::toParamRange(int v, int imSize)
726 {
727 double s2 = imSize / 2.;
728 return (double(v) - s2) * 100. / s2;
729 }
730
731
knots_to_list(std::vector<double> & out) const732 void AreaMask::Polygon::knots_to_list(std::vector<double> &out) const
733 {
734 if (knots.empty()) {
735 out.clear();
736 return;
737 }
738
739 out.resize(knots.size() * 3);
740
741 for (size_t i = 0, j = 0; i < knots.size() ; ++i) {
742 out[j++] = knots[i].x;
743 out[j++] = knots[i].y;
744 out[j++] = knots[i].roundness;
745 }
746 }
747
748
knots_from_list(const std::vector<double> & v)749 void AreaMask::Polygon::knots_from_list(const std::vector<double> &v)
750 {
751 size_t size = v.size() / 3;
752 knots.resize(size);
753
754 for (size_t i = 0, j = 0; i < size ; ++i) {
755 knots[i].x = v.at(j++);
756 knots[i].y = v.at(j++);
757 knots[i].roundness = v.at(j++);
758 }
759 }
760
761
operator !=(const Knot & other) const762 bool AreaMask::Polygon::Knot::operator!=(const Knot &other) const
763 {
764 return !(*this == other);
765 }
766
767
operator ==(const Shape & other) const768 bool AreaMask::Rectangle::operator==(const Shape &other) const
769 {
770 const Rectangle *o = dynamic_cast<const Rectangle *>(&other);
771 if (!o) {
772 return false;
773 }
774
775 return
776 x == o->x
777 && y == o->y
778 && width == o->width
779 && height == o->height
780 && angle == o->angle
781 && roundness == o->roundness
782 && AreaMask::Shape::operator==(other);
783 }
784
785
operator !=(const Shape & other) const786 bool AreaMask::Rectangle::operator!=(const Shape &other) const
787 {
788 return !(*this == other);
789 }
790
791
operator ==(const Shape & other) const792 bool AreaMask::Polygon::operator==(const Shape &other) const
793 {
794 const Polygon *o = dynamic_cast<const Polygon *>(&other);
795 if (!o) {
796 return false;
797 }
798
799 return
800 knots == o->knots
801 && AreaMask::Shape::operator==(other);
802 }
803
804
operator !=(const Shape & other) const805 bool AreaMask::Polygon::operator!=(const Shape &other) const
806 {
807 return !(*this == other);
808 }
809
810
operator ==(const Shape & other) const811 bool AreaMask::Gradient::operator==(const Shape &other) const
812 {
813 const Gradient *o = dynamic_cast<const Gradient *>(&other);
814 if (!o) {
815 return false;
816 }
817
818 return
819 x == o->x
820 && y == o->y
821 && strengthStart == o->strengthStart
822 && strengthEnd == o->strengthEnd
823 && angle == o->angle
824 && AreaMask::Shape::operator==(other);
825 }
826
827
operator !=(const Shape & other) const828 bool AreaMask::Gradient::operator!=(const Shape &other) const
829 {
830 return !(*this == other);
831 }
832
833
AreaMask()834 AreaMask::AreaMask():
835 enabled(false),
836 feather(0),
837 blur(0),
838 contrast{DCT_Linear},
839 shapes{}
840 {
841 }
842
843
operator ==(const AreaMask & other) const844 bool AreaMask::operator==(const AreaMask &other) const
845 {
846 return enabled == other.enabled
847 && feather == other.feather
848 && blur == other.blur
849 && contrast == other.contrast
850 && shapes == other.shapes;
851 }
852
853
operator !=(const AreaMask & other) const854 bool AreaMask::operator!=(const AreaMask &other) const
855 {
856 return !(*this == other);
857 }
858
859
isTrivial() const860 bool AreaMask::isTrivial() const
861 {
862 AreaMask n;
863 n.enabled = true;
864 return (!enabled || *this == n);
865 }
866
867
AreaMask(const AreaMask & other)868 AreaMask::AreaMask(const AreaMask &other):
869 enabled(other.enabled),
870 feather(other.feather),
871 blur(other.blur),
872 contrast(other.contrast)
873 {
874 for (const auto &s : other.shapes) {
875 shapes.emplace_back(s->clone());
876 }
877 }
878
879
operator =(const AreaMask & other)880 AreaMask &AreaMask::operator=(const AreaMask &other)
881 {
882 enabled = other.enabled;
883 feather = other.feather;
884 blur = other.blur;
885 contrast = other.contrast;
886
887 shapes.clear();
888 for (const auto &s : other.shapes) {
889 shapes.emplace_back(s->clone());
890 }
891 return *this;
892 }
893
894
DeltaEMask()895 DeltaEMask::DeltaEMask():
896 enabled(false),
897 L(0.0),
898 C(0.0),
899 H(0.0),
900 range(1.0),
901 decay(1),
902 weight_L(50),
903 weight_C(75),
904 weight_H(100)
905 {
906 }
907
908
operator ==(const DeltaEMask & other) const909 bool DeltaEMask::operator==(const DeltaEMask &other) const
910 {
911 return enabled == other.enabled
912 && L == other.L
913 && C == other.C
914 && H == other.H
915 && range == other.range
916 && decay == other.decay
917 && weight_L == other.weight_L
918 && weight_C == other.weight_C
919 && weight_H == other.weight_H;
920 }
921
922
operator !=(const DeltaEMask & other) const923 bool DeltaEMask::operator!=(const DeltaEMask &other) const
924 {
925 return !(*this == other);
926 }
927
928
Stroke()929 DrawnMask::Stroke::Stroke():
930 x(-1),
931 y(-1),
932 radius(0),
933 hardness(1),
934 erase(false)
935 {
936 }
937
938
operator ==(const Stroke & other) const939 bool DrawnMask::Stroke::operator==(const Stroke &other) const
940 {
941 return x == other.x
942 && y == other.y
943 && radius == other.radius
944 && erase == other.erase
945 && hardness == other.hardness;
946 }
947
948
operator !=(const Stroke & other) const949 bool DrawnMask::Stroke::operator!=(const Stroke &other) const
950 {
951 return !(*this == other);
952 }
953
954
DrawnMask()955 DrawnMask::DrawnMask():
956 enabled(false),
957 feather(0.0),
958 transparency(0),
959 smoothness(0),
960 contrast{DCT_Linear},
961 strokes(),
962 mode(INTERSECT)
963 {
964 }
965
966
operator ==(const DrawnMask & other) const967 bool DrawnMask::operator==(const DrawnMask &other) const
968 {
969 return enabled == other.enabled
970 && feather == other.feather
971 && transparency == other.transparency
972 && smoothness == other.smoothness
973 && contrast == other.contrast
974 && strokes == other.strokes
975 && mode == other.mode;
976 }
977
978
operator !=(const DrawnMask & other) const979 bool DrawnMask::operator!=(const DrawnMask &other) const
980 {
981 return !(*this == other);
982 }
983
984
isTrivial() const985 bool DrawnMask::isTrivial() const
986 {
987 return !enabled;
988 }
989
990
strokes_to_list(std::vector<double> & out) const991 void DrawnMask::strokes_to_list(std::vector<double> &out) const
992 {
993 if (strokes.empty()) {
994 return;
995 }
996
997 const auto same =
998 [](const Stroke &a, const Stroke &b) -> bool
999 {
1000 return a.radius == b.radius
1001 && a.erase == b.erase
1002 && a.hardness == b.hardness;
1003 };
1004
1005 auto cur = strokes[0];
1006 size_t pos = 0;
1007 while (true) {
1008 int n = 0;
1009 while (pos + n < strokes.size() && same(strokes[pos + n], cur)) {
1010 ++n;
1011 }
1012 out.push_back(n);
1013 out.push_back(cur.radius);
1014 out.push_back(int(!cur.erase));
1015 out.push_back(cur.hardness);
1016 for (int i = 0; i < n; ++i) {
1017 out.push_back(strokes[pos].x);
1018 out.push_back(strokes[pos].y);
1019 ++pos;
1020 }
1021 if (pos >= strokes.size()) {
1022 break;
1023 } else {
1024 cur = strokes[pos];
1025 }
1026 }
1027 }
1028
1029
strokes_from_list(const std::vector<double> & v)1030 void DrawnMask::strokes_from_list(const std::vector<double> &v)
1031 {
1032 strokes.clear();
1033 size_t pos = 0;
1034 while (pos + 4 < v.size()) {
1035 int n = v[pos++];
1036 Stroke s;
1037 s.radius = v[pos++];
1038 s.erase = !bool(v[pos++]);
1039 s.hardness = v[pos++];
1040 for (int i = 0; i < n && pos + 1 < v.size(); ++i) {
1041 strokes.push_back(s);
1042 strokes.back().x = v[pos++];
1043 strokes.back().y = v[pos++];
1044 }
1045 }
1046 }
1047
1048
ParametricMask()1049 ParametricMask::ParametricMask():
1050 enabled(false),
1051 blur(0),
1052 hue{
1053 FCT_MinMaxCPoints,
1054 0.166666667,
1055 1.,
1056 0.35,
1057 0.35,
1058 0.8287775246,
1059 1.,
1060 0.35,
1061 0.35
1062 },
1063 chromaticity{
1064 FCT_MinMaxCPoints,
1065 0.,
1066 1.,
1067 0.35,
1068 0.35,
1069 1.,
1070 1.,
1071 0.35,
1072 0.35
1073 },
1074 lightness{
1075 FCT_MinMaxCPoints,
1076 0.,
1077 1.,
1078 0.35,
1079 0.35,
1080 1.,
1081 1.,
1082 0.35,
1083 0.35
1084 },
1085 lightnessDetail(0),
1086 contrastThreshold(0)
1087 {
1088 }
1089
1090
operator ==(const ParametricMask & other) const1091 bool ParametricMask::operator==(const ParametricMask &other) const
1092 {
1093 return enabled == other.enabled
1094 && blur == other.blur
1095 && hue == other.hue
1096 && chromaticity == other.chromaticity
1097 && lightness == other.lightness
1098 && lightnessDetail == other.lightnessDetail
1099 && contrastThreshold == other.contrastThreshold;
1100 }
1101
1102
operator !=(const ParametricMask & other) const1103 bool ParametricMask::operator!=(const ParametricMask &other) const
1104 {
1105 return !(*this == other);
1106 }
1107
1108
Mask()1109 Mask::Mask():
1110 enabled(true),
1111 inverted(false),
1112 parametricMask(),
1113 areaMask(),
1114 deltaEMask(),
1115 drawnMask(),
1116 name("")
1117 {
1118 }
1119
1120
operator ==(const Mask & other) const1121 bool Mask::operator==(const Mask &other) const
1122 {
1123 return enabled == other.enabled
1124 && inverted == other.inverted
1125 && parametricMask == other.parametricMask
1126 && areaMask == other.areaMask
1127 && deltaEMask == other.deltaEMask
1128 && drawnMask == other.drawnMask
1129 && name == other.name;
1130 }
1131
1132
operator !=(const Mask & other) const1133 bool Mask::operator!=(const Mask &other) const
1134 {
1135 return !(*this == other);
1136 }
1137
1138
1139 namespace {
1140
str2mode(const Glib::ustring & mode)1141 AreaMask::Shape::Mode str2mode(const Glib::ustring &mode)
1142 {
1143 if (mode == "subtract") {
1144 return AreaMask::Shape::SUBTRACT;
1145 } else if (mode == "intersect") {
1146 return AreaMask::Shape::INTERSECT;
1147 } else {
1148 return AreaMask::Shape::ADD;
1149 }
1150 }
1151
1152
mode2str(AreaMask::Shape::Mode mode)1153 Glib::ustring mode2str(AreaMask::Shape::Mode mode)
1154 {
1155 switch (mode) {
1156 case AreaMask::Shape::ADD: return "add";
1157 case AreaMask::Shape::SUBTRACT: return "subtract";
1158 case AreaMask::Shape::INTERSECT: return "intersect";
1159 default:
1160 assert(false);
1161 return "";
1162 }
1163 }
1164
str2type(const Glib::ustring & type)1165 AreaMask::Shape::Type str2type(const Glib::ustring &type)
1166 {
1167 if (type == "rectangle") {
1168 return AreaMask::Shape::RECTANGLE;
1169 } else if (type == "gradient") {
1170 return AreaMask::Shape::GRADIENT;
1171 } else {
1172 return AreaMask::Shape::POLYGON;
1173 }
1174 }
1175
1176
type2str(AreaMask::Shape::Type type)1177 Glib::ustring type2str(AreaMask::Shape::Type type)
1178 {
1179 switch (type) {
1180 case AreaMask::Shape::RECTANGLE: return "rectangle";
1181 case AreaMask::Shape::GRADIENT: return "gradient";
1182 case AreaMask::Shape::POLYGON: return "polygon";
1183 default:
1184 assert(false);
1185 return "";
1186 }
1187 }
1188
1189 } // namespace
1190
1191
load(int ppVersion,const KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & prefix,const Glib::ustring & suffix)1192 bool Mask::load(int ppVersion, const KeyFile &keyfile, const Glib::ustring &group_name, const Glib::ustring &prefix, const Glib::ustring &suffix)
1193 {
1194 bool ret = false;
1195 ret |= assignFromKeyfile(keyfile, group_name, prefix + "MaskEnabled" + suffix, enabled);
1196 ret |= assignFromKeyfile(keyfile, group_name, prefix + "MaskInverted" + suffix, inverted);
1197 ret |= assignFromKeyfile(keyfile, group_name, prefix + "MaskName" + suffix, name);
1198 if (ppVersion < 1008) {
1199 parametricMask.enabled = true;
1200 } else {
1201 ret |= assignFromKeyfile(keyfile, group_name, prefix + "ParametricMaskEnabled" + suffix, parametricMask.enabled);
1202 }
1203 ret |= assignFromKeyfile(keyfile, group_name, prefix + "HueMask" + suffix, parametricMask.hue);
1204 if (assignFromKeyfile(keyfile, group_name, prefix + "ChromaticityMask" + suffix, parametricMask.chromaticity)) {
1205 if (ppVersion < 1023) {
1206 for (size_t i = 1; i < parametricMask.chromaticity.size(); i += 4) {
1207 auto &x = parametricMask.chromaticity[i];
1208 x = lin2log(log2lin(x, 10.0), 50.0);
1209 }
1210 }
1211 ret = true;
1212 }
1213 ret |= assignFromKeyfile(keyfile, group_name, prefix + "LightnessMask" + suffix, parametricMask.lightness);
1214 ret |= assignFromKeyfile(keyfile, group_name, prefix + "LightnessMaskDetail" + suffix, parametricMask.lightnessDetail);
1215 ret |= assignFromKeyfile(keyfile, group_name, prefix + "ContrastThresholdMask" + suffix, parametricMask.contrastThreshold);
1216 if (ppVersion < 1008) {
1217 ret |= assignFromKeyfile(keyfile, group_name, prefix + "MaskBlur" + suffix, parametricMask.blur);
1218 areaMask.blur = parametricMask.blur;
1219 } else {
1220 ret |= assignFromKeyfile(keyfile, group_name, prefix + "ParametricMaskBlur" + suffix, parametricMask.blur);
1221 ret |= assignFromKeyfile(keyfile, group_name, prefix + "AreaMaskBlur" + suffix, areaMask.blur);
1222 }
1223 ret |= assignFromKeyfile(keyfile, group_name, prefix + "AreaMaskEnabled" + suffix, areaMask.enabled);
1224 ret |= assignFromKeyfile(keyfile, group_name, prefix + "AreaMaskFeather" + suffix, areaMask.feather);
1225 ret |= assignFromKeyfile(keyfile, group_name, prefix + "AreaMaskContrast" + suffix, areaMask.contrast);
1226 if (areaMask.contrast.empty() || areaMask.contrast[0] < DCT_Linear || areaMask.contrast[0] >= DCT_Unchanged) {
1227 areaMask.contrast = {DCT_Linear};
1228 }
1229 std::vector<std::unique_ptr<AreaMask::Shape>> s;
1230 for (int i = 0; ; ++i) {
1231 Glib::ustring type;
1232 Glib::ustring mode;
1233 bool found = true; // skipping the entire element if one key is missing
1234 std::string n = i ? std::string("_") + std::to_string(i) + "_" : "";
1235 if (ppVersion >= 1014) {
1236 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "Type" + suffix, type);
1237 }
1238 if (ppVersion < 1014 || found) {
1239 std::unique_ptr<AreaMask::Shape> shape;
1240 if (ppVersion < 1014 || str2type(type) == AreaMask::Shape::Type::RECTANGLE) {
1241 AreaMask::Rectangle *rect = new AreaMask::Rectangle();
1242 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "X" + suffix, rect->x);
1243 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "Y" + suffix, rect->y);
1244 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "Width" + suffix, rect->width);
1245 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "Height" + suffix, rect->height);
1246 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "Angle" + suffix, rect->angle);
1247 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "Roundness" + suffix, rect->roundness);
1248 if (found) {
1249 shape.reset(rect);
1250 } else {
1251 delete rect;
1252 }
1253 } else if (str2type(type) == AreaMask::Shape::Type::POLYGON) {
1254 AreaMask::Polygon *poly = new AreaMask::Polygon();
1255 if (ppVersion < 1019) {
1256 std::vector<float> v; // important: use vector<float> to avoid calling rtengine::sanitizeCurve -- need to think of a better way
1257 if ((found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "Knots" + suffix, v))) {
1258 ret = true;
1259 std::vector<double> vv(v.begin(), v.end());
1260 poly->knots_from_list(vv);
1261 }
1262 } else {
1263 Glib::ustring raw;
1264 if ((found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "Knots" + suffix, raw))) {
1265 ret = true;
1266 std::vector<double> vv = unpack_list(raw);//.raw());
1267 poly->knots_from_list(vv);
1268 }
1269 }
1270 if (found) {
1271 shape.reset(poly);
1272 } else {
1273 delete poly;
1274 }
1275 } else if (str2type(type) == AreaMask::Shape::Type::GRADIENT) {
1276 AreaMask::Gradient *gradient = new AreaMask::Gradient();
1277 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "X" + suffix, gradient->x);
1278 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "Y" + suffix, gradient->y);
1279 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "StrengthStart" + suffix, gradient->strengthStart);
1280 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "StrengthEnd" + suffix, gradient->strengthEnd);
1281 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "Angle" + suffix, gradient->angle);
1282 if (found) {
1283 shape.reset(gradient);
1284 } else {
1285 delete gradient;
1286 }
1287 }
1288 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "Mode" + suffix, mode);
1289 if (ppVersion >= 1015) {
1290 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "ShapeFeather" + suffix, shape->feather);
1291 found &= assignFromKeyfile(keyfile, group_name, prefix + "AreaMask" + n + "ShapeBlur" + suffix, shape->blur);
1292 }
1293 if (found) {
1294 shape->mode = str2mode(mode);
1295 s.emplace_back(std::move(shape));
1296 ret = true;
1297 } else {
1298 break;
1299 }
1300 } else {
1301 break;
1302 }
1303 }
1304 if (!s.empty()) {
1305 areaMask.shapes = std::move(s);
1306 }
1307
1308 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DeltaEMaskEnabled" + suffix, deltaEMask.enabled);
1309 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DeltaEMaskL" + suffix, deltaEMask.L);
1310 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DeltaEMaskC" + suffix, deltaEMask.C);
1311 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DeltaEMaskH" + suffix, deltaEMask.H);
1312 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DeltaEMaskRange" + suffix, deltaEMask.range);
1313 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DeltaEMaskDecay" + suffix, deltaEMask.decay);
1314 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DeltaEMaskWeightL" + suffix, deltaEMask.weight_L);
1315 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DeltaEMaskWeightC" + suffix, deltaEMask.weight_C);
1316 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DeltaEMaskWeightH" + suffix, deltaEMask.weight_H);
1317 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DrawnMaskEnabled" + suffix, drawnMask.enabled);
1318 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DrawnMaskFeather" + suffix, drawnMask.feather);
1319 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DrawnMaskTransparency" + suffix, drawnMask.transparency);
1320 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DrawnMaskSmoothness" + suffix, drawnMask.smoothness);
1321 ret |= assignFromKeyfile(keyfile, group_name, prefix + "DrawnMaskContrast" + suffix, drawnMask.contrast);
1322 if (ppVersion < 1019) {
1323 bool addmode = false;
1324 if (assignFromKeyfile(keyfile, group_name, prefix + "DrawnMaskAddMode" + suffix, addmode)) {
1325 ret = true;
1326 drawnMask.mode = addmode ? DrawnMask::ADD : DrawnMask::INTERSECT;
1327 }
1328 } else {
1329 int mode = 0;
1330 if (assignFromKeyfile(keyfile, group_name, prefix + "DrawnMaskMode" + suffix, mode)) {
1331 ret = true;
1332 drawnMask.mode = DrawnMask::Mode(LIM(mode, 0, 2));
1333 }
1334 }
1335 if (ppVersion < 1019) {
1336 std::vector<float> v; // important: use vector<float> to avoid calling rtengine::sanitizeCurve -- need to think of a better way
1337 if (assignFromKeyfile(keyfile, group_name, prefix + "DrawnMaskStrokes" + suffix, v)) {
1338 ret = true;
1339 std::vector<double> vv(v.begin(), v.end());
1340 drawnMask.strokes_from_list(vv);
1341 }
1342 } else {
1343 Glib::ustring raw;
1344 if (assignFromKeyfile(keyfile, group_name, prefix + "DrawnMaskStrokes" + suffix, raw)) {
1345 ret = true;
1346 std::vector<double> vv = unpack_list(raw);
1347 drawnMask.strokes_from_list(vv);
1348 if (ppVersion < 1022 && !drawnMask.strokes.empty()) {
1349 std::vector<DrawnMask::Stroke> stmp;
1350 stmp.swap(drawnMask.strokes);
1351 drawnMask.strokes.push_back(stmp[0]);
1352 for (size_t i = 1; i < stmp.size(); ++i) {
1353 auto &p = drawnMask.strokes.back();
1354 auto &s = stmp[i];
1355 if (p.radius != s.radius && p.radius > 0 && s.radius > 0 &&
1356 p.hardness == s.hardness && p.erase == s.erase) {
1357 drawnMask.strokes.push_back(DrawnMask::Stroke());
1358 }
1359 drawnMask.strokes.push_back(s);
1360 }
1361 }
1362 }
1363 }
1364
1365 return ret;
1366 }
1367
1368
save(KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & prefix,const Glib::ustring & suffix) const1369 void Mask::save(KeyFile &keyfile, const Glib::ustring &group_name, const Glib::ustring &prefix, const Glib::ustring &suffix) const
1370 {
1371 putToKeyfile(group_name, prefix + "MaskEnabled" + suffix, enabled, keyfile);
1372 putToKeyfile(group_name, prefix + "MaskInverted" + suffix, inverted, keyfile);
1373 putToKeyfile(group_name, prefix + "MaskName" + suffix, name, keyfile);
1374 putToKeyfile(group_name, prefix + "ParametricMaskEnabled" + suffix, parametricMask.enabled, keyfile);
1375 putToKeyfile(group_name, prefix + "HueMask" + suffix, parametricMask.hue, keyfile);
1376 putToKeyfile(group_name, prefix + "ChromaticityMask" + suffix, parametricMask.chromaticity, keyfile);
1377 putToKeyfile(group_name, prefix + "LightnessMask" + suffix, parametricMask.lightness, keyfile);
1378 putToKeyfile(group_name, prefix + "LightnessMaskDetail" + suffix, parametricMask.lightnessDetail, keyfile);
1379 putToKeyfile(group_name, prefix + "ContrastThresholdMask" + suffix, parametricMask.contrastThreshold, keyfile);
1380 putToKeyfile(group_name, prefix + "ParametricMaskBlur" + suffix, parametricMask.blur, keyfile);
1381 putToKeyfile(group_name, prefix + "AreaMaskEnabled" + suffix, areaMask.enabled, keyfile);
1382 putToKeyfile(group_name, prefix + "AreaMaskFeather" + suffix, areaMask.feather, keyfile);
1383 putToKeyfile(group_name, prefix + "AreaMaskBlur" + suffix, areaMask.blur, keyfile);
1384 putToKeyfile(group_name, prefix + "AreaMaskContrast" + suffix, areaMask.contrast, keyfile);
1385
1386 for (size_t i = 0; i < areaMask.shapes.size(); ++i) {
1387 auto &a = areaMask.shapes[i];
1388 std::string n = i ? std::string("_") + std::to_string(i) + "_" : "";
1389 putToKeyfile(group_name, prefix + "AreaMask" + n + "Type" + suffix, type2str(a->getType()), keyfile);
1390 switch (a->getType()) {
1391 case AreaMask::Shape::Type::POLYGON:
1392 {
1393 auto poly = static_cast<AreaMask::Polygon*>(a.get());
1394 std::vector<double> v;
1395 poly->knots_to_list(v);
1396 putToKeyfile(group_name, prefix + "AreaMask" + n + "Knots" + suffix, pack_list(v), keyfile);
1397 break;
1398 }
1399 case AreaMask::Shape::Type::GRADIENT:
1400 {
1401 auto gradient = static_cast<AreaMask::Gradient*>(a.get());
1402 putToKeyfile(group_name, prefix + "AreaMask" + n + "X" + suffix, gradient->x, keyfile);
1403 putToKeyfile(group_name, prefix + "AreaMask" + n + "Y" + suffix, gradient->y, keyfile);
1404 putToKeyfile(group_name, prefix + "AreaMask" + n + "StrengthStart" + suffix, gradient->strengthStart, keyfile);
1405 putToKeyfile(group_name, prefix + "AreaMask" + n + "StrengthEnd" + suffix, gradient->strengthEnd, keyfile);
1406 putToKeyfile(group_name, prefix + "AreaMask" + n + "Angle" + suffix, gradient->angle, keyfile);
1407 break;
1408 }
1409 case AreaMask::Shape::Type::RECTANGLE:
1410 default:
1411 {
1412 auto rect = static_cast<AreaMask::Rectangle*>(a.get());
1413 putToKeyfile(group_name, prefix + "AreaMask" + n + "X" + suffix, rect->x, keyfile);
1414 putToKeyfile(group_name, prefix + "AreaMask" + n + "Y" + suffix, rect->y, keyfile);
1415 putToKeyfile(group_name, prefix + "AreaMask" + n + "Width" + suffix, rect->width, keyfile);
1416 putToKeyfile(group_name, prefix + "AreaMask" + n + "Height" + suffix, rect->height, keyfile);
1417 putToKeyfile(group_name, prefix + "AreaMask" + n + "Angle" + suffix, rect->angle, keyfile);
1418 putToKeyfile(group_name, prefix + "AreaMask" + n + "Roundness" + suffix, rect->roundness, keyfile);
1419 }
1420 }
1421 putToKeyfile(group_name, prefix + "AreaMask" + n + "Mode" + suffix, mode2str(a->mode), keyfile);
1422 putToKeyfile(group_name, prefix + "AreaMask" + n + "ShapeFeather" + suffix, a->feather, keyfile);
1423 putToKeyfile(group_name, prefix + "AreaMask" + n + "ShapeBlur" + suffix, a->blur, keyfile);
1424 }
1425
1426 putToKeyfile(group_name, prefix + "DeltaEMaskEnabled" + suffix, deltaEMask.enabled, keyfile);
1427 putToKeyfile(group_name, prefix + "DeltaEMaskL" + suffix, deltaEMask.L, keyfile);
1428 putToKeyfile(group_name, prefix + "DeltaEMaskC" + suffix, deltaEMask.C, keyfile);
1429 putToKeyfile(group_name, prefix + "DeltaEMaskH" + suffix, deltaEMask.H, keyfile);
1430 putToKeyfile(group_name, prefix + "DeltaEMaskRange" + suffix, deltaEMask.range, keyfile);
1431 putToKeyfile(group_name, prefix + "DeltaEMaskDecay" + suffix, deltaEMask.decay, keyfile);
1432 putToKeyfile(group_name, prefix + "DeltaEMaskWeightL" + suffix, deltaEMask.weight_L, keyfile);
1433 putToKeyfile(group_name, prefix + "DeltaEMaskWeightC" + suffix, deltaEMask.weight_C, keyfile);
1434 putToKeyfile(group_name, prefix + "DeltaEMaskWeightH" + suffix, deltaEMask.weight_H, keyfile);
1435 putToKeyfile(group_name, prefix + "DrawnMaskEnabled" + suffix, drawnMask.enabled, keyfile);
1436 putToKeyfile(group_name, prefix + "DrawnMaskFeather" + suffix, drawnMask.feather, keyfile);
1437 putToKeyfile(group_name, prefix + "DrawnMaskTransparency" + suffix, drawnMask.transparency, keyfile);
1438 putToKeyfile(group_name, prefix + "DrawnMaskSmoothness" + suffix, drawnMask.smoothness, keyfile);
1439 putToKeyfile(group_name, prefix + "DrawnMaskContrast" + suffix, drawnMask.contrast, keyfile);
1440 putToKeyfile(group_name, prefix + "DrawnMaskMode" + suffix, int(drawnMask.mode), keyfile);
1441 std::vector<double> v;
1442 drawnMask.strokes_to_list(v);
1443 putToKeyfile(group_name, prefix + "DrawnMaskStrokes" + suffix, pack_list(v), keyfile);
1444 }
1445
1446
ExposureParams()1447 ExposureParams::ExposureParams():
1448 enabled(true),
1449 hrmode(HR_OFF),
1450 expcomp(0),
1451 black(0)
1452 {
1453 }
1454
1455
operator ==(const ExposureParams & other) const1456 bool ExposureParams::operator==(const ExposureParams &other) const
1457 {
1458 return enabled == other.enabled
1459 && hrmode == other.hrmode
1460 && expcomp == other.expcomp
1461 && black == other.black;
1462 }
1463
1464
operator !=(const ExposureParams & other) const1465 bool ExposureParams::operator!=(const ExposureParams &other) const
1466 {
1467 return !(*this == other);
1468 }
1469
1470
SaturationParams()1471 SaturationParams::SaturationParams():
1472 enabled(false),
1473 saturation(0),
1474 vibrance(0)
1475 {
1476 }
1477
1478
operator ==(const SaturationParams & other) const1479 bool SaturationParams::operator==(const SaturationParams &other) const
1480 {
1481 return enabled == other.enabled
1482 && saturation == other.saturation
1483 && vibrance == other.vibrance;
1484 }
1485
1486
operator !=(const SaturationParams & other) const1487 bool SaturationParams::operator!=(const SaturationParams &other) const
1488 {
1489 return !(*this == other);
1490 }
1491
1492
ToneCurveParams()1493 ToneCurveParams::ToneCurveParams():
1494 enabled(false),
1495 contrast(0),
1496 curve{
1497 DCT_Linear
1498 },
1499 curve2{
1500 DCT_Linear
1501 },
1502 curveMode(ToneCurveParams::TcMode::STD),
1503 curveMode2(ToneCurveParams::TcMode::STD),
1504 histmatching(false),
1505 fromHistMatching(false),
1506 saturation{
1507 FCT_Linear
1508 },
1509 perceptualStrength(100)
1510 {
1511 }
1512
1513
operator ==(const ToneCurveParams & other) const1514 bool ToneCurveParams::operator ==(const ToneCurveParams& other) const
1515 {
1516 return enabled == other.enabled
1517 && contrast == other.contrast
1518 && curve == other.curve
1519 && curve2 == other.curve2
1520 && curveMode == other.curveMode
1521 && curveMode2 == other.curveMode2
1522 && histmatching == other.histmatching
1523 && fromHistMatching == other.fromHistMatching
1524 && saturation == other.saturation
1525 && perceptualStrength == other.perceptualStrength;
1526 }
1527
1528
operator !=(const ToneCurveParams & other) const1529 bool ToneCurveParams::operator !=(const ToneCurveParams& other) const
1530 {
1531 return !(*this == other);
1532 }
1533
1534
LabCurveParams()1535 LabCurveParams::LabCurveParams() :
1536 enabled(false),
1537 brightness(0),
1538 contrast(0),
1539 chromaticity(0),
1540 lcurve{
1541 DCT_Linear
1542 },
1543 acurve{
1544 DCT_Linear
1545 },
1546 bcurve{
1547 DCT_Linear
1548 }
1549 {
1550 }
1551
operator ==(const LabCurveParams & other) const1552 bool LabCurveParams::operator ==(const LabCurveParams& other) const
1553 {
1554 return
1555 enabled == other.enabled
1556 && brightness == other.brightness
1557 && contrast == other.contrast
1558 && chromaticity == other.chromaticity
1559 && lcurve == other.lcurve
1560 && acurve == other.acurve
1561 && bcurve == other.bcurve;
1562 }
1563
operator !=(const LabCurveParams & other) const1564 bool LabCurveParams::operator !=(const LabCurveParams& other) const
1565 {
1566 return !(*this == other);
1567 }
1568
RGBCurvesParams()1569 RGBCurvesParams::RGBCurvesParams() :
1570 enabled(false),
1571 rcurve{
1572 DCT_Linear
1573 },
1574 gcurve{
1575 DCT_Linear
1576 },
1577 bcurve{
1578 DCT_Linear
1579 }
1580 {
1581 }
1582
operator ==(const RGBCurvesParams & other) const1583 bool RGBCurvesParams::operator ==(const RGBCurvesParams& other) const
1584 {
1585 return
1586 enabled == other.enabled
1587 && rcurve == other.rcurve
1588 && gcurve == other.gcurve
1589 && bcurve == other.bcurve;
1590 }
1591
operator !=(const RGBCurvesParams & other) const1592 bool RGBCurvesParams::operator !=(const RGBCurvesParams& other) const
1593 {
1594 return !(*this == other);
1595 }
1596
1597
Region()1598 LocalContrastParams::Region::Region():
1599 contrast(0),
1600 curve{
1601 FCT_MinMaxCPoints,
1602 0.0,
1603 0.5,
1604 0.0,
1605 0.0,
1606 1.0,
1607 0.5,
1608 0.0,
1609 0.0
1610 }
1611 {
1612 }
1613
1614
operator ==(const Region & other) const1615 bool LocalContrastParams::Region::operator==(const Region &other) const
1616 {
1617 return contrast == other.contrast
1618 && curve == other.curve;
1619 }
1620
1621
operator !=(const Region & other) const1622 bool LocalContrastParams::Region::operator!=(const Region &other) const
1623 {
1624 return !(*this == other);
1625 }
1626
1627
LocalContrastParams()1628 LocalContrastParams::LocalContrastParams():
1629 enabled(false),
1630 regions{Region()},
1631 labmasks{Mask()},
1632 showMask(-1)
1633 {
1634 }
1635
1636
operator ==(const LocalContrastParams & other) const1637 bool LocalContrastParams::operator==(const LocalContrastParams &other) const
1638 {
1639 return
1640 enabled == other.enabled
1641 && regions == other.regions
1642 && labmasks == other.labmasks
1643 && showMask == other.showMask;
1644 }
1645
1646
operator !=(const LocalContrastParams & other) const1647 bool LocalContrastParams::operator!=(const LocalContrastParams &other) const
1648 {
1649 return !(*this == other);
1650 }
1651
1652
SharpeningParams()1653 SharpeningParams::SharpeningParams() :
1654 enabled(false),
1655 contrast(20.0),
1656 radius(0.5),
1657 amount(200),
1658 threshold(20, 80, 2000, 1200, false),
1659 edgesonly(false),
1660 edges_radius(1.9),
1661 edges_tolerance(1800),
1662 halocontrol(false),
1663 halocontrol_amount(85),
1664 method("rld"),
1665 deconvamount(100),
1666 deconvradius(0.75),
1667 deconvAutoRadius(true),
1668 deconvCornerBoost(0.0),
1669 deconvCornerLatitude(25)
1670 {
1671 }
1672
operator ==(const SharpeningParams & other) const1673 bool SharpeningParams::operator ==(const SharpeningParams& other) const
1674 {
1675 return
1676 enabled == other.enabled
1677 && contrast == other.contrast
1678 && radius == other.radius
1679 && amount == other.amount
1680 && threshold == other.threshold
1681 && edgesonly == other.edgesonly
1682 && edges_radius == other.edges_radius
1683 && edges_tolerance == other.edges_tolerance
1684 && halocontrol == other.halocontrol
1685 && halocontrol_amount == other.halocontrol_amount
1686 && method == other.method
1687 && deconvamount == other.deconvamount
1688 && deconvradius == other.deconvradius
1689 && deconvAutoRadius == other.deconvAutoRadius
1690 && deconvCornerBoost == other.deconvCornerBoost
1691 && deconvCornerLatitude == other.deconvCornerLatitude;
1692 }
1693
operator !=(const SharpeningParams & other) const1694 bool SharpeningParams::operator !=(const SharpeningParams& other) const
1695 {
1696 return !(*this == other);
1697 }
1698
1699
WBParams()1700 WBParams::WBParams() :
1701 enabled(true),
1702 method(CAMERA),
1703 temperature(6504),
1704 green(1.0),
1705 equal(1.0),
1706 mult{1.0, 1.0, 1.0}
1707 {
1708 }
1709
operator ==(const WBParams & other) const1710 bool WBParams::operator ==(const WBParams& other) const
1711 {
1712 return
1713 enabled == other.enabled
1714 && method == other.method
1715 && temperature == other.temperature
1716 && green == other.green
1717 && equal == other.equal
1718 && mult == other.mult;
1719 }
1720
operator !=(const WBParams & other) const1721 bool WBParams::operator !=(const WBParams& other) const
1722 {
1723 return !(*this == other);
1724 }
1725
1726
DefringeParams()1727 DefringeParams::DefringeParams() :
1728 enabled(false),
1729 radius(2.0),
1730 threshold(13),
1731 huecurve{
1732 FCT_MinMaxCPoints,
1733 0.166666667,
1734 0.,
1735 0.35,
1736 0.35,
1737 0.347,
1738 0.,
1739 0.35,
1740 0.35,
1741 0.513667426,
1742 0,
1743 0.35,
1744 0.35,
1745 0.668944571,
1746 0.,
1747 0.35,
1748 0.35,
1749 0.8287775246,
1750 0.97835991,
1751 0.35,
1752 0.35,
1753 0.9908883827,
1754 0.,
1755 0.35,
1756 0.35
1757 }
1758 {
1759 }
1760
operator ==(const DefringeParams & other) const1761 bool DefringeParams::operator ==(const DefringeParams& other) const
1762 {
1763 return
1764 enabled == other.enabled
1765 && radius == other.radius
1766 && threshold == other.threshold
1767 && huecurve == other.huecurve;
1768 }
1769
operator !=(const DefringeParams & other) const1770 bool DefringeParams::operator !=(const DefringeParams& other) const
1771 {
1772 return !(*this == other);
1773 }
1774
ImpulseDenoiseParams()1775 ImpulseDenoiseParams::ImpulseDenoiseParams() :
1776 enabled(false),
1777 thresh(50)
1778 {
1779 }
1780
operator ==(const ImpulseDenoiseParams & other) const1781 bool ImpulseDenoiseParams::operator ==(const ImpulseDenoiseParams& other) const
1782 {
1783 return
1784 enabled == other.enabled
1785 && thresh == other.thresh;
1786 }
1787
operator !=(const ImpulseDenoiseParams & other) const1788 bool ImpulseDenoiseParams::operator !=(const ImpulseDenoiseParams& other) const
1789 {
1790 return !(*this == other);
1791 }
1792
DenoiseParams()1793 DenoiseParams::DenoiseParams() :
1794 enabled(false),
1795 colorSpace(ColorSpace::RGB),
1796 aggressive(false),
1797 gamma(1.7),
1798 luminance(0),
1799 luminanceDetail(0),
1800 luminanceDetailThreshold(0),
1801 chrominanceMethod(ChrominanceMethod::AUTOMATIC),
1802 chrominanceAutoFactor(1),
1803 chrominance(15),
1804 chrominanceRedGreen(0),
1805 chrominanceBlueYellow(0),
1806 smoothingEnabled(false),
1807 guidedChromaRadius(3),
1808 nlDetail(80),
1809 nlStrength(0)
1810 {
1811 }
1812
1813
operator ==(const DenoiseParams & other) const1814 bool DenoiseParams::operator ==(const DenoiseParams& other) const
1815 {
1816 return
1817 enabled == other.enabled
1818 && colorSpace == other.colorSpace
1819 && aggressive == other.aggressive
1820 && gamma == other.gamma
1821 && luminance == other.luminance
1822 && luminanceDetail == other.luminanceDetail
1823 && luminanceDetailThreshold == other.luminanceDetailThreshold
1824 && chrominanceMethod == other.chrominanceMethod
1825 && chrominanceAutoFactor == other.chrominanceAutoFactor
1826 && chrominance == other.chrominance
1827 && chrominanceRedGreen == other.chrominanceRedGreen
1828 && chrominanceBlueYellow == other.chrominanceBlueYellow
1829 && smoothingEnabled == other.smoothingEnabled
1830 && guidedChromaRadius == other.guidedChromaRadius
1831 && nlDetail == other.nlDetail
1832 && nlStrength == other.nlStrength;
1833 }
1834
1835
operator !=(const DenoiseParams & other) const1836 bool DenoiseParams::operator !=(const DenoiseParams& other) const
1837 {
1838 return !(*this == other);
1839 }
1840
1841
Region()1842 TextureBoostParams::Region::Region():
1843 strength(0.5),
1844 detailThreshold(1.0),
1845 iterations(1)
1846 {
1847 }
1848
1849
operator ==(const Region & other) const1850 bool TextureBoostParams::Region::operator==(const Region &other) const
1851 {
1852 return strength == other.strength
1853 && detailThreshold == other.detailThreshold
1854 && iterations == other.iterations;
1855 }
1856
1857
operator !=(const Region & other) const1858 bool TextureBoostParams::Region::operator!=(const Region &other) const
1859 {
1860 return !(*this == other);
1861 }
1862
SpotEntry()1863 SpotEntry::SpotEntry() :
1864 radius(25),
1865 feather(1.f),
1866 opacity(1.f),
1867 detail(2)
1868 {
1869 }
getFeatherRadius() const1870 float SpotEntry::getFeatherRadius() const
1871 {
1872 return radius * (1.f + feather);
1873 }
1874
operator ==(const SpotEntry & other) const1875 bool SpotEntry::operator ==(const SpotEntry& other) const
1876 {
1877 return other.sourcePos == sourcePos
1878 && other.targetPos == targetPos
1879 && other.radius == radius
1880 && other.feather == feather
1881 && other.opacity == opacity
1882 && other.detail == detail;
1883 }
1884
operator !=(const SpotEntry & other) const1885 bool SpotEntry::operator !=(const SpotEntry& other) const
1886 {
1887 return !(*this == other);
1888 }
1889
1890
SpotParams()1891 SpotParams::SpotParams() :
1892 enabled(false)
1893 {
1894 entries.clear ();
1895 }
1896
operator ==(const SpotParams & other) const1897 bool SpotParams::operator ==(const SpotParams& other) const
1898 {
1899 return enabled == other.enabled && entries == other.entries;
1900 }
1901
operator !=(const SpotParams & other) const1902 bool SpotParams::operator !=(const SpotParams& other) const
1903 {
1904 return !(*this == other);
1905 }
1906
TextureBoostParams()1907 TextureBoostParams::TextureBoostParams() :
1908 enabled(false),
1909 regions{Region()},
1910 labmasks{Mask()},
1911 showMask(-1)
1912 {
1913 }
1914
operator ==(const TextureBoostParams & other) const1915 bool TextureBoostParams::operator ==(const TextureBoostParams& other) const
1916 {
1917 return
1918 enabled == other.enabled
1919 && regions == other.regions
1920 && labmasks == other.labmasks
1921 && showMask == other.showMask;
1922 }
1923
operator !=(const TextureBoostParams & other) const1924 bool TextureBoostParams::operator !=(const TextureBoostParams& other) const
1925 {
1926 return !(*this == other);
1927 }
1928
1929
LogEncodingParams()1930 LogEncodingParams::LogEncodingParams():
1931 enabled(false),
1932 autocompute(false),
1933 autogain(false),
1934 gain(0.0),
1935 targetGray(18.0),
1936 blackEv(-13.5),
1937 whiteEv(2.5),
1938 regularization(60)
1939 {
1940 }
1941
operator ==(const LogEncodingParams & other) const1942 bool LogEncodingParams::operator ==(const LogEncodingParams& other) const
1943 {
1944 return
1945 enabled == other.enabled
1946 && autocompute == other.autocompute
1947 && autogain == other.autogain
1948 && gain == other.gain
1949 && blackEv == other.blackEv
1950 && whiteEv == other.whiteEv
1951 && targetGray == other.targetGray
1952 && regularization == other.regularization;
1953 }
1954
operator !=(const LogEncodingParams & other) const1955 bool LogEncodingParams::operator !=(const LogEncodingParams& other) const
1956 {
1957 return !(*this == other);
1958 }
1959
1960
FattalToneMappingParams()1961 FattalToneMappingParams::FattalToneMappingParams() :
1962 enabled(false),
1963 threshold(30),
1964 amount(20),
1965 satcontrol(false)
1966 {
1967 }
1968
operator ==(const FattalToneMappingParams & other) const1969 bool FattalToneMappingParams::operator ==(const FattalToneMappingParams& other) const
1970 {
1971 return
1972 enabled == other.enabled
1973 && threshold == other.threshold
1974 && amount == other.amount
1975 && satcontrol == other.satcontrol;
1976 }
1977
operator !=(const FattalToneMappingParams & other) const1978 bool FattalToneMappingParams::operator !=(const FattalToneMappingParams& other) const
1979 {
1980 return !(*this == other);
1981 }
1982
1983
ToneEqualizerParams()1984 ToneEqualizerParams::ToneEqualizerParams():
1985 enabled(false),
1986 bands{0,0,0,0,0},
1987 regularization(4),
1988 show_colormap(false)
1989 {
1990 }
1991
1992
operator ==(const ToneEqualizerParams & other) const1993 bool ToneEqualizerParams::operator ==(const ToneEqualizerParams& other) const
1994 {
1995 return
1996 enabled == other.enabled
1997 && bands == other.bands
1998 && regularization == other.regularization
1999 && show_colormap == other.show_colormap;
2000 }
2001
2002
operator !=(const ToneEqualizerParams & other) const2003 bool ToneEqualizerParams::operator !=(const ToneEqualizerParams& other) const
2004 {
2005 return !(*this == other);
2006 }
2007
2008
CropParams()2009 CropParams::CropParams() :
2010 enabled(false),
2011 x(-1),
2012 y(-1),
2013 w(15000),
2014 h(15000),
2015 fixratio(true),
2016 ratio("As Image"),
2017 orientation("As Image"),
2018 guide("Frame")
2019 {
2020 }
2021
operator ==(const CropParams & other) const2022 bool CropParams::operator ==(const CropParams& other) const
2023 {
2024 return
2025 enabled == other.enabled
2026 && x == other.x
2027 && y == other.y
2028 && w == other.w
2029 && h == other.h
2030 && fixratio == other.fixratio
2031 && ratio == other.ratio
2032 && orientation == other.orientation
2033 && guide == other.guide;
2034 }
2035
operator !=(const CropParams & other) const2036 bool CropParams::operator !=(const CropParams& other) const
2037 {
2038 return !(*this == other);
2039 }
2040
mapToResized(int resizedWidth,int resizedHeight,int scale,int & x1,int & x2,int & y1,int & y2) const2041 void CropParams::mapToResized(int resizedWidth, int resizedHeight, int scale, int& x1, int& x2, int& y1, int& y2) const
2042 {
2043 x1 = 0, x2 = resizedWidth, y1 = 0, y2 = resizedHeight;
2044
2045 if (enabled) {
2046 x1 = min(resizedWidth - 1, max(0, x / scale));
2047 y1 = min(resizedHeight - 1, max(0, y / scale));
2048 x2 = min(resizedWidth, max(0, (x + w) / scale));
2049 y2 = min(resizedHeight, max(0, (y + h) / scale));
2050 }
2051 }
2052
CoarseTransformParams()2053 CoarseTransformParams::CoarseTransformParams() :
2054 rotate(0),
2055 hflip(false),
2056 vflip(false)
2057 {
2058 }
2059
operator ==(const CoarseTransformParams & other) const2060 bool CoarseTransformParams::operator ==(const CoarseTransformParams& other) const
2061 {
2062 return
2063 rotate == other.rotate
2064 && hflip == other.hflip
2065 && vflip == other.vflip;
2066 }
2067
operator !=(const CoarseTransformParams & other) const2068 bool CoarseTransformParams::operator !=(const CoarseTransformParams& other) const
2069 {
2070 return !(*this == other);
2071 }
2072
CommonTransformParams()2073 CommonTransformParams::CommonTransformParams() :
2074 autofill(true)
2075 {
2076 }
2077
operator ==(const CommonTransformParams & other) const2078 bool CommonTransformParams::operator ==(const CommonTransformParams& other) const
2079 {
2080 return autofill == other.autofill;
2081 }
2082
operator !=(const CommonTransformParams & other) const2083 bool CommonTransformParams::operator !=(const CommonTransformParams& other) const
2084 {
2085 return !(*this == other);
2086 }
2087
RotateParams()2088 RotateParams::RotateParams() :
2089 enabled(false),
2090 degree(0.0)
2091 {
2092 }
2093
operator ==(const RotateParams & other) const2094 bool RotateParams::operator ==(const RotateParams& other) const
2095 {
2096 return enabled == other.enabled && degree == other.degree;
2097 }
2098
operator !=(const RotateParams & other) const2099 bool RotateParams::operator !=(const RotateParams& other) const
2100 {
2101 return !(*this == other);
2102 }
2103
DistortionParams()2104 DistortionParams::DistortionParams() :
2105 enabled(false),
2106 amount(0.0),
2107 autocompute(false)
2108 {
2109 }
2110
operator ==(const DistortionParams & other) const2111 bool DistortionParams::operator ==(const DistortionParams& other) const
2112 {
2113 return enabled == other.enabled && amount == other.amount
2114 && autocompute == other.autocompute;
2115 }
2116
operator !=(const DistortionParams & other) const2117 bool DistortionParams::operator !=(const DistortionParams& other) const
2118 {
2119 return !(*this == other);
2120 }
2121
LensProfParams()2122 LensProfParams::LensProfParams() :
2123 lcMode(LcMode::NONE),
2124 useDist(true),
2125 useVign(true),
2126 useCA(false)
2127 {
2128 }
2129
operator ==(const LensProfParams & other) const2130 bool LensProfParams::operator ==(const LensProfParams& other) const
2131 {
2132 return
2133 lcMode == other.lcMode
2134 && lcpFile == other.lcpFile
2135 && useCA == other.useCA
2136 && lfCameraMake == other.lfCameraMake
2137 && lfCameraModel == other.lfCameraModel
2138 && lfLens == other.lfLens;
2139 }
2140
operator !=(const LensProfParams & other) const2141 bool LensProfParams::operator !=(const LensProfParams& other) const
2142 {
2143 return !(*this == other);
2144 }
2145
useLensfun() const2146 bool LensProfParams::useLensfun() const
2147 {
2148 return lcMode == LcMode::LENSFUNAUTOMATCH || lcMode == LcMode::LENSFUNMANUAL;
2149 }
2150
lfAutoMatch() const2151 bool LensProfParams::lfAutoMatch() const
2152 {
2153 return lcMode == LcMode::LENSFUNAUTOMATCH;
2154 }
2155
useLcp() const2156 bool LensProfParams::useLcp() const
2157 {
2158 return lcMode == LcMode::LCP && lcpFile.length() > 0;
2159 }
2160
lfManual() const2161 bool LensProfParams::lfManual() const
2162 {
2163 return lcMode == LcMode::LENSFUNMANUAL;
2164 }
2165
2166
useExif() const2167 bool LensProfParams::useExif() const
2168 {
2169 return lcMode == LcMode::EXIF;
2170 }
2171
2172
needed() const2173 bool LensProfParams::needed() const
2174 {
2175 return useLensfun() || useLcp() || useExif();
2176 }
2177
2178
getMethodStrings() const2179 const std::vector<const char*>& LensProfParams::getMethodStrings() const
2180 {
2181 static const std::vector<const char*> method_strings = {
2182 "none",
2183 "lfauto",
2184 "lfmanual",
2185 "lcp",
2186 "exif"
2187 };
2188 return method_strings;
2189 }
2190
getMethodString(LcMode mode) const2191 Glib::ustring LensProfParams::getMethodString(LcMode mode) const
2192 {
2193 return getMethodStrings()[toUnderlying(mode)];
2194 }
2195
getMethodNumber(const Glib::ustring & mode) const2196 LensProfParams::LcMode LensProfParams::getMethodNumber(const Glib::ustring& mode) const
2197 {
2198 for (std::vector<const char*>::size_type i = 0; i < getMethodStrings().size(); ++i) {
2199 if (getMethodStrings()[i] == mode) {
2200 return static_cast<LcMode>(i);
2201 }
2202 }
2203
2204 return LcMode::NONE;
2205 }
2206
PerspectiveParams()2207 PerspectiveParams::PerspectiveParams() :
2208 enabled(false),
2209 horizontal(0.0),
2210 vertical(0.0),
2211 angle(0.0),
2212 shear(0.0),
2213 flength(0),
2214 cropfactor(1),
2215 aspect(1),
2216 control_lines()
2217 {
2218 }
2219
operator ==(const PerspectiveParams & other) const2220 bool PerspectiveParams::operator ==(const PerspectiveParams& other) const
2221 {
2222 return
2223 enabled == other.enabled
2224 && horizontal == other.horizontal
2225 && vertical == other.vertical
2226 && angle == other.angle
2227 && shear == other.shear
2228 && flength == other.flength
2229 && cropfactor == other.cropfactor
2230 && aspect == other.aspect
2231 && control_lines == other.control_lines;
2232 }
2233
operator !=(const PerspectiveParams & other) const2234 bool PerspectiveParams::operator !=(const PerspectiveParams& other) const
2235 {
2236 return !(*this == other);
2237 }
2238
GradientParams()2239 GradientParams::GradientParams() :
2240 enabled(false),
2241 degree(0.0),
2242 feather(25),
2243 strength(0.60),
2244 centerX(0),
2245 centerY(0)
2246 {
2247 }
2248
operator ==(const GradientParams & other) const2249 bool GradientParams::operator ==(const GradientParams& other) const
2250 {
2251 return
2252 enabled == other.enabled
2253 && degree == other.degree
2254 && feather == other.feather
2255 && strength == other.strength
2256 && centerX == other.centerX
2257 && centerY == other.centerY;
2258 }
2259
operator !=(const GradientParams & other) const2260 bool GradientParams::operator !=(const GradientParams& other) const
2261 {
2262 return !(*this == other);
2263 }
2264
PCVignetteParams()2265 PCVignetteParams::PCVignetteParams() :
2266 enabled(false),
2267 strength(0.60),
2268 feather(50),
2269 roundness(50),
2270 centerX(0),
2271 centerY(0)
2272 {
2273 }
2274
operator ==(const PCVignetteParams & other) const2275 bool PCVignetteParams::operator ==(const PCVignetteParams& other) const
2276 {
2277 return
2278 enabled == other.enabled
2279 && strength == other.strength
2280 && feather == other.feather
2281 && roundness == other.roundness
2282 && centerX == other.centerX
2283 && centerY == other.centerY;
2284 }
2285
operator !=(const PCVignetteParams & other) const2286 bool PCVignetteParams::operator !=(const PCVignetteParams& other) const
2287 {
2288 return !(*this == other);
2289 }
2290
VignettingParams()2291 VignettingParams::VignettingParams() :
2292 enabled(false),
2293 amount(0),
2294 radius(50),
2295 strength(1),
2296 centerX(0),
2297 centerY(0)
2298 {
2299 }
2300
operator ==(const VignettingParams & other) const2301 bool VignettingParams::operator ==(const VignettingParams& other) const
2302 {
2303 return
2304 enabled == other.enabled
2305 && amount == other.amount
2306 && radius == other.radius
2307 && strength == other.strength
2308 && centerX == other.centerX
2309 && centerY == other.centerY;
2310 }
2311
operator !=(const VignettingParams & other) const2312 bool VignettingParams::operator !=(const VignettingParams& other) const
2313 {
2314 return !(*this == other);
2315 }
2316
ChannelMixerParams()2317 ChannelMixerParams::ChannelMixerParams() :
2318 enabled(false),
2319 mode(RGB_MATRIX),
2320 red{1000, 0, 0},
2321 green{0, 1000, 0},
2322 blue{0, 0, 1000},
2323 hue_tweak{0, 0, 0},
2324 sat_tweak{0, 0, 0}
2325 {
2326 }
2327
operator ==(const ChannelMixerParams & other) const2328 bool ChannelMixerParams::operator ==(const ChannelMixerParams& other) const
2329 {
2330 if (enabled != other.enabled || mode != other.mode) {
2331 return false;
2332 }
2333
2334 for (unsigned int i = 0; i < 3; ++i) {
2335 if (
2336 red[i] != other.red[i]
2337 || green[i] != other.green[i]
2338 || blue[i] != other.blue[i]
2339 || hue_tweak[i] != other.hue_tweak[i]
2340 || sat_tweak[i] != other.sat_tweak[i]
2341 ) {
2342 return false;
2343 }
2344 }
2345
2346 return true;
2347 }
2348
operator !=(const ChannelMixerParams & other) const2349 bool ChannelMixerParams::operator !=(const ChannelMixerParams& other) const
2350 {
2351 return !(*this == other);
2352 }
2353
BlackWhiteParams()2354 BlackWhiteParams::BlackWhiteParams() :
2355 enabled(false),
2356 filter("None"),
2357 setting("RGB-Rel"),
2358 mixerRed(33),
2359 mixerGreen(33),
2360 mixerBlue(33),
2361 gammaRed(0),
2362 gammaGreen(0),
2363 gammaBlue(0),
2364 colorCast(0, 0, false)
2365 {
2366 }
2367
operator ==(const BlackWhiteParams & other) const2368 bool BlackWhiteParams::operator ==(const BlackWhiteParams& other) const
2369 {
2370 return
2371 enabled == other.enabled
2372 && filter == other.filter
2373 && setting == other.setting
2374 && mixerRed == other.mixerRed
2375 && mixerGreen == other.mixerGreen
2376 && mixerBlue == other.mixerBlue
2377 && gammaRed == other.gammaRed
2378 && gammaGreen == other.gammaGreen
2379 && gammaBlue == other.gammaBlue
2380 && colorCast == other.colorCast;
2381 }
2382
operator !=(const BlackWhiteParams & other) const2383 bool BlackWhiteParams::operator !=(const BlackWhiteParams& other) const
2384 {
2385 return !(*this == other);
2386 }
2387
2388
HSLEqualizerParams()2389 HSLEqualizerParams::HSLEqualizerParams():
2390 enabled(false),
2391 hCurve{FCT_Linear},
2392 sCurve{FCT_Linear},
2393 lCurve{FCT_Linear},
2394 smoothing(0)
2395 {
2396 }
2397
2398
operator ==(const HSLEqualizerParams & other) const2399 bool HSLEqualizerParams::operator==(const HSLEqualizerParams &other) const
2400 {
2401 return enabled == other.enabled
2402 && hCurve == other.hCurve
2403 && sCurve == other.sCurve
2404 && lCurve == other.lCurve
2405 && smoothing == other.smoothing;
2406 }
2407
2408
operator !=(const HSLEqualizerParams & other) const2409 bool HSLEqualizerParams::operator!=(const HSLEqualizerParams &other) const
2410 {
2411 return !(*this == other);
2412 }
2413
2414
CACorrParams()2415 CACorrParams::CACorrParams() :
2416 enabled(false),
2417 red(0.0),
2418 blue(0.0)
2419 {
2420 }
2421
operator ==(const CACorrParams & other) const2422 bool CACorrParams::operator ==(const CACorrParams& other) const
2423 {
2424 return
2425 enabled == other.enabled
2426 && red == other.red
2427 && blue == other.blue;
2428 }
2429
operator !=(const CACorrParams & other) const2430 bool CACorrParams::operator !=(const CACorrParams& other) const
2431 {
2432 return !(*this == other);
2433 }
2434
ResizeParams()2435 ResizeParams::ResizeParams() :
2436 enabled(false),
2437 scale(1.0),
2438 appliesTo("Cropped area"),
2439 dataspec(3),
2440 width(900),
2441 height(900),
2442 allowUpscaling(false),
2443 ppi(300),
2444 unit(PX)
2445 {
2446 }
2447
operator ==(const ResizeParams & other) const2448 bool ResizeParams::operator ==(const ResizeParams& other) const
2449 {
2450 return
2451 enabled == other.enabled
2452 && scale == other.scale
2453 && appliesTo == other.appliesTo
2454 && dataspec == other.dataspec
2455 && width == other.width
2456 && height == other.height
2457 && allowUpscaling == other.allowUpscaling
2458 && ppi == other.ppi
2459 && unit == other.unit;
2460 }
2461
operator !=(const ResizeParams & other) const2462 bool ResizeParams::operator !=(const ResizeParams& other) const
2463 {
2464 return !(*this == other);
2465 }
2466
2467
get_width() const2468 int ResizeParams::get_width() const
2469 {
2470 switch (unit) {
2471 case PX: return width;
2472 case CM: return std::round(ppi * (width / 2.54));
2473 case INCHES: return std::round(ppi * width);
2474 default:
2475 assert(false);
2476 return width;
2477 }
2478 }
2479
2480
get_height() const2481 int ResizeParams::get_height() const
2482 {
2483 switch (unit) {
2484 case PX: return height;
2485 case CM: return std::round(ppi * (height / 2.54));
2486 case INCHES: return std::round(ppi * height);
2487 default:
2488 assert(false);
2489 return height;
2490 }
2491 }
2492
2493
2494 const Glib::ustring ColorManagementParams::NoICMString = Glib::ustring("No ICM: sRGB output");
2495 const Glib::ustring ColorManagementParams::NoProfileString = Glib::ustring("(none)");
2496
ColorManagementParams()2497 ColorManagementParams::ColorManagementParams() :
2498 inputProfile("(cameraICC)"),
2499 toneCurve(false),
2500 applyLookTable(false),
2501 applyBaselineExposureOffset(true),
2502 applyHueSatMap(true),
2503 dcpIlluminant(0),
2504 workingProfile("ProPhoto"),
2505 outputProfile(options.rtSettings.srgb),
2506 outputIntent(RI_RELATIVE),
2507 outputBPC(true)
2508 {
2509 }
2510
operator ==(const ColorManagementParams & other) const2511 bool ColorManagementParams::operator ==(const ColorManagementParams& other) const
2512 {
2513 return
2514 inputProfile == other.inputProfile
2515 && toneCurve == other.toneCurve
2516 && applyLookTable == other.applyLookTable
2517 && applyBaselineExposureOffset == other.applyBaselineExposureOffset
2518 && applyHueSatMap == other.applyHueSatMap
2519 && dcpIlluminant == other.dcpIlluminant
2520 && workingProfile == other.workingProfile
2521 && outputProfile == other.outputProfile
2522 && outputIntent == other.outputIntent
2523 && outputBPC == other.outputBPC;
2524 }
2525
operator !=(const ColorManagementParams & other) const2526 bool ColorManagementParams::operator !=(const ColorManagementParams& other) const
2527 {
2528 return !(*this == other);
2529 }
2530
2531
FilmSimulationParams()2532 FilmSimulationParams::FilmSimulationParams() :
2533 enabled(false),
2534 strength(100)
2535 {
2536 }
2537
operator ==(const FilmSimulationParams & other) const2538 bool FilmSimulationParams::operator ==(const FilmSimulationParams& other) const
2539 {
2540 return
2541 enabled == other.enabled
2542 && clutFilename == other.clutFilename
2543 && strength == other.strength;
2544 }
2545
operator !=(const FilmSimulationParams & other) const2546 bool FilmSimulationParams::operator !=(const FilmSimulationParams& other) const
2547 {
2548 return !(*this == other);
2549 }
2550
2551
SoftLightParams()2552 SoftLightParams::SoftLightParams() :
2553 enabled(false),
2554 strength(30)
2555 {
2556 }
2557
operator ==(const SoftLightParams & other) const2558 bool SoftLightParams::operator ==(const SoftLightParams& other) const
2559 {
2560 return
2561 enabled == other.enabled
2562 && strength == other.strength;
2563 }
2564
operator !=(const SoftLightParams & other) const2565 bool SoftLightParams::operator !=(const SoftLightParams& other) const
2566 {
2567 return !(*this == other);
2568 }
2569
2570
DehazeParams()2571 DehazeParams::DehazeParams() :
2572 enabled(false),
2573 strength{
2574 FCT_MinMaxCPoints,
2575 0.0,
2576 0.75,
2577 0.0,
2578 0.0,
2579 1.0,
2580 0.75,
2581 0.0,
2582 0.0
2583 },
2584 showDepthMap(false),
2585 depth(25),
2586 luminance(false),
2587 blackpoint(0)
2588 {
2589 }
2590
operator ==(const DehazeParams & other) const2591 bool DehazeParams::operator ==(const DehazeParams& other) const
2592 {
2593 return
2594 enabled == other.enabled
2595 && strength == other.strength
2596 && showDepthMap == other.showDepthMap
2597 && depth == other.depth
2598 && luminance == other.luminance
2599 && blackpoint == other.blackpoint;
2600 }
2601
operator !=(const DehazeParams & other) const2602 bool DehazeParams::operator !=(const DehazeParams& other) const
2603 {
2604 return !(*this == other);
2605 }
2606
2607
GrainParams()2608 GrainParams::GrainParams():
2609 enabled(false),
2610 iso(400),
2611 strength(25),
2612 scale(100)
2613 {
2614 }
2615
operator ==(const GrainParams & other) const2616 bool GrainParams::operator==(const GrainParams &other) const
2617 {
2618 return enabled == other.enabled
2619 && iso == other.iso
2620 && strength == other.strength
2621 && scale == other.scale;
2622 }
2623
operator !=(const GrainParams & other) const2624 bool GrainParams::operator!=(const GrainParams &other) const
2625 {
2626 return !(*this == other);
2627 }
2628
2629
Region()2630 SmoothingParams::Region::Region():
2631 mode(Mode::GUIDED),
2632 channel(Channel::RGB),
2633 radius(0),
2634 sigma(0),
2635 epsilon(0),
2636 iterations(1),
2637 falloff(1),
2638 nldetail(50),
2639 nlstrength(0)
2640 {
2641 }
2642
2643
operator ==(const Region & other) const2644 bool SmoothingParams::Region::operator==(const Region &other) const
2645 {
2646 return mode == other.mode
2647 && channel == other.channel
2648 && radius == other.radius
2649 && sigma == other.sigma
2650 && epsilon == other.epsilon
2651 && iterations == other.iterations
2652 && falloff == other.falloff
2653 && nlstrength == other.nlstrength
2654 && nldetail == other.nldetail;
2655 }
2656
2657
operator !=(const Region & other) const2658 bool SmoothingParams::Region::operator!=(const Region &other) const
2659 {
2660 return !(*this == other);
2661 }
2662
2663
SmoothingParams()2664 SmoothingParams::SmoothingParams():
2665 enabled(false),
2666 regions{Region()},
2667 labmasks{Mask()},
2668 showMask(-1)
2669 {
2670 }
2671
2672
operator ==(const SmoothingParams & other) const2673 bool SmoothingParams::operator==(const SmoothingParams &other) const
2674 {
2675 return enabled == other.enabled
2676 && regions == other.regions
2677 && labmasks == other.labmasks
2678 && showMask == other.showMask;
2679 }
2680
2681
operator !=(const SmoothingParams & other) const2682 bool SmoothingParams::operator!=(const SmoothingParams &other) const
2683 {
2684 return !(*this == other);
2685 }
2686
2687
Region()2688 ColorCorrectionParams::Region::Region():
2689 a(0),
2690 b(0),
2691 abscale(1),
2692 inSaturation(0),
2693 outSaturation(0),
2694 slope{1,1,1},
2695 offset{0,0,0},
2696 power{1,1,1},
2697 pivot{1,1,1},
2698 hue{0,0,0},
2699 sat{0,0,0},
2700 factor{0,0,0},
2701 rgbluminance(false),
2702 mode(ColorCorrectionParams::Mode::YUV)
2703 {
2704 }
2705
2706
operator ==(const Region & other) const2707 bool ColorCorrectionParams::Region::operator==(const Region &other) const
2708 {
2709 return a == other.a
2710 && b == other.b
2711 && abscale == other.abscale
2712 && inSaturation == other.inSaturation
2713 && outSaturation == other.outSaturation
2714 && slope == other.slope
2715 && offset == other.offset
2716 && power == other.power
2717 && pivot == other.pivot
2718 && hue == other.hue
2719 && sat == other.sat
2720 && factor == other.factor
2721 && rgbluminance == other.rgbluminance
2722 && mode == other.mode;
2723 }
2724
2725
operator !=(const Region & other) const2726 bool ColorCorrectionParams::Region::operator!=(const Region &other) const
2727 {
2728 return !(*this == other);
2729 }
2730
2731
ColorCorrectionParams()2732 ColorCorrectionParams::ColorCorrectionParams():
2733 enabled(false),
2734 regions{Region()},
2735 labmasks{Mask()},
2736 showMask(-1)
2737 {
2738 }
2739
2740
operator ==(const ColorCorrectionParams & other) const2741 bool ColorCorrectionParams::operator==(const ColorCorrectionParams &other) const
2742 {
2743 return enabled == other.enabled
2744 && regions == other.regions
2745 && labmasks == other.labmasks
2746 && showMask == other.showMask;
2747 }
2748
2749
operator !=(const ColorCorrectionParams & other) const2750 bool ColorCorrectionParams::operator!=(const ColorCorrectionParams &other) const
2751 {
2752 return !(*this == other);
2753 }
2754
2755
BayerSensor()2756 RAWParams::BayerSensor::BayerSensor() :
2757 method(Method::RCD),
2758 border(4),
2759 imageNum(0),
2760 ccSteps(0),
2761 black0(0.0),
2762 black1(0.0),
2763 black2(0.0),
2764 black3(0.0),
2765 twogreen(true),
2766 linenoise(0),
2767 linenoiseDirection(LineNoiseDirection::BOTH),
2768 greenthresh(0),
2769 dcb_iterations(2),
2770 lmmse_iterations(2),
2771 dualDemosaicAutoContrast(true),
2772 dualDemosaicContrast(20),
2773 pixelShiftMotionCorrectionMethod(PSMotionCorrectionMethod::AUTO),
2774 pixelShiftEperIso(0.0),
2775 pixelShiftSigma(1.0),
2776 pixelShiftShowMotion(false),
2777 pixelShiftShowMotionMaskOnly(false),
2778 pixelShiftHoleFill(true),
2779 pixelShiftMedian(false),
2780 pixelShiftGreen(true),
2781 pixelShiftBlur(true),
2782 pixelShiftSmoothFactor(0.7),
2783 pixelShiftEqualBright(false),
2784 pixelShiftEqualBrightChannel(false),
2785 pixelShiftNonGreenCross(true),
2786 pixelShiftDemosaicMethod(getPSDemosaicMethodString(PSDemosaicMethod::AMAZE)),
2787 dcb_enhance(true),
2788 pdafLinesFilter(false),
2789 dynamicRowNoiseFilter(false),
2790 enable_black(false),
2791 enable_preproc(false)
2792 {
2793 }
2794
operator ==(const BayerSensor & other) const2795 bool RAWParams::BayerSensor::operator ==(const BayerSensor& other) const
2796 {
2797 return
2798 method == other.method
2799 && border == other.border
2800 && imageNum == other.imageNum
2801 && ccSteps == other.ccSteps
2802 && black0 == other.black0
2803 && black1 == other.black1
2804 && black2 == other.black2
2805 && black3 == other.black3
2806 && twogreen == other.twogreen
2807 && linenoise == other.linenoise
2808 && linenoiseDirection == other.linenoiseDirection
2809 && greenthresh == other.greenthresh
2810 && dcb_iterations == other.dcb_iterations
2811 && lmmse_iterations == other.lmmse_iterations
2812 && dualDemosaicAutoContrast == other.dualDemosaicAutoContrast
2813 && dualDemosaicContrast == other.dualDemosaicContrast
2814 && pixelShiftMotionCorrectionMethod == other.pixelShiftMotionCorrectionMethod
2815 && pixelShiftEperIso == other.pixelShiftEperIso
2816 && pixelShiftSigma == other.pixelShiftSigma
2817 && pixelShiftShowMotion == other.pixelShiftShowMotion
2818 && pixelShiftShowMotionMaskOnly == other.pixelShiftShowMotionMaskOnly
2819 && pixelShiftHoleFill == other.pixelShiftHoleFill
2820 && pixelShiftMedian == other.pixelShiftMedian
2821 && pixelShiftGreen == other.pixelShiftGreen
2822 && pixelShiftBlur == other.pixelShiftBlur
2823 && pixelShiftSmoothFactor == other.pixelShiftSmoothFactor
2824 && pixelShiftEqualBright == other.pixelShiftEqualBright
2825 && pixelShiftEqualBrightChannel == other.pixelShiftEqualBrightChannel
2826 && pixelShiftNonGreenCross == other.pixelShiftNonGreenCross
2827 && pixelShiftDemosaicMethod == other.pixelShiftDemosaicMethod
2828 && dcb_enhance == other.dcb_enhance
2829 && pdafLinesFilter == other.pdafLinesFilter
2830 && dynamicRowNoiseFilter == other.dynamicRowNoiseFilter
2831 && enable_black == other.enable_black
2832 && enable_preproc == other.enable_preproc;
2833 }
2834
operator !=(const BayerSensor & other) const2835 bool RAWParams::BayerSensor::operator !=(const BayerSensor& other) const
2836 {
2837 return !(*this == other);
2838 }
2839
setPixelShiftDefaults()2840 void RAWParams::BayerSensor::setPixelShiftDefaults()
2841 {
2842 pixelShiftMotionCorrectionMethod = RAWParams::BayerSensor::PSMotionCorrectionMethod::AUTO;
2843 pixelShiftEperIso = 0.0;
2844 pixelShiftSigma = 1.0;
2845 pixelShiftHoleFill = true;
2846 pixelShiftMedian = false;
2847 pixelShiftGreen = true;
2848 pixelShiftBlur = true;
2849 pixelShiftSmoothFactor = 0.7;
2850 pixelShiftEqualBright = false;
2851 pixelShiftEqualBrightChannel = false;
2852 pixelShiftNonGreenCross = true;
2853 pixelShiftDemosaicMethod = getPSDemosaicMethodString(PSDemosaicMethod::AMAZE);
2854 }
2855
getMethodStrings()2856 const std::vector<const char*>& RAWParams::BayerSensor::getMethodStrings()
2857 {
2858 static const std::vector<const char*> method_strings {
2859 "amaze",
2860 "rcd",
2861 "lmmse",
2862 "igv",
2863 "amazebilinear",
2864 "rcdbilinear",
2865 "vng4",
2866 "fast",
2867 "mono",
2868 "pixelshift",
2869 "none"
2870 // "amazevng4",
2871 // "rcdvng4",
2872 // "dcb",
2873 // "dcbbilinear",
2874 // "dcbvng4",
2875 // "ahd",
2876 // "eahd",
2877 // "hphd"
2878 };
2879 return method_strings;
2880 }
2881
getMethodString(Method method)2882 Glib::ustring RAWParams::BayerSensor::getMethodString(Method method)
2883 {
2884 size_t i = toUnderlying(method);
2885 auto &v = getMethodStrings();
2886 return i < v.size() ? v[i] : "";
2887 }
2888
getPSDemosaicMethodStrings()2889 const std::vector<const char*>& RAWParams::BayerSensor::getPSDemosaicMethodStrings()
2890 {
2891 static const std::vector<const char*> method_strings {
2892 "amaze",
2893 "amazevng4",
2894 "lmmse"
2895 };
2896 return method_strings;
2897 }
2898
getPSDemosaicMethodString(PSDemosaicMethod method)2899 Glib::ustring RAWParams::BayerSensor::getPSDemosaicMethodString(PSDemosaicMethod method)
2900 {
2901 return getPSDemosaicMethodStrings()[toUnderlying(method)];
2902 }
2903
2904
2905
XTransSensor()2906 RAWParams::XTransSensor::XTransSensor() :
2907 method(Method::THREE_PASS),
2908 dualDemosaicAutoContrast(true),
2909 dualDemosaicContrast(20),
2910 border(7),
2911 ccSteps(0),
2912 blackred(0.0),
2913 blackgreen(0.0),
2914 blackblue(0.0),
2915 enable_black(false)
2916 {
2917 }
2918
operator ==(const XTransSensor & other) const2919 bool RAWParams::XTransSensor::operator ==(const XTransSensor& other) const
2920 {
2921 return
2922 method == other.method
2923 && dualDemosaicAutoContrast == other.dualDemosaicAutoContrast
2924 && dualDemosaicContrast == other.dualDemosaicContrast
2925 && border == other.border
2926 && ccSteps == other.ccSteps
2927 && blackred == other.blackred
2928 && blackgreen == other.blackgreen
2929 && blackblue == other.blackblue
2930 && enable_black == other.enable_black;
2931 }
2932
operator !=(const XTransSensor & other) const2933 bool RAWParams::XTransSensor::operator !=(const XTransSensor& other) const
2934 {
2935 return !(*this == other);
2936 }
2937
getMethodStrings()2938 const std::vector<const char*>& RAWParams::XTransSensor::getMethodStrings()
2939 {
2940 static const std::vector<const char*> method_strings {
2941 "4-pass",
2942 "3-pass (best)",
2943 "2-pass",
2944 "1-pass (medium)",
2945 "fast",
2946 "mono",
2947 "none"
2948 };
2949 return method_strings;
2950 }
2951
getMethodString(Method method)2952 Glib::ustring RAWParams::XTransSensor::getMethodString(Method method)
2953 {
2954 return getMethodStrings()[toUnderlying(method)];
2955 }
2956
RAWParams()2957 RAWParams::RAWParams() :
2958 df_autoselect(false),
2959 ff_AutoSelect(false),
2960 ff_BlurRadius(32),
2961 ff_BlurType(getFlatFieldBlurTypeString(FlatFieldBlurType::AREA)),
2962 ff_AutoClipControl(false),
2963 ff_clipControl(0),
2964 ff_embedded(false),
2965 ca_autocorrect(false),
2966 ca_avoidcolourshift(true),
2967 caautoiterations(2),
2968 cared(0.0),
2969 cablue(0.0),
2970 expos(1.0),
2971 hotPixelFilter(false),
2972 deadPixelFilter(false),
2973 hotdeadpix_thresh(100),
2974 enable_darkframe(false),
2975 enable_flatfield(false),
2976 enable_ca(false),
2977 enable_hotdeadpix(false),
2978 enable_whitepoint(false)
2979 {
2980 }
2981
operator ==(const RAWParams & other) const2982 bool RAWParams::operator ==(const RAWParams& other) const
2983 {
2984 return
2985 bayersensor == other.bayersensor
2986 && xtranssensor == other.xtranssensor
2987 && dark_frame == other.dark_frame
2988 && df_autoselect == other.df_autoselect
2989 && ff_file == other.ff_file
2990 && ff_AutoSelect == other.ff_AutoSelect
2991 && ff_BlurRadius == other.ff_BlurRadius
2992 && ff_BlurType == other.ff_BlurType
2993 && ff_AutoClipControl == other.ff_AutoClipControl
2994 && ff_clipControl == other.ff_clipControl
2995 && ff_embedded == other.ff_embedded
2996 && ca_autocorrect == other.ca_autocorrect
2997 && ca_avoidcolourshift == other.ca_avoidcolourshift
2998 && caautoiterations == other.caautoiterations
2999 && cared == other.cared
3000 && cablue == other.cablue
3001 && expos == other.expos
3002 && hotPixelFilter == other.hotPixelFilter
3003 && deadPixelFilter == other.deadPixelFilter
3004 && hotdeadpix_thresh == other.hotdeadpix_thresh
3005 && enable_darkframe == other.enable_darkframe
3006 && enable_flatfield == other.enable_flatfield
3007 && enable_ca == other.enable_ca
3008 && enable_hotdeadpix == other.enable_hotdeadpix
3009 && enable_whitepoint == other.enable_whitepoint;
3010 }
3011
operator !=(const RAWParams & other) const3012 bool RAWParams::operator !=(const RAWParams& other) const
3013 {
3014 return !(*this == other);
3015 }
3016
getFlatFieldBlurTypeStrings()3017 const std::vector<const char*>& RAWParams::getFlatFieldBlurTypeStrings()
3018 {
3019 static const std::vector<const char*> blur_type_strings {
3020 "Area Flatfield",
3021 "Vertical Flatfield",
3022 "Horizontal Flatfield",
3023 "V+H Flatfield"
3024 };
3025 return blur_type_strings;
3026 }
3027
getFlatFieldBlurTypeString(FlatFieldBlurType type)3028 Glib::ustring RAWParams::getFlatFieldBlurTypeString(FlatFieldBlurType type)
3029 {
3030 return getFlatFieldBlurTypeStrings()[toUnderlying(type)];
3031 }
3032
3033
FilmNegativeParams()3034 FilmNegativeParams::FilmNegativeParams() :
3035 enabled(false),
3036 redRatio(1.36),
3037 greenExp(1.5),
3038 blueRatio(0.86),
3039 redBase(0),
3040 greenBase(0),
3041 blueBase(0)
3042 {
3043 }
3044
operator ==(const FilmNegativeParams & other) const3045 bool FilmNegativeParams::operator ==(const FilmNegativeParams& other) const
3046 {
3047 return
3048 enabled == other.enabled
3049 && redRatio == other.redRatio
3050 && greenExp == other.greenExp
3051 && blueRatio == other.blueRatio
3052 && redBase == other.redBase
3053 && greenBase == other.greenBase
3054 && blueBase == other.blueBase;
3055 }
3056
operator !=(const FilmNegativeParams & other) const3057 bool FilmNegativeParams::operator !=(const FilmNegativeParams& other) const
3058 {
3059 return !(*this == other);
3060 }
3061
3062
3063 namespace {
3064
3065 const std::map<Glib::ustring, Glib::ustring> exif_keys = {
3066 {"Copyright", "Exif.Image.Copyright"},
3067 {"Artist", "Exif.Image.Artist"},
3068 {"ImageDescription", "Exif.Image.ImageDescription"},
3069 {"Exif.UserComment", "Exif.Photo.UserComment"},
3070 {"ISOSpeed", "Exif.Photo.ISOSpeedRatings"},
3071 {"FNumber", "Exif.Photo.FNumber"},
3072 {"ShutterSpeed", "Exif.Photo.ExposureTime"},
3073 {"FocalLength", "Exif.Photo.FocalLength"},
3074 {"ExpComp", "Exif.Photo.ExposureBiasValue"},
3075 {"Flash", "Exif.Photo.Flash"},
3076 {"Make", "Exif.Image.Make"},
3077 {"Model", "Exif.Image.Model"},
3078 {"Lens", "Exif.Photo.LensModel"},
3079 {"DateTime", "Exif.Photo.DateTimeOriginal"},
3080 {"XResolution", "Exif.Image.XResolution"},
3081 {"YResolution", "Exif.Image.YResolution"}
3082 };
3083
3084 const std::map<Glib::ustring, Glib::ustring> iptc_keys = {
3085 {"Title", "Iptc.Application2.ObjectName"},
3086 {"Category", "Iptc.Application2.Category"},
3087 {"SupplementalCategories", "Iptc.Application2.SuppCategory"},
3088 {"Keywords", "Iptc.Application2.Keywords"},
3089 {"Instructions", "Iptc.Application2.SpecialInstructions"},
3090 {"DateCreated", "Iptc.Application2.DateCreated"},
3091 {"Creator", "Iptc.Application2.Byline"},
3092 {"CreatorJobTitle", "Iptc.Application2.BylineTitle"},
3093 {"City", "Iptc.Application2.City"},
3094 {"Province", "Iptc.Application2.ProvinceState"},
3095 {"Country", "Iptc.Application2.CountryName"},
3096 {"TransReference", "Iptc.Application2.TransmissionReference"},
3097 {"Headline", "Iptc.Application2.Headline"},
3098 {"Credit", "Iptc.Application2.Credit"},
3099 {"Source", "Iptc.Application2.Source"},
3100 {"Copyright", "Iptc.Application2.Copyright"},
3101 {"Caption", "Iptc.Application2.Caption"},
3102 {"CaptionWriter", "Iptc.Application2.Writer"}
3103 };
3104
3105 } // namespace
3106
3107
3108 std::vector<std::string> MetaDataParams::basicExifKeys = {
3109 "Exif.Image.Copyright",
3110 "Exif.Image.Artist",
3111 "Exif.Image.ImageDescription",
3112 "Exif.Photo.UserComment",
3113 "Exif.Image.Make",
3114 "Exif.Image.Model",
3115 "Exif.Photo.LensModel",
3116 "Exif.Photo.FNumber",
3117 "Exif.Photo.ExposureTime",
3118 "Exif.Photo.FocalLength",
3119 "Exif.Photo.ISOSpeedRatings",
3120 "Exif.Photo.ExposureBiasValue",
3121 "Exif.Photo.Flash",
3122 "Exif.Photo.DateTimeOriginal",
3123 "Exif.Image.XResolution",
3124 "Exif.Image.YResolution"
3125 };
3126
3127
MetaDataParams()3128 MetaDataParams::MetaDataParams():
3129 mode(MetaDataParams::EDIT),
3130 exifKeys{},
3131 exif{},
3132 iptc{}
3133 {
3134 exifKeys = basicExifKeys;
3135 }
3136
3137
operator ==(const MetaDataParams & other) const3138 bool MetaDataParams::operator==(const MetaDataParams &other) const
3139 {
3140 return mode == other.mode
3141 && exifKeys == other.exifKeys
3142 && exif == other.exif
3143 && iptc == other.iptc;
3144 }
3145
operator !=(const MetaDataParams & other) const3146 bool MetaDataParams::operator!=(const MetaDataParams &other) const
3147 {
3148 return !(*this == other);
3149 }
3150
3151
ProcParams()3152 ProcParams::ProcParams()
3153 {
3154 setDefaults();
3155 }
3156
setDefaults()3157 void ProcParams::setDefaults()
3158 {
3159 exposure = ExposureParams();
3160 saturation = SaturationParams();
3161 toneCurve = ToneCurveParams();
3162 labCurve = LabCurveParams();
3163 rgbCurves = RGBCurvesParams();
3164 localContrast = LocalContrastParams();
3165 sharpening = SharpeningParams();
3166 prsharpening = SharpeningParams();
3167 prsharpening.contrast = 25.0;
3168 prsharpening.method = "usm";
3169 wb = WBParams();
3170 defringe = DefringeParams();
3171 impulseDenoise = ImpulseDenoiseParams();
3172 denoise = DenoiseParams();
3173 textureBoost = TextureBoostParams();
3174 fattal = FattalToneMappingParams();
3175 logenc = LogEncodingParams();
3176 toneEqualizer = ToneEqualizerParams();
3177 crop = CropParams();
3178 coarse = CoarseTransformParams();
3179 commonTrans = CommonTransformParams();
3180 rotate = RotateParams();
3181 distortion = DistortionParams();
3182 lensProf = LensProfParams();
3183 perspective = PerspectiveParams();
3184 gradient = GradientParams();
3185 pcvignette = PCVignetteParams();
3186 vignetting = VignettingParams();
3187 chmixer = ChannelMixerParams();
3188 blackwhite = BlackWhiteParams();
3189 hsl = HSLEqualizerParams();
3190 cacorrection = CACorrParams();
3191 resize = ResizeParams();
3192 icm = ColorManagementParams();
3193 filmSimulation = FilmSimulationParams();
3194 softlight = SoftLightParams();
3195 dehaze = DehazeParams();
3196 grain = GrainParams();
3197 smoothing = SmoothingParams();
3198 colorcorrection = ColorCorrectionParams();
3199 raw = RAWParams();
3200 metadata = MetaDataParams();
3201 filmNegative = FilmNegativeParams();
3202 // exif.clear();
3203 // iptc.clear();
3204
3205 spot = SpotParams();
3206
3207 rank = -1;
3208 colorlabel = 0;
3209 inTrash = false;
3210
3211 ppVersion = PPVERSION;
3212 }
3213
3214
save(ProgressListener * pl,const Glib::ustring & fname,const Glib::ustring & fname2,const ParamsEdited * pedited)3215 int ProcParams::save(ProgressListener *pl, const Glib::ustring& fname, const Glib::ustring& fname2, const ParamsEdited *pedited)
3216 {
3217 if (fname.empty() && fname2.empty()) {
3218 return 0;
3219 }
3220
3221 Glib::ustring sPParams;
3222
3223 try {
3224 KeyFile keyFile;
3225 int ret = save(pl, keyFile, pedited, fname);
3226 if (ret != 0) {
3227 return ret;
3228 }
3229
3230 sPParams = keyFile.to_data();
3231 } catch (Glib::KeyFileError &exc) {
3232 if (pl) {
3233 pl->error(Glib::ustring::compose(M("PROCPARAMS_SAVE_ERROR"), fname, exc.what()));
3234 }
3235 }
3236
3237 if (sPParams.empty()) {
3238 return 1;
3239 }
3240
3241 int error1, error2;
3242 error1 = write(pl, fname, sPParams);
3243
3244 if (!fname2.empty()) {
3245
3246 error2 = write(pl, fname2, sPParams);
3247 // If at least one file has been saved, it's a success
3248 return error1 & error2;
3249 } else {
3250 return error1;
3251 }
3252 }
3253
3254
saveEmbedded(ProgressListener * pl,const Glib::ustring & fname)3255 int ProcParams::saveEmbedded(ProgressListener *pl, const Glib::ustring &fname)
3256 {
3257 if (fname.empty()) {
3258 return 0;
3259 }
3260
3261 Glib::ustring sPParams;
3262
3263 try {
3264 KeyFile keyFile;
3265 int ret = save(pl, keyFile, nullptr, fname);
3266 if (ret != 0) {
3267 return ret;
3268 }
3269
3270 sPParams = keyFile.to_data();
3271 } catch (Glib::KeyFileError &exc) {
3272 if (pl) {
3273 pl->error(Glib::ustring::compose(M("PROCPARAMS_SAVE_ERROR"), fname, exc.what()));
3274 }
3275 }
3276
3277 if (sPParams.empty()) {
3278 return 1;
3279 }
3280
3281 try {
3282 // Exiv2Metadata md(fname, false);
3283 // md.load();
3284 // md.xmpData()["Xmp.ART.arp"] = to_xmp(sPParams);
3285 // md.saveToImage(pl, fname, true);
3286 Exiv2Metadata::embedProcParamsData(fname, to_xmp(sPParams));
3287 return 0;
3288 } catch (std::exception &exc) {
3289 if (pl) {
3290 pl->error(Glib::ustring::compose(M("PROCPARAMS_SAVE_ERROR"), fname, exc.what()));
3291 }
3292 return 1;
3293 }
3294 }
3295
3296
3297
save(ProgressListener * pl,bool save_general,KeyFile & keyFile,const ParamsEdited * pedited,const Glib::ustring & fname) const3298 int ProcParams::save(ProgressListener *pl, bool save_general,
3299 KeyFile &keyFile, const ParamsEdited *pedited,
3300 const Glib::ustring &fname) const
3301 {
3302 #define RELEVANT_(n) (!pedited || pedited->n)
3303 try {
3304 Glib::ustring basedir = Glib::path_get_dirname(fname);
3305
3306 // Version
3307 if (save_general) {
3308 keyFile.set_string("Version", "AppVersion", RTVERSION);
3309 keyFile.set_integer("Version", "Version", PPVERSION);
3310
3311 if (RELEVANT_(general)) {
3312 if (rank >= 0) {
3313 saveToKeyfile("General", "Rank", rank, keyFile);
3314 }
3315 saveToKeyfile("General", "ColorLabel", colorlabel, keyFile);
3316 saveToKeyfile("General", "InTrash", inTrash, keyFile);
3317 }
3318 }
3319
3320 // Exposure
3321 if (RELEVANT_(exposure)) {
3322 saveToKeyfile("Exposure", "Enabled", exposure.enabled, keyFile);
3323 saveToKeyfile("Exposure", "Compensation", exposure.expcomp, keyFile);
3324 saveToKeyfile("Exposure", "Black", exposure.black, keyFile);
3325 Glib::ustring hr = "Off";
3326 switch (exposure.hrmode) {
3327 case ExposureParams::HR_OFF: hr = "Off"; break;
3328 case ExposureParams::HR_BLEND: hr = "Blend"; break;
3329 case ExposureParams::HR_COLOR: hr = "Color"; break;
3330 case ExposureParams::HR_COLORSOFT: hr = "ColorBlend"; break;
3331 }
3332 saveToKeyfile("Exposure", "HLRecovery", hr, keyFile);
3333 }
3334
3335 // Brightness, Contrast, Saturation
3336 if (RELEVANT_(saturation)) {
3337 saveToKeyfile("Saturation", "Enabled", saturation.enabled, keyFile);
3338 saveToKeyfile("Saturation", "Saturation", saturation.saturation, keyFile);
3339 saveToKeyfile("Saturation", "Vibrance", saturation.vibrance, keyFile);
3340 }
3341
3342 // Tone curve
3343 if (RELEVANT_(toneCurve)) {
3344 saveToKeyfile("ToneCurve", "Enabled", toneCurve.enabled, keyFile);
3345 saveToKeyfile("ToneCurve", "Contrast", toneCurve.contrast, keyFile);
3346 saveToKeyfile("ToneCurve", "HistogramMatching", toneCurve.histmatching, keyFile);
3347 saveToKeyfile("ToneCurve", "CurveFromHistogramMatching", toneCurve.fromHistMatching, keyFile);
3348
3349 const std::map<ToneCurveParams::TcMode, const char*> tc_mapping = {
3350 {ToneCurveParams::TcMode::STD, "Standard"},
3351 {ToneCurveParams::TcMode::FILMLIKE, "FilmLike"},
3352 {ToneCurveParams::TcMode::SATANDVALBLENDING, "SatAndValueBlending"},
3353 {ToneCurveParams::TcMode::WEIGHTEDSTD, "WeightedStd"},
3354 {ToneCurveParams::TcMode::LUMINANCE, "Luminance"},
3355 {ToneCurveParams::TcMode::PERCEPTUAL, "Perceptual"}
3356 };
3357
3358 saveToKeyfile("ToneCurve", "CurveMode", tc_mapping, toneCurve.curveMode, keyFile);
3359 saveToKeyfile("ToneCurve", "CurveMode2", tc_mapping, toneCurve.curveMode2, keyFile);
3360
3361 saveToKeyfile("ToneCurve", "Curve", toneCurve.curve, keyFile);
3362 saveToKeyfile("ToneCurve", "Curve2", toneCurve.curve2, keyFile);
3363 saveToKeyfile("ToneCurve", "Saturation", toneCurve.saturation, keyFile);
3364 saveToKeyfile("ToneCurve", "PerceptualStrength", toneCurve.perceptualStrength, keyFile);
3365 }
3366
3367 // Local contrast
3368 if (RELEVANT_(localContrast)) {
3369 saveToKeyfile("Local Contrast", "Enabled", localContrast.enabled, keyFile);
3370 for (size_t j = 0; j < localContrast.regions.size(); ++j) {
3371 std::string n = j ? std::string("_") + std::to_string(j) : std::string("");
3372 auto &r = localContrast.regions[j];
3373 putToKeyfile("Local Contrast", Glib::ustring("Contrast") + n, r.contrast, keyFile);
3374 putToKeyfile("Local Contrast", Glib::ustring("Curve") + n, r.curve, keyFile);
3375 localContrast.labmasks[j].save(keyFile, "Local Contrast", "", n);
3376 }
3377 saveToKeyfile("Local Contrast", "showMask", localContrast.showMask, keyFile);
3378 }
3379
3380
3381 // Channel mixer
3382 if (RELEVANT_(chmixer)) {
3383 saveToKeyfile("Channel Mixer", "Enabled", chmixer.enabled, keyFile);
3384 saveToKeyfile("Channel Mixer", "Mode", int(chmixer.mode), keyFile);
3385 Glib::ArrayHandle<int> rmix(chmixer.red, 3, Glib::OWNERSHIP_NONE);
3386 keyFile.set_integer_list("Channel Mixer", "Red", rmix);
3387 Glib::ArrayHandle<int> gmix(chmixer.green, 3, Glib::OWNERSHIP_NONE);
3388 keyFile.set_integer_list("Channel Mixer", "Green", gmix);
3389 Glib::ArrayHandle<int> bmix(chmixer.blue, 3, Glib::OWNERSHIP_NONE);
3390 keyFile.set_integer_list("Channel Mixer", "Blue", bmix);
3391 Glib::ArrayHandle<int> h(chmixer.hue_tweak, 3, Glib::OWNERSHIP_NONE);
3392 keyFile.set_integer_list("Channel Mixer", "HueTweak", h);
3393 Glib::ArrayHandle<int> s(chmixer.sat_tweak, 3, Glib::OWNERSHIP_NONE);
3394 keyFile.set_integer_list("Channel Mixer", "SatTweak", s);
3395 }
3396
3397 // Black & White
3398 if (RELEVANT_(blackwhite)) {
3399 saveToKeyfile("Black & White", "Enabled", blackwhite.enabled, keyFile);
3400 saveToKeyfile("Black & White", "Setting", blackwhite.setting, keyFile);
3401 saveToKeyfile("Black & White", "Filter", blackwhite.filter, keyFile);
3402 saveToKeyfile("Black & White", "MixerRed", blackwhite.mixerRed, keyFile);
3403 saveToKeyfile("Black & White", "MixerGreen", blackwhite.mixerGreen, keyFile);
3404 saveToKeyfile("Black & White", "MixerBlue", blackwhite.mixerBlue, keyFile);
3405 saveToKeyfile("Black & White", "GammaRed", blackwhite.gammaRed, keyFile);
3406 saveToKeyfile("Black & White", "GammaGreen", blackwhite.gammaGreen, keyFile);
3407 saveToKeyfile("Black & White", "GammaBlue", blackwhite.gammaBlue, keyFile);
3408 saveToKeyfile("Black & White", "ColorCast", blackwhite.colorCast.toVector(), keyFile);
3409 }
3410
3411 // HSL equalizer
3412 if (RELEVANT_(hsl)) {
3413 saveToKeyfile("HSL Equalizer", "Enabled", hsl.enabled, keyFile);
3414 saveToKeyfile("HSL Equalizer", "HCurve", hsl.hCurve, keyFile);
3415 saveToKeyfile("HSL Equalizer", "SCurve", hsl.sCurve, keyFile);
3416 saveToKeyfile("HSL Equalizer", "LCurve", hsl.lCurve, keyFile);
3417 saveToKeyfile("HSL Equalizer", "Smoothing", hsl.smoothing, keyFile);
3418 }
3419
3420 // Luma curve
3421 if (RELEVANT_(labCurve)) {
3422 saveToKeyfile("Luminance Curve", "Enabled", labCurve.enabled, keyFile);
3423 saveToKeyfile("Luminance Curve", "Brightness", labCurve.brightness, keyFile);
3424 saveToKeyfile("Luminance Curve", "Contrast", labCurve.contrast, keyFile);
3425 saveToKeyfile("Luminance Curve", "Chromaticity", labCurve.chromaticity, keyFile);
3426 saveToKeyfile("Luminance Curve", "LCurve", labCurve.lcurve, keyFile);
3427 saveToKeyfile("Luminance Curve", "aCurve", labCurve.acurve, keyFile);
3428 saveToKeyfile("Luminance Curve", "bCurve", labCurve.bcurve, keyFile);
3429 }
3430
3431 // Sharpening
3432 if (RELEVANT_(sharpening)) {
3433 saveToKeyfile("Sharpening", "Enabled", sharpening.enabled, keyFile);
3434 saveToKeyfile("Sharpening", "Contrast", sharpening.contrast, keyFile);
3435 saveToKeyfile("Sharpening", "Method", sharpening.method, keyFile);
3436 saveToKeyfile("Sharpening", "Radius", sharpening.radius, keyFile);
3437 saveToKeyfile("Sharpening", "Amount", sharpening.amount, keyFile);
3438 saveToKeyfile("Sharpening", "Threshold", sharpening.threshold.toVector(), keyFile);
3439 saveToKeyfile("Sharpening", "OnlyEdges", sharpening.edgesonly, keyFile);
3440 saveToKeyfile("Sharpening", "EdgedetectionRadius", sharpening.edges_radius, keyFile);
3441 saveToKeyfile("Sharpening", "EdgeTolerance", sharpening.edges_tolerance, keyFile);
3442 saveToKeyfile("Sharpening", "HalocontrolEnabled", sharpening.halocontrol, keyFile);
3443 saveToKeyfile("Sharpening", "HalocontrolAmount", sharpening.halocontrol_amount, keyFile);
3444 saveToKeyfile("Sharpening", "DeconvRadius", sharpening.deconvradius, keyFile);
3445 saveToKeyfile("Sharpening", "DeconvAmount", sharpening.deconvamount, keyFile);
3446 saveToKeyfile("Sharpening", "DeconvAutoRadius", sharpening.deconvAutoRadius, keyFile);
3447 saveToKeyfile("Sharpening", "DeconvCornerBoost", sharpening.deconvCornerBoost, keyFile);
3448 saveToKeyfile("Sharpening", "DeconvCornerLatitude", sharpening.deconvCornerLatitude, keyFile);
3449 }
3450
3451 // WB
3452 if (RELEVANT_(wb)) {
3453 saveToKeyfile("White Balance", "Enabled", wb.enabled, keyFile);
3454 std::string method = "Camera";
3455 switch (wb.method) {
3456 case WBParams::CAMERA:
3457 method = "Camera";
3458 break;
3459 case WBParams::AUTO:
3460 method = "Auto";
3461 break;
3462 case WBParams::CUSTOM_TEMP:
3463 method = "CustomTemp";
3464 break;
3465 case WBParams::CUSTOM_MULT:
3466 default:
3467 method = "CustomMult";
3468 break;
3469 }
3470 saveToKeyfile("White Balance", "Setting", method, keyFile);
3471 saveToKeyfile("White Balance", "Temperature", wb.temperature, keyFile);
3472 saveToKeyfile("White Balance", "Green", wb.green, keyFile);
3473 saveToKeyfile("White Balance", "Equal", wb.equal, keyFile);
3474 std::vector<double> m(wb.mult.begin(), wb.mult.end());
3475 saveToKeyfile("White Balance", "Multipliers", m, keyFile);
3476 }
3477
3478
3479 // Impulse denoise
3480 if (RELEVANT_(impulseDenoise)) {
3481 saveToKeyfile("Impulse Denoising", "Enabled", impulseDenoise.enabled, keyFile);
3482 saveToKeyfile("Impulse Denoising", "Threshold", impulseDenoise.thresh, keyFile);
3483 }
3484
3485 // Defringe
3486 if (RELEVANT_(defringe)) {
3487 saveToKeyfile("Defringing", "Enabled", defringe.enabled, keyFile);
3488 saveToKeyfile("Defringing", "Radius", defringe.radius, keyFile);
3489 saveToKeyfile("Defringing", "Threshold", defringe.threshold, keyFile);
3490 saveToKeyfile("Defringing", "HueCurve", defringe.huecurve, keyFile);
3491 }
3492
3493 // Dehaze
3494 if (RELEVANT_(dehaze)) {
3495 saveToKeyfile("Dehaze", "Enabled", dehaze.enabled, keyFile);
3496 saveToKeyfile("Dehaze", "Strength", dehaze.strength, keyFile);
3497 saveToKeyfile("Dehaze", "ShowDepthMap", dehaze.showDepthMap, keyFile);
3498 saveToKeyfile("Dehaze", "Depth", dehaze.depth, keyFile);
3499 saveToKeyfile("Dehaze", "Luminance", dehaze.luminance, keyFile);
3500 saveToKeyfile("Dehaze", "Blackpoint", dehaze.blackpoint, keyFile);
3501 }
3502
3503 // Denoising
3504 if (RELEVANT_(denoise)) {
3505 saveToKeyfile("Denoise", "Enabled", denoise.enabled, keyFile);
3506 saveToKeyfile("Denoise", "ColorSpace", denoise.colorSpace == DenoiseParams::ColorSpace::LAB ? Glib::ustring("LAB") : Glib::ustring("RGB"), keyFile);
3507 saveToKeyfile("Denoise", "Aggressive", denoise.aggressive, keyFile);
3508 saveToKeyfile("Denoise", "Gamma", denoise.gamma, keyFile);
3509 saveToKeyfile("Denoise", "Luminance", denoise.luminance, keyFile);
3510 saveToKeyfile("Denoise", "LuminanceDetail", denoise.luminanceDetail, keyFile);
3511 saveToKeyfile("Denoise", "LuminanceDetailThreshold", denoise.luminanceDetailThreshold, keyFile);
3512 saveToKeyfile("Denoise", "ChrominanceMethod", int(denoise.chrominanceMethod), keyFile);
3513 saveToKeyfile("Denoise", "ChrominanceAutoFactor", denoise.chrominanceAutoFactor, keyFile);
3514 saveToKeyfile("Denoise", "Chrominance", denoise.chrominance, keyFile);
3515 saveToKeyfile("Denoise", "ChrominanceRedGreen", denoise.chrominanceRedGreen, keyFile);
3516 saveToKeyfile("Denoise", "ChrominanceBlueYellow", denoise.chrominanceBlueYellow, keyFile);
3517 saveToKeyfile("Denoise", "SmoothingEnabled", denoise.smoothingEnabled, keyFile);
3518 saveToKeyfile("Denoise", "GuidedChromaRadius", denoise.guidedChromaRadius, keyFile);
3519 saveToKeyfile("Denoise", "NLDetail", denoise.nlDetail, keyFile);
3520 saveToKeyfile("Denoise", "NLStrength", denoise.nlStrength, keyFile);
3521 }
3522
3523 // TextureBoost
3524 if (RELEVANT_(textureBoost)) {
3525 saveToKeyfile("TextureBoost", "Enabled", textureBoost.enabled, keyFile);
3526 for (size_t j = 0; j < textureBoost.regions.size(); ++j) {
3527 std::string n = j ? std::string("_") + std::to_string(j) : std::string("");
3528 auto &r = textureBoost.regions[j];
3529 putToKeyfile("TextureBoost", Glib::ustring("Strength") + n, r.strength, keyFile);
3530 putToKeyfile("TextureBoost", Glib::ustring("DetailThreshold") + n, r.detailThreshold, keyFile);
3531 putToKeyfile("TextureBoost", Glib::ustring("Iterations") + n, r.iterations, keyFile);
3532 textureBoost.labmasks[j].save(keyFile, "TextureBoost", "", n);
3533 }
3534 saveToKeyfile("TextureBoost", "showMask", textureBoost.showMask, keyFile);
3535 }
3536
3537 // Fattal
3538 if (RELEVANT_(fattal)) {
3539 saveToKeyfile("FattalToneMapping", "Enabled", fattal.enabled, keyFile);
3540 saveToKeyfile("FattalToneMapping", "Threshold", fattal.threshold, keyFile);
3541 saveToKeyfile("FattalToneMapping", "Amount", fattal.amount, keyFile);
3542 saveToKeyfile("FattalToneMapping", "SaturationControl", fattal.satcontrol, keyFile);
3543 }
3544
3545 // Log encoding
3546 if (RELEVANT_(logenc)) {
3547 saveToKeyfile("LogEncoding", "Enabled", logenc.enabled, keyFile);
3548 saveToKeyfile("LogEncoding", "Auto", logenc.autocompute, keyFile);
3549 saveToKeyfile("LogEncoding", "AutoGain", logenc.autogain, keyFile);
3550 saveToKeyfile("LogEncoding", "Gain", logenc.gain, keyFile);
3551 saveToKeyfile("LogEncoding", "TargetGray", logenc.targetGray, keyFile);
3552 saveToKeyfile("LogEncoding", "BlackEv", logenc.blackEv, keyFile);
3553 saveToKeyfile("LogEncoding", "WhiteEv", logenc.whiteEv, keyFile);
3554 saveToKeyfile("LogEncoding", "Regularization", logenc.regularization, keyFile);
3555 }
3556
3557 // ToneEqualizer
3558 if (RELEVANT_(toneEqualizer)) {
3559 saveToKeyfile("ToneEqualizer", "Enabled", toneEqualizer.enabled, keyFile);
3560 for (size_t i = 0; i < toneEqualizer.bands.size(); ++i) {
3561 saveToKeyfile("ToneEqualizer", "Band" + std::to_string(i), toneEqualizer.bands[i], keyFile);
3562 }
3563 saveToKeyfile("ToneEqualizer", "Regularization", toneEqualizer.regularization, keyFile);
3564 }
3565
3566 // Crop
3567 if (RELEVANT_(crop)) {
3568 saveToKeyfile("Crop", "Enabled", crop.enabled, keyFile);
3569 saveToKeyfile("Crop", "X", crop.x, keyFile);
3570 saveToKeyfile("Crop", "Y", crop.y, keyFile);
3571 saveToKeyfile("Crop", "W", crop.w, keyFile);
3572 saveToKeyfile("Crop", "H", crop.h, keyFile);
3573 saveToKeyfile("Crop", "FixedRatio", crop.fixratio, keyFile);
3574 saveToKeyfile("Crop", "Ratio", crop.ratio, keyFile);
3575 saveToKeyfile("Crop", "Orientation", crop.orientation, keyFile);
3576 saveToKeyfile("Crop", "Guide", crop.guide, keyFile);
3577 }
3578
3579 // Coarse transformation
3580 if (RELEVANT_(coarse)) {
3581 saveToKeyfile("Coarse Transformation", "Rotate", coarse.rotate, keyFile);
3582 saveToKeyfile("Coarse Transformation", "HorizontalFlip", coarse.hflip, keyFile);
3583 saveToKeyfile("Coarse Transformation", "VerticalFlip", coarse.vflip, keyFile);
3584 }
3585
3586 // Common properties for transformations
3587 if (RELEVANT_(commonTrans)) {
3588 saveToKeyfile("Common Properties for Transformations", "AutoFill", commonTrans.autofill, keyFile);
3589 }
3590
3591 // Rotation
3592 if (RELEVANT_(rotate)) {
3593 saveToKeyfile("Rotation", "Enabled", rotate.enabled, keyFile);
3594 saveToKeyfile("Rotation", "Degree", rotate.degree, keyFile);
3595 }
3596
3597 // Distortion
3598 if (RELEVANT_(distortion)) {
3599 saveToKeyfile("Distortion", "Enabled", distortion.enabled, keyFile);
3600 saveToKeyfile("Distortion", "Amount", distortion.amount, keyFile);
3601 saveToKeyfile("Distortion", "Auto", distortion.autocompute, keyFile);
3602 }
3603
3604 // Lens profile
3605 if (RELEVANT_(lensProf)) {
3606 saveToKeyfile("LensProfile", "LcMode", lensProf.getMethodString(lensProf.lcMode), keyFile);
3607 saveToKeyfile("LensProfile", "LCPFile", filenameToUri(lensProf.lcpFile, basedir), keyFile);
3608 saveToKeyfile("LensProfile", "UseDistortion", lensProf.useDist, keyFile);
3609 saveToKeyfile("LensProfile", "UseVignette", lensProf.useVign, keyFile);
3610 saveToKeyfile("LensProfile", "UseCA", lensProf.useCA, keyFile);
3611 saveToKeyfile("LensProfile", "LFCameraMake", lensProf.lfCameraMake, keyFile);
3612 saveToKeyfile("LensProfile", "LFCameraModel", lensProf.lfCameraModel, keyFile);
3613 saveToKeyfile("LensProfile", "LFLens", lensProf.lfLens, keyFile);
3614 }
3615
3616 // Perspective correction
3617 if (RELEVANT_(perspective)) {
3618 saveToKeyfile("Perspective", "Enabled", perspective.enabled, keyFile);
3619 saveToKeyfile("Perspective", "Horizontal", perspective.horizontal, keyFile);
3620 saveToKeyfile("Perspective", "Vertical", perspective.vertical, keyFile);
3621 saveToKeyfile("Perspective", "Angle", perspective.angle, keyFile);
3622 saveToKeyfile("Perspective", "Shear", perspective.shear, keyFile);
3623 saveToKeyfile("Perspective", "FocalLength", perspective.flength, keyFile);
3624 saveToKeyfile("Perspective", "CropFactor", perspective.cropfactor, keyFile);
3625 saveToKeyfile("Perspective", "Aspect", perspective.aspect, keyFile);
3626 saveToKeyfile("Perspective", "ControlLines", perspective.control_lines, keyFile);
3627 }
3628
3629 // Gradient
3630 if (RELEVANT_(gradient)) {
3631 saveToKeyfile("Gradient", "Enabled", gradient.enabled, keyFile);
3632 saveToKeyfile("Gradient", "Degree", gradient.degree, keyFile);
3633 saveToKeyfile("Gradient", "Feather", gradient.feather, keyFile);
3634 saveToKeyfile("Gradient", "Strength", gradient.strength, keyFile);
3635 saveToKeyfile("Gradient", "CenterX", gradient.centerX, keyFile);
3636 saveToKeyfile("Gradient", "CenterY", gradient.centerY, keyFile);
3637 }
3638
3639 // Post-crop vignette
3640 if (RELEVANT_(pcvignette)) {
3641 saveToKeyfile("PCVignette", "Enabled", pcvignette.enabled, keyFile);
3642 saveToKeyfile("PCVignette", "Strength", pcvignette.strength, keyFile);
3643 saveToKeyfile("PCVignette", "Feather", pcvignette.feather, keyFile);
3644 saveToKeyfile("PCVignette", "Roundness", pcvignette.roundness, keyFile);
3645 saveToKeyfile("PCVignette", "CenterX", pcvignette.centerX, keyFile);
3646 saveToKeyfile("PCVignette", "CenterY", pcvignette.centerY, keyFile);
3647 }
3648
3649 // C/A correction
3650 if (RELEVANT_(cacorrection)) {
3651 saveToKeyfile("CACorrection", "Enabled", cacorrection.enabled, keyFile);
3652 saveToKeyfile("CACorrection", "Red", cacorrection.red, keyFile);
3653 saveToKeyfile("CACorrection", "Blue", cacorrection.blue, keyFile);
3654 }
3655
3656 // Vignetting correction
3657 if (RELEVANT_(vignetting)) {
3658 saveToKeyfile("Vignetting Correction", "Enabled", vignetting.enabled, keyFile);
3659 saveToKeyfile("Vignetting Correction", "Amount", vignetting.amount, keyFile);
3660 saveToKeyfile("Vignetting Correction", "Radius", vignetting.radius, keyFile);
3661 saveToKeyfile("Vignetting Correction", "Strength", vignetting.strength, keyFile);
3662 saveToKeyfile("Vignetting Correction", "CenterX", vignetting.centerX, keyFile);
3663 saveToKeyfile("Vignetting Correction", "CenterY", vignetting.centerY, keyFile);
3664 }
3665
3666 // Resize
3667 if (RELEVANT_(resize)) {
3668 saveToKeyfile("Resize", "Enabled", resize.enabled, keyFile);
3669 saveToKeyfile("Resize", "Scale", resize.scale, keyFile);
3670 saveToKeyfile("Resize", "AppliesTo", resize.appliesTo, keyFile);
3671 saveToKeyfile("Resize", "DataSpecified", resize.dataspec, keyFile);
3672 saveToKeyfile("Resize", "Width", resize.width, keyFile);
3673 saveToKeyfile("Resize", "Height", resize.height, keyFile);
3674 saveToKeyfile("Resize", "AllowUpscaling", resize.allowUpscaling, keyFile);
3675 saveToKeyfile("Resize", "PPI", resize.ppi, keyFile);
3676 const char *u = "px";
3677 switch (resize.unit) {
3678 case ResizeParams::CM: u = "cm"; break;
3679 case ResizeParams::INCHES: u = "in"; break;
3680 default: u = "px"; break;
3681 }
3682 saveToKeyfile("Resize", "Unit", Glib::ustring(u), keyFile);
3683 }
3684
3685 // Post resize sharpening
3686 if (RELEVANT_(prsharpening)) {
3687 saveToKeyfile("OutputSharpening", "Enabled", prsharpening.enabled, keyFile);
3688 saveToKeyfile("OutputSharpening", "Contrast", prsharpening.contrast, keyFile);
3689 saveToKeyfile("OutputSharpening", "Method", prsharpening.method, keyFile);
3690 saveToKeyfile("OutputSharpening", "Radius", prsharpening.radius, keyFile);
3691 saveToKeyfile("OutputSharpening", "Amount", prsharpening.amount, keyFile);
3692 saveToKeyfile("OutputSharpening", "Threshold", prsharpening.threshold.toVector(), keyFile);
3693 saveToKeyfile("OutputSharpening", "OnlyEdges", prsharpening.edgesonly, keyFile);
3694 saveToKeyfile("OutputSharpening", "EdgedetectionRadius", prsharpening.edges_radius, keyFile);
3695 saveToKeyfile("OutputSharpening", "EdgeTolerance", prsharpening.edges_tolerance, keyFile);
3696 saveToKeyfile("OutputSharpening", "HalocontrolEnabled", prsharpening.halocontrol, keyFile);
3697 saveToKeyfile("OutputSharpening", "HalocontrolAmount", prsharpening.halocontrol_amount, keyFile);
3698 saveToKeyfile("OutputSharpening", "DeconvRadius", prsharpening.deconvradius, keyFile);
3699 saveToKeyfile("OutputSharpening", "DeconvAmount", prsharpening.deconvamount, keyFile);
3700 }
3701
3702 // Color management
3703 if (RELEVANT_(icm)) {
3704 if (icm.inputProfile.substr(0, 5) == "file:") {
3705 saveToKeyfile("Color Management", "InputProfile", filenameToUri(icm.inputProfile.substr(5), basedir), keyFile);
3706 } else {
3707 saveToKeyfile("Color Management", "InputProfile", icm.inputProfile, keyFile);
3708 }
3709 saveToKeyfile("Color Management", "ToneCurve", icm.toneCurve, keyFile);
3710 saveToKeyfile("Color Management", "ApplyLookTable", icm.applyLookTable, keyFile);
3711 saveToKeyfile("Color Management", "ApplyBaselineExposureOffset", icm.applyBaselineExposureOffset, keyFile);
3712 saveToKeyfile("Color Management", "ApplyHueSatMap", icm.applyHueSatMap, keyFile);
3713 saveToKeyfile("Color Management", "DCPIlluminant", icm.dcpIlluminant, keyFile);
3714 saveToKeyfile("Color Management", "WorkingProfile", icm.workingProfile, keyFile);
3715 saveToKeyfile("Color Management", "OutputProfile", icm.outputProfile, keyFile);
3716 saveToKeyfile(
3717 "Color Management",
3718 "OutputProfileIntent",
3719 {
3720 {RI_PERCEPTUAL, "Perceptual"},
3721 {RI_RELATIVE, "Relative"},
3722 {RI_SATURATION, "Saturation"},
3723 {RI_ABSOLUTE, "Absolute"}
3724
3725 },
3726 icm.outputIntent,
3727 keyFile
3728 );
3729 saveToKeyfile("Color Management", "OutputBPC", icm.outputBPC, keyFile);
3730 }
3731
3732
3733 // Soft Light
3734 if (RELEVANT_(softlight)) {
3735 saveToKeyfile("SoftLight", "Enabled", softlight.enabled, keyFile);
3736 saveToKeyfile("SoftLight", "Strength", softlight.strength, keyFile);
3737 }
3738
3739 // Film simulation
3740 if (RELEVANT_(filmSimulation)) {
3741 saveToKeyfile("Film Simulation", "Enabled", filmSimulation.enabled, keyFile);
3742 auto filename = filenameToUri(filmSimulation.clutFilename, basedir);
3743 saveToKeyfile("Film Simulation", "ClutFilename", filename, keyFile);
3744 saveToKeyfile("Film Simulation", "Strength", filmSimulation.strength, keyFile);
3745 }
3746
3747 // RGB curves
3748 if (RELEVANT_(rgbCurves)) {
3749 saveToKeyfile("RGB Curves", "Enabled", rgbCurves.enabled, keyFile);
3750 saveToKeyfile("RGB Curves", "rCurve", rgbCurves.rcurve, keyFile);
3751 saveToKeyfile("RGB Curves", "gCurve", rgbCurves.gcurve, keyFile);
3752 saveToKeyfile("RGB Curves", "bCurve", rgbCurves.bcurve, keyFile);
3753 }
3754
3755 // Grain
3756 if (RELEVANT_(grain)) {
3757 saveToKeyfile("Grain", "Enabled", grain.enabled, keyFile);
3758 saveToKeyfile("Grain", "ISO", grain.iso, keyFile);
3759 saveToKeyfile("Grain", "Strength", grain.strength, keyFile);
3760 saveToKeyfile("Grain", "Scale", grain.scale, keyFile);
3761 }
3762
3763
3764 // Smoothing
3765 if (RELEVANT_(smoothing)) {
3766 saveToKeyfile("Smoothing", "Enabled", smoothing.enabled, keyFile);
3767 for (size_t j = 0; j < smoothing.regions.size(); ++j) {
3768 std::string n = std::to_string(j+1);
3769 auto &r = smoothing.regions[j];
3770 putToKeyfile("Smoothing", Glib::ustring("Mode_") + n, int(r.mode), keyFile);
3771 putToKeyfile("Smoothing", Glib::ustring("Channel_") + n, int(r.channel), keyFile);
3772 putToKeyfile("Smoothing", Glib::ustring("Radius_") + n, r.radius, keyFile);
3773 putToKeyfile("Smoothing", Glib::ustring("Sigma_") + n, r.sigma, keyFile);
3774 putToKeyfile("Smoothing", Glib::ustring("Epsilon_") + n, r.epsilon, keyFile);
3775 putToKeyfile("Smoothing", Glib::ustring("Iterations_") + n, r.iterations, keyFile);
3776 putToKeyfile("Smoothing", Glib::ustring("Falloff_") + n, r.falloff, keyFile);
3777 putToKeyfile("Smoothing", Glib::ustring("NLStrength_") + n, r.nlstrength, keyFile);
3778 putToKeyfile("Smoothing", Glib::ustring("NLDetail_") + n, r.nldetail, keyFile);
3779 smoothing.labmasks[j].save(keyFile, "Smoothing", "", Glib::ustring("_") + n);
3780 }
3781 saveToKeyfile("Smoothing", "ShowMask", smoothing.showMask, keyFile);
3782 }
3783
3784 // ColorCorrection
3785 if (RELEVANT_(colorcorrection)) {
3786 saveToKeyfile("ColorCorrection", "Enabled", colorcorrection.enabled, keyFile);
3787 for (size_t j = 0; j < colorcorrection.regions.size(); ++j) {
3788 std::string n = std::to_string(j+1);
3789 auto &l = colorcorrection.regions[j];
3790 Glib::ustring mode = "YUV";
3791 if (l.mode == ColorCorrectionParams::Mode::RGB) {
3792 mode = "RGB";
3793 } else if (l.mode == ColorCorrectionParams::Mode::HSL) {
3794 mode = "HSL";
3795 }
3796 putToKeyfile("ColorCorrection", Glib::ustring("Mode_") + n, mode, keyFile);
3797 {
3798 const char *chan[3] = { "Slope", "Offset", "Power" };
3799 for (int c = 0; c < 3; ++c) {
3800 Glib::ustring w = chan[c];
3801 putToKeyfile("ColorCorrection", w + "H" + "_" + n, l.hue[c], keyFile);
3802 putToKeyfile("ColorCorrection", w + "S" + "_" + n, l.sat[c], keyFile);
3803 putToKeyfile("ColorCorrection", w + "L" + "_" + n, l.factor[c], keyFile);
3804 }
3805 }
3806 {
3807 const char *chan[3] = { "R", "G", "B" };
3808 for (int c = 0; c < 3; ++c) {
3809 putToKeyfile("ColorCorrection", Glib::ustring("Slope") + chan[c] + "_" + n, l.slope[c], keyFile);
3810 putToKeyfile("ColorCorrection", Glib::ustring("Offset") + chan[c] + "_" + n, l.offset[c], keyFile);
3811 putToKeyfile("ColorCorrection", Glib::ustring("Power") + chan[c] + "_" + n, l.power[c], keyFile);
3812 putToKeyfile("ColorCorrection", Glib::ustring("Pivot") + chan[c] + "_" + n, l.pivot[0], keyFile);
3813 }
3814 }
3815 {
3816 putToKeyfile("ColorCorrection", Glib::ustring("A_") + n, l.a, keyFile);
3817 putToKeyfile("ColorCorrection", Glib::ustring("B_") + n, l.b, keyFile);
3818 putToKeyfile("ColorCorrection", Glib::ustring("ABScale_") + n, l.abscale, keyFile);
3819 putToKeyfile("ColorCorrection", Glib::ustring("InSaturation_") + n, l.inSaturation, keyFile);
3820 putToKeyfile("ColorCorrection", Glib::ustring("OutSaturation_") + n, l.outSaturation, keyFile);
3821 putToKeyfile("ColorCorrection", Glib::ustring("Slope_") + n, l.slope[0], keyFile);
3822 putToKeyfile("ColorCorrection", Glib::ustring("Offset_") + n, l.offset[0], keyFile);
3823 putToKeyfile("ColorCorrection", Glib::ustring("Power_") + n, l.power[0], keyFile);
3824 putToKeyfile("ColorCorrection", Glib::ustring("Pivot_") + n, l.pivot[0], keyFile);
3825 putToKeyfile("ColorCorrection", Glib::ustring("RGBLuminance_") + n, l.rgbluminance, keyFile);
3826 }
3827 colorcorrection.labmasks[j].save(keyFile, "ColorCorrection", "", Glib::ustring("_") + n);
3828 }
3829 saveToKeyfile("ColorCorrection", "showMask", colorcorrection.showMask, keyFile);
3830 }
3831
3832 // Raw
3833 if (RELEVANT_(darkframe)) {
3834 saveToKeyfile("RAW", "DarkFrameEnabled", raw.enable_darkframe, keyFile);
3835 saveToKeyfile("RAW", "DarkFrame", filenameToUri(raw.dark_frame, basedir), keyFile);
3836 saveToKeyfile("RAW", "DarkFrameAuto", raw.df_autoselect, keyFile);
3837 }
3838 if (RELEVANT_(flatfield)) {
3839 saveToKeyfile("RAW", "FlatFieldEnabled", raw.enable_flatfield, keyFile);
3840 saveToKeyfile("RAW", "FlatFieldFile", filenameToUri(raw.ff_file, basedir), keyFile);
3841 saveToKeyfile("RAW", "FlatFieldAutoSelect", raw.ff_AutoSelect, keyFile);
3842 saveToKeyfile("RAW", "FlatFieldBlurRadius", raw.ff_BlurRadius, keyFile);
3843 saveToKeyfile("RAW", "FlatFieldBlurType", raw.ff_BlurType, keyFile);
3844 saveToKeyfile("RAW", "FlatFieldAutoClipControl", raw.ff_AutoClipControl, keyFile);
3845 saveToKeyfile("RAW", "FlatFieldClipControl", raw.ff_clipControl, keyFile);
3846 saveToKeyfile("RAW", "FlatFieldUseEmbedded", raw.ff_embedded, keyFile);
3847 }
3848 if (RELEVANT_(rawCA)) {
3849 saveToKeyfile("RAW", "CAEnabled", raw.enable_ca, keyFile);
3850 saveToKeyfile("RAW", "CA", raw.ca_autocorrect, keyFile);
3851 saveToKeyfile("RAW", "CAAvoidColourshift", raw.ca_avoidcolourshift, keyFile);
3852 saveToKeyfile("RAW", "CAAutoIterations", raw.caautoiterations, keyFile);
3853 saveToKeyfile("RAW", "CARed", raw.cared, keyFile);
3854 saveToKeyfile("RAW", "CABlue", raw.cablue, keyFile);
3855 }
3856 if (RELEVANT_(hotDeadPixelFilter)) {
3857 saveToKeyfile("RAW", "HotDeadPixelEnabled", raw.enable_hotdeadpix, keyFile);
3858 saveToKeyfile("RAW", "HotPixelFilter", raw.hotPixelFilter, keyFile);
3859 saveToKeyfile("RAW", "DeadPixelFilter", raw.deadPixelFilter, keyFile);
3860 saveToKeyfile("RAW", "HotDeadPixelThresh", raw.hotdeadpix_thresh, keyFile);
3861 }
3862 if (RELEVANT_(demosaic)) {
3863 saveToKeyfile("RAW Bayer", "Method", RAWParams::BayerSensor::getMethodString(raw.bayersensor.method), keyFile);
3864 saveToKeyfile("RAW Bayer", "Border", raw.bayersensor.border, keyFile);
3865 saveToKeyfile("RAW Bayer", "ImageNum", raw.bayersensor.imageNum + 1, keyFile);
3866 saveToKeyfile("RAW Bayer", "CcSteps", raw.bayersensor.ccSteps, keyFile);
3867 }
3868 if (RELEVANT_(rawBlack)) {
3869 saveToKeyfile("RAW Bayer", "PreBlackEnabled", raw.bayersensor.enable_black, keyFile);
3870 saveToKeyfile("RAW Bayer", "PreBlack0", raw.bayersensor.black0, keyFile);
3871 saveToKeyfile("RAW Bayer", "PreBlack1", raw.bayersensor.black1, keyFile);
3872 saveToKeyfile("RAW Bayer", "PreBlack2", raw.bayersensor.black2, keyFile);
3873 saveToKeyfile("RAW Bayer", "PreBlack3", raw.bayersensor.black3, keyFile);
3874 saveToKeyfile("RAW Bayer", "PreTwoGreen", raw.bayersensor.twogreen, keyFile);
3875 }
3876 if (RELEVANT_(rawPreprocessing)) {
3877 saveToKeyfile("RAW Bayer", "PreprocessingEnabled", raw.bayersensor.enable_preproc, keyFile);
3878 saveToKeyfile("RAW Bayer", "LineDenoise", raw.bayersensor.linenoise, keyFile);
3879 saveToKeyfile("RAW Bayer", "LineDenoiseDirection", toUnderlying(raw.bayersensor.linenoiseDirection), keyFile);
3880 saveToKeyfile("RAW Bayer", "GreenEqThreshold", raw.bayersensor.greenthresh, keyFile);
3881 }
3882 if (RELEVANT_(demosaic)) {
3883 // saveToKeyfile("RAW Bayer", "DCBIterations", raw.bayersensor.dcb_iterations, keyFile);
3884 // saveToKeyfile("RAW Bayer", "DCBEnhance", raw.bayersensor.dcb_enhance, keyFile);
3885 saveToKeyfile("RAW Bayer", "LMMSEIterations", raw.bayersensor.lmmse_iterations, keyFile);
3886 saveToKeyfile("RAW Bayer", "DualDemosaicAutoContrast", raw.bayersensor.dualDemosaicAutoContrast, keyFile);
3887 saveToKeyfile("RAW Bayer", "DualDemosaicContrast", raw.bayersensor.dualDemosaicContrast, keyFile);
3888 saveToKeyfile("RAW Bayer", "PixelShiftMotionCorrectionMethod", toUnderlying(raw.bayersensor.pixelShiftMotionCorrectionMethod), keyFile);
3889 saveToKeyfile("RAW Bayer", "PixelShiftEperIso", raw.bayersensor.pixelShiftEperIso, keyFile);
3890 saveToKeyfile("RAW Bayer", "PixelShiftSigma", raw.bayersensor.pixelShiftSigma, keyFile);
3891 saveToKeyfile("RAW Bayer", "PixelShiftShowMotion", raw.bayersensor.pixelShiftShowMotion, keyFile);
3892 saveToKeyfile("RAW Bayer", "PixelShiftShowMotionMaskOnly", raw.bayersensor.pixelShiftShowMotionMaskOnly, keyFile);
3893 saveToKeyfile("RAW Bayer", "pixelShiftHoleFill", raw.bayersensor.pixelShiftHoleFill, keyFile);
3894 saveToKeyfile("RAW Bayer", "pixelShiftMedian", raw.bayersensor.pixelShiftMedian, keyFile);
3895 saveToKeyfile("RAW Bayer", "pixelShiftGreen", raw.bayersensor.pixelShiftGreen, keyFile);
3896 saveToKeyfile("RAW Bayer", "pixelShiftBlur", raw.bayersensor.pixelShiftBlur, keyFile);
3897 saveToKeyfile("RAW Bayer", "pixelShiftSmoothFactor", raw.bayersensor.pixelShiftSmoothFactor, keyFile);
3898 saveToKeyfile("RAW Bayer", "pixelShiftEqualBright", raw.bayersensor.pixelShiftEqualBright, keyFile);
3899 saveToKeyfile("RAW Bayer", "pixelShiftEqualBrightChannel", raw.bayersensor.pixelShiftEqualBrightChannel, keyFile);
3900 saveToKeyfile("RAW Bayer", "pixelShiftNonGreenCross", raw.bayersensor.pixelShiftNonGreenCross, keyFile);
3901 saveToKeyfile("RAW Bayer", "pixelShiftDemosaicMethod", raw.bayersensor.pixelShiftDemosaicMethod, keyFile);
3902 }
3903 if (RELEVANT_(rawPreprocessing)) {
3904 saveToKeyfile("RAW Bayer", "PDAFLinesFilter", raw.bayersensor.pdafLinesFilter, keyFile);
3905 saveToKeyfile("RAW Bayer", "DynamicRowNoiseFilter", raw.bayersensor.dynamicRowNoiseFilter, keyFile);
3906 }
3907 if (RELEVANT_(demosaic)) {
3908 saveToKeyfile("RAW X-Trans", "Method", RAWParams::XTransSensor::getMethodString(raw.xtranssensor.method), keyFile);
3909 saveToKeyfile("RAW X-Trans", "DualDemosaicAutoContrast", raw.xtranssensor.dualDemosaicAutoContrast, keyFile);
3910 saveToKeyfile("RAW X-Trans", "DualDemosaicContrast", raw.xtranssensor.dualDemosaicContrast, keyFile);
3911 saveToKeyfile("RAW X-Trans", "Border", raw.xtranssensor.border, keyFile);
3912 saveToKeyfile("RAW X-Trans", "CcSteps", raw.xtranssensor.ccSteps, keyFile);
3913 }
3914 if (RELEVANT_(rawBlack)) {
3915 saveToKeyfile("RAW X-Trans", "PreBlackEnabled", raw.xtranssensor.enable_black, keyFile);
3916 saveToKeyfile("RAW X-Trans", "PreBlackRed", raw.xtranssensor.blackred, keyFile);
3917 saveToKeyfile("RAW X-Trans", "PreBlackGreen", raw.xtranssensor.blackgreen, keyFile);
3918 saveToKeyfile("RAW X-Trans", "PreBlackBlue", raw.xtranssensor.blackblue, keyFile);
3919 }
3920
3921 // Raw exposition
3922 if (RELEVANT_(rawWhite)) {
3923 saveToKeyfile("RAW", "PreExposureEnabled", raw.enable_whitepoint, keyFile);
3924 saveToKeyfile("RAW", "PreExposure", raw.expos, keyFile);
3925 }
3926
3927 // Film negative
3928 if (RELEVANT_(filmNegative)) {
3929 saveToKeyfile("Film Negative", "Enabled", filmNegative.enabled, keyFile);
3930 saveToKeyfile("Film Negative", "RedRatio", filmNegative.redRatio, keyFile);
3931 saveToKeyfile("Film Negative", "GreenExponent", filmNegative.greenExp, keyFile);
3932 saveToKeyfile("Film Negative", "BlueRatio", filmNegative.blueRatio, keyFile);
3933 saveToKeyfile("Film Negative", "RedBase", filmNegative.redBase, keyFile);
3934 saveToKeyfile("Film Negative", "GreenBase", filmNegative.greenBase, keyFile);
3935 saveToKeyfile("Film Negative", "BlueBase", filmNegative.blueBase, keyFile);
3936 }
3937
3938 // MetaData
3939 if (RELEVANT_(metadata)) {
3940 saveToKeyfile("MetaData", "Mode", metadata.mode, keyFile);
3941 saveToKeyfile("MetaData", "ExifKeys", metadata.exifKeys, keyFile);
3942 }
3943
3944 // EXIF change list
3945 if (RELEVANT_(exif)) {
3946 std::map<Glib::ustring, Glib::ustring> m;
3947 for (auto &p : exif_keys) {
3948 m[p.second] = p.first;
3949 }
3950 for (auto &p : metadata.exif) {
3951 auto it = m.find(p.first);
3952 if (it != m.end()) {
3953 keyFile.set_string("Exif", it->second, p.second);
3954 }
3955 }
3956 }
3957
3958 // IPTC change list
3959 if (RELEVANT_(iptc)) {
3960 std::map<Glib::ustring, Glib::ustring> m;
3961 for (auto &p : iptc_keys) {
3962 m[p.second] = p.first;
3963 }
3964 for (auto &p : metadata.iptc) {
3965 auto it = m.find(p.first);
3966 if (it != m.end()) {
3967 Glib::ArrayHandle<Glib::ustring> values = p.second;
3968 keyFile.set_string_list("IPTC", it->second, values);
3969 }
3970 }
3971 }
3972 //Spot Removal
3973 if (RELEVANT_(spot)) {
3974 //Spot removal
3975 saveToKeyfile("Spot Removal", "Enabled", spot.enabled, keyFile);
3976 for (size_t i = 0; i < spot.entries.size (); ++i) {
3977 std::vector<double> entry = {
3978 double(spot.entries[i].sourcePos.x),
3979 double(spot.entries[i].sourcePos.y),
3980 double(spot.entries[i].targetPos.x),
3981 double(spot.entries[i].targetPos.y),
3982 double(spot.entries[i].radius),
3983 double(spot.entries[i].feather),
3984 double(spot.entries[i].opacity),
3985 double(spot.entries[i].detail)
3986 };
3987
3988 std::stringstream ss;
3989 ss << "Spot" << (i + 1);
3990
3991 saveToKeyfile("Spot Removal", ss.str(), entry, keyFile);
3992 }
3993 }
3994 } catch (Glib::KeyFileError &exc) {
3995 if (pl) {
3996 pl->error(Glib::ustring::compose(M("PROCPARAMS_SAVE_ERROR"), fname, exc.what()));
3997 }
3998 return 1;
3999 }
4000
4001 return 0;
4002 #undef RELEVANT_
4003 }
4004
4005
save(ProgressListener * pl,KeyFile & keyFile,const ParamsEdited * pedited,const Glib::ustring & fname) const4006 int ProcParams::save(ProgressListener *pl,
4007 KeyFile &keyFile, const ParamsEdited *pedited,
4008 const Glib::ustring &fname) const
4009 {
4010 return save(pl, true, keyFile, pedited, fname);
4011 }
4012
4013
load(ProgressListener * pl,const Glib::ustring & fname,const ParamsEdited * pedited)4014 int ProcParams::load(ProgressListener *pl,
4015 const Glib::ustring& fname, const ParamsEdited *pedited)
4016 {
4017 setlocale(LC_NUMERIC, "C"); // to set decimal point to "."
4018
4019 if (fname.empty()) {
4020 return 1;
4021 }
4022
4023 KeyFile keyFile;
4024 keyFile.setProgressListener(pl);
4025
4026 try {
4027 if (!Glib::file_test(fname, Glib::FILE_TEST_EXISTS)) {
4028 return 1;
4029 }
4030
4031 if (!keyFile.load_from_file(fname)) {
4032 // not an error to report
4033 return 1;
4034 }
4035
4036 return load(pl, keyFile, pedited, true, fname);
4037 } catch (const Glib::Error& e) {
4038 //printf("-->%s\n", e.what().c_str());
4039 try {
4040 Exiv2Metadata md(fname, false);
4041 md.load();
4042 std::string xd = md.xmpData()["Xmp.ART.arp"].toString();
4043 Glib::ustring data = from_xmp(xd);
4044 if (!keyFile.load_from_data(data)) {
4045 return 1;
4046 }
4047 return load(pl, keyFile, pedited, true, fname);
4048 } catch (std::exception &exc) {
4049 if (pl) {
4050 pl->error(Glib::ustring::compose(M("PROCPARAMS_LOAD_ERROR"), fname, e.what()));
4051 }
4052 setDefaults();
4053 return 1;
4054 }
4055 } catch (std::exception &e) {
4056 if (pl) {
4057 pl->error(Glib::ustring::compose(M("PROCPARAMS_LOAD_ERROR"), fname, e.what()));
4058 }
4059 setDefaults();
4060 return 1;
4061 } catch (...) {
4062 if (pl) {
4063 pl->error(Glib::ustring::compose(M("PROCPARAMS_LOAD_ERROR"), fname, "unknown exception"));
4064 }
4065 //printf("-->unknown exception!\n");
4066 setDefaults();
4067 return 1;
4068 }
4069 }
4070
4071
load(ProgressListener * pl,bool load_general,const KeyFile & keyFile,const ParamsEdited * pedited,bool resetOnError,const Glib::ustring & fname)4072 int ProcParams::load(ProgressListener *pl, bool load_general,
4073 const KeyFile &keyFile, const ParamsEdited *pedited,
4074 bool resetOnError, const Glib::ustring &fname)
4075 {
4076 #define RELEVANT_(n) (!pedited || pedited->n)
4077
4078 try {
4079 Glib::ustring basedir = Glib::path_get_dirname(fname);
4080
4081 if (load_general) {
4082 ppVersion = PPVERSION;
4083 appVersion = RTVERSION;
4084
4085 if (keyFile.has_group("Version")) {
4086 if (keyFile.has_key("Version", "AppVersion")) {
4087 appVersion = keyFile.get_string("Version", "AppVersion");
4088 }
4089
4090 if (keyFile.has_key("Version", "Version")) {
4091 ppVersion = keyFile.get_integer("Version", "Version");
4092 }
4093 }
4094
4095 if (keyFile.has_group("General") && RELEVANT_(general)) {
4096 assignFromKeyfile(keyFile, "General", "Rank", rank);
4097 assignFromKeyfile(keyFile, "General", "ColorLabel", colorlabel);
4098 assignFromKeyfile(keyFile, "General", "InTrash", inTrash);
4099 }
4100 }
4101
4102 const std::map<std::string, ToneCurveParams::TcMode> tc_mapping = {
4103 {"Standard", ToneCurveParams::TcMode::STD},
4104 {"FilmLike", ToneCurveParams::TcMode::FILMLIKE},
4105 {"SatAndValueBlending", ToneCurveParams::TcMode::SATANDVALBLENDING},
4106 {"WeightedStd", ToneCurveParams::TcMode::WEIGHTEDSTD},
4107 {"Luminance", ToneCurveParams::TcMode::LUMINANCE},
4108 {"Perceptual", ToneCurveParams::TcMode::PERCEPTUAL}
4109 };
4110
4111 if (ppVersion < 350) {
4112 if (keyFile.has_group("Exposure")) {
4113 if (RELEVANT_(exposure)) {
4114 exposure.enabled = true;
4115 assignFromKeyfile(keyFile, "Exposure", "Compensation", exposure.expcomp);
4116 }
4117
4118 if (RELEVANT_(toneCurve)) {
4119 toneCurve.enabled = true;
4120
4121 assignFromKeyfile(keyFile, "Exposure", "CurveMode", tc_mapping, toneCurve.curveMode);
4122 assignFromKeyfile(keyFile, "Exposure", "CurveMode2", tc_mapping, toneCurve.curveMode2);
4123
4124 if (ppVersion > 200) {
4125 assignFromKeyfile(keyFile, "Exposure", "Curve", toneCurve.curve);
4126 assignFromKeyfile(keyFile, "Exposure", "Curve2", toneCurve.curve2);
4127 }
4128
4129 assignFromKeyfile(keyFile, "Exposure", "HistogramMatching", toneCurve.histmatching);
4130 if (ppVersion < 340) {
4131 toneCurve.fromHistMatching = false;
4132 } else {
4133 assignFromKeyfile(keyFile, "Exposure", "CurveFromHistogramMatching", toneCurve.fromHistMatching);
4134 }
4135 }
4136 if (RELEVANT_(saturation)) {
4137 saturation.enabled = true;
4138 assignFromKeyfile(keyFile, "Exposure", "Saturation", saturation.saturation);
4139 }
4140 }
4141 if (keyFile.has_group("HLRecovery") && RELEVANT_(exposure)) {
4142 bool en = false;
4143 Glib::ustring method;
4144 assignFromKeyfile(keyFile, "HLRecovery", "Enabled", en);
4145 assignFromKeyfile(keyFile, "HLRecovery", "Method", method);
4146 if (!en) {
4147 exposure.hrmode = ExposureParams::HR_OFF;
4148 } else if (method == "Blend") {
4149 exposure.hrmode = ExposureParams::HR_BLEND;
4150 } else if (method == "Color") {
4151 exposure.hrmode = ExposureParams::HR_COLOR;
4152 } else {
4153 exposure.hrmode = ExposureParams::HR_OFF;
4154 }
4155 }
4156 } else {
4157 if (keyFile.has_group("Exposure") && RELEVANT_(exposure)) {
4158 assignFromKeyfile(keyFile, "Exposure", "Enabled", exposure.enabled);
4159 assignFromKeyfile(keyFile, "Exposure", "Compensation", exposure.expcomp);
4160 assignFromKeyfile(keyFile, "Exposure", "Black", exposure.black);
4161 if (ppVersion >= 1000) {
4162 Glib::ustring hr;
4163 assignFromKeyfile(keyFile, "Exposure", "HLRecovery", hr);
4164 if (hr == "Blend") {
4165 exposure.hrmode = ExposureParams::HR_BLEND;
4166 } else if (hr == "Color") {
4167 exposure.hrmode = ExposureParams::HR_COLOR;
4168 } else if (hr == "ColorBlend") {
4169 exposure.hrmode = ExposureParams::HR_COLORSOFT;
4170 } else {
4171 exposure.hrmode = ExposureParams::HR_OFF;
4172 }
4173 } else {
4174 bool en = false;
4175 Glib::ustring method;
4176 assignFromKeyfile(keyFile, "Exposure", "HLRecoveryEnabled", en);
4177 assignFromKeyfile(keyFile, "Exposure", "HLRecoveryMethod", method);
4178 if (!en) {
4179 exposure.hrmode = ExposureParams::HR_OFF;
4180 } else if (method == "Blend") {
4181 exposure.hrmode = ExposureParams::HR_BLEND;
4182 } else if (method == "Color") {
4183 exposure.hrmode = ExposureParams::HR_COLOR;
4184 } else {
4185 exposure.hrmode = ExposureParams::HR_OFF;
4186 }
4187 }
4188 }
4189 if (keyFile.has_group("Saturation") && RELEVANT_(saturation)) {
4190 assignFromKeyfile(keyFile, "Saturation", "Enabled", saturation.enabled);
4191 assignFromKeyfile(keyFile, "Saturation", "Saturation", saturation.saturation);
4192 assignFromKeyfile(keyFile, "Saturation", "Vibrance", saturation.vibrance);
4193 }
4194 if (keyFile.has_group("ToneCurve") && RELEVANT_(toneCurve)) {
4195 assignFromKeyfile(keyFile, "ToneCurve", "Enabled", toneCurve.enabled);
4196 assignFromKeyfile(keyFile, "ToneCurve", "Contrast", toneCurve.contrast);
4197 assignFromKeyfile(keyFile, "ToneCurve", "CurveMode", tc_mapping, toneCurve.curveMode);
4198 assignFromKeyfile(keyFile, "ToneCurve", "CurveMode2", tc_mapping, toneCurve.curveMode2);
4199
4200 assignFromKeyfile(keyFile, "ToneCurve", "Curve", toneCurve.curve);
4201 assignFromKeyfile(keyFile, "ToneCurve", "Curve2", toneCurve.curve2);
4202 assignFromKeyfile(keyFile, "ToneCurve", "HistogramMatching", toneCurve.histmatching);
4203 assignFromKeyfile(keyFile, "ToneCurve", "CurveFromHistogramMatching", toneCurve.fromHistMatching);
4204 assignFromKeyfile(keyFile, "ToneCurve", "Saturation", toneCurve.saturation);
4205 assignFromKeyfile(keyFile, "ToneCurve", "PerceptualStrength", toneCurve.perceptualStrength);
4206 }
4207 }
4208
4209 if (keyFile.has_group("Channel Mixer") && RELEVANT_(chmixer)) {
4210 if (ppVersion >= 329) {
4211 assignFromKeyfile(keyFile, "Channel Mixer", "Enabled", chmixer.enabled);
4212 } else {
4213 chmixer.enabled = true;
4214 }
4215
4216 int mode = 0;
4217 if (assignFromKeyfile(keyFile, "Channel Mixer", "Mode", mode)) {
4218 chmixer.mode = ChannelMixerParams::Mode(mode);
4219 }
4220
4221 if (keyFile.has_key("Channel Mixer", "Red") && keyFile.has_key("Channel Mixer", "Green") && keyFile.has_key("Channel Mixer", "Blue")) {
4222 const std::vector<int> rmix = keyFile.get_integer_list("Channel Mixer", "Red");
4223 const std::vector<int> gmix = keyFile.get_integer_list("Channel Mixer", "Green");
4224 const std::vector<int> bmix = keyFile.get_integer_list("Channel Mixer", "Blue");
4225
4226 if (rmix.size() == 3 && gmix.size() == 3 && bmix.size() == 3) {
4227 memcpy(chmixer.red, rmix.data(), 3 * sizeof(int));
4228 memcpy(chmixer.green, gmix.data(), 3 * sizeof(int));
4229 memcpy(chmixer.blue, bmix.data(), 3 * sizeof(int));
4230 }
4231 if (ppVersion < 338) {
4232 for (int i = 0; i < 3; ++i) {
4233 chmixer.red[i] *= 10;
4234 chmixer.green[i] *= 10;
4235 chmixer.blue[i] *= 10;
4236 }
4237 }
4238 }
4239
4240 if (keyFile.has_key("Channel Mixer", "HueTweak")) {
4241 const std::vector<int> h = keyFile.get_integer_list("Channel Mixer", "HueTweak");
4242 if (h.size() == 3) {
4243 for (int i = 0; i < 3; ++i) {
4244 chmixer.hue_tweak[i] = h[i];
4245 }
4246 }
4247 }
4248 if (keyFile.has_key("Channel Mixer", "SatTweak")) {
4249 const std::vector<int> s = keyFile.get_integer_list("Channel Mixer", "SatTweak");
4250 if (s.size() == 3) {
4251 for (int i = 0; i < 3; ++i) {
4252 chmixer.sat_tweak[i] = s[i];
4253 }
4254 }
4255 }
4256 }
4257
4258 if (keyFile.has_group("Black & White") && RELEVANT_(blackwhite)) {
4259 assignFromKeyfile(keyFile, "Black & White", "Enabled", blackwhite.enabled);
4260 assignFromKeyfile(keyFile, "Black & White", "MixerRed", blackwhite.mixerRed);
4261 assignFromKeyfile(keyFile, "Black & White", "MixerGreen", blackwhite.mixerGreen);
4262 assignFromKeyfile(keyFile, "Black & White", "MixerBlue", blackwhite.mixerBlue);
4263 assignFromKeyfile(keyFile, "Black & White", "GammaRed", blackwhite.gammaRed);
4264 assignFromKeyfile(keyFile, "Black & White", "GammaGreen", blackwhite.gammaGreen);
4265 assignFromKeyfile(keyFile, "Black & White", "GammaBlue", blackwhite.gammaBlue);
4266 assignFromKeyfile(keyFile, "Black & White", "Filter", blackwhite.filter);
4267 assignFromKeyfile(keyFile, "Black & White", "Setting", blackwhite.setting);
4268 if (keyFile.has_key("Black & White", "ColorCast")) {
4269 std::vector<int> ccast = keyFile.get_integer_list("Black & White", "ColorCast");
4270 if (ccast.size() >= 2) {
4271 blackwhite.colorCast.setValues(ccast[0], ccast[1]);
4272 }
4273 }
4274 }
4275
4276 if (keyFile.has_group("HSL Equalizer") && RELEVANT_(hsl)) {
4277 assignFromKeyfile(keyFile, "HSL Equalizer", "Enabled", hsl.enabled);
4278 assignFromKeyfile(keyFile, "HSL Equalizer", "HCurve", hsl.hCurve);
4279 assignFromKeyfile(keyFile, "HSL Equalizer", "SCurve", hsl.sCurve);
4280 assignFromKeyfile(keyFile, "HSL Equalizer", "LCurve", hsl.lCurve);
4281 assignFromKeyfile(keyFile, "HSL Equalizer", "Smoothing", hsl.smoothing);
4282 }
4283
4284 if (keyFile.has_group("Local Contrast") && RELEVANT_(localContrast)) {
4285 assignFromKeyfile(keyFile, "Local Contrast", "Enabled", localContrast.enabled);
4286
4287 std::vector<LocalContrastParams::Region> ll;
4288 std::vector<Mask> lm;
4289 bool found = false;
4290 bool done = false;
4291 for (int i = 0; !done; ++i) {
4292 LocalContrastParams::Region cur;
4293 Mask curmask;
4294 done = true;
4295 std::string n = i ? std::string("_") + std::to_string(i) : std::string("");
4296 if (assignFromKeyfile(keyFile, "Local Contrast", Glib::ustring("Contrast") + n, cur.contrast)) {
4297 found = true;
4298 done = false;
4299 }
4300 if (assignFromKeyfile(keyFile, "Local Contrast", Glib::ustring("Curve") + n, cur.curve)) {
4301 found = true;
4302 done = false;
4303 }
4304 if (curmask.load(ppVersion, keyFile, "Local Contrast", "", n)) {
4305 found = true;
4306 done = false;
4307 }
4308 if (!done) {
4309 ll.emplace_back(cur);
4310 lm.emplace_back(curmask);
4311 }
4312 }
4313 if (found) {
4314 localContrast.regions = std::move(ll);
4315 localContrast.labmasks = std::move(lm);
4316 }
4317 assert(localContrast.regions.size() == localContrast.labmasks.size());
4318 assignFromKeyfile(keyFile, "Local Contrast", "ShowMask", localContrast.showMask);
4319 }
4320
4321 if (keyFile.has_group("Luminance Curve") && RELEVANT_(labCurve)) {
4322 assignFromKeyfile(keyFile, "Luminance Curve", "Enabled", labCurve.enabled);
4323 assignFromKeyfile(keyFile, "Luminance Curve", "Brightness", labCurve.brightness);
4324 assignFromKeyfile(keyFile, "Luminance Curve", "Contrast", labCurve.contrast);
4325 assignFromKeyfile(keyFile, "Luminance Curve", "Chromaticity", labCurve.chromaticity);
4326 assignFromKeyfile(keyFile, "Luminance Curve", "LCurve", labCurve.lcurve);
4327 assignFromKeyfile(keyFile, "Luminance Curve", "aCurve", labCurve.acurve);
4328 assignFromKeyfile(keyFile, "Luminance Curve", "bCurve", labCurve.bcurve);
4329 }
4330
4331 if (keyFile.has_group("Sharpening") && RELEVANT_(sharpening)) {
4332 assignFromKeyfile(keyFile, "Sharpening", "Enabled", sharpening.enabled);
4333 if (ppVersion >= 334) {
4334 assignFromKeyfile(keyFile, "Sharpening", "Contrast", sharpening.contrast);
4335 } else {
4336 sharpening.contrast = 0;
4337 }
4338 assignFromKeyfile(keyFile, "Sharpening", "Radius", sharpening.radius);
4339 assignFromKeyfile(keyFile, "Sharpening", "Amount", sharpening.amount);
4340
4341 if (keyFile.has_key("Sharpening", "Threshold")) {
4342 if (ppVersion < 302) {
4343 int thresh = min(keyFile.get_integer("Sharpening", "Threshold"), 2000);
4344 sharpening.threshold.setValues(thresh, thresh, 2000, 2000); // TODO: 2000 is the maximum value and is taken of rtgui/sharpening.cc ; should be changed by the tool modularization
4345 } else {
4346 const std::vector<int> thresh = keyFile.get_integer_list("Sharpening", "Threshold");
4347
4348 if (thresh.size() >= 4) {
4349 sharpening.threshold.setValues(thresh[0], thresh[1], min(thresh[2], 2000), min(thresh[3], 2000));
4350 }
4351 }
4352 }
4353
4354 assignFromKeyfile(keyFile, "Sharpening", "OnlyEdges", sharpening.edgesonly);
4355 assignFromKeyfile(keyFile, "Sharpening", "EdgedetectionRadius", sharpening.edges_radius);
4356 assignFromKeyfile(keyFile, "Sharpening", "EdgeTolerance", sharpening.edges_tolerance);
4357 assignFromKeyfile(keyFile, "Sharpening", "HalocontrolEnabled", sharpening.halocontrol);
4358 assignFromKeyfile(keyFile, "Sharpening", "HalocontrolAmount", sharpening.halocontrol_amount);
4359 assignFromKeyfile(keyFile, "Sharpening", "Method", sharpening.method);
4360 assignFromKeyfile(keyFile, "Sharpening", "DeconvRadius", sharpening.deconvradius);
4361 assignFromKeyfile(keyFile, "Sharpening", "DeconvAmount", sharpening.deconvamount);
4362 assignFromKeyfile(keyFile, "Sharpening", "DeconvAutoRadius", sharpening.deconvAutoRadius);
4363 assignFromKeyfile(keyFile, "Sharpening", "DeconvCornerBoost", sharpening.deconvCornerBoost);
4364 assignFromKeyfile(keyFile, "Sharpening", "DeconvCornerLatitude", sharpening.deconvCornerLatitude);
4365 }
4366
4367 if (keyFile.has_group("White Balance") && RELEVANT_(wb)) {
4368 assignFromKeyfile(keyFile, "White Balance", "Enabled", wb.enabled);
4369 Glib::ustring method = "CustomTemp";
4370 assignFromKeyfile(keyFile, "White Balance", "Setting", method);
4371 assignFromKeyfile(keyFile, "White Balance", "Temperature", wb.temperature);
4372 assignFromKeyfile(keyFile, "White Balance", "Green", wb.green);
4373 assignFromKeyfile(keyFile, "White Balance", "Equal", wb.equal);
4374 std::vector<float> m;
4375 if (assignFromKeyfile(keyFile, "White Balance", "Multipliers", m) && m.size() == 3) {
4376 for (int i = 0; i < 3; ++i) {
4377 wb.mult[i] = m[i];
4378 }
4379 }
4380 if (method == "Camera") {
4381 wb.method = WBParams::CAMERA;
4382 } else if (method == "Auto") {
4383 wb.method = WBParams::AUTO;
4384 } else if (method == "CustomMult") {
4385 wb.method = WBParams::CUSTOM_MULT;
4386 } else {
4387 wb.method = WBParams::CUSTOM_TEMP;
4388 }
4389 }
4390
4391 if (keyFile.has_group("Defringing") && RELEVANT_(defringe)) {
4392 assignFromKeyfile(keyFile, "Defringing", "Enabled", defringe.enabled);
4393 assignFromKeyfile(keyFile, "Defringing", "Radius", defringe.radius);
4394
4395 if (keyFile.has_key("Defringing", "Threshold")) {
4396 defringe.threshold = (float)keyFile.get_integer("Defringing", "Threshold");
4397 }
4398
4399 if (ppVersion < 310) {
4400 defringe.threshold = sqrt(defringe.threshold * 33.f / 5.f);
4401 }
4402
4403 assignFromKeyfile(keyFile, "Defringing", "HueCurve", defringe.huecurve);
4404 }
4405
4406 if (keyFile.has_group("Impulse Denoising") && RELEVANT_(impulseDenoise)) {
4407 assignFromKeyfile(keyFile, "Impulse Denoising", "Enabled", impulseDenoise.enabled);
4408 assignFromKeyfile(keyFile, "Impulse Denoising", "Threshold", impulseDenoise.thresh);
4409 }
4410
4411 if (ppVersion < 346) {
4412 if (keyFile.has_group("Directional Pyramid Denoising") && RELEVANT_(denoise)) { //TODO: No longer an accurate description for FT denoise
4413 assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Enabled", denoise.enabled);
4414 assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Luma", denoise.luminance);
4415 assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Ldetail", denoise.luminanceDetail);
4416 assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Chroma", denoise.chrominance);
4417 Glib::ustring val;
4418 if (assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "C2Method", val)) {
4419 if (val == "MANU") {
4420 denoise.chrominanceMethod = DenoiseParams::ChrominanceMethod::MANUAL;
4421 } else {
4422 denoise.chrominanceMethod = DenoiseParams::ChrominanceMethod::AUTOMATIC;
4423 }
4424 }
4425 if (assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "SMethod", val)) {
4426 denoise.aggressive = (val == "shalbi");
4427 }
4428 assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Redchro", denoise.chrominanceRedGreen);
4429 assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Bluechro", denoise.chrominanceBlueYellow);
4430 }
4431 } else {
4432 if (keyFile.has_group("Denoise") && RELEVANT_(denoise)) {
4433 assignFromKeyfile(keyFile, "Denoise", "Enabled", denoise.enabled);
4434 Glib::ustring cs = "RGB";
4435 assignFromKeyfile(keyFile, "Denoise", "ColorSpace", cs);
4436 if (cs == "LAB") {
4437 denoise.colorSpace = DenoiseParams::ColorSpace::LAB;
4438 } else {
4439 denoise.colorSpace = DenoiseParams::ColorSpace::RGB;
4440 }
4441 int val;
4442 assignFromKeyfile(keyFile, "Denoise", "Aggressive", denoise.aggressive);
4443 assignFromKeyfile(keyFile, "Denoise", "Gamma", denoise.gamma);
4444 assignFromKeyfile(keyFile, "Denoise", "Luminance", denoise.luminance);
4445 assignFromKeyfile(keyFile, "Denoise", "LuminanceDetail", denoise.luminanceDetail);
4446 assignFromKeyfile(keyFile, "Denoise", "LuminanceDetailThreshold", denoise.luminanceDetailThreshold);
4447 if (assignFromKeyfile(keyFile, "Denoise", "ChrominanceMethod", val)) {
4448 denoise.chrominanceMethod = static_cast<DenoiseParams::ChrominanceMethod>(val);
4449 }
4450 assignFromKeyfile(keyFile, "Denoise", "ChrominanceAutoFactor", denoise.chrominanceAutoFactor);
4451 assignFromKeyfile(keyFile, "Denoise", "Chrominance", denoise.chrominance);
4452 assignFromKeyfile(keyFile, "Denoise", "ChrominanceRedGreen", denoise.chrominanceRedGreen);
4453 assignFromKeyfile(keyFile, "Denoise", "ChrominanceBlueYellow", denoise.chrominanceBlueYellow);
4454 assignFromKeyfile(keyFile, "Denoise", "SmoothingEnabled", denoise.smoothingEnabled);
4455 if (assignFromKeyfile(keyFile, "Denoise", "SmoothingMethod", val) && val != 1) {
4456 denoise.smoothingEnabled = false;
4457 }
4458 assignFromKeyfile(keyFile, "Denoise", "GuidedChromaRadius", denoise.guidedChromaRadius);
4459 assignFromKeyfile(keyFile, "Denoise", "NLDetail", denoise.nlDetail);
4460 assignFromKeyfile(keyFile, "Denoise", "NLStrength", denoise.nlStrength);
4461 }
4462 }
4463
4464 const Glib::ustring tbgroup = ppVersion < 1000 ? "EPD" : "TextureBoost";
4465 if (keyFile.has_group(tbgroup) && RELEVANT_(textureBoost)) {
4466 assignFromKeyfile(keyFile, tbgroup, "Enabled", textureBoost.enabled);
4467
4468 std::vector<TextureBoostParams::Region> ll;
4469 std::vector<Mask> lm;
4470 bool found = false;
4471 bool done = false;
4472 for (int i = 0; !done; ++i) {
4473 TextureBoostParams::Region cur;
4474 Mask curmask;
4475 done = true;
4476 std::string n = i ? std::string("_") + std::to_string(i) : std::string("");
4477 if (assignFromKeyfile(keyFile, tbgroup, Glib::ustring("Strength") + n, cur.strength)) {
4478 found = true;
4479 done = false;
4480 }
4481 if (assignFromKeyfile(keyFile, tbgroup, Glib::ustring(ppVersion < 1009 ? "EdgeStopping" : "DetailThreshold") + n, cur.detailThreshold)) {
4482 found = true;
4483 done = false;
4484 }
4485 if (assignFromKeyfile(keyFile, tbgroup, Glib::ustring("Iterations") + n, cur.iterations)) {
4486 found = true;
4487 done = false;
4488 }
4489 if (curmask.load(ppVersion, keyFile, tbgroup, "", n)) {
4490 found = true;
4491 done = false;
4492 }
4493 if (!done) {
4494 ll.emplace_back(cur);
4495 lm.emplace_back(curmask);
4496 }
4497 }
4498 if (found) {
4499 textureBoost.regions = std::move(ll);
4500 textureBoost.labmasks = std::move(lm);
4501 }
4502 assert(textureBoost.regions.size() == textureBoost.labmasks.size());
4503 assignFromKeyfile(keyFile, tbgroup, "ShowMask", textureBoost.showMask);
4504 }
4505
4506 if (keyFile.has_group("FattalToneMapping") && RELEVANT_(fattal)) {
4507 assignFromKeyfile(keyFile, "FattalToneMapping", "Enabled", fattal.enabled);
4508 assignFromKeyfile(keyFile, "FattalToneMapping", "Threshold", fattal.threshold);
4509 assignFromKeyfile(keyFile, "FattalToneMapping", "Amount", fattal.amount);
4510 assignFromKeyfile(keyFile, "FattalToneMapping", "SaturationControl", fattal.satcontrol);
4511 }
4512
4513 if (keyFile.has_group("LogEncoding") && RELEVANT_(logenc)) {
4514 assignFromKeyfile(keyFile, "LogEncoding", "Enabled", logenc.enabled);
4515 if (ppVersion >= 1013) {
4516 assignFromKeyfile(keyFile, "LogEncoding", "Auto", logenc.autocompute);
4517 } else {
4518 logenc.autocompute = false;
4519 }
4520 assignFromKeyfile(keyFile, "LogEncoding", ppVersion < 1024 ? "AutoGray" : "AutoGain", logenc.autogain);
4521 if (ppVersion < 349) {
4522 if (assignFromKeyfile(keyFile, "LogEncoding", "GrayPoint", logenc.gain) && logenc.gain > 0) {
4523 logenc.gain = std::log2(18.0/logenc.gain);
4524 }
4525 } else {
4526 if (ppVersion < 1024) {
4527 if (assignFromKeyfile(keyFile, "LogEncoding", "SourceGray", logenc.gain) && logenc.gain > 0) {
4528 logenc.gain = std::log2(18.0/logenc.gain);
4529 }
4530 } else {
4531 assignFromKeyfile(keyFile, "LogEncoding", "Gain", logenc.gain);
4532 }
4533 assignFromKeyfile(keyFile, "LogEncoding", "TargetGray", logenc.targetGray);
4534 }
4535 assignFromKeyfile(keyFile, "LogEncoding", "BlackEv", logenc.blackEv);
4536 assignFromKeyfile(keyFile, "LogEncoding", "WhiteEv", logenc.whiteEv);
4537 if (ppVersion >= 1006) {
4538 assignFromKeyfile(keyFile, "LogEncoding", "Regularization", logenc.regularization);
4539 } else {
4540 logenc.regularization = 0;
4541 }
4542 if (ppVersion < 1025) {
4543 toneCurve.contrast *= 2;
4544 }
4545 }
4546
4547 if (keyFile.has_group("ToneEqualizer") && RELEVANT_(toneEqualizer)) {
4548 assignFromKeyfile(keyFile, "ToneEqualizer", "Enabled", toneEqualizer.enabled);
4549 for (size_t i = 0; i < toneEqualizer.bands.size(); ++i) {
4550 assignFromKeyfile(keyFile, "ToneEqualizer", "Band" + std::to_string(i), toneEqualizer.bands[i]);
4551 }
4552 if (ppVersion >= 1020) {
4553 assignFromKeyfile(keyFile, "ToneEqualizer", "Regularization", toneEqualizer.regularization);
4554 } else if (ppVersion >= 1002) {
4555 if (assignFromKeyfile(keyFile, "ToneEqualizer", "Regularization", toneEqualizer.regularization)) {
4556 if (toneEqualizer.regularization > 0) {
4557 //toneEqualizer.regularization = 6 - std::min(toneEqualizer.regularization, 5);
4558 toneEqualizer.regularization = 4;
4559 } else if (toneEqualizer.regularization == -5) {
4560 toneEqualizer.regularization = 0;
4561 } else {
4562 toneEqualizer.regularization = 1;
4563 }
4564 }
4565 } else {
4566 assignFromKeyfile(keyFile, "ToneEqualizer", "Detail", toneEqualizer.regularization);
4567 }
4568 }
4569
4570 if (keyFile.has_group("Crop") && RELEVANT_(crop)) {
4571 assignFromKeyfile(keyFile, "Crop", "Enabled", crop.enabled);
4572 assignFromKeyfile(keyFile, "Crop", "X", crop.x);
4573 assignFromKeyfile(keyFile, "Crop", "Y", crop.y);
4574
4575 if (keyFile.has_key("Crop", "W")) {
4576 crop.w = std::max(keyFile.get_integer("Crop", "W"), 1);
4577 }
4578
4579 if (keyFile.has_key("Crop", "H")) {
4580 crop.h = std::max(keyFile.get_integer("Crop", "H"), 1);
4581 }
4582
4583 assignFromKeyfile(keyFile, "Crop", "FixedRatio", crop.fixratio);
4584
4585 if (assignFromKeyfile(keyFile, "Crop", "Ratio", crop.ratio)) {
4586 //backwards compatibility for crop.ratio
4587 if (crop.ratio == "DIN") {
4588 crop.ratio = "1.414 - DIN EN ISO 216";
4589 }
4590
4591 if (crop.ratio == "8.5:11") {
4592 crop.ratio = "8.5:11 - US Letter";
4593 }
4594
4595 if (crop.ratio == "11:17") {
4596 crop.ratio = "11:17 - Tabloid";
4597 }
4598 }
4599
4600 assignFromKeyfile(keyFile, "Crop", "Orientation", crop.orientation);
4601 assignFromKeyfile(keyFile, "Crop", "Guide", crop.guide);
4602 }
4603
4604 if (keyFile.has_group("Coarse Transformation") && RELEVANT_(coarse)) {
4605 assignFromKeyfile(keyFile, "Coarse Transformation", "Rotate", coarse.rotate);
4606 assignFromKeyfile(keyFile, "Coarse Transformation", "HorizontalFlip", coarse.hflip);
4607 assignFromKeyfile(keyFile, "Coarse Transformation", "VerticalFlip", coarse.vflip);
4608 }
4609
4610 if (keyFile.has_group("Rotation") && RELEVANT_(rotate)) {
4611 assignFromKeyfile(keyFile, "Rotation", "Enabled", rotate.enabled);
4612 assignFromKeyfile(keyFile, "Rotation", "Degree", rotate.degree);
4613 }
4614
4615 if (keyFile.has_group("Common Properties for Transformations") && RELEVANT_(commonTrans)) {
4616 assignFromKeyfile(keyFile, "Common Properties for Transformations", "AutoFill", commonTrans.autofill);
4617 }
4618
4619 if (keyFile.has_group("Distortion") && RELEVANT_(distortion)) {
4620 assignFromKeyfile(keyFile, "Distortion", "Enabled", distortion.enabled);
4621 assignFromKeyfile(keyFile, "Distortion", "Amount", distortion.amount);
4622 assignFromKeyfile(keyFile, "Distortion", "Auto", distortion.autocompute);
4623 }
4624
4625 if (keyFile.has_group("LensProfile") && RELEVANT_(lensProf)) {
4626 if (keyFile.has_key("LensProfile", "LcMode")) {
4627 lensProf.lcMode = lensProf.getMethodNumber(keyFile.get_string("LensProfile", "LcMode"));
4628 }
4629
4630 if (keyFile.has_key("LensProfile", "LCPFile")) {
4631 if (ppVersion >= 1017) {
4632 lensProf.lcpFile = filenameFromUri(keyFile.get_string("LensProfile", "LCPFile"), basedir);
4633 } else {
4634 lensProf.lcpFile = expandRelativePath(fname, "", keyFile.get_string("LensProfile", "LCPFile"));
4635 }
4636
4637 if (ppVersion < 327 && !lensProf.lcpFile.empty()) {
4638 lensProf.lcMode = LensProfParams::LcMode::LCP;
4639 }
4640 }
4641
4642 assignFromKeyfile(keyFile, "LensProfile", "UseDistortion", lensProf.useDist);
4643 assignFromKeyfile(keyFile, "LensProfile", "UseVignette", lensProf.useVign);
4644 assignFromKeyfile(keyFile, "LensProfile", "UseCA", lensProf.useCA);
4645
4646 if (keyFile.has_key("LensProfile", "LFCameraMake")) {
4647 lensProf.lfCameraMake = keyFile.get_string("LensProfile", "LFCameraMake");
4648 }
4649
4650 if (keyFile.has_key("LensProfile", "LFCameraModel")) {
4651 lensProf.lfCameraModel = keyFile.get_string("LensProfile", "LFCameraModel");
4652 }
4653
4654 if (keyFile.has_key("LensProfile", "LFLens")) {
4655 lensProf.lfLens = keyFile.get_string("LensProfile", "LFLens");
4656 }
4657 }
4658
4659 if (keyFile.has_group("Perspective") && RELEVANT_(perspective)) {
4660 assignFromKeyfile(keyFile, "Perspective", "Enabled", perspective.enabled);
4661 assignFromKeyfile(keyFile, "Perspective", "Horizontal", perspective.horizontal);
4662 assignFromKeyfile(keyFile, "Perspective", "Vertical", perspective.vertical);
4663 assignFromKeyfile(keyFile, "Perspective", "Angle", perspective.angle);
4664 assignFromKeyfile(keyFile, "Perspective", "Shear", perspective.shear);
4665 assignFromKeyfile(keyFile, "Perspective", "FocalLength", perspective.flength);
4666 assignFromKeyfile(keyFile, "Perspective", "CropFactor", perspective.cropfactor);
4667 assignFromKeyfile(keyFile, "Perspective", "Aspect", perspective.aspect);
4668 if (keyFile.has_key("Perspective", "ControlLines")) {
4669 perspective.control_lines = keyFile.get_integer_list("Perspective", "ControlLines");
4670 }
4671 }
4672
4673 if (keyFile.has_group("Gradient") && RELEVANT_(gradient)) {
4674 assignFromKeyfile(keyFile, "Gradient", "Enabled", gradient.enabled);
4675 assignFromKeyfile(keyFile, "Gradient", "Degree", gradient.degree);
4676 assignFromKeyfile(keyFile, "Gradient", "Feather", gradient.feather);
4677 assignFromKeyfile(keyFile, "Gradient", "Strength", gradient.strength);
4678 assignFromKeyfile(keyFile, "Gradient", "CenterX", gradient.centerX);
4679 assignFromKeyfile(keyFile, "Gradient", "CenterY", gradient.centerY);
4680 }
4681
4682 if (keyFile.has_group("PCVignette") && RELEVANT_(pcvignette)) {
4683 assignFromKeyfile(keyFile, "PCVignette", "Enabled", pcvignette.enabled);
4684 assignFromKeyfile(keyFile, "PCVignette", "Strength", pcvignette.strength);
4685 assignFromKeyfile(keyFile, "PCVignette", "Feather", pcvignette.feather);
4686 assignFromKeyfile(keyFile, "PCVignette", "Roundness", pcvignette.roundness);
4687 assignFromKeyfile(keyFile, "PCVignette", "CenterX", pcvignette.centerX);
4688 assignFromKeyfile(keyFile, "PCVignette", "CenterY", pcvignette.centerY);
4689 }
4690
4691 if (keyFile.has_group("CACorrection") && RELEVANT_(cacorrection)) {
4692 assignFromKeyfile(keyFile, "CACorrection", "Enabled", cacorrection.enabled);
4693 assignFromKeyfile(keyFile, "CACorrection", "Red", cacorrection.red);
4694 assignFromKeyfile(keyFile, "CACorrection", "Blue", cacorrection.blue);
4695 }
4696
4697 if (keyFile.has_group("Vignetting Correction") && RELEVANT_(vignetting)) {
4698 assignFromKeyfile(keyFile, "Vignetting Correction", "Enabled", vignetting.enabled);
4699 assignFromKeyfile(keyFile, "Vignetting Correction", "Amount", vignetting.amount);
4700 assignFromKeyfile(keyFile, "Vignetting Correction", "Radius", vignetting.radius);
4701 assignFromKeyfile(keyFile, "Vignetting Correction", "Strength", vignetting.strength);
4702 assignFromKeyfile(keyFile, "Vignetting Correction", "CenterX", vignetting.centerX);
4703 assignFromKeyfile(keyFile, "Vignetting Correction", "CenterY", vignetting.centerY);
4704 }
4705
4706 if (keyFile.has_group("Resize") && RELEVANT_(resize)) {
4707 assignFromKeyfile(keyFile, "Resize", "Enabled", resize.enabled);
4708 assignFromKeyfile(keyFile, "Resize", "Scale", resize.scale);
4709 assignFromKeyfile(keyFile, "Resize", "AppliesTo", resize.appliesTo);
4710 assignFromKeyfile(keyFile, "Resize", "DataSpecified", resize.dataspec);
4711 assignFromKeyfile(keyFile, "Resize", "Width", resize.width);
4712 assignFromKeyfile(keyFile, "Resize", "Height", resize.height);
4713 if (ppVersion >= 339) {
4714 assignFromKeyfile(keyFile, "Resize", "AllowUpscaling", resize.allowUpscaling);
4715 } else {
4716 resize.allowUpscaling = false;
4717 }
4718 assignFromKeyfile(keyFile, "Resize", "PPI", resize.ppi);
4719 if (ppVersion < 1004) {
4720 resize.unit = ResizeParams::PX;
4721 } else {
4722 Glib::ustring u = "px";
4723 assignFromKeyfile(keyFile, "Resize", "Unit", u);
4724 if (u == "cm") {
4725 resize.unit = ResizeParams::CM;
4726 } else if (u == "in") {
4727 resize.unit = ResizeParams::INCHES;
4728 } else {
4729 resize.unit = ResizeParams::PX;
4730 }
4731 }
4732 }
4733
4734 if (keyFile.has_group ("Spot Removal") && RELEVANT_(spot)) {
4735 assignFromKeyfile(keyFile, "Spot Removal", "Enabled", spot.enabled);
4736 int i = 0;
4737 do {
4738 std::stringstream ss;
4739 ss << "Spot" << (i++ + 1);
4740
4741 if (keyFile.has_key ("Spot Removal", ss.str())) {
4742 Glib::ArrayHandle<double> entry = keyFile.get_double_list("Spot Removal", ss.str());
4743 const double epsilon = 0.001; // to circumvent rounding of integer saved as double
4744 SpotEntry se;
4745
4746 if (entry.size() == 8) {
4747 se.sourcePos.set(int(entry.data()[0] + epsilon), int(entry.data()[1] + epsilon));
4748 se.targetPos.set(int(entry.data()[2] + epsilon), int(entry.data()[3] + epsilon));
4749 se.radius = LIM<int>(int(entry.data()[4] + epsilon), SpotParams::minRadius, SpotParams::maxRadius);
4750 se.feather = float(entry.data()[5]);
4751 se.opacity = float(entry.data()[6]);
4752 se.detail = entry.data()[7];
4753 spot.entries.push_back(se);
4754 }
4755 } else {
4756 break;
4757 }
4758 } while (1);
4759 }
4760
4761 const char *psgrp = ppVersion < 1021 ? "PostResizeSharpening" : "OutputSharpening";
4762 if (keyFile.has_group(psgrp) && RELEVANT_(prsharpening)) {
4763 assignFromKeyfile(keyFile, psgrp, "Enabled", prsharpening.enabled);
4764 assignFromKeyfile(keyFile, psgrp, "Contrast", prsharpening.contrast);
4765 assignFromKeyfile(keyFile, psgrp, "Radius", prsharpening.radius);
4766 assignFromKeyfile(keyFile, psgrp, "Amount", prsharpening.amount);
4767
4768 if (keyFile.has_key(psgrp, "Threshold")) {
4769 if (ppVersion < 302) {
4770 int thresh = min(keyFile.get_integer(psgrp, "Threshold"), 2000);
4771 prsharpening.threshold.setValues(thresh, thresh, 2000, 2000); // TODO: 2000 is the maximum value and is taken of rtgui/sharpening.cc ; should be changed by the tool modularization
4772 } else {
4773 const std::vector<int> thresh = keyFile.get_integer_list(psgrp, "Threshold");
4774
4775 if (thresh.size() >= 4) {
4776 prsharpening.threshold.setValues(thresh[0], thresh[1], min(thresh[2], 2000), min(thresh[3], 2000));
4777 }
4778 }
4779 }
4780
4781 assignFromKeyfile(keyFile, psgrp, "OnlyEdges", prsharpening.edgesonly);
4782 assignFromKeyfile(keyFile, psgrp, "EdgedetectionRadius", prsharpening.edges_radius);
4783 assignFromKeyfile(keyFile, psgrp, "EdgeTolerance", prsharpening.edges_tolerance);
4784 assignFromKeyfile(keyFile, psgrp, "HalocontrolEnabled", prsharpening.halocontrol);
4785 assignFromKeyfile(keyFile, psgrp, "HalocontrolAmount", prsharpening.halocontrol_amount);
4786 assignFromKeyfile(keyFile, psgrp, "Method", prsharpening.method);
4787 assignFromKeyfile(keyFile, psgrp, "DeconvRadius", prsharpening.deconvradius);
4788 assignFromKeyfile(keyFile, psgrp, "DeconvAmount", prsharpening.deconvamount);
4789 if (ppVersion < 1021 && !resize.enabled) {
4790 prsharpening.enabled = false;
4791 }
4792 }
4793
4794 if (keyFile.has_group("Color Management") && RELEVANT_(icm)) {
4795 if (keyFile.has_key("Color Management", "InputProfile")) {
4796 icm.inputProfile = keyFile.get_string("Color Management", "InputProfile");
4797 if (icm.inputProfile.substr(0, 5) == "file:") {
4798 if (ppVersion >= 1017) {
4799 icm.inputProfile = "file:" + filenameFromUri(icm.inputProfile, basedir);
4800 } else {
4801 icm.inputProfile = expandRelativePath(fname, "file:", icm.inputProfile);
4802 }
4803 }
4804 }
4805
4806 assignFromKeyfile(keyFile, "Color Management", "ToneCurve", icm.toneCurve);
4807 assignFromKeyfile(keyFile, "Color Management", "ApplyLookTable", icm.applyLookTable);
4808 assignFromKeyfile(keyFile, "Color Management", "ApplyBaselineExposureOffset", icm.applyBaselineExposureOffset);
4809 assignFromKeyfile(keyFile, "Color Management", "ApplyHueSatMap", icm.applyHueSatMap);
4810 assignFromKeyfile(keyFile, "Color Management", "DCPIlluminant", icm.dcpIlluminant);
4811 assignFromKeyfile(keyFile, "Color Management", "WorkingProfile", icm.workingProfile);
4812
4813 assignFromKeyfile(keyFile, "Color Management", "OutputProfile", icm.outputProfile);
4814 if (ppVersion < 341) {
4815 if (icm.outputProfile == "RT_Medium_gsRGB") {
4816 icm.outputProfile = "RTv4_Medium";
4817 } else if (icm.outputProfile == "RT_Large_gBT709" || icm.outputProfile == "RT_Large_g10" || icm.outputProfile == "RT_Large_gsRGB") {
4818 icm.outputProfile = "RTv4_Large";
4819 } else if (icm.outputProfile == "WideGamutRGB") {
4820 icm.outputProfile = "RTv4_Wide";
4821 } else if (icm.outputProfile == "RT_sRGB_gBT709" || icm.outputProfile == "RT_sRGB_g10" || icm.outputProfile == "RT_sRGB") {
4822 icm.outputProfile = "RTv4_sRGB";
4823 } else if (icm.outputProfile == "BetaRGB") { // Have we ever provided this profile ? Should we convert this filename ?
4824 icm.outputProfile = "RTv4_Beta";
4825 } else if (icm.outputProfile == "BestRGB") { // Have we ever provided this profile ? Should we convert this filename ?
4826 icm.outputProfile = "RTv4_Best";
4827 } else if (icm.outputProfile == "Rec2020") {
4828 icm.outputProfile = "RTv4_Rec2020";
4829 } else if (icm.outputProfile == "Bruce") { // Have we ever provided this profile ? Should we convert this filename ?
4830 icm.outputProfile = "RTv4_Bruce";
4831 } else if (icm.outputProfile == "ACES") {
4832 icm.outputProfile = "RTv4_ACES-AP0";
4833 }
4834 }
4835 if (keyFile.has_key("Color Management", "OutputProfileIntent")) {
4836 Glib::ustring intent = keyFile.get_string("Color Management", "OutputProfileIntent");
4837
4838 if (intent == "Perceptual") {
4839 icm.outputIntent = RI_PERCEPTUAL;
4840 } else if (intent == "Relative") {
4841 icm.outputIntent = RI_RELATIVE;
4842 } else if (intent == "Saturation") {
4843 icm.outputIntent = RI_SATURATION;
4844 } else if (intent == "Absolute") {
4845 icm.outputIntent = RI_ABSOLUTE;
4846 }
4847 }
4848 assignFromKeyfile(keyFile, "Color Management", "OutputBPC", icm.outputBPC);
4849 }
4850
4851 if (keyFile.has_group("SoftLight") && RELEVANT_(softlight)) {
4852 assignFromKeyfile(keyFile, "SoftLight", "Enabled", softlight.enabled);
4853 assignFromKeyfile(keyFile, "SoftLight", "Strength", softlight.strength);
4854 }
4855
4856 if (keyFile.has_group("Dehaze") && RELEVANT_(dehaze)) {
4857 assignFromKeyfile(keyFile, "Dehaze", "Enabled", dehaze.enabled);
4858 if (ppVersion < 1010) {
4859 int s = 0;
4860 if (assignFromKeyfile(keyFile, "Dehaze", "Strength", s)) {
4861 float v = 0.5f + LIM((float(s) / 200.f) * 1.38f, -0.5f, 0.5f);
4862 dehaze.strength = {
4863 FCT_MinMaxCPoints,
4864 0.0,
4865 v,
4866 0.0,
4867 0.0,
4868 1.0,
4869 v,
4870 0.0,
4871 0.0
4872 };
4873 }
4874 } else {
4875 assignFromKeyfile(keyFile, "Dehaze", "Strength", dehaze.strength);
4876 }
4877 assignFromKeyfile(keyFile, "Dehaze", "ShowDepthMap", dehaze.showDepthMap);
4878 assignFromKeyfile(keyFile, "Dehaze", "Depth", dehaze.depth);
4879 assignFromKeyfile(keyFile, "Dehaze", "Luminance", dehaze.luminance);
4880 assignFromKeyfile(keyFile, "Dehaze", "Blackpoint", dehaze.blackpoint);
4881 }
4882
4883 if (keyFile.has_group("Film Simulation") && RELEVANT_(filmSimulation)) {
4884 assignFromKeyfile(keyFile, "Film Simulation", "Enabled", filmSimulation.enabled);
4885 assignFromKeyfile(keyFile, "Film Simulation", "ClutFilename", filmSimulation.clutFilename);
4886 if (ppVersion >= 1017) {
4887 filmSimulation.clutFilename = filenameFromUri(filmSimulation.clutFilename, basedir);
4888 }
4889
4890 if (keyFile.has_key("Film Simulation", "Strength")) {
4891 if (ppVersion < 321) {
4892 filmSimulation.strength = keyFile.get_double("Film Simulation", "Strength") * 100 + 0.1;
4893 } else {
4894 filmSimulation.strength = keyFile.get_integer("Film Simulation", "Strength");
4895 }
4896 }
4897 }
4898
4899 if (keyFile.has_group("RGB Curves") && RELEVANT_(rgbCurves)) {
4900 if (ppVersion >= 329) {
4901 assignFromKeyfile(keyFile, "RGB Curves", "Enabled", rgbCurves.enabled);
4902 } else {
4903 rgbCurves.enabled = true;
4904 }
4905
4906 assignFromKeyfile(keyFile, "RGB Curves", "rCurve", rgbCurves.rcurve);
4907 assignFromKeyfile(keyFile, "RGB Curves", "gCurve", rgbCurves.gcurve);
4908 assignFromKeyfile(keyFile, "RGB Curves", "bCurve", rgbCurves.bcurve);
4909 }
4910
4911 if (keyFile.has_group("Grain") && RELEVANT_(grain)) {
4912 assignFromKeyfile(keyFile, "Grain", "Enabled", grain.enabled);
4913 assignFromKeyfile(keyFile, "Grain", "ISO", grain.iso);
4914 assignFromKeyfile(keyFile, "Grain", "Strength", grain.strength);
4915 assignFromKeyfile(keyFile, "Grain", "Scale", grain.scale);
4916 }
4917
4918 const char *smoothing_group = ppVersion < 1016 ? "GuidedSmoothing" : "Smoothing";
4919 if (keyFile.has_group(smoothing_group) && RELEVANT_(smoothing)) {
4920 assignFromKeyfile(keyFile, smoothing_group, "Enabled", smoothing.enabled);
4921
4922 std::vector<SmoothingParams::Region> ll;
4923 std::vector<Mask> lm;
4924 bool found = false;
4925 bool done = false;
4926 for (int i = 1; !done; ++i) {
4927 SmoothingParams::Region cur;
4928 Mask curmask;
4929 done = true;
4930 std::string n = std::to_string(i);
4931 int c;
4932 if (assignFromKeyfile(keyFile, smoothing_group, Glib::ustring("Channel_") + n, c)) {
4933 cur.channel = SmoothingParams::Region::Channel(c);
4934 found = true;
4935 done = false;
4936 }
4937 if (assignFromKeyfile(keyFile, smoothing_group, Glib::ustring("Mode_") + n, c)) {
4938 cur.mode = SmoothingParams::Region::Mode(c);
4939 found = true;
4940 done = false;
4941 }
4942 if (assignFromKeyfile(keyFile, smoothing_group, Glib::ustring("Radius_") + n, cur.radius)) {
4943 found = true;
4944 done = false;
4945 }
4946 if (assignFromKeyfile(keyFile, smoothing_group, Glib::ustring("Sigma_") + n, cur.sigma)) {
4947 found = true;
4948 done = false;
4949 }
4950 if (assignFromKeyfile(keyFile, smoothing_group, Glib::ustring("Epsilon_") + n, cur.epsilon)) {
4951 found = true;
4952 done = false;
4953 }
4954 if (assignFromKeyfile(keyFile, smoothing_group, Glib::ustring("Iterations_") + n, cur.iterations)) {
4955 found = true;
4956 done = false;
4957 }
4958 if (assignFromKeyfile(keyFile, smoothing_group, Glib::ustring("Falloff_") + n, cur.falloff)) {
4959 found = true;
4960 done = false;
4961 }
4962 if (assignFromKeyfile(keyFile, smoothing_group, Glib::ustring("NLStrength_") + n, cur.nlstrength)) {
4963 found = true;
4964 done = false;
4965 }
4966 if (assignFromKeyfile(keyFile, smoothing_group, Glib::ustring("NLDetail_") + n, cur.nldetail)) {
4967 found = true;
4968 done = false;
4969 }
4970 if (curmask.load(ppVersion, keyFile, smoothing_group, "", Glib::ustring("_") + n)) {
4971 found = true;
4972 done = false;
4973 }
4974 if (!done) {
4975 ll.emplace_back(cur);
4976 lm.emplace_back(curmask);
4977 }
4978 }
4979 if (found) {
4980 smoothing.regions = std::move(ll);
4981 smoothing.labmasks = std::move(lm);
4982 }
4983 assert(smoothing.regions.size() == smoothing.labmasks.size());
4984 assignFromKeyfile(keyFile, smoothing_group, "ShowMask", smoothing.showMask);
4985 }
4986
4987 const char *ccgroup = "ColorCorrection";
4988 if (keyFile.has_group(ccgroup) && RELEVANT_(colorcorrection)) {
4989 const Glib::ustring prefix = "";
4990 assignFromKeyfile(keyFile, ccgroup, "Enabled", colorcorrection.enabled);
4991 std::vector<ColorCorrectionParams::Region> lg;
4992 std::vector<Mask> lm;
4993 bool found = false;
4994 bool done = false;
4995
4996 for (int i = 1; !done; ++i) {
4997 ColorCorrectionParams::Region cur;
4998 Mask curmask;
4999 done = true;
5000 std::string n = std::to_string(i);
5001
5002 const auto get =
5003 [&](const Glib::ustring &key, double &val) -> bool
5004 {
5005 if (assignFromKeyfile(keyFile, ccgroup, prefix + key + n, val)) {
5006 found = true;
5007 done = false;
5008 return true;
5009 } else {
5010 return false;
5011 }
5012 };
5013
5014
5015 get("A_", cur.a);
5016 get("B_", cur.b);
5017 get("ABScale_", cur.abscale);
5018 if (ppVersion < 1005) {
5019 int c = -1;
5020 if (assignFromKeyfile(keyFile, ccgroup, prefix + Glib::ustring("Channel_") + n, c)) {
5021 found = true;
5022 done = false;
5023 }
5024 if (c < 0) {
5025 cur.mode = ColorCorrectionParams::Mode::YUV;
5026 c = 0;
5027 } else {
5028 cur.mode = ColorCorrectionParams::Mode::RGB;
5029 }
5030 get("Slope_", cur.slope[c]);
5031 if (get("Offset_", cur.offset[c])) {
5032 if (ppVersion <= 1002) {
5033 cur.offset[c] *= 2;
5034 }
5035 }
5036 get("Power_", cur.power[c]);
5037 get("Pivot_", cur.pivot[c]);
5038 } else {
5039 bool rgb_channels = false;
5040 Glib::ustring mode;
5041 if (assignFromKeyfile(keyFile, ccgroup, prefix + Glib::ustring("RGBChannels_") + n, rgb_channels)) {
5042 found = true;
5043 done = false;
5044 cur.mode = rgb_channels ? ColorCorrectionParams::Mode::RGB : ColorCorrectionParams::Mode::YUV;
5045 } else if (assignFromKeyfile(keyFile, ccgroup, prefix + Glib::ustring("Mode_") + n, mode)) {
5046 if (mode == "YUV") {
5047 cur.mode = ColorCorrectionParams::Mode::YUV;
5048 } else if (mode == "RGB") {
5049 cur.mode = ColorCorrectionParams::Mode::RGB;
5050 } else if (mode == "HSL") {
5051 cur.mode = ColorCorrectionParams::Mode::HSL;
5052 }
5053 found = true;
5054 done = false;
5055 }
5056
5057 if (cur.mode != ColorCorrectionParams::Mode::RGB) {
5058 get("Slope_", cur.slope[0]);
5059 cur.slope[1] = cur.slope[2] = cur.slope[0];
5060 get("Offset_", cur.offset[0]);
5061 cur.offset[1] = cur.offset[2] = cur.offset[0];
5062 get("Power_", cur.power[0]);
5063 cur.power[1] = cur.power[2] = cur.power[0];
5064 get("Pivot_", cur.pivot[0]);
5065 cur.pivot[1] = cur.pivot[2] = cur.pivot[0];
5066 } else {
5067 const char *chan[3] = { "R", "G", "B" };
5068 for (int c = 0; c < 3; ++c) {
5069 get(Glib::ustring("Slope") + chan[c] + "_", cur.slope[c]);
5070 get(Glib::ustring("Offset") + chan[c] + "_", cur.offset[c]);
5071 get(Glib::ustring("Power") + chan[c] + "_", cur.power[c]);
5072 get(Glib::ustring("Pivot") + chan[c] + "_", cur.pivot[c]);
5073 }
5074 }
5075 {
5076 const char *chan[3] = { "Slope", "Offset", "Power" };
5077 for (int c = 0; c < 3; ++c) {
5078 Glib::ustring w = chan[c];
5079 get(w + "H_", cur.hue[c]);
5080 get(w + "S_", cur.sat[c]);
5081 get(w + "L_", cur.factor[c]);
5082 }
5083 }
5084 }
5085 if (ppVersion < 1018) {
5086 double sat = 0;
5087 get("Saturation_", sat);
5088 if (cur.mode == ColorCorrectionParams::Mode::YUV) {
5089 cur.inSaturation = sat;
5090 cur.outSaturation = 0;
5091 } else {
5092 cur.inSaturation = 0;
5093 cur.outSaturation = sat;
5094 }
5095 } else {
5096 get("InSaturation_", cur.inSaturation);
5097 get("OutSaturation_", cur.outSaturation);
5098 }
5099 if (assignFromKeyfile(keyFile, ccgroup, prefix + "RGBLuminance_" + n, cur.rgbluminance)) {
5100 found = true;
5101 done = false;
5102 }
5103 if (curmask.load(ppVersion, keyFile, ccgroup, prefix, Glib::ustring("_") + n)) {
5104 found = true;
5105 done = false;
5106 }
5107 if (!done) {
5108 lg.emplace_back(cur);
5109 lm.emplace_back(curmask);
5110 }
5111 }
5112 if (found) {
5113 colorcorrection.regions = std::move(lg);
5114 colorcorrection.labmasks = std::move(lm);
5115 }
5116 assert(colorcorrection.regions.size() == colorcorrection.labmasks.size());
5117 assignFromKeyfile(keyFile, ccgroup, ppVersion < 348 ? "showMask" : "LabRegionsShowMask", colorcorrection.showMask);
5118 }
5119
5120 if (keyFile.has_group("RAW")) {
5121 if (RELEVANT_(darkframe)) {
5122 assignFromKeyfile(keyFile, "RAW", "DarkFrameEnabled", raw.enable_darkframe);
5123 if (keyFile.has_key("RAW", "DarkFrame")) {
5124 if (ppVersion >= 1017) {
5125 raw.dark_frame = filenameFromUri(keyFile.get_string("RAW", "DarkFrame"), basedir);
5126 } else {
5127 raw.dark_frame = expandRelativePath(fname, "", keyFile.get_string("RAW", "DarkFrame"));
5128 }
5129 }
5130
5131 assignFromKeyfile(keyFile, "RAW", "DarkFrameAuto", raw.df_autoselect);
5132 }
5133
5134 if (RELEVANT_(flatfield)) {
5135 assignFromKeyfile(keyFile, "RAW", "FlatFieldEnabled", raw.enable_flatfield);
5136 if (keyFile.has_key("RAW", "FlatFieldFile")) {
5137 if (ppVersion >= 1017) {
5138 raw.ff_file = filenameFromUri(keyFile.get_string("RAW", "FlatFieldFile"), basedir);
5139 } else {
5140 raw.ff_file = expandRelativePath(fname, "", keyFile.get_string("RAW", "FlatFieldFile"));
5141 }
5142 }
5143
5144 assignFromKeyfile(keyFile, "RAW", "FlatFieldAutoSelect", raw.ff_AutoSelect);
5145 assignFromKeyfile(keyFile, "RAW", "FlatFieldBlurRadius", raw.ff_BlurRadius);
5146 assignFromKeyfile(keyFile, "RAW", "FlatFieldBlurType", raw.ff_BlurType);
5147 assignFromKeyfile(keyFile, "RAW", "FlatFieldAutoClipControl", raw.ff_AutoClipControl);
5148
5149 if (ppVersion < 328) {
5150 // With ppversion < 328 this value was stored as a boolean, which is nonsense.
5151 // To avoid annoying warnings we skip reading and assume 0.
5152 raw.ff_clipControl = 0;
5153 } else {
5154 assignFromKeyfile(keyFile, "RAW", "FlatFieldClipControl", raw.ff_clipControl);
5155 }
5156 assignFromKeyfile(keyFile, "RAW", "FlatFieldUseEmbedded", raw.ff_embedded);
5157 }
5158
5159 if (RELEVANT_(rawCA)) {
5160 assignFromKeyfile(keyFile, "RAW", "CAEnabled", raw.enable_ca);
5161 assignFromKeyfile(keyFile, "RAW", "CA", raw.ca_autocorrect);
5162 if (ppVersion >= 342) {
5163 assignFromKeyfile(keyFile, "RAW", "CAAutoIterations", raw.caautoiterations);
5164 } else {
5165 raw.caautoiterations = 1;
5166 }
5167
5168 if (ppVersion >= 343) {
5169 assignFromKeyfile(keyFile, "RAW", "CAAvoidColourshift", raw.ca_avoidcolourshift);
5170 } else {
5171 raw.ca_avoidcolourshift = false;
5172 }
5173 assignFromKeyfile(keyFile, "RAW", "CARed", raw.cared);
5174 assignFromKeyfile(keyFile, "RAW", "CABlue", raw.cablue);
5175 }
5176
5177 if (RELEVANT_(hotDeadPixelFilter)) {
5178 assignFromKeyfile(keyFile, "RAW", "HotDeadPixelEnabled", raw.enable_hotdeadpix);
5179 // For compatibility to elder pp3 versions
5180 assignFromKeyfile(keyFile, "RAW", "HotDeadPixels", raw.hotPixelFilter);
5181 raw.deadPixelFilter = raw.hotPixelFilter;
5182
5183 assignFromKeyfile(keyFile, "RAW", "HotPixelFilter", raw.hotPixelFilter);
5184 assignFromKeyfile(keyFile, "RAW", "DeadPixelFilter", raw.deadPixelFilter);
5185 assignFromKeyfile(keyFile, "RAW", "HotDeadPixelThresh", raw.hotdeadpix_thresh);
5186 }
5187 if (RELEVANT_(rawWhite)) {
5188 assignFromKeyfile(keyFile, "RAW", "PreExposureEnabled", raw.enable_whitepoint);
5189 assignFromKeyfile(keyFile, "RAW", "PreExposure", raw.expos);
5190 }
5191
5192 if (ppVersion < 320) {
5193 if (RELEVANT_(demosaic)) {
5194 //assignFromKeyfile(keyFile, "RAW", "Method", raw.bayersensor.method);
5195 assignFromKeyfile(keyFile, "RAW", "CcSteps", raw.bayersensor.ccSteps);
5196 // assignFromKeyfile(keyFile, "RAW", "DCBIterations", raw.bayersensor.dcb_iterations);
5197 // assignFromKeyfile(keyFile, "RAW", "DCBEnhance", raw.bayersensor.dcb_enhance);
5198 assignFromKeyfile(keyFile, "RAW", "LMMSEIterations", raw.bayersensor.lmmse_iterations);
5199 }
5200 if (RELEVANT_(rawPreprocessing)) {
5201 assignFromKeyfile(keyFile, "RAW", "LineDenoise", raw.bayersensor.linenoise);
5202 assignFromKeyfile(keyFile, "RAW", "GreenEqThreshold", raw.bayersensor.greenthresh);
5203 }
5204 if (RELEVANT_(rawBlack)) {
5205 assignFromKeyfile(keyFile, "RAW", "PreBlackzero", raw.bayersensor.black0);
5206 assignFromKeyfile(keyFile, "RAW", "PreBlackone", raw.bayersensor.black1);
5207 assignFromKeyfile(keyFile, "RAW", "PreBlacktwo", raw.bayersensor.black2);
5208 assignFromKeyfile(keyFile, "RAW", "PreBlackthree", raw.bayersensor.black3);
5209 assignFromKeyfile(keyFile, "RAW", "PreTwoGreen", raw.bayersensor.twogreen);
5210 }
5211 }
5212 }
5213
5214 if (keyFile.has_group("RAW Bayer")) {
5215 if (RELEVANT_(demosaic)) {
5216 Glib::ustring method;
5217 if (assignFromKeyfile(keyFile, "RAW Bayer", "Method", method)) {
5218 auto &v = raw.bayersensor.getMethodStrings();
5219 auto it = std::find(v.begin(), v.end(), method);
5220 if (it != v.end()) {
5221 raw.bayersensor.method = RAWParams::BayerSensor::Method(it - v.begin());
5222 } else if (method == "amazevng4" || method == "dcbvng4") {
5223 raw.bayersensor.method = RAWParams::BayerSensor::Method::AMAZEBILINEAR;
5224 } else if (method == "rcdvng4") {
5225 raw.bayersensor.method = RAWParams::BayerSensor::Method::RCDBILINEAR;
5226 } else {
5227 raw.bayersensor.method = RAWParams::BayerSensor::Method::AMAZE;
5228 }
5229 }
5230 assignFromKeyfile(keyFile, "RAW Bayer", "Border", raw.bayersensor.border);
5231
5232 if (keyFile.has_key("RAW Bayer", "ImageNum")) {
5233 raw.bayersensor.imageNum = keyFile.get_integer("RAW Bayer", "ImageNum") - 1;
5234 }
5235
5236 assignFromKeyfile(keyFile, "RAW Bayer", "CcSteps", raw.bayersensor.ccSteps);
5237 }
5238
5239 if (RELEVANT_(rawBlack)) {
5240 assignFromKeyfile(keyFile, "RAW Bayer", "PreBlackEnabled", raw.bayersensor.enable_black);
5241 assignFromKeyfile(keyFile, "RAW Bayer", "PreBlack0", raw.bayersensor.black0);
5242 assignFromKeyfile(keyFile, "RAW Bayer", "PreBlack1", raw.bayersensor.black1);
5243 assignFromKeyfile(keyFile, "RAW Bayer", "PreBlack2", raw.bayersensor.black2);
5244 assignFromKeyfile(keyFile, "RAW Bayer", "PreBlack3", raw.bayersensor.black3);
5245 assignFromKeyfile(keyFile, "RAW Bayer", "PreTwoGreen", raw.bayersensor.twogreen);
5246 }
5247
5248 if (RELEVANT_(rawPreprocessing)) {
5249 assignFromKeyfile(keyFile, "RAW Bayer", "PreprocessingEnabled", raw.bayersensor.enable_preproc);
5250 assignFromKeyfile(keyFile, "RAW Bayer", "LineDenoise", raw.bayersensor.linenoise);
5251
5252 if (keyFile.has_key("RAW Bayer", "LineDenoiseDirection")) {
5253 raw.bayersensor.linenoiseDirection = RAWParams::BayerSensor::LineNoiseDirection(keyFile.get_integer("RAW Bayer", "LineDenoiseDirection"));
5254 }
5255
5256 assignFromKeyfile(keyFile, "RAW Bayer", "GreenEqThreshold", raw.bayersensor.greenthresh);
5257 }
5258
5259 if (RELEVANT_(demosaic)) {
5260 // assignFromKeyfile(keyFile, "RAW Bayer", "DCBIterations", raw.bayersensor.dcb_iterations);
5261 // assignFromKeyfile(keyFile, "RAW Bayer", "DCBEnhance", raw.bayersensor.dcb_enhance);
5262 assignFromKeyfile(keyFile, "RAW Bayer", "LMMSEIterations", raw.bayersensor.lmmse_iterations);
5263 assignFromKeyfile(keyFile, "RAW Bayer", "DualDemosaicAutoContrast", raw.bayersensor.dualDemosaicAutoContrast);
5264 if (ppVersion < 345) {
5265 raw.bayersensor.dualDemosaicAutoContrast = false;
5266 }
5267 assignFromKeyfile(keyFile, "RAW Bayer", "DualDemosaicContrast", raw.bayersensor.dualDemosaicContrast);
5268
5269 if (keyFile.has_key("RAW Bayer", "PixelShiftMotionCorrectionMethod")) {
5270 raw.bayersensor.pixelShiftMotionCorrectionMethod = (RAWParams::BayerSensor::PSMotionCorrectionMethod)keyFile.get_integer("RAW Bayer", "PixelShiftMotionCorrectionMethod");
5271 }
5272
5273 assignFromKeyfile(keyFile, "RAW Bayer", "PixelShiftEperIso", raw.bayersensor.pixelShiftEperIso);
5274 if (ppVersion < 332) {
5275 raw.bayersensor.pixelShiftEperIso += 1.0;
5276 }
5277 assignFromKeyfile(keyFile, "RAW Bayer", "PixelShiftSigma", raw.bayersensor.pixelShiftSigma);
5278 assignFromKeyfile(keyFile, "RAW Bayer", "PixelShiftShowMotion", raw.bayersensor.pixelShiftShowMotion);
5279 assignFromKeyfile(keyFile, "RAW Bayer", "PixelShiftShowMotionMaskOnly", raw.bayersensor.pixelShiftShowMotionMaskOnly);
5280 assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftHoleFill", raw.bayersensor.pixelShiftHoleFill);
5281 assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftMedian", raw.bayersensor.pixelShiftMedian);
5282 assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftGreen", raw.bayersensor.pixelShiftGreen);
5283 assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftBlur", raw.bayersensor.pixelShiftBlur);
5284 assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftSmoothFactor", raw.bayersensor.pixelShiftSmoothFactor);
5285 assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftEqualBright", raw.bayersensor.pixelShiftEqualBright);
5286 assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftEqualBrightChannel", raw.bayersensor.pixelShiftEqualBrightChannel);
5287 assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftNonGreenCross", raw.bayersensor.pixelShiftNonGreenCross);
5288
5289 if (ppVersion < 336) {
5290 if (keyFile.has_key("RAW Bayer", "pixelShiftLmmse")) {
5291 bool useLmmse = keyFile.get_boolean ("RAW Bayer", "pixelShiftLmmse");
5292 if (useLmmse) {
5293 raw.bayersensor.pixelShiftDemosaicMethod = raw.bayersensor.getPSDemosaicMethodString(RAWParams::BayerSensor::PSDemosaicMethod::LMMSE);
5294 } else {
5295 raw.bayersensor.pixelShiftDemosaicMethod = raw.bayersensor.getPSDemosaicMethodString(RAWParams::BayerSensor::PSDemosaicMethod::AMAZE);
5296 }
5297 }
5298 } else {
5299 assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftDemosaicMethod", raw.bayersensor.pixelShiftDemosaicMethod);
5300 }
5301 }
5302
5303 if (RELEVANT_(rawPreprocessing)) {
5304 assignFromKeyfile(keyFile, "RAW Bayer", "PDAFLinesFilter", raw.bayersensor.pdafLinesFilter);
5305 assignFromKeyfile(keyFile, "RAW Bayer", "DynamicRowNoiseFilter", raw.bayersensor.dynamicRowNoiseFilter);
5306 }
5307 }
5308
5309 if (keyFile.has_group("RAW X-Trans")) {
5310 if (RELEVANT_(demosaic)) {
5311 Glib::ustring method;
5312 if (assignFromKeyfile(keyFile, "RAW X-Trans", "Method", method)) {
5313 const auto &v = RAWParams::XTransSensor::getMethodStrings();
5314 auto it = std::find(v.begin(), v.end(), method);
5315 if (it != v.end()) {
5316 raw.xtranssensor.method = RAWParams::XTransSensor::Method(it - v.begin());
5317 } else {
5318 raw.xtranssensor.method = RAWParams::XTransSensor::Method::THREE_PASS;
5319 }
5320 }
5321 assignFromKeyfile(keyFile, "RAW X-Trans", "DualDemosaicAutoContrast", raw.xtranssensor.dualDemosaicAutoContrast);
5322 if (ppVersion < 345) {
5323 raw.xtranssensor.dualDemosaicAutoContrast = false;
5324 }
5325 assignFromKeyfile(keyFile, "RAW X-Trans", "DualDemosaicContrast", raw.xtranssensor.dualDemosaicContrast);
5326 assignFromKeyfile(keyFile, "RAW X-Trans", "Border", raw.xtranssensor.border);
5327 assignFromKeyfile(keyFile, "RAW X-Trans", "CcSteps", raw.xtranssensor.ccSteps);
5328 }
5329 if (RELEVANT_(rawBlack)) {
5330 assignFromKeyfile(keyFile, "RAW X-Trans", "PreBlackEnabled", raw.xtranssensor.enable_black);
5331 assignFromKeyfile(keyFile, "RAW X-Trans", "PreBlackRed", raw.xtranssensor.blackred);
5332 assignFromKeyfile(keyFile, "RAW X-Trans", "PreBlackGreen", raw.xtranssensor.blackgreen);
5333 assignFromKeyfile(keyFile, "RAW X-Trans", "PreBlackBlue", raw.xtranssensor.blackblue);
5334 }
5335 }
5336
5337 if (keyFile.has_group("Film Negative") && RELEVANT_(filmNegative)) {
5338 assignFromKeyfile(keyFile, "Film Negative", "Enabled", filmNegative.enabled);
5339 assignFromKeyfile(keyFile, "Film Negative", "RedRatio", filmNegative.redRatio);
5340 assignFromKeyfile(keyFile, "Film Negative", "GreenExponent", filmNegative.greenExp);
5341 assignFromKeyfile(keyFile, "Film Negative", "BlueRatio", filmNegative.blueRatio);
5342 if (ppVersion >= 1011) {
5343 assignFromKeyfile(keyFile, "Film Negative", "RedBase", filmNegative.redBase);
5344 assignFromKeyfile(keyFile, "Film Negative", "GreenBase", filmNegative.greenBase);
5345 assignFromKeyfile(keyFile, "Film Negative", "BlueBase", filmNegative.blueBase);
5346 } else {
5347 // Backwards compatibility: use special film base value -1
5348 filmNegative.redBase = -1.f;
5349 filmNegative.greenBase = -1.f;
5350 filmNegative.blueBase = -1.f;
5351 }
5352 }
5353
5354 if (keyFile.has_group("MetaData") && RELEVANT_(metadata)) {
5355 int mode = int(ppVersion < 1012 ? MetaDataParams::TUNNEL : MetaDataParams::EDIT);
5356 assignFromKeyfile(keyFile, "MetaData", "Mode", mode);
5357
5358 if (mode >= int(MetaDataParams::TUNNEL) && mode <= int(MetaDataParams::STRIP)) {
5359 metadata.mode = static_cast<MetaDataParams::Mode>(mode);
5360 }
5361
5362 if (!assignFromKeyfile(keyFile, "MetaData", "ExifKeys", metadata.exifKeys)) {
5363 if (ppVersion < 1012) {
5364 metadata.exifKeys = { "*" };
5365 }
5366 }
5367 }
5368
5369 if (keyFile.has_group("Exif") && RELEVANT_(exif)) {
5370 for (const auto& key : keyFile.get_keys("Exif")) {
5371 auto it = exif_keys.find(key);
5372 if (it != exif_keys.end()) {
5373 metadata.exif[it->second] = keyFile.get_string("Exif", key);
5374 }
5375 }
5376 }
5377
5378 /*
5379 * Load iptc change settings
5380 *
5381 * Existing values are preserved, and the stored values
5382 * are added to the list. To reset a field, the user has to
5383 * save the profile with the field leaved empty, but still
5384 * terminated by a semi-column ";"
5385 *
5386 * Please note that the old Keywords and SupplementalCategories
5387 * tag content is fully replaced by the new one,
5388 * i.e. they don't merge
5389 */
5390 if (keyFile.has_group("IPTC") && RELEVANT_(iptc)) {
5391 for (const auto& key : keyFile.get_keys("IPTC")) {
5392 // does this key already exist?
5393 auto it = iptc_keys.find(key);
5394 if (it == iptc_keys.end()) {
5395 continue;
5396 }
5397 auto kk = it->second;
5398 const IPTCPairs::iterator element = metadata.iptc.find(kk);
5399
5400 if (element != metadata.iptc.end()) {
5401 // it already exist so we cleanup the values
5402 element->second.clear();
5403 }
5404
5405 // TODO: look out if merging Keywords and SupplementalCategories from the procparams chain would be interesting
5406 for (const auto& currLoadedTagValue : keyFile.get_string_list("IPTC", key)) {
5407 metadata.iptc[kk].push_back(currLoadedTagValue);
5408 }
5409 }
5410 }
5411
5412 return 0;
5413 } catch (const Glib::Error& e) {
5414 //printf("-->%s\n", e.what().c_str());
5415 if (pl) {
5416 pl->error(Glib::ustring::compose(M("PROCPARAMS_LOAD_ERROR"), fname, e.what()));
5417 }
5418 if (resetOnError) {
5419 setDefaults();
5420 }
5421 return 1;
5422 } catch (std::exception &e) {
5423 if (pl) {
5424 pl->error(Glib::ustring::compose(M("PROCPARAMS_LOAD_ERROR"), fname, e.what()));
5425 }
5426 if (resetOnError) {
5427 setDefaults();
5428 }
5429 return 1;
5430 } catch (...) {
5431 //printf("-->unknown exception!\n");
5432 if (pl) {
5433 pl->error(Glib::ustring::compose(M("PROCPARAMS_LOAD_ERROR"), fname, "unknown exception"));
5434 }
5435 if (resetOnError) {
5436 setDefaults();
5437 }
5438 return 1;
5439 }
5440
5441 return 0;
5442
5443 #undef RELEVANT_
5444 }
5445
5446
load(ProgressListener * pl,const KeyFile & keyFile,const ParamsEdited * pedited,bool resetOnError,const Glib::ustring & fname)5447 int ProcParams::load(ProgressListener *pl,
5448 const KeyFile &keyFile, const ParamsEdited *pedited,
5449 bool resetOnError, const Glib::ustring &fname)
5450 {
5451 return load(pl, true, keyFile, pedited, resetOnError, fname);
5452 }
5453
5454
create()5455 ProcParams* ProcParams::create()
5456 {
5457 return new ProcParams();
5458 }
5459
destroy(ProcParams * pp)5460 void ProcParams::destroy(ProcParams* pp)
5461 {
5462 delete pp;
5463 }
5464
operator ==(const ProcParams & other) const5465 bool ProcParams::operator ==(const ProcParams& other) const
5466 {
5467 return
5468 exposure == other.exposure
5469 && saturation == other.saturation
5470 && toneCurve == other.toneCurve
5471 && localContrast == other.localContrast
5472 && labCurve == other.labCurve
5473 && sharpening == other.sharpening
5474 && prsharpening == other.prsharpening
5475 && wb == other.wb
5476 && impulseDenoise == other.impulseDenoise
5477 && denoise == other.denoise
5478 && textureBoost == other.textureBoost
5479 && fattal == other.fattal
5480 && logenc == other.logenc
5481 && defringe == other.defringe
5482 && toneEqualizer == other.toneEqualizer
5483 && crop == other.crop
5484 && coarse == other.coarse
5485 && rotate == other.rotate
5486 && commonTrans == other.commonTrans
5487 && distortion == other.distortion
5488 && lensProf == other.lensProf
5489 && perspective == other.perspective
5490 && gradient == other.gradient
5491 && pcvignette == other.pcvignette
5492 && cacorrection == other.cacorrection
5493 && vignetting == other.vignetting
5494 && chmixer == other.chmixer
5495 && blackwhite == other.blackwhite
5496 && hsl == other.hsl
5497 && resize == other.resize
5498 && raw == other.raw
5499 && icm == other.icm
5500 && filmSimulation == other.filmSimulation
5501 && softlight == other.softlight
5502 && rgbCurves == other.rgbCurves
5503 && metadata == other.metadata
5504 && dehaze == other.dehaze
5505 && grain == other.grain
5506 && smoothing == other.smoothing
5507 && colorcorrection == other.colorcorrection
5508 && filmNegative == other.filmNegative
5509 && spot == other.spot;
5510 }
5511
operator !=(const ProcParams & other) const5512 bool ProcParams::operator !=(const ProcParams& other) const
5513 {
5514 return !(*this == other);
5515 }
5516
init()5517 void ProcParams::init()
5518 {
5519 }
5520
cleanup()5521 void ProcParams::cleanup()
5522 {
5523 }
5524
write(ProgressListener * pl,const Glib::ustring & fname,const Glib::ustring & content) const5525 int ProcParams::write(ProgressListener *pl,
5526 const Glib::ustring& fname, const Glib::ustring& content) const
5527 {
5528 int error = 0;
5529
5530 if (fname.length()) {
5531 FILE *f;
5532 f = g_fopen(fname.c_str(), "wt");
5533
5534 if (f == nullptr) {
5535 if (pl) {
5536 pl->error(Glib::ustring::compose(M("PROCPARAMS_SAVE_ERROR"), fname, "write error"));
5537 }
5538 error = 1;
5539 } else {
5540 fprintf(f, "%s", content.c_str());
5541 fclose(f);
5542 }
5543 }
5544
5545 return error;
5546 }
5547
5548
FullPartialProfile(const ProcParams & pp)5549 FullPartialProfile::FullPartialProfile(const ProcParams &pp):
5550 pp_(pp)
5551 {
5552 }
5553
5554
applyTo(ProcParams & pp) const5555 bool FullPartialProfile::applyTo(ProcParams &pp) const
5556 {
5557 pp = pp_;
5558 return true;
5559 }
5560
5561
FilePartialProfile(ProgressListener * pl,const Glib::ustring & fname,bool full)5562 FilePartialProfile::FilePartialProfile(ProgressListener *pl, const Glib::ustring &fname, bool full):
5563 pl_(pl),
5564 fname_(fname),
5565 full_(full)
5566 {
5567 }
5568
5569
applyTo(ProcParams & pp) const5570 bool FilePartialProfile::applyTo(ProcParams &pp) const
5571 {
5572 if (full_) {
5573 pp.setDefaults();
5574 }
5575 return fname_.empty() || (pp.load(pl_, fname_) == 0);
5576 }
5577
5578
PEditedPartialProfile(ProgressListener * pl,const Glib::ustring & fname,const ParamsEdited & pe)5579 PEditedPartialProfile::PEditedPartialProfile(ProgressListener *pl, const Glib::ustring &fname, const ParamsEdited &pe):
5580 pl_(pl),
5581 fname_(fname),
5582 pp_(),
5583 pe_(pe)
5584 {
5585 }
5586
5587
PEditedPartialProfile(const ProcParams & pp,const ParamsEdited & pe)5588 PEditedPartialProfile::PEditedPartialProfile(const ProcParams &pp, const ParamsEdited &pe):
5589 pl_(nullptr),
5590 fname_(""),
5591 pp_(pp),
5592 pe_(pe)
5593 {
5594 }
5595
5596
applyTo(ProcParams & pp) const5597 bool PEditedPartialProfile::applyTo(ProcParams &pp) const
5598 {
5599 if (!fname_.empty()) {
5600 KeyFile keyfile;
5601 try {
5602 if (!Glib::file_test(fname_, Glib::FILE_TEST_EXISTS) ||
5603 !keyfile.load_from_file(fname_)) {
5604 // not an error to repor
5605 return false;
5606 }
5607 } catch (const Glib::Error& e) {
5608 //printf("-->%s\n", e.what().c_str());
5609 if (pl_) {
5610 pl_->error(Glib::ustring::compose(M("PROCPARAMS_LOAD_ERROR"), fname_, e.what()));
5611 }
5612 return false;
5613 }
5614 return pp.load(pl_, keyfile, &pe_, false) == 0;
5615 } else {
5616 KeyFile keyfile;
5617 if (pp_.save(pl_, keyfile, &pe_) == 0) {
5618 return pp.load(pl_, keyfile, &pe_, false) == 0;
5619 }
5620 }
5621 return false;
5622 }
5623
5624
5625 //-----------------------------------------------------------------------------
5626 // ProcParamsWithSnapshots
5627 //-----------------------------------------------------------------------------
5628
load(ProgressListener * pl,const Glib::ustring & fname)5629 int ProcParamsWithSnapshots::load(ProgressListener *pl,
5630 const Glib::ustring &fname)
5631 {
5632 setlocale(LC_NUMERIC, "C"); // to set decimal point to "."
5633
5634 if (fname.empty()) {
5635 return 1;
5636 }
5637
5638 KeyFile keyfile;
5639 keyfile.setProgressListener(pl);
5640
5641 snapshots.clear();
5642
5643 try {
5644 if (!Glib::file_test(fname, Glib::FILE_TEST_EXISTS) ||
5645 !keyfile.load_from_file(fname)) {
5646 // not an error to report
5647 return 1;
5648 }
5649 if (master.load(pl, true, keyfile, nullptr, true, fname) != 0) {
5650 return 1;
5651 }
5652 const std::string sn = "Snapshot_";
5653 if (keyfile.has_group("Snapshots")) {
5654 for (size_t i = 1; ; ++i) {
5655 Glib::ustring key = sn + std::to_string(i);
5656 if (keyfile.has_key("Snapshots", key)) {
5657 auto name = keyfile.get_string("Snapshots", key);
5658 snapshots.push_back(std::make_pair(name, ProcParams()));
5659 } else {
5660 break;
5661 }
5662 }
5663 }
5664
5665 for (size_t i = 0; i < snapshots.size(); ++i) {
5666 keyfile.set_prefix(sn + std::to_string(i+1) + " ");
5667 snapshots[i].second.appVersion = master.appVersion;
5668 snapshots[i].second.ppVersion = master.ppVersion;
5669 if (snapshots[i].second.load(pl, false, keyfile, nullptr, true, fname) != 0) {
5670 snapshots.resize(i);
5671 break;
5672 }
5673 }
5674
5675 return 0;
5676 } catch (const Glib::Error &e) {
5677 if (pl) {
5678 pl->error(Glib::ustring::compose(M("PROCPARAMS_LOAD_ERROR"), fname, e.what()));
5679 }
5680 //printf("-->%s\n", e.what().c_str());
5681 master.setDefaults();
5682 snapshots.clear();
5683 return 1;
5684 } catch (...) {
5685 if (pl) {
5686 pl->error(Glib::ustring::compose(M("PROCPARAMS_LOAD_ERROR"), fname, "unknown exception"));
5687 }
5688 //printf("-->unknown exception!\n");
5689 master.setDefaults();
5690 snapshots.clear();
5691 return 1;
5692 }
5693 }
5694
5695
save(ProgressListener * pl,const Glib::ustring & fname,const Glib::ustring & fname2)5696 int ProcParamsWithSnapshots::save(ProgressListener *pl,
5697 const Glib::ustring &fname, const Glib::ustring &fname2)
5698 {
5699 if (fname.empty() && fname2.empty()) {
5700 return 0;
5701 }
5702
5703 Glib::ustring data;
5704
5705 try {
5706 KeyFile keyfile;
5707
5708 keyfile.set_string("Version", "AppVersion", RTVERSION);
5709 keyfile.set_integer("Version", "Version", PPVERSION);
5710 if (master.rank >= 0) {
5711 saveToKeyfile("General", "Rank", master.rank, keyfile);
5712 }
5713 saveToKeyfile("General", "ColorLabel", master.colorlabel, keyfile);
5714 saveToKeyfile("General", "InTrash", master.inTrash, keyfile);
5715
5716 const std::string sn = "Snapshot_";
5717 for (size_t i = 0; i < snapshots.size(); ++i) {
5718 Glib::ustring key = sn + std::to_string(i+1);
5719 keyfile.set_string("Snapshots", key, snapshots[i].first);
5720 }
5721
5722 int ret = master.save(pl, false, keyfile, nullptr, fname);
5723 if (ret != 0) {
5724 return ret;
5725 }
5726
5727 for (size_t i = 0; i < snapshots.size(); ++i) {
5728 keyfile.set_prefix(sn + std::to_string(i+1) + " ");
5729 ret = snapshots[i].second.save(pl, false, keyfile, nullptr, fname);
5730 if (ret != 0) {
5731 return ret;
5732 }
5733 }
5734
5735 data = keyfile.to_data();
5736 } catch (Glib::KeyFileError &exc) {
5737 if (pl) {
5738 pl->error(Glib::ustring::compose(M("PROCPARAMS_SAVE_ERROR"), fname, exc.what()));
5739 }
5740 }
5741
5742 if (data.empty()) {
5743 return 1;
5744 }
5745
5746 int error1, error2;
5747 error1 = master.write(pl, fname, data);
5748
5749 if (!fname2.empty()) {
5750 error2 = master.write(pl, fname2, data);
5751 // If at least one file has been saved, it's a success
5752 return error1 & error2;
5753 } else {
5754 return error1;
5755 }
5756
5757 return 0;
5758 }
5759
5760 }} // namespace rtengine::procparams
5761
5762