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 <https://www.gnu.org/licenses/>.
18  */
19 
20 #include <map>
21 
22 #include <locale.h>
23 
24 #include <glib/gstdio.h>
25 #include <glibmm/fileutils.h>
26 #include <glibmm/miscutils.h>
27 #include <glibmm/keyfile.h>
28 
29 #include "color.h"
30 #include "curves.h"
31 #include "procparams.h"
32 #include "utils.h"
33 
34 #include "../rtgui/multilangmgr.h"
35 #include "../rtgui/options.h"
36 #include "../rtgui/paramsedited.h"
37 #include "../rtgui/ppversion.h"
38 #include "../rtgui/version.h"
39 
40 using namespace std;
41 
42 namespace
43 {
44 
expandRelativePath(const Glib::ustring & procparams_fname,const Glib::ustring & prefix,Glib::ustring embedded_fname)45 Glib::ustring expandRelativePath(const Glib::ustring &procparams_fname, const Glib::ustring &prefix, Glib::ustring embedded_fname)
46 {
47     if (embedded_fname.empty() || !Glib::path_is_absolute(procparams_fname)) {
48         return embedded_fname;
49     }
50 
51     if (!prefix.empty()) {
52         if (embedded_fname.length() < prefix.length() || embedded_fname.substr(0, prefix.length()) != prefix) {
53             return embedded_fname;
54         }
55 
56         embedded_fname = embedded_fname.substr(prefix.length());
57     }
58 
59     if (Glib::path_is_absolute(embedded_fname)) {
60         return prefix + embedded_fname;
61     }
62 
63     Glib::ustring absPath = prefix + Glib::path_get_dirname(procparams_fname) + G_DIR_SEPARATOR_S + embedded_fname;
64     return absPath;
65 }
66 
relativePathIfInside(const Glib::ustring & procparams_fname,bool fnameAbsolute,Glib::ustring embedded_fname)67 Glib::ustring relativePathIfInside(const Glib::ustring &procparams_fname, bool fnameAbsolute, Glib::ustring embedded_fname)
68 {
69     if (fnameAbsolute || embedded_fname.empty() || !Glib::path_is_absolute(procparams_fname)) {
70         return embedded_fname;
71     }
72 
73     Glib::ustring prefix;
74 
75     if (embedded_fname.length() > 5 && embedded_fname.substr(0, 5) == "file:") {
76         embedded_fname = embedded_fname.substr(5);
77         prefix = "file:";
78     }
79 
80     if (!Glib::path_is_absolute(embedded_fname)) {
81         return prefix + embedded_fname;
82     }
83 
84     Glib::ustring dir1 = Glib::path_get_dirname(procparams_fname) + G_DIR_SEPARATOR_S;
85     Glib::ustring dir2 = Glib::path_get_dirname(embedded_fname) + G_DIR_SEPARATOR_S;
86 
87     if (dir2.substr(0, dir1.length()) != dir1) {
88         // it's in a different directory, ie not inside
89         return prefix + embedded_fname;
90     }
91 
92     return prefix + embedded_fname.substr(dir1.length());
93 }
94 
getFromKeyfile(const Glib::KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,int & value)95 void getFromKeyfile(
96     const Glib::KeyFile& keyfile,
97     const Glib::ustring& group_name,
98     const Glib::ustring& key,
99     int& value
100 )
101 {
102     value = keyfile.get_integer(group_name, key);
103 }
104 
getFromKeyfile(const Glib::KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,double & value)105 void getFromKeyfile(
106     const Glib::KeyFile& keyfile,
107     const Glib::ustring& group_name,
108     const Glib::ustring& key,
109     double& value
110 )
111 {
112     value = keyfile.get_double(group_name, key);
113 }
114 
getFromKeyfile(const Glib::KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,bool & value)115 void getFromKeyfile(
116     const Glib::KeyFile& keyfile,
117     const Glib::ustring& group_name,
118     const Glib::ustring& key,
119     bool& value
120 )
121 {
122     value = keyfile.get_boolean(group_name, key);
123 }
124 
getFromKeyfile(const Glib::KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,Glib::ustring & value)125 void getFromKeyfile(
126     const Glib::KeyFile& keyfile,
127     const Glib::ustring& group_name,
128     const Glib::ustring& key,
129     Glib::ustring& value
130 )
131 {
132     value = keyfile.get_string(group_name, key);
133 }
134 
getFromKeyfile(const Glib::KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,std::vector<double> & value)135 void getFromKeyfile(
136     const Glib::KeyFile& keyfile,
137     const Glib::ustring& group_name,
138     const Glib::ustring& key,
139     std::vector<double>& value
140 )
141 {
142     value = keyfile.get_double_list(group_name, key);
143     rtengine::sanitizeCurve(value);
144 }
145 
146 template<typename T>
assignFromKeyfile(const Glib::KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,bool has_params_edited,T & value,bool & params_edited_value)147 bool assignFromKeyfile(
148     const Glib::KeyFile& keyfile,
149     const Glib::ustring& group_name,
150     const Glib::ustring& key,
151     bool has_params_edited,
152     T& value,
153     bool& params_edited_value
154 )
155 {
156     if (keyfile.has_key(group_name, key)) {
157         getFromKeyfile(keyfile, group_name, key, value);
158 
159         if (has_params_edited) {
160             params_edited_value = true;
161         }
162 
163         return true;
164     }
165 
166     return false;
167 }
168 
169 template<typename T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
assignFromKeyfile(const Glib::KeyFile & keyfile,const Glib::ustring & group_name,const Glib::ustring & key,bool has_params_edited,const std::map<std::string,T> & mapping,T & value,bool & params_edited_value)170 bool assignFromKeyfile(
171     const Glib::KeyFile& keyfile,
172     const Glib::ustring& group_name,
173     const Glib::ustring& key,
174     bool has_params_edited,
175     const std::map<std::string, T>& mapping,
176     T& value,
177     bool& params_edited_value
178 )
179 {
180     if (keyfile.has_key(group_name, key)) {
181         Glib::ustring v;
182         getFromKeyfile(keyfile, group_name, key, v);
183 
184         const typename std::map<std::string, T>::const_iterator m = mapping.find(v);
185 
186         if (m != mapping.end()) {
187             value = m->second;
188         } else {
189             return false;
190         }
191 
192         if (has_params_edited) {
193             params_edited_value = true;
194         }
195 
196         return true;
197     }
198 
199     return false;
200 }
201 
putToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,int value,Glib::KeyFile & keyfile)202 void putToKeyfile(
203     const Glib::ustring& group_name,
204     const Glib::ustring& key,
205     int value,
206     Glib::KeyFile& keyfile
207 )
208 {
209     keyfile.set_integer(group_name, key, value);
210 }
211 
putToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,double value,Glib::KeyFile & keyfile)212 void putToKeyfile(
213     const Glib::ustring& group_name,
214     const Glib::ustring& key,
215     double value,
216     Glib::KeyFile& keyfile
217 )
218 {
219     keyfile.set_double(group_name, key, value);
220 }
221 
putToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,bool value,Glib::KeyFile & keyfile)222 void putToKeyfile(
223     const Glib::ustring& group_name,
224     const Glib::ustring& key,
225     bool value,
226     Glib::KeyFile& keyfile
227 )
228 {
229     keyfile.set_boolean(group_name, key, value);
230 }
231 
putToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,const Glib::ustring & value,Glib::KeyFile & keyfile)232 void putToKeyfile(
233     const Glib::ustring& group_name,
234     const Glib::ustring& key,
235     const Glib::ustring& value,
236     Glib::KeyFile& keyfile
237 )
238 {
239     keyfile.set_string(group_name, key, value);
240 }
241 
putToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,const std::vector<int> & value,Glib::KeyFile & keyfile)242 void putToKeyfile(
243     const Glib::ustring& group_name,
244     const Glib::ustring& key,
245     const std::vector<int>& value,
246     Glib::KeyFile& keyfile
247 )
248 {
249     const Glib::ArrayHandle<int> list = value;
250     keyfile.set_integer_list(group_name, key, list);
251 }
252 
putToKeyfile(const Glib::ustring & group_name,const Glib::ustring & key,const std::vector<double> & value,Glib::KeyFile & keyfile)253 void putToKeyfile(
254     const Glib::ustring& group_name,
255     const Glib::ustring& key,
256     const std::vector<double>& value,
257     Glib::KeyFile& keyfile
258 )
259 {
260     const Glib::ArrayHandle<double> list = value;
261     keyfile.set_double_list(group_name, key, list);
262 }
263 
264 template<typename T>
saveToKeyfile(bool save,const Glib::ustring & group_name,const Glib::ustring & key,const T & value,Glib::KeyFile & keyfile)265 bool saveToKeyfile(
266     bool save,
267     const Glib::ustring& group_name,
268     const Glib::ustring& key,
269     const T& value,
270     Glib::KeyFile& keyfile
271 )
272 {
273     if (save) {
274         putToKeyfile(group_name, key, value, keyfile);
275         return true;
276     }
277 
278     return false;
279 }
280 
281 template<typename T, typename = typename std::enable_if<std::is_enum<T>::value>::type>
saveToKeyfile(bool save,const Glib::ustring & group_name,const Glib::ustring & key,const std::map<T,const char * > & mapping,const T & value,Glib::KeyFile & keyfile)282 bool saveToKeyfile(
283     bool save,
284     const Glib::ustring& group_name,
285     const Glib::ustring& key,
286     const std::map<T, const char*>& mapping,
287     const T& value,
288     Glib::KeyFile& keyfile
289 )
290 {
291     if (save) {
292         const typename std::map<T, const char*>::const_iterator m = mapping.find(value);
293 
294         if (m != mapping.end()) {
295             keyfile.set_string(group_name, key, m->second);
296             return true;
297         }
298     }
299 
300     return false;
301 }
302 
303 }
304 
305 namespace rtengine
306 {
307 
308 namespace procparams
309 {
310 
ToneCurveParams()311 ToneCurveParams::ToneCurveParams() :
312     autoexp(false),
313     clip(0.02),
314     hrenabled(false),
315     method("Blend"),
316     expcomp(0),
317     curve{
318         DCT_Linear
319     },
320     curve2{
321         DCT_Linear
322     },
323     curveMode(ToneCurveMode::STD),
324     curveMode2(ToneCurveMode::STD),
325     brightness(0),
326     black(0),
327     contrast(0),
328     saturation(0),
329     shcompr(50),
330     hlcompr(0),
331     hlcomprthresh(0),
332     histmatching(false),
333     fromHistMatching(false),
334     clampOOG(true)
335 {
336 }
337 
isPanningRelatedChange(const ToneCurveParams & other) const338 bool ToneCurveParams::isPanningRelatedChange(const ToneCurveParams& other) const
339 {
340     return !
341         (autoexp == other.autoexp
342         && clip == other.clip
343         && hrenabled == other.hrenabled
344         && method == other.method
345         && expcomp == other.expcomp
346         && curve == other.curve
347         && curve2 == other.curve2
348         && curveMode == other.curveMode
349         && curveMode2 == other.curveMode2
350         && brightness == other.brightness
351         && black == other.black
352         && contrast == other.contrast
353         && saturation == other.saturation
354         && shcompr == other.shcompr
355         && hlcompr == other.hlcompr
356         && hlcomprthresh == other.hlcomprthresh
357         && histmatching == other.histmatching
358         && clampOOG == other.clampOOG);
359 }
360 
operator ==(const ToneCurveParams & other) const361 bool ToneCurveParams::operator ==(const ToneCurveParams& other) const
362 {
363     return
364         autoexp == other.autoexp
365         && clip == other.clip
366         && hrenabled == other.hrenabled
367         && method == other.method
368         && expcomp == other.expcomp
369         && curve == other.curve
370         && curve2 == other.curve2
371         && curveMode == other.curveMode
372         && curveMode2 == other.curveMode2
373         && brightness == other.brightness
374         && black == other.black
375         && contrast == other.contrast
376         && saturation == other.saturation
377         && shcompr == other.shcompr
378         && hlcompr == other.hlcompr
379         && hlcomprthresh == other.hlcomprthresh
380         && histmatching == other.histmatching
381         && fromHistMatching == other.fromHistMatching
382         && clampOOG == other.clampOOG;
383 }
384 
operator !=(const ToneCurveParams & other) const385 bool ToneCurveParams::operator !=(const ToneCurveParams& other) const
386 {
387     return !(*this == other);
388 }
389 
RetinexParams()390 RetinexParams::RetinexParams() :
391     enabled(false),
392     cdcurve{
393         DCT_Linear
394     },
395     cdHcurve{
396         DCT_Linear
397     },
398     lhcurve{
399         DCT_Linear
400     },
401     transmissionCurve{
402         FCT_MinMaxCPoints,
403         0.00,
404         0.50,
405         0.35,
406         0.35,
407         0.60,
408         0.75,
409         0.35,
410         0.35,
411         1.00,
412         0.50,
413         0.35,
414         0.35
415     },
416     gaintransmissionCurve{
417         FCT_MinMaxCPoints,
418         0.00,
419         0.1,
420         0.35,
421         0.00,
422         0.25,
423         0.25,
424         0.35,
425         0.35,
426         0.70,
427         0.25,
428         0.35,
429         0.35,
430         1.00,
431         0.1,
432         0.00,
433         0.00
434     },
435     mapcurve{
436         DCT_Linear
437     },
438     str(20),
439     scal(3),
440     iter(1),
441     grad(1),
442     grads(1),
443     gam(1.30),
444     slope(3.),
445     neigh(80),
446     offs(0),
447     highlights(0),
448     htonalwidth(80),
449     shadows(0),
450     stonalwidth(80),
451     radius(40),
452     retinexMethod("high"),
453     retinexcolorspace("Lab"),
454     gammaretinex("none"),
455     mapMethod("none"),
456     viewMethod("none"),
457     vart(200),
458     limd(8),
459     highl(4),
460     skal(3),
461     medianmap(false)
462 {
463 }
464 
operator ==(const RetinexParams & other) const465 bool RetinexParams::operator ==(const RetinexParams& other) const
466 {
467     return
468         enabled == other.enabled
469         && cdcurve == other.cdcurve
470         && cdHcurve == other.cdHcurve
471         && lhcurve == other.lhcurve
472         && transmissionCurve == other.transmissionCurve
473         && gaintransmissionCurve == other.gaintransmissionCurve
474         && mapcurve == other.mapcurve
475         && str == other.str
476         && scal == other.scal
477         && iter == other.iter
478         && grad == other.grad
479         && grads == other.grads
480         && gam == other.gam
481         && slope == other.slope
482         && neigh == other.neigh
483         && offs == other.offs
484         && highlights == other.highlights
485         && htonalwidth == other.htonalwidth
486         && shadows == other.shadows
487         && stonalwidth == other.stonalwidth
488         && radius == other.radius
489         && retinexMethod == other.retinexMethod
490         && retinexcolorspace == other.retinexcolorspace
491         && gammaretinex == other.gammaretinex
492         && mapMethod == other.mapMethod
493         && viewMethod == other.viewMethod
494         && vart == other.vart
495         && limd == other.limd
496         && highl == other.highl
497         && skal == other.skal
498         && medianmap == other.medianmap;
499 }
500 
operator !=(const RetinexParams & other) const501 bool RetinexParams::operator !=(const RetinexParams& other) const
502 {
503     return !(*this == other);
504 }
505 
getCurves(RetinextransmissionCurve & transmissionCurveLUT,RetinexgaintransmissionCurve & gaintransmissionCurveLUT) const506 void RetinexParams::getCurves(RetinextransmissionCurve &transmissionCurveLUT, RetinexgaintransmissionCurve &gaintransmissionCurveLUT) const
507 {
508     transmissionCurveLUT.Set(this->transmissionCurve);
509     gaintransmissionCurveLUT.Set(this->gaintransmissionCurve);
510 
511 }
512 
LCurveParams()513 LCurveParams::LCurveParams() :
514     enabled(false),
515     lcurve{
516         DCT_Linear
517     },
518     acurve{
519         DCT_Linear
520     },
521     bcurve{
522         DCT_Linear
523     },
524     cccurve{
525         DCT_Linear
526     },
527     chcurve{
528         FCT_Linear
529     },
530     lhcurve{
531         FCT_Linear
532     },
533     hhcurve{
534         FCT_Linear
535     },
536     lccurve{
537         DCT_Linear
538     },
539     clcurve{
540         DCT_Linear
541     },
542     brightness(0),
543     contrast(0),
544     chromaticity(0),
545     avoidcolorshift(false),
546     rstprotection(0),
547     lcredsk(true)
548 {
549 }
550 
operator ==(const LCurveParams & other) const551 bool LCurveParams::operator ==(const LCurveParams& other) const
552 {
553     return
554         enabled == other.enabled
555         && lcurve == other.lcurve
556         && acurve == other.acurve
557         && bcurve == other.bcurve
558         && cccurve == other.cccurve
559         && chcurve == other.chcurve
560         && lhcurve == other.lhcurve
561         && hhcurve == other.hhcurve
562         && lccurve == other.lccurve
563         && clcurve == other.clcurve
564         && brightness == other.brightness
565         && contrast == other.contrast
566         && chromaticity == other.chromaticity
567         && avoidcolorshift == other.avoidcolorshift
568         && rstprotection == other.rstprotection
569         && lcredsk == other.lcredsk;
570 }
571 
operator !=(const LCurveParams & other) const572 bool LCurveParams::operator !=(const LCurveParams& other) const
573 {
574     return !(*this == other);
575 }
576 
RGBCurvesParams()577 RGBCurvesParams::RGBCurvesParams() :
578     enabled(false),
579     lumamode(false),
580     rcurve{
581         DCT_Linear
582     },
583     gcurve{
584         DCT_Linear
585     },
586     bcurve{
587         DCT_Linear
588     }
589 {
590 }
591 
operator ==(const RGBCurvesParams & other) const592 bool RGBCurvesParams::operator ==(const RGBCurvesParams& other) const
593 {
594     return
595         enabled == other.enabled
596         && lumamode == other.lumamode
597         && rcurve == other.rcurve
598         && gcurve == other.gcurve
599         && bcurve == other.bcurve;
600 }
601 
operator !=(const RGBCurvesParams & other) const602 bool RGBCurvesParams::operator !=(const RGBCurvesParams& other) const
603 {
604     return !(*this == other);
605 }
606 
607 
LocalContrastParams()608 LocalContrastParams::LocalContrastParams():
609     enabled(false),
610     radius(80),
611     amount(0.2),
612     darkness(1.0),
613     lightness(1.0)
614 {
615 }
616 
617 
operator ==(const LocalContrastParams & other) const618 bool LocalContrastParams::operator==(const LocalContrastParams &other) const
619 {
620     return
621         enabled == other.enabled
622         && radius == other.radius
623         && amount == other.amount
624         && darkness == other.darkness
625         && lightness == other.lightness;
626 }
627 
628 
operator !=(const LocalContrastParams & other) const629 bool LocalContrastParams::operator!=(const LocalContrastParams &other) const
630 {
631     return !(*this == other);
632 }
633 
634 
635 const double ColorToningParams::LABGRID_CORR_MAX = 12000.f;
636 const double ColorToningParams::LABGRID_CORR_SCALE = 3.f;
637 
LabCorrectionRegion()638 ColorToningParams::LabCorrectionRegion::LabCorrectionRegion():
639     a(0),
640     b(0),
641     saturation(0),
642     slope(1),
643     offset(0),
644     power(1),
645     hueMask{
646         FCT_MinMaxCPoints,
647             0.166666667,
648             1.,
649             0.35,
650             0.35,
651             0.8287775246,
652             1.,
653             0.35,
654             0.35
655     },
656     chromaticityMask{
657         FCT_MinMaxCPoints,
658             0.,
659             1.,
660             0.35,
661             0.35,
662             1.,
663             1.,
664             0.35,
665             0.35
666             },
667     lightnessMask{
668         FCT_MinMaxCPoints,
669             0.,
670             1.,
671             0.35,
672             0.35,
673             1.,
674             1.,
675             0.35,
676             0.35
677             },
678     maskBlur(0),
679     channel(ColorToningParams::LabCorrectionRegion::CHAN_ALL)
680 {
681 }
682 
683 
operator ==(const LabCorrectionRegion & other) const684 bool ColorToningParams::LabCorrectionRegion::operator==(const LabCorrectionRegion &other) const
685 {
686     return a == other.a
687         && b == other.b
688         && saturation == other.saturation
689         && slope == other.slope
690         && offset == other.offset
691         && power == other.power
692         && hueMask == other.hueMask
693         && chromaticityMask == other.chromaticityMask
694         && lightnessMask == other.lightnessMask
695         && maskBlur == other.maskBlur
696         && channel == other.channel;
697 }
698 
699 
operator !=(const LabCorrectionRegion & other) const700 bool ColorToningParams::LabCorrectionRegion::operator!=(const LabCorrectionRegion &other) const
701 {
702     return !(*this == other);
703 }
704 
705 
ColorToningParams()706 ColorToningParams::ColorToningParams() :
707     enabled(false),
708     autosat(true),
709     opacityCurve{
710         FCT_MinMaxCPoints,
711         0.00,
712         0.3,
713         0.35,
714         0.00,
715         0.25,
716         0.8,
717         0.35,
718         0.35,
719         0.70,
720         0.8,
721         0.35,
722         0.35,
723         1.00,
724         0.3,
725         0.00,
726         0.00
727     },
728     colorCurve{
729         FCT_MinMaxCPoints,
730         0.050,
731         0.62,
732         0.25,
733         0.25,
734         0.585,
735         0.11,
736         0.25,
737         0.25
738     },
739     satProtectionThreshold(30),
740     saturatedOpacity(80),
741     strength(50),
742     balance(0),
743     hlColSat(60, 80, false),
744     shadowsColSat (80, 208, false),
745     clcurve{
746         DCT_NURBS,
747         0.00,
748         0.00,
749         0.35,
750         0.65,
751         1.00,
752         1.00
753     },
754     cl2curve{
755         DCT_NURBS,
756         0.00,
757         0.00,
758         0.35,
759         0.65,
760         1.00,
761         1.00
762     },
763     method("LabRegions"),
764     twocolor("Std"),
765     redlow(0.0),
766     greenlow(0.0),
767     bluelow(0.0),
768     redmed(0.0),
769     greenmed(0.0),
770     bluemed(0.0),
771     redhigh(0.0),
772     greenhigh(0.0),
773     bluehigh(0.0),
774     satlow(0.0),
775     sathigh(0.0),
776     lumamode(true),
777     labgridALow(0.0),
778     labgridBLow(0.0),
779     labgridAHigh(0.0),
780     labgridBHigh(0.0),
781     labregions{LabCorrectionRegion()},
782     labregionsShowMask(-1)
783 {
784 }
785 
operator ==(const ColorToningParams & other) const786 bool ColorToningParams::operator ==(const ColorToningParams& other) const
787 {
788     return
789         enabled == other.enabled
790         && autosat == other.autosat
791         && opacityCurve == other.opacityCurve
792         && colorCurve == other.colorCurve
793         && satProtectionThreshold == other.satProtectionThreshold
794         && saturatedOpacity == other.saturatedOpacity
795         && strength == other.strength
796         && balance == other.balance
797         && hlColSat == other.hlColSat
798         && shadowsColSat == other.shadowsColSat
799         && clcurve == other.clcurve
800         && cl2curve == other.cl2curve
801         && method == other.method
802         && twocolor == other.twocolor
803         && redlow == other.redlow
804         && greenlow == other.greenlow
805         && bluelow == other.bluelow
806         && redmed == other.redmed
807         && greenmed == other.greenmed
808         && bluemed == other.bluemed
809         && redhigh == other.redhigh
810         && greenhigh == other.greenhigh
811         && bluehigh == other.bluehigh
812         && satlow == other.satlow
813         && sathigh == other.sathigh
814         && lumamode == other.lumamode
815         && labgridALow == other.labgridALow
816         && labgridBLow == other.labgridBLow
817         && labgridAHigh == other.labgridAHigh
818         && labgridBHigh == other.labgridBHigh
819         && labregions == other.labregions
820         && labregionsShowMask == other.labregionsShowMask;
821 }
822 
operator !=(const ColorToningParams & other) const823 bool ColorToningParams::operator !=(const ColorToningParams& other) const
824 {
825     return !(*this == other);
826 }
827 
mixerToCurve(std::vector<double> & colorCurve,std::vector<double> & opacityCurve) const828 void ColorToningParams::mixerToCurve(std::vector<double>& colorCurve, std::vector<double>& opacityCurve) const
829 {
830     // check if non null first
831     if (!redlow && !greenlow && !bluelow && !redmed && !greenmed && !bluemed && !redhigh && !greenhigh && !bluehigh) {
832         colorCurve.resize(1);
833         colorCurve.at(0) = FCT_Linear;
834         opacityCurve.resize(1);
835         opacityCurve.at(0) = FCT_Linear;
836         return;
837     }
838 
839     float low[3]; // RGB color for shadows
840     float med[3]; // RGB color for mid-tones
841     float high[3]; // RGB color for highlights
842     float lowSat = 0.f;
843     float medSat = 0.f;
844     float highSat = 0.f;
845     float minTmp, maxTmp;
846 
847 // Fill the shadow mixer values of the Color TOning tool
848     low[0] = float (redlow) / 100.f;  // [-1. ; +1.]
849     low[1] = float (greenlow) / 100.f; // [-1. ; +1.]
850     low[2] = float (bluelow) / 100.f;  // [-1. ; +1.]
851     minTmp = min<float> (low[0], low[1], low[2]);
852     maxTmp = max<float> (low[0], low[1], low[2]);
853 
854     if (maxTmp - minTmp > 0.005f) {
855         float v[3];
856         lowSat = (maxTmp - minTmp) / 2.f;
857 
858         if (low[0] == minTmp) {
859             v[0] = 0.f;
860         } else if (low[1] == minTmp) {
861             v[1] = 0.f;
862         } else if (low[2] == minTmp) {
863             v[2] = 0.f;
864         }
865 
866         if (low[0] == maxTmp) {
867             v[0] = 1.f;
868         } else if (low[1] == maxTmp) {
869             v[1] = 1.f;
870         } else if (low[2] == maxTmp) {
871             v[2] = 1.f;
872         }
873 
874         if (low[0] != minTmp && low[0] != maxTmp) {
875             v[0] = (low[0] - minTmp) / (maxTmp - minTmp);
876         } else if (low[1] != minTmp && low[1] != maxTmp) {
877             v[1] = (low[1] - minTmp) / (maxTmp - minTmp);
878         } else if (low[2] != minTmp && low[2] != maxTmp) {
879             v[2] = (low[2] - minTmp) / (maxTmp - minTmp);
880         }
881 
882         low[0] = v[0];
883         low[1] = v[1];
884         low[2] = v[2];
885     } else {
886         low[0] = low[1] = low[2] = 1.f;
887     }
888 
889 // Fill the mid-tones mixer values of the Color TOning tool
890     med[0] = float (redmed) / 100.f;  // [-1. ; +1.]
891     med[1] = float (greenmed) / 100.f; // [-1. ; +1.]
892     med[2] = float (bluemed) / 100.f;  // [-1. ; +1.]
893     minTmp = min<float> (med[0], med[1], med[2]);
894     maxTmp = max<float> (med[0], med[1], med[2]);
895 
896     if (maxTmp - minTmp > 0.005f) {
897         float v[3];
898         medSat = (maxTmp - minTmp) / 2.f;
899 
900         if (med[0] == minTmp) {
901             v[0] = 0.f;
902         } else if (med[1] == minTmp) {
903             v[1] = 0.f;
904         } else if (med[2] == minTmp) {
905             v[2] = 0.f;
906         }
907 
908         if (med[0] == maxTmp) {
909             v[0] = 1.f;
910         } else if (med[1] == maxTmp) {
911             v[1] = 1.f;
912         } else if (med[2] == maxTmp) {
913             v[2] = 1.f;
914         }
915 
916         if (med[0] != minTmp && med[0] != maxTmp) {
917             v[0] = (med[0] - minTmp) / (maxTmp - minTmp);
918         } else if (med[1] != minTmp && med[1] != maxTmp) {
919             v[1] = (med[1] - minTmp) / (maxTmp - minTmp);
920         } else if (med[2] != minTmp && med[2] != maxTmp) {
921             v[2] = (med[2] - minTmp) / (maxTmp - minTmp);
922         }
923 
924         med[0] = v[0];
925         med[1] = v[1];
926         med[2] = v[2];
927     } else {
928         med[0] = med[1] = med[2] = 1.f;
929     }
930 
931     // Fill the highlight mixer values of the Color TOning tool
932     high[0] = float (redhigh) / 100.f;   // [-1. ; +1.]
933     high[1] = float (greenhigh) / 100.f; // [-1. ; +1.]
934     high[2] = float (bluehigh) / 100.f;  // [-1. ; +1.]
935     minTmp = min<float> (high[0], high[1], high[2]);
936     maxTmp = max<float> (high[0], high[1], high[2]);
937 
938     if (maxTmp - minTmp > 0.005f) {
939         float v[3];
940         highSat = (maxTmp - minTmp) / 2.f;
941 
942         if (high[0] == minTmp) {
943             v[0] = 0.f;
944         } else if (high[1] == minTmp) {
945             v[1] = 0.f;
946         } else if (high[2] == minTmp) {
947             v[2] = 0.f;
948         }
949 
950         if (high[0] == maxTmp) {
951             v[0] = 1.f;
952         } else if (high[1] == maxTmp) {
953             v[1] = 1.f;
954         } else if (high[2] == maxTmp) {
955             v[2] = 1.f;
956         }
957 
958         if (high[0] != minTmp && high[0] != maxTmp) {
959             v[0] = (high[0] - minTmp) / (maxTmp - minTmp);
960         } else if (high[1] != minTmp && high[1] != maxTmp) {
961             v[1] = (high[1] - minTmp) / (maxTmp - minTmp);
962         } else if (high[2] != minTmp && high[2] != maxTmp) {
963             v[2] = (high[2] - minTmp) / (maxTmp - minTmp);
964         }
965 
966         high[0] = v[0];
967         high[1] = v[1];
968         high[2] = v[2];
969     } else {
970         high[0] = high[1] = high[2] = 1.f;
971     }
972 
973     const double xPosLow  = 0.1;
974     const double xPosMed  = 0.4;
975     const double xPosHigh = 0.7;
976 
977     colorCurve.resize(medSat != 0.f ? 13 : 9);
978     colorCurve.at(0) = FCT_MinMaxCPoints;
979     opacityCurve.resize(13);
980     opacityCurve.at(0) = FCT_MinMaxCPoints;
981 
982     float h, s, l;
983     int idx = 1;
984 
985     if (lowSat == 0.f) {
986         if (medSat != 0.f) {
987             Color::rgb2hsl(med[0], med[1], med[2], h, s, l);
988         } else { // highSat can't be null if the 2 other ones are!
989             Color::rgb2hsl(high[0], high[1], high[2], h, s, l);
990         }
991     } else {
992         Color::rgb2hsl(low[0], low[1], low[2], h, s, l);
993     }
994 
995     colorCurve.at(idx++) = xPosLow;
996     colorCurve.at(idx++) = h;
997     colorCurve.at(idx++) = 0.35;
998     colorCurve.at(idx++) = 0.35;
999 
1000     if (medSat != 0.f) {
1001         Color::rgb2hsl(med[0], med[1], med[2], h, s, l);
1002         colorCurve.at(idx++) = xPosMed;
1003         colorCurve.at(idx++) = h;
1004         colorCurve.at(idx++) = 0.35;
1005         colorCurve.at(idx++) = 0.35;
1006     }
1007 
1008     if (highSat == 0.f) {
1009         if (medSat != 0.f) {
1010             Color::rgb2hsl(med[0], med[1], med[2], h, s, l);
1011         } else { // lowSat can't be null if the 2 other ones are!
1012             Color::rgb2hsl(low[0], low[1], low[2], h, s, l);
1013         }
1014     } else {
1015         Color::rgb2hsl(high[0], high[1], high[2], h, s, l);
1016     }
1017 
1018     colorCurve.at(idx++) = xPosHigh;
1019     colorCurve.at(idx++) = h;
1020     colorCurve.at(idx++) = 0.35;
1021     colorCurve.at(idx)   = 0.35;
1022 
1023     opacityCurve.at(1)  = xPosLow;
1024     opacityCurve.at(2)  = double (lowSat);
1025     opacityCurve.at(3)  = 0.35;
1026     opacityCurve.at(4)  = 0.35;
1027     opacityCurve.at(5)  = xPosMed;
1028     opacityCurve.at(6)  = double (medSat);
1029     opacityCurve.at(7)  = 0.35;
1030     opacityCurve.at(8)  = 0.35;
1031     opacityCurve.at(9)  = xPosHigh;
1032     opacityCurve.at(10) = double (highSat);
1033     opacityCurve.at(11) = 0.35;
1034     opacityCurve.at(12) = 0.35;
1035 }
1036 
slidersToCurve(std::vector<double> & colorCurve,std::vector<double> & opacityCurve) const1037 void ColorToningParams::slidersToCurve(std::vector<double>& colorCurve, std::vector<double>& opacityCurve) const
1038 {
1039     if (hlColSat.getBottom() == 0 && shadowsColSat.getBottom() == 0) { // if both opacity are null, set both curves to Linear
1040         colorCurve.resize(1);
1041         colorCurve.at(0) = FCT_Linear;
1042         opacityCurve.resize(1);
1043         opacityCurve.at(0) = FCT_Linear;
1044         return;
1045     }
1046 
1047     colorCurve.resize(9);
1048     colorCurve.at(0) = FCT_MinMaxCPoints;
1049     colorCurve.at(1) = 0.26 + 0.12 * double (balance) / 100.;
1050     colorCurve.at(2) = double (shadowsColSat.getTop()) / 360.;
1051     colorCurve.at(3) = 0.35;
1052     colorCurve.at(4) = 0.35;
1053     colorCurve.at(5) = 0.64 + 0.12 * double (balance) / 100.;
1054     colorCurve.at(6) = double (hlColSat.getTop()) / 360.;
1055     colorCurve.at(7) = 0.35;
1056     colorCurve.at(8) = 0.35;
1057 
1058     opacityCurve.resize(9);
1059     opacityCurve.at(0) = FCT_MinMaxCPoints;
1060     opacityCurve.at(1) = colorCurve.at(1);
1061     opacityCurve.at(2) = double (shadowsColSat.getBottom()) / 100.;
1062     opacityCurve.at(3) = 0.35;
1063     opacityCurve.at(4) = 0.35;
1064     opacityCurve.at(5) = colorCurve.at(5);
1065     opacityCurve.at(6) = double (hlColSat.getBottom()) / 100.;
1066     opacityCurve.at(7) = 0.35;
1067     opacityCurve.at(8) = 0.35;
1068 }
1069 
getCurves(ColorGradientCurve & colorCurveLUT,OpacityCurve & opacityCurveLUT,const double xyz_rgb[3][3],bool & opautili) const1070 void ColorToningParams::getCurves(ColorGradientCurve& colorCurveLUT, OpacityCurve& opacityCurveLUT, const double xyz_rgb[3][3], bool& opautili) const
1071 {
1072     float satur = 0.8f;
1073     float lumin = 0.5f; //middle of luminance for optimization of gamut - no real importance...as we work in XYZ and gamut control
1074 
1075     // Transform slider values to control points
1076     std::vector<double> cCurve, oCurve;
1077 
1078     if (method == "RGBSliders" || method == "Splitlr") {
1079         slidersToCurve(cCurve, oCurve);
1080     } else if (method == "Splitco") {
1081         mixerToCurve(cCurve, oCurve);
1082     } else {
1083         cCurve = this->colorCurve;
1084         oCurve = this->opacityCurve;
1085     }
1086 
1087     if (method == "Lab") {
1088         if (twocolor == "Separ") {
1089             satur = 0.9f;
1090         }
1091 
1092         if (twocolor == "All" || twocolor == "Two") {
1093             satur = 0.9f;
1094         }
1095 
1096         colorCurveLUT.SetXYZ(cCurve, xyz_rgb, satur, lumin);
1097         opacityCurveLUT.Set(oCurve, opautili);
1098     } else if (method == "Splitlr" || method == "Splitco") {
1099         colorCurveLUT.SetXYZ(cCurve, xyz_rgb, satur, lumin);
1100         opacityCurveLUT.Set(oCurve, opautili);
1101     } else if (method.substr(0, 3) == "RGB") {
1102         colorCurveLUT.SetRGB(cCurve);
1103         opacityCurveLUT.Set(oCurve, opautili);
1104     }
1105 }
1106 
SharpeningParams()1107 SharpeningParams::SharpeningParams() :
1108     enabled(false),
1109     contrast(20.0),
1110     autoContrast(false),
1111     blurradius(0.2),
1112     gamma(1.0),
1113     radius(0.5),
1114     amount(200),
1115     threshold(20, 80, 2000, 1200, false),
1116     edgesonly(false),
1117     edges_radius(1.9),
1118     edges_tolerance(1800),
1119     halocontrol(false),
1120     halocontrol_amount(85),
1121     method("usm"),
1122     deconvamount(100),
1123     deconvradius(0.75),
1124     deconviter(30),
1125     deconvdamping(0)
1126 {
1127 }
1128 
operator ==(const SharpeningParams & other) const1129 bool SharpeningParams::operator ==(const SharpeningParams& other) const
1130 {
1131     return
1132         enabled == other.enabled
1133         && contrast == other.contrast
1134         && blurradius == other.blurradius
1135         && gamma == other.gamma
1136         && radius == other.radius
1137         && amount == other.amount
1138         && threshold == other.threshold
1139         && autoContrast == other.autoContrast
1140         && edgesonly == other.edgesonly
1141         && edges_radius == other.edges_radius
1142         && edges_tolerance == other.edges_tolerance
1143         && halocontrol == other.halocontrol
1144         && halocontrol_amount == other.halocontrol_amount
1145         && method == other.method
1146         && deconvamount == other.deconvamount
1147         && deconvradius == other.deconvradius
1148         && deconviter == other.deconviter
1149         && deconvdamping == other.deconvdamping;
1150 }
1151 
operator !=(const SharpeningParams & other) const1152 bool SharpeningParams::operator !=(const SharpeningParams& other) const
1153 {
1154     return !(*this == other);
1155 }
1156 
CaptureSharpeningParams()1157 CaptureSharpeningParams::CaptureSharpeningParams() :
1158     enabled(false),
1159     autoContrast(true),
1160     autoRadius(true),
1161     contrast(10.0),
1162     deconvradius(0.75),
1163     deconvradiusOffset(0.0),
1164     deconviter(20),
1165     deconvitercheck(true)
1166 {
1167 }
1168 
operator ==(const CaptureSharpeningParams & other) const1169 bool CaptureSharpeningParams::operator ==(const CaptureSharpeningParams& other) const
1170 {
1171     return
1172         enabled == other.enabled
1173         && contrast == other.contrast
1174         && autoContrast == other.autoContrast
1175         && autoRadius == other.autoRadius
1176         && deconvradius == other.deconvradius
1177         && deconvitercheck == other.deconvitercheck
1178         && deconvradiusOffset == other.deconvradiusOffset
1179         && deconviter == other.deconviter;
1180 }
1181 
operator !=(const CaptureSharpeningParams & other) const1182 bool CaptureSharpeningParams::operator !=(const CaptureSharpeningParams& other) const
1183 {
1184     return !(*this == other);
1185 }
1186 
SharpenEdgeParams()1187 SharpenEdgeParams::SharpenEdgeParams() :
1188     enabled(false),
1189     passes(2),
1190     amount(50.0),
1191     threechannels(false)
1192 {
1193 }
1194 
operator ==(const SharpenEdgeParams & other) const1195 bool SharpenEdgeParams::operator ==(const SharpenEdgeParams& other) const
1196 {
1197     return
1198         enabled == other.enabled
1199         && passes == other.passes
1200         && amount == other.amount
1201         && threechannels == other.threechannels;
1202 }
1203 
operator !=(const SharpenEdgeParams & other) const1204 bool SharpenEdgeParams::operator !=(const SharpenEdgeParams& other) const
1205 {
1206     return !(*this == other);
1207 }
1208 
SharpenMicroParams()1209 SharpenMicroParams::SharpenMicroParams() :
1210     enabled(false),
1211     matrix(false),
1212     amount(20.0),
1213     contrast(20.0),
1214     uniformity(5)
1215 {
1216 }
1217 
operator ==(const SharpenMicroParams & other) const1218 bool SharpenMicroParams::operator ==(const SharpenMicroParams& other) const
1219 {
1220     return
1221         enabled == other.enabled
1222         && matrix == other.matrix
1223         && amount == other.amount
1224         && contrast == other.contrast
1225         && uniformity == other.uniformity;
1226 }
1227 
operator !=(const SharpenMicroParams & other) const1228 bool SharpenMicroParams::operator !=(const SharpenMicroParams& other) const
1229 {
1230     return !(*this == other);
1231 }
1232 
VibranceParams()1233 VibranceParams::VibranceParams() :
1234     enabled(false),
1235     pastels(0),
1236     saturated(0),
1237     psthreshold(0, 75, false),
1238     protectskins(false),
1239     avoidcolorshift(true),
1240     pastsattog(true),
1241     skintonescurve{
1242         DCT_Linear
1243     }
1244 {
1245 }
1246 
operator ==(const VibranceParams & other) const1247 bool VibranceParams::operator ==(const VibranceParams& other) const
1248 {
1249     return
1250         enabled == other.enabled
1251         && pastels == other.pastels
1252         && saturated == other.saturated
1253         && psthreshold == other.psthreshold
1254         && protectskins == other.protectskins
1255         && avoidcolorshift == other.avoidcolorshift
1256         && pastsattog == other.pastsattog
1257         && skintonescurve == other.skintonescurve;
1258 }
1259 
operator !=(const VibranceParams & other) const1260 bool VibranceParams::operator !=(const VibranceParams& other) const
1261 {
1262     return !(*this == other);
1263 }
1264 
WBParams()1265 WBParams::WBParams() :
1266     enabled(true),
1267     method("Camera"),
1268     temperature(6504),
1269     green(1.0),
1270     equal(1.0),
1271     tempBias(0.0)
1272 {
1273 }
1274 
isPanningRelatedChange(const WBParams & other) const1275 bool WBParams::isPanningRelatedChange(const WBParams& other) const
1276 {
1277     return !
1278         (enabled == other.enabled
1279         && ((method == "Camera" && other.method == "Camera")
1280         ||
1281         (method == other.method
1282         && temperature == other.temperature
1283         && green == other.green
1284         && equal == other.equal
1285         && tempBias == other.tempBias)
1286         )
1287         );
1288 }
1289 
operator ==(const WBParams & other) const1290 bool WBParams::operator ==(const WBParams& other) const
1291 {
1292     return
1293         enabled == other.enabled
1294         && method == other.method
1295         && temperature == other.temperature
1296         && green == other.green
1297         && equal == other.equal
1298         && tempBias == other.tempBias;
1299 }
1300 
operator !=(const WBParams & other) const1301 bool WBParams::operator !=(const WBParams& other) const
1302 {
1303     return !(*this == other);
1304 }
1305 
getWbEntries()1306 const std::vector<WBEntry>& WBParams::getWbEntries()
1307 {
1308     static const std::vector<WBEntry> wb_entries = {
1309         {"Camera",               WBEntry::Type::CAMERA,      M("TP_WBALANCE_CAMERA"),         0, 1.f,   1.f,   0.f},
1310         {"Auto",                 WBEntry::Type::AUTO,        M("TP_WBALANCE_AUTO"),           0, 1.f,   1.f,   0.f},
1311         {"Daylight",             WBEntry::Type::DAYLIGHT,    M("TP_WBALANCE_DAYLIGHT"),    5300, 1.f,   1.f,   0.f},
1312         {"Cloudy",               WBEntry::Type::CLOUDY,      M("TP_WBALANCE_CLOUDY"),      6200, 1.f,   1.f,   0.f},
1313         {"Shade",                WBEntry::Type::SHADE,       M("TP_WBALANCE_SHADE"),       7600, 1.f,   1.f,   0.f},
1314         {"Water 1",              WBEntry::Type::WATER,       M("TP_WBALANCE_WATER1"),     35000, 0.3f,  1.1f,  0.f},
1315         {"Water 2",              WBEntry::Type::WATER,       M("TP_WBALANCE_WATER2"),     48000, 0.63f, 1.38f, 0.f},
1316         {"Tungsten",             WBEntry::Type::TUNGSTEN,    M("TP_WBALANCE_TUNGSTEN"),    2856, 1.f,   1.f,   0.f},
1317         {"Fluo F1",              WBEntry::Type::FLUORESCENT, M("TP_WBALANCE_FLUO1"),       6430, 1.f,   1.f,   0.f},
1318         {"Fluo F2",              WBEntry::Type::FLUORESCENT, M("TP_WBALANCE_FLUO2"),       4230, 1.f,   1.f,   0.f},
1319         {"Fluo F3",              WBEntry::Type::FLUORESCENT, M("TP_WBALANCE_FLUO3"),       3450, 1.f,   1.f,   0.f},
1320         {"Fluo F4",              WBEntry::Type::FLUORESCENT, M("TP_WBALANCE_FLUO4"),       2940, 1.f,   1.f,   0.f},
1321         {"Fluo F5",              WBEntry::Type::FLUORESCENT, M("TP_WBALANCE_FLUO5"),       6350, 1.f,   1.f,   0.f},
1322         {"Fluo F6",              WBEntry::Type::FLUORESCENT, M("TP_WBALANCE_FLUO6"),       4150, 1.f,   1.f,   0.f},
1323         {"Fluo F7",              WBEntry::Type::FLUORESCENT, M("TP_WBALANCE_FLUO7"),       6500, 1.f,   1.f,   0.f},
1324         {"Fluo F8",              WBEntry::Type::FLUORESCENT, M("TP_WBALANCE_FLUO8"),       5020, 1.f,   1.f,   0.f},
1325         {"Fluo F9",              WBEntry::Type::FLUORESCENT, M("TP_WBALANCE_FLUO9"),       4330, 1.f,   1.f,   0.f},
1326         {"Fluo F10",             WBEntry::Type::FLUORESCENT, M("TP_WBALANCE_FLUO10"),      5300, 1.f,   1.f,   0.f},
1327         {"Fluo F11",             WBEntry::Type::FLUORESCENT, M("TP_WBALANCE_FLUO11"),      4000, 1.f,   1.f,   0.f},
1328         {"Fluo F12",             WBEntry::Type::FLUORESCENT, M("TP_WBALANCE_FLUO12"),      3000, 1.f,   1.f,   0.f},
1329         {"HMI Lamp",             WBEntry::Type::LAMP,        M("TP_WBALANCE_HMI"),         4800, 1.f,   1.f,   0.f},
1330         {"GTI Lamp",             WBEntry::Type::LAMP,        M("TP_WBALANCE_GTI"),         5000, 1.f,   1.f,   0.f},
1331         {"JudgeIII Lamp",        WBEntry::Type::LAMP,        M("TP_WBALANCE_JUDGEIII"),    5100, 1.f,   1.f,   0.f},
1332         {"Solux Lamp 3500K",     WBEntry::Type::LAMP,        M("TP_WBALANCE_SOLUX35"),     3480, 1.f,   1.f,   0.f},
1333         {"Solux Lamp 4100K",     WBEntry::Type::LAMP,        M("TP_WBALANCE_SOLUX41"),     3930, 1.f,   1.f,   0.f},
1334         {"Solux Lamp 4700K",     WBEntry::Type::LAMP,        M("TP_WBALANCE_SOLUX47"),     4700, 1.f,   1.f,   0.f},
1335         {"NG Solux Lamp 4700K",  WBEntry::Type::LAMP,        M("TP_WBALANCE_SOLUX47_NG"),  4480, 1.f,   1.f,   0.f},
1336         {"LED LSI Lumelex 2040", WBEntry::Type::LED,         M("TP_WBALANCE_LED_LSI"),     2970, 1.f,   1.f,   0.f},
1337         {"LED CRS SP12 WWMR16",  WBEntry::Type::LED,         M("TP_WBALANCE_LED_CRS"),     3050, 1.f,   1.f,   0.f},
1338         {"Flash 5500K",          WBEntry::Type::FLASH,       M("TP_WBALANCE_FLASH55"),     5500, 1.f,   1.f,   0.f},
1339         {"Flash 6000K",          WBEntry::Type::FLASH,       M("TP_WBALANCE_FLASH60"),     6000, 1.f,   1.f,   0.f},
1340         {"Flash 6500K",          WBEntry::Type::FLASH,       M("TP_WBALANCE_FLASH65"),     6500, 1.f,   1.f,   0.f},
1341         // Should remain the last one
1342         {"Custom",               WBEntry::Type::CUSTOM,      M("TP_WBALANCE_CUSTOM"),        0, 1.f,   1.f,   0.f}
1343     };
1344 
1345     return wb_entries;
1346 }
1347 
ColorAppearanceParams()1348 ColorAppearanceParams::ColorAppearanceParams() :
1349     enabled(false),
1350     degree(90),
1351     autodegree(true),
1352     degreeout(90),
1353     autodegreeout(true),
1354     curve{
1355        DCT_Linear
1356     },
1357     curve2{
1358        DCT_Linear
1359     },
1360     curve3{
1361        DCT_Linear
1362     },
1363     curveMode(TcMode::LIGHT),
1364     curveMode2(TcMode::LIGHT),
1365     curveMode3(CtcMode::CHROMA),
1366     surround("Average"),
1367     surrsrc("Average"),
1368     adapscen(2000.0),
1369     autoadapscen(true),
1370     ybscen(18),
1371     autoybscen(true),
1372     adaplum(16),
1373     badpixsl(0),
1374     wbmodel("RawT"),
1375     algo("No"),
1376     contrast(0.0),
1377     qcontrast(0.0),
1378     jlight(0.0),
1379     qbright(0.0),
1380     chroma(0.0),
1381     schroma(0.0),
1382     mchroma(0.0),
1383     colorh(0.0),
1384     rstprotection(0.0),
1385     surrsource(false),
1386     gamut(true),
1387     datacie(false),
1388     tonecie(false),
1389     tempout(5000),
1390     ybout(18),
1391     greenout(1.0),
1392     tempsc(5000),
1393     greensc(1.0)
1394 {
1395 }
1396 
operator ==(const ColorAppearanceParams & other) const1397 bool ColorAppearanceParams::operator ==(const ColorAppearanceParams& other) const
1398 {
1399     return
1400         enabled == other.enabled
1401         && degree == other.degree
1402         && autodegree == other.autodegree
1403         && degreeout == other.degreeout
1404         && autodegreeout == other.autodegreeout
1405         && curve == other.curve
1406         && curve2 == other.curve2
1407         && curve3 == other.curve3
1408         && curveMode == other.curveMode
1409         && curveMode2 == other.curveMode2
1410         && curveMode3 == other.curveMode3
1411         && surround == other.surround
1412         && surrsrc == other.surrsrc
1413         && adapscen == other.adapscen
1414         && autoadapscen == other.autoadapscen
1415         && ybscen == other.ybscen
1416         && autoybscen == other.autoybscen
1417         && adaplum == other.adaplum
1418         && badpixsl == other.badpixsl
1419         && wbmodel == other.wbmodel
1420         && algo == other.algo
1421         && contrast == other.contrast
1422         && qcontrast == other.qcontrast
1423         && jlight == other.jlight
1424         && qbright == other.qbright
1425         && chroma == other.chroma
1426         && schroma == other.schroma
1427         && mchroma == other.mchroma
1428         && colorh == other.colorh
1429         && rstprotection == other.rstprotection
1430         && surrsource == other.surrsource
1431         && gamut == other.gamut
1432         && datacie == other.datacie
1433         && tonecie == other.tonecie
1434         && tempout == other.tempout
1435         && ybout == other.ybout
1436         && greenout == other.greenout
1437         && tempsc == other.tempsc
1438         && greensc == other.greensc;
1439 }
1440 
operator !=(const ColorAppearanceParams & other) const1441 bool ColorAppearanceParams::operator !=(const ColorAppearanceParams& other) const
1442 {
1443     return !(*this == other);
1444 }
1445 
DefringeParams()1446 DefringeParams::DefringeParams() :
1447     enabled(false),
1448     radius(2.0),
1449     threshold(13),
1450     huecurve{
1451         FCT_MinMaxCPoints,
1452         0.166666667,
1453         0.,
1454         0.35,
1455         0.35,
1456         0.347,
1457         0.,
1458         0.35,
1459         0.35,
1460         0.513667426,
1461         0,
1462         0.35,
1463         0.35,
1464         0.668944571,
1465         0.,
1466         0.35,
1467         0.35,
1468         0.8287775246,
1469         0.97835991,
1470         0.35,
1471         0.35,
1472         0.9908883827,
1473         0.,
1474         0.35,
1475         0.35
1476     }
1477 {
1478 }
1479 
operator ==(const DefringeParams & other) const1480 bool DefringeParams::operator ==(const DefringeParams& other) const
1481 {
1482     return
1483         enabled == other.enabled
1484         && radius == other.radius
1485         && threshold == other.threshold
1486         && huecurve == other.huecurve;
1487 }
1488 
operator !=(const DefringeParams & other) const1489 bool DefringeParams::operator !=(const DefringeParams& other) const
1490 {
1491     return !(*this == other);
1492 }
1493 
ImpulseDenoiseParams()1494 ImpulseDenoiseParams::ImpulseDenoiseParams() :
1495     enabled(false),
1496     thresh(50)
1497 {
1498 }
1499 
operator ==(const ImpulseDenoiseParams & other) const1500 bool ImpulseDenoiseParams::operator ==(const ImpulseDenoiseParams& other) const
1501 {
1502     return
1503         enabled == other.enabled
1504         && thresh == other.thresh;
1505 }
1506 
operator !=(const ImpulseDenoiseParams & other) const1507 bool ImpulseDenoiseParams::operator !=(const ImpulseDenoiseParams& other) const
1508 {
1509     return !(*this == other);
1510 }
1511 
DirPyrDenoiseParams()1512 DirPyrDenoiseParams::DirPyrDenoiseParams() :
1513     lcurve{
1514         FCT_MinMaxCPoints,
1515         0.05,
1516         0.15,
1517         0.35,
1518         0.35,
1519         0.55,
1520         0.04,
1521         0.35,
1522         0.35
1523     },
1524     cccurve{
1525         FCT_MinMaxCPoints,
1526         0.05,
1527         0.50,
1528         0.35,
1529         0.35,
1530         0.35,
1531         0.05,
1532         0.35,
1533         0.35
1534     },
1535     enabled(false),
1536     enhance(false),
1537     median(false),
1538     perform(false),
1539     luma(0),
1540     Ldetail(0),
1541     chroma(15),
1542     redchro(0),
1543     bluechro(0),
1544     gamma(1.7),
1545     dmethod("Lab"),
1546     Lmethod("SLI"),
1547     Cmethod("MAN"),
1548     C2method("AUTO"),
1549     smethod("shal"),
1550     medmethod("soft"),
1551     methodmed("none"),
1552     rgbmethod("soft"),
1553     passes(1)
1554 {
1555 }
1556 
operator ==(const DirPyrDenoiseParams & other) const1557 bool DirPyrDenoiseParams::operator ==(const DirPyrDenoiseParams& other) const
1558 {
1559     return
1560         lcurve == other.lcurve
1561         && cccurve == other.cccurve
1562         && enabled == other.enabled
1563         && enhance == other.enhance
1564         && median == other.median
1565         && perform == other.perform
1566         && luma == other.luma
1567         && Ldetail == other.Ldetail
1568         && chroma == other.chroma
1569         && redchro == other.redchro
1570         && bluechro == other.bluechro
1571         && gamma == other.gamma
1572         && dmethod == other.dmethod
1573         && Lmethod == other.Lmethod
1574         && Cmethod == other.Cmethod
1575         && C2method == other.C2method
1576         && smethod == other.smethod
1577         && medmethod == other.medmethod
1578         && methodmed == other.methodmed
1579         && rgbmethod == other.rgbmethod
1580         && passes == other.passes;
1581 }
1582 
operator !=(const DirPyrDenoiseParams & other) const1583 bool DirPyrDenoiseParams::operator !=(const DirPyrDenoiseParams& other) const
1584 {
1585     return !(*this == other);
1586 }
1587 
getCurves(NoiseCurve & lCurve,NoiseCurve & cCurve) const1588 void DirPyrDenoiseParams::getCurves(NoiseCurve &lCurve, NoiseCurve &cCurve) const
1589 {
1590     lCurve.Set(this->lcurve);
1591     cCurve.Set(this->cccurve);
1592 }
1593 
EPDParams()1594 EPDParams::EPDParams() :
1595     enabled(false),
1596     strength(0.5),
1597     gamma(1.0),
1598     edgeStopping(1.4),
1599     scale(1.0),
1600     reweightingIterates(0)
1601 {
1602 }
1603 
operator ==(const EPDParams & other) const1604 bool EPDParams::operator ==(const EPDParams& other) const
1605 {
1606     return
1607         enabled == other.enabled
1608         && strength == other.strength
1609         && gamma == other.gamma
1610         && edgeStopping == other.edgeStopping
1611         && scale == other.scale
1612         && reweightingIterates == other.reweightingIterates;
1613 }
1614 
operator !=(const EPDParams & other) const1615 bool EPDParams::operator !=(const EPDParams& other) const
1616 {
1617     return !(*this == other);
1618 }
1619 
FattalToneMappingParams()1620 FattalToneMappingParams::FattalToneMappingParams() :
1621     enabled(false),
1622     threshold(30),
1623     amount(20),
1624     anchor(50)
1625 {
1626 }
1627 
operator ==(const FattalToneMappingParams & other) const1628 bool FattalToneMappingParams::operator ==(const FattalToneMappingParams& other) const
1629 {
1630     return
1631         enabled == other.enabled
1632         && threshold == other.threshold
1633         && amount == other.amount
1634         && anchor == other.anchor;
1635 }
1636 
operator !=(const FattalToneMappingParams & other) const1637 bool FattalToneMappingParams::operator !=(const FattalToneMappingParams& other) const
1638 {
1639     return !(*this == other);
1640 }
1641 
SHParams()1642 SHParams::SHParams() :
1643     enabled(false),
1644     highlights(0),
1645     htonalwidth(70),
1646     shadows(0),
1647     stonalwidth(30),
1648     radius(40),
1649     lab(false)
1650 {
1651 }
1652 
operator ==(const SHParams & other) const1653 bool SHParams::operator ==(const SHParams& other) const
1654 {
1655     return
1656         enabled == other.enabled
1657         && highlights == other.highlights
1658         && htonalwidth == other.htonalwidth
1659         && shadows == other.shadows
1660         && stonalwidth == other.stonalwidth
1661         && radius == other.radius
1662         && lab == other.lab;
1663 }
1664 
operator !=(const SHParams & other) const1665 bool SHParams::operator !=(const SHParams& other) const
1666 {
1667     return !(*this == other);
1668 }
1669 
CropParams()1670 CropParams::CropParams() :
1671     enabled(false),
1672     x(-1),
1673     y(-1),
1674     w(15000),
1675     h(15000),
1676     fixratio(true),
1677     ratio("As Image"),
1678     orientation("As Image"),
1679     guide("Frame")
1680 {
1681 }
1682 
operator ==(const CropParams & other) const1683 bool CropParams::operator ==(const CropParams& other) const
1684 {
1685     return
1686         enabled == other.enabled
1687         && x == other.x
1688         && y == other.y
1689         && w == other.w
1690         && h == other.h
1691         && fixratio == other.fixratio
1692         && ratio == other.ratio
1693         && orientation == other.orientation
1694         && guide == other.guide;
1695 }
1696 
operator !=(const CropParams & other) const1697 bool CropParams::operator !=(const CropParams& other) const
1698 {
1699     return !(*this == other);
1700 }
1701 
mapToResized(int resizedWidth,int resizedHeight,int scale,int & x1,int & x2,int & y1,int & y2) const1702 void CropParams::mapToResized(int resizedWidth, int resizedHeight, int scale, int& x1, int& x2, int& y1, int& y2) const
1703 {
1704     x1 = 0, x2 = resizedWidth, y1 = 0, y2 = resizedHeight;
1705 
1706     if (enabled) {
1707         x1 = min(resizedWidth - 1, max(0, x / scale));
1708         y1 = min(resizedHeight - 1, max(0, y / scale));
1709         x2 = min(resizedWidth, max(0, (x + w) / scale));
1710         y2 = min(resizedHeight, max(0, (y + h) / scale));
1711     }
1712 }
1713 
CoarseTransformParams()1714 CoarseTransformParams::CoarseTransformParams() :
1715     rotate(0),
1716     hflip(false),
1717     vflip(false)
1718 {
1719 }
1720 
operator ==(const CoarseTransformParams & other) const1721 bool CoarseTransformParams::operator ==(const CoarseTransformParams& other) const
1722 {
1723     return
1724         rotate == other.rotate
1725         && hflip == other.hflip
1726         && vflip == other.vflip;
1727 }
1728 
operator !=(const CoarseTransformParams & other) const1729 bool CoarseTransformParams::operator !=(const CoarseTransformParams& other) const
1730 {
1731     return !(*this == other);
1732 }
1733 
CommonTransformParams()1734 CommonTransformParams::CommonTransformParams() :
1735     method("log"),
1736     autofill(true)
1737 {
1738 }
1739 
operator ==(const CommonTransformParams & other) const1740 bool CommonTransformParams::operator ==(const CommonTransformParams& other) const
1741 {
1742     return method == other.method && autofill == other.autofill;
1743 }
1744 
operator !=(const CommonTransformParams & other) const1745 bool CommonTransformParams::operator !=(const CommonTransformParams& other) const
1746 {
1747     return !(*this == other);
1748 }
1749 
RotateParams()1750 RotateParams::RotateParams() :
1751     degree(0.0)
1752 {
1753 }
1754 
operator ==(const RotateParams & other) const1755 bool RotateParams::operator ==(const RotateParams& other) const
1756 {
1757     return degree == other.degree;
1758 }
1759 
operator !=(const RotateParams & other) const1760 bool RotateParams::operator !=(const RotateParams& other) const
1761 {
1762     return !(*this == other);
1763 }
1764 
DistortionParams()1765 DistortionParams::DistortionParams() :
1766     amount(0.0)
1767 {
1768 }
1769 
operator ==(const DistortionParams & other) const1770 bool DistortionParams::operator ==(const DistortionParams& other) const
1771 {
1772     return amount == other.amount;
1773 }
1774 
operator !=(const DistortionParams & other) const1775 bool DistortionParams::operator !=(const DistortionParams& other) const
1776 {
1777     return !(*this == other);
1778 }
1779 
LensProfParams()1780 LensProfParams::LensProfParams() :
1781     lcMode(LcMode::NONE),
1782     useDist(true),
1783     useVign(true),
1784     useCA(false)
1785 {
1786 }
1787 
operator ==(const LensProfParams & other) const1788 bool LensProfParams::operator ==(const LensProfParams& other) const
1789 {
1790     return
1791         lcMode == other.lcMode
1792         && lcpFile == other.lcpFile
1793         && useCA == other.useCA
1794         && lfCameraMake == other.lfCameraMake
1795         && lfCameraModel == other.lfCameraModel
1796         && lfLens == other.lfLens
1797         && useDist == other.useDist
1798         && useVign == other.useVign;
1799 }
1800 
operator !=(const LensProfParams & other) const1801 bool LensProfParams::operator !=(const LensProfParams& other) const
1802 {
1803     return !(*this == other);
1804 }
1805 
useLensfun() const1806 bool LensProfParams::useLensfun() const
1807 {
1808     return lcMode == LcMode::LENSFUNAUTOMATCH || lcMode == LcMode::LENSFUNMANUAL;
1809 }
1810 
lfAutoMatch() const1811 bool LensProfParams::lfAutoMatch() const
1812 {
1813     return lcMode == LcMode::LENSFUNAUTOMATCH;
1814 }
1815 
useLcp() const1816 bool LensProfParams::useLcp() const
1817 {
1818     return lcMode == LcMode::LCP && lcpFile.length() > 0;
1819 }
1820 
lfManual() const1821 bool LensProfParams::lfManual() const
1822 {
1823     return lcMode == LcMode::LENSFUNMANUAL;
1824 }
1825 
getMethodStrings() const1826 const std::vector<const char*>& LensProfParams::getMethodStrings() const
1827 {
1828     static const std::vector<const char*> method_strings = {
1829         "none",
1830         "lfauto",
1831         "lfmanual",
1832         "lcp"
1833     };
1834     return method_strings;
1835 }
1836 
getMethodString(LcMode mode) const1837 Glib::ustring LensProfParams::getMethodString(LcMode mode) const
1838 {
1839     return getMethodStrings()[toUnderlying(mode)];
1840 }
1841 
getMethodNumber(const Glib::ustring & mode) const1842 LensProfParams::LcMode LensProfParams::getMethodNumber(const Glib::ustring& mode) const
1843 {
1844     for (std::vector<const char*>::size_type i = 0; i < getMethodStrings().size(); ++i) {
1845         if (getMethodStrings()[i] == mode) {
1846             return static_cast<LcMode>(i);
1847         }
1848     }
1849 
1850     return LcMode::NONE;
1851 }
1852 
PerspectiveParams()1853 PerspectiveParams::PerspectiveParams() :
1854     horizontal(0.0),
1855     vertical(0.0)
1856 {
1857 }
1858 
operator ==(const PerspectiveParams & other) const1859 bool PerspectiveParams::operator ==(const PerspectiveParams& other) const
1860 {
1861     return
1862         horizontal == other.horizontal
1863         && vertical == other.vertical;
1864 }
1865 
operator !=(const PerspectiveParams & other) const1866 bool PerspectiveParams::operator !=(const PerspectiveParams& other) const
1867 {
1868     return !(*this == other);
1869 }
1870 
GradientParams()1871 GradientParams::GradientParams() :
1872     enabled(false),
1873     degree(0.0),
1874     feather(25),
1875     strength(0.60),
1876     centerX(0),
1877     centerY(0)
1878 {
1879 }
1880 
operator ==(const GradientParams & other) const1881 bool GradientParams::operator ==(const GradientParams& other) const
1882 {
1883     return
1884         enabled == other.enabled
1885         && degree == other.degree
1886         && feather == other.feather
1887         && strength == other.strength
1888         && centerX == other.centerX
1889         && centerY == other.centerY;
1890 }
1891 
operator !=(const GradientParams & other) const1892 bool GradientParams::operator !=(const GradientParams& other) const
1893 {
1894     return !(*this == other);
1895 }
1896 
PCVignetteParams()1897 PCVignetteParams::PCVignetteParams() :
1898     enabled(false),
1899     strength(0.60),
1900     feather(50),
1901     roundness(50)
1902 {
1903 }
1904 
operator ==(const PCVignetteParams & other) const1905 bool PCVignetteParams::operator ==(const PCVignetteParams& other) const
1906 {
1907     return
1908         enabled == other.enabled
1909         && strength == other.strength
1910         && feather == other.feather
1911         && roundness == other.roundness;
1912 }
1913 
operator !=(const PCVignetteParams & other) const1914 bool PCVignetteParams::operator !=(const PCVignetteParams& other) const
1915 {
1916     return !(*this == other);
1917 }
1918 
VignettingParams()1919 VignettingParams::VignettingParams() :
1920     amount(0),
1921     radius(50),
1922     strength(1),
1923     centerX(0),
1924     centerY(0)
1925 {
1926 }
1927 
operator ==(const VignettingParams & other) const1928 bool VignettingParams::operator ==(const VignettingParams& other) const
1929 {
1930     return
1931         amount == other.amount
1932         && radius == other.radius
1933         && strength == other.strength
1934         && centerX == other.centerX
1935         && centerY == other.centerY;
1936 }
1937 
operator !=(const VignettingParams & other) const1938 bool VignettingParams::operator !=(const VignettingParams& other) const
1939 {
1940     return !(*this == other);
1941 }
1942 
ChannelMixerParams()1943 ChannelMixerParams::ChannelMixerParams() :
1944     enabled(false),
1945     red{
1946         1000,
1947         0,
1948         0
1949     },
1950     green{
1951         0,
1952         1000,
1953         0
1954     },
1955     blue{
1956         0,
1957         0,
1958         1000
1959     }
1960 {
1961 }
1962 
operator ==(const ChannelMixerParams & other) const1963 bool ChannelMixerParams::operator ==(const ChannelMixerParams& other) const
1964 {
1965     if (enabled != other.enabled) {
1966         return false;
1967     }
1968 
1969     for (unsigned int i = 0; i < 3; ++i) {
1970         if (
1971             red[i] != other.red[i]
1972             || green[i] != other.green[i]
1973             || blue[i] != other.blue[i]
1974         ) {
1975             return false;
1976         }
1977     }
1978 
1979     return true;
1980 }
1981 
operator !=(const ChannelMixerParams & other) const1982 bool ChannelMixerParams::operator !=(const ChannelMixerParams& other) const
1983 {
1984     return !(*this == other);
1985 }
1986 
BlackWhiteParams()1987 BlackWhiteParams::BlackWhiteParams() :
1988     beforeCurve{
1989         DCT_Linear
1990     },
1991     beforeCurveMode(BlackWhiteParams::TcMode::STD_BW),
1992     afterCurve{
1993         DCT_Linear
1994     },
1995     afterCurveMode(BlackWhiteParams::TcMode::STD_BW),
1996     algo("SP"),
1997     luminanceCurve{
1998         FCT_Linear
1999     },
2000     autoc(false),
2001     enabledcc(true),
2002     enabled(false),
2003     filter("None"),
2004     setting("RGB-Rel"),
2005     method("Desaturation"),
2006     mixerRed(33),
2007     mixerOrange(33),
2008     mixerYellow(33),
2009     mixerGreen(33),
2010     mixerCyan(33),
2011     mixerBlue(33),
2012     mixerMagenta(33),
2013     mixerPurple(33),
2014     gammaRed(0),
2015     gammaGreen(0),
2016     gammaBlue(0)
2017 {
2018 }
2019 
operator ==(const BlackWhiteParams & other) const2020 bool BlackWhiteParams::operator ==(const BlackWhiteParams& other) const
2021 {
2022     return
2023         beforeCurve == other.beforeCurve
2024         && beforeCurveMode == other.beforeCurveMode
2025         && afterCurve == other.afterCurve
2026         && afterCurveMode == other.afterCurveMode
2027         && algo == other.algo
2028         && luminanceCurve == other.luminanceCurve
2029         && autoc == other.autoc
2030         && enabledcc == other.enabledcc
2031         && enabled == other.enabled
2032         && filter == other.filter
2033         && setting == other.setting
2034         && method == other.method
2035         && mixerRed == other.mixerRed
2036         && mixerOrange == other.mixerOrange
2037         && mixerYellow == other.mixerYellow
2038         && mixerGreen == other.mixerGreen
2039         && mixerCyan == other.mixerCyan
2040         && mixerBlue == other.mixerBlue
2041         && mixerMagenta == other.mixerMagenta
2042         && mixerPurple == other.mixerPurple
2043         && gammaRed == other.gammaRed
2044         && gammaGreen == other.gammaGreen
2045         && gammaBlue == other.gammaBlue;
2046 }
2047 
operator !=(const BlackWhiteParams & other) const2048 bool BlackWhiteParams::operator !=(const BlackWhiteParams& other) const
2049 {
2050     return !(*this == other);
2051 }
2052 
CACorrParams()2053 CACorrParams::CACorrParams() :
2054     red(0.0),
2055     blue(0.0)
2056 {
2057 }
2058 
operator ==(const CACorrParams & other) const2059 bool CACorrParams::operator ==(const CACorrParams& other) const
2060 {
2061     return
2062         red == other.red
2063         && blue == other.blue;
2064 }
2065 
operator !=(const CACorrParams & other) const2066 bool CACorrParams::operator !=(const CACorrParams& other) const
2067 {
2068     return !(*this == other);
2069 }
2070 
ResizeParams()2071 ResizeParams::ResizeParams() :
2072     enabled(false),
2073     scale(1.0),
2074     appliesTo("Cropped area"),
2075     method("Lanczos"),
2076     dataspec(3),
2077     width(900),
2078     height(900),
2079     allowUpscaling(false)
2080 {
2081 }
2082 
operator ==(const ResizeParams & other) const2083 bool ResizeParams::operator ==(const ResizeParams& other) const
2084 {
2085     return
2086         enabled == other.enabled
2087         && scale == other.scale
2088         && appliesTo == other.appliesTo
2089         && method == other.method
2090         && dataspec == other.dataspec
2091         && width == other.width
2092         && height == other.height
2093         && allowUpscaling == other.allowUpscaling;
2094 }
2095 
operator !=(const ResizeParams & other) const2096 bool ResizeParams::operator !=(const ResizeParams& other) const
2097 {
2098     return !(*this == other);
2099 }
2100 
2101 const Glib::ustring ColorManagementParams::NoICMString = Glib::ustring("No ICM: sRGB output");
2102 
ColorManagementParams()2103 ColorManagementParams::ColorManagementParams() :
2104     inputProfile("(cameraICC)"),
2105     toneCurve(false),
2106     applyLookTable(false),
2107     applyBaselineExposureOffset(true),
2108     applyHueSatMap(true),
2109     dcpIlluminant(0),
2110     workingProfile("ProPhoto"),
2111     workingTRC("none"),
2112     workingTRCGamma(2.4),
2113     workingTRCSlope(12.92310),
2114     outputProfile(options.rtSettings.srgb),
2115     outputIntent(RI_RELATIVE),
2116     outputBPC(true)
2117 {
2118 }
2119 
operator ==(const ColorManagementParams & other) const2120 bool ColorManagementParams::operator ==(const ColorManagementParams& other) const
2121 {
2122     return
2123         inputProfile == other.inputProfile
2124         && toneCurve == other.toneCurve
2125         && applyLookTable == other.applyLookTable
2126         && applyBaselineExposureOffset == other.applyBaselineExposureOffset
2127         && applyHueSatMap == other.applyHueSatMap
2128         && dcpIlluminant == other.dcpIlluminant
2129         && workingProfile == other.workingProfile
2130         && workingTRC == other.workingTRC
2131         && workingTRCGamma == other.workingTRCGamma
2132         && workingTRCSlope == other.workingTRCSlope
2133         && outputProfile == other.outputProfile
2134         && outputIntent == other.outputIntent
2135         && outputBPC == other.outputBPC;
2136 }
2137 
operator !=(const ColorManagementParams & other) const2138 bool ColorManagementParams::operator !=(const ColorManagementParams& other) const
2139 {
2140     return !(*this == other);
2141 }
2142 
WaveletParams()2143 WaveletParams::WaveletParams() :
2144     ccwcurve{
2145         static_cast<double>(FCT_MinMaxCPoints),
2146         0.0,
2147         0.25,
2148         0.35,
2149         0.35,
2150         0.50,
2151         0.75,
2152         0.35,
2153         0.35,
2154         0.90,
2155         0.0,
2156         0.35,
2157         0.35
2158     },
2159     opacityCurveRG{
2160         static_cast<double>(FCT_MinMaxCPoints),
2161         0.0,
2162         0.50,
2163         0.35,
2164         0.35,
2165         1.00,
2166         0.50,
2167         0.35,
2168         0.35
2169     },
2170     opacityCurveBY{
2171         static_cast<double>(FCT_MinMaxCPoints),
2172         0.0,
2173         0.50,
2174         0.35,
2175         0.35,
2176         1.00,
2177         0.50,
2178         0.35,
2179         0.35
2180     },
2181     opacityCurveW{
2182         static_cast<double>(FCT_MinMaxCPoints),
2183         0.00,
2184         0.35,
2185         0.35,
2186         0.00,
2187         0.35,
2188         0.75,
2189         0.35,
2190         0.35,
2191         0.60,
2192         0.75,
2193         0.35,
2194         0.35,
2195         1.00,
2196         0.35,
2197         0.00,
2198         0.00
2199     },
2200     opacityCurveWL{
2201         static_cast<double>(FCT_MinMaxCPoints),
2202         0.0,
2203         0.50,
2204         0.35,
2205         0.35,
2206         1.00,
2207         0.50,
2208         0.35,
2209         0.35
2210     },
2211     hhcurve{
2212         FCT_Linear
2213     },
2214     Chcurve{
2215         FCT_Linear
2216     },
2217     wavclCurve {
2218         DCT_Linear
2219     },
2220     enabled(false),
2221     median(false),
2222     medianlev(false),
2223     linkedg(true),
2224     cbenab(false),
2225     greenlow(0),
2226     bluelow(0),
2227     greenmed(0),
2228     bluemed(0),
2229     greenhigh(0),
2230     bluehigh(0),
2231     lipst(false),
2232     avoid(false),
2233     tmr(false),
2234     strength(100),
2235     balance(0),
2236     iter(0),
2237     expcontrast(false),
2238     expchroma(false),
2239     c{},
2240     ch{},
2241     expedge(false),
2242     expresid(false),
2243     expfinal(false),
2244     exptoning(false),
2245     expnoise(false),
2246     Lmethod(4),
2247     CLmethod("all"),
2248     Backmethod("grey"),
2249     Tilesmethod("full"),
2250     daubcoeffmethod("4_"),
2251     CHmethod("without"),
2252     Medgreinf("less"),
2253     CHSLmethod("SL"),
2254     EDmethod("CU"),
2255     NPmethod("none"),
2256     BAmethod("none"),
2257     TMmethod("cont"),
2258     Dirmethod("all"),
2259     HSmethod("with"),
2260     rescon(0),
2261     resconH(0),
2262     reschro(0),
2263     tmrs(0),
2264     gamma(1),
2265     sup(0),
2266     sky(0.0),
2267     thres(7),
2268     chroma(5),
2269     chro(0),
2270     threshold(5),
2271     threshold2(4),
2272     edgedetect(90),
2273     edgedetectthr(20),
2274     edgedetectthr2(0),
2275     edgesensi(60),
2276     edgeampli(10),
2277     contrast(0),
2278     edgrad(15),
2279     edgval(0),
2280     edgthresh(10),
2281     thr(35),
2282     thrH(65),
2283     skinprotect(0.0),
2284     hueskin(-5, 25, 170, 120, false),
2285     hueskin2(-260, -250, -130, -140, false),
2286     hllev(50, 75, 100, 98, false),
2287     bllev(0, 2, 50, 25, false),
2288     pastlev(0, 2, 30, 20, false),
2289     satlev(30, 45, 130, 100, false),
2290     edgcont(0, 10, 75, 40, false),
2291     level0noise(0, 0, false),
2292     level1noise(0, 0, false),
2293     level2noise(0, 0, false),
2294     level3noise(0, 0, false)
2295 {
2296 }
2297 
operator ==(const WaveletParams & other) const2298 bool WaveletParams::operator ==(const WaveletParams& other) const
2299 {
2300     return
2301         ccwcurve == other.ccwcurve
2302         && opacityCurveRG == other.opacityCurveRG
2303         && opacityCurveBY == other.opacityCurveBY
2304         && opacityCurveW == other.opacityCurveW
2305         && opacityCurveWL == other.opacityCurveWL
2306         && hhcurve == other.hhcurve
2307         && Chcurve == other.Chcurve
2308         && wavclCurve == other.wavclCurve
2309         && enabled == other.enabled
2310         && median == other.median
2311         && medianlev == other.medianlev
2312         && linkedg == other.linkedg
2313         && cbenab == other.cbenab
2314         && greenlow == other.greenlow
2315         && bluelow == other.bluelow
2316         && greenmed == other.greenmed
2317         && bluemed == other.bluemed
2318         && greenhigh == other.greenhigh
2319         && bluehigh == other.bluehigh
2320         && lipst == other.lipst
2321         && avoid == other.avoid
2322         && tmr == other.tmr
2323         && strength == other.strength
2324         && balance == other.balance
2325         && iter == other.iter
2326         && expcontrast == other.expcontrast
2327         && expchroma == other.expchroma
2328         && [this, &other]() -> bool
2329             {
2330                 for (unsigned int i = 0; i < 9; ++i) {
2331                     if (c[i] != other.c[i] || ch[i] != other.ch[i]) {
2332                         return false;
2333                     }
2334                 }
2335                 return true;
2336             }()
2337         && expedge == other.expedge
2338         && expresid == other.expresid
2339         && expfinal == other.expfinal
2340         && exptoning == other.exptoning
2341         && expnoise == other.expnoise
2342         && Lmethod == other.Lmethod
2343         && CLmethod == other.CLmethod
2344         && Backmethod == other.Backmethod
2345         && Tilesmethod == other.Tilesmethod
2346         && daubcoeffmethod == other.daubcoeffmethod
2347         && CHmethod == other.CHmethod
2348         && Medgreinf == other.Medgreinf
2349         && CHSLmethod == other.CHSLmethod
2350         && EDmethod == other.EDmethod
2351         && NPmethod == other.NPmethod
2352         && BAmethod == other.BAmethod
2353         && TMmethod == other.TMmethod
2354         && Dirmethod == other.Dirmethod
2355         && HSmethod == other.HSmethod
2356         && rescon == other.rescon
2357         && resconH == other.resconH
2358         && reschro == other.reschro
2359         && tmrs == other.tmrs
2360         && gamma == other.gamma
2361         && sup == other.sup
2362         && sky == other.sky
2363         && thres == other.thres
2364         && chroma == other.chroma
2365         && chro == other.chro
2366         && threshold == other.threshold
2367         && threshold2 == other.threshold2
2368         && edgedetect == other.edgedetect
2369         && edgedetectthr == other.edgedetectthr
2370         && edgedetectthr2 == other.edgedetectthr2
2371         && edgesensi == other.edgesensi
2372         && edgeampli == other.edgeampli
2373         && contrast == other.contrast
2374         && edgrad == other.edgrad
2375         && edgval == other.edgval
2376         && edgthresh == other.edgthresh
2377         && thr == other.thr
2378         && thrH == other.thrH
2379         && skinprotect == other.skinprotect
2380         && hueskin == other.hueskin
2381         && hueskin2 == other.hueskin2
2382         && hllev == other.hllev
2383         && bllev == other.bllev
2384         && pastlev == other.pastlev
2385         && satlev == other.satlev
2386         && edgcont == other.edgcont
2387         && level0noise == other.level0noise
2388         && level1noise == other.level1noise
2389         && level2noise == other.level2noise
2390         && level3noise == other.level3noise;
2391 }
2392 
operator !=(const WaveletParams & other) const2393 bool WaveletParams::operator !=(const WaveletParams& other) const
2394 {
2395     return !(*this == other);
2396 }
2397 
getCurves(WavCurve & cCurve,WavOpacityCurveRG & opacityCurveLUTRG,WavOpacityCurveBY & opacityCurveLUTBY,WavOpacityCurveW & opacityCurveLUTW,WavOpacityCurveWL & opacityCurveLUTWL) const2398 void WaveletParams::getCurves(
2399     WavCurve& cCurve,
2400     WavOpacityCurveRG& opacityCurveLUTRG,
2401     WavOpacityCurveBY& opacityCurveLUTBY,
2402     WavOpacityCurveW& opacityCurveLUTW,
2403     WavOpacityCurveWL& opacityCurveLUTWL
2404 ) const
2405 {
2406     cCurve.Set(this->ccwcurve);
2407     opacityCurveLUTRG.Set(this->opacityCurveRG);
2408     opacityCurveLUTBY.Set(this->opacityCurveBY);
2409     opacityCurveLUTW.Set(this->opacityCurveW);
2410     opacityCurveLUTWL.Set(this->opacityCurveWL);
2411 
2412 }
2413 
DirPyrEqualizerParams()2414 DirPyrEqualizerParams::DirPyrEqualizerParams() :
2415     enabled(false),
2416     gamutlab(false),
2417     mult{
2418         1.0,
2419         1.0,
2420         1.0,
2421         1.0,
2422         1.0,
2423         1.0
2424     },
2425     threshold(0.2),
2426     skinprotect(0.0),
2427     hueskin (-5, 25, 170, 120, false),
2428     cbdlMethod("bef")
2429 {
2430 }
2431 
operator ==(const DirPyrEqualizerParams & other) const2432 bool DirPyrEqualizerParams::operator ==(const DirPyrEqualizerParams& other) const
2433 {
2434     return
2435         enabled == other.enabled
2436         && gamutlab == other.gamutlab
2437         && [this, &other]() -> bool
2438             {
2439                 for (unsigned int i = 0; i < 6; ++i) {
2440                     if (mult[i] != other.mult[i]) {
2441                         return false;
2442                     }
2443                 }
2444                 return true;
2445             }()
2446         && threshold == other.threshold
2447         && skinprotect == other.skinprotect
2448         && hueskin == other.hueskin
2449         && cbdlMethod == other.cbdlMethod;
2450 }
2451 
operator !=(const DirPyrEqualizerParams & other) const2452 bool DirPyrEqualizerParams::operator !=(const DirPyrEqualizerParams& other) const
2453 {
2454     return !(*this == other);
2455 }
2456 
HSVEqualizerParams()2457 HSVEqualizerParams::HSVEqualizerParams() :
2458     enabled(false),
2459     hcurve{
2460         FCT_Linear
2461     },
2462     scurve{
2463         FCT_Linear
2464     },
2465     vcurve{
2466         FCT_Linear
2467     }
2468 {
2469 }
2470 
operator ==(const HSVEqualizerParams & other) const2471 bool HSVEqualizerParams::operator ==(const HSVEqualizerParams& other) const
2472 {
2473     return
2474         enabled == other.enabled
2475         && hcurve == other.hcurve
2476         && scurve == other.scurve
2477         && vcurve == other.vcurve;
2478 }
2479 
operator !=(const HSVEqualizerParams & other) const2480 bool HSVEqualizerParams::operator !=(const HSVEqualizerParams& other) const
2481 {
2482     return !(*this == other);
2483 }
2484 
FilmSimulationParams()2485 FilmSimulationParams::FilmSimulationParams() :
2486     enabled(false),
2487     strength(100)
2488 {
2489 }
2490 
operator ==(const FilmSimulationParams & other) const2491 bool FilmSimulationParams::operator ==(const FilmSimulationParams& other) const
2492 {
2493     return
2494         enabled == other.enabled
2495         && clutFilename == other.clutFilename
2496         && strength == other.strength;
2497 }
2498 
operator !=(const FilmSimulationParams & other) const2499 bool FilmSimulationParams::operator !=(const FilmSimulationParams& other) const
2500 {
2501     return !(*this == other);
2502 }
2503 
2504 
SoftLightParams()2505 SoftLightParams::SoftLightParams() :
2506     enabled(false),
2507     strength(30)
2508 {
2509 }
2510 
operator ==(const SoftLightParams & other) const2511 bool SoftLightParams::operator ==(const SoftLightParams& other) const
2512 {
2513     return
2514         enabled == other.enabled
2515         && strength == other.strength;
2516 }
2517 
operator !=(const SoftLightParams & other) const2518 bool SoftLightParams::operator !=(const SoftLightParams& other) const
2519 {
2520     return !(*this == other);
2521 }
2522 
2523 
DehazeParams()2524 DehazeParams::DehazeParams() :
2525     enabled(false),
2526     strength(50),
2527     showDepthMap(false),
2528     depth(25),
2529     luminance(false)
2530 {
2531 }
2532 
operator ==(const DehazeParams & other) const2533 bool DehazeParams::operator ==(const DehazeParams& other) const
2534 {
2535     return
2536         enabled == other.enabled
2537         && strength == other.strength
2538         && showDepthMap == other.showDepthMap
2539         && depth == other.depth
2540         && luminance == other.luminance;
2541 }
2542 
operator !=(const DehazeParams & other) const2543 bool DehazeParams::operator !=(const DehazeParams& other) const
2544 {
2545     return !(*this == other);
2546 }
2547 
2548 
BayerSensor()2549 RAWParams::BayerSensor::BayerSensor() :
2550     method(getMethodString(Method::AMAZE)),
2551     border(4),
2552     imageNum(0),
2553     ccSteps(0),
2554     black0(0.0),
2555     black1(0.0),
2556     black2(0.0),
2557     black3(0.0),
2558     twogreen(true),
2559     linenoise(0),
2560     linenoiseDirection(LineNoiseDirection::BOTH),
2561     greenthresh(0),
2562     dcb_iterations(2),
2563     lmmse_iterations(2),
2564     dualDemosaicAutoContrast(true),
2565     dualDemosaicContrast(20),
2566     pixelShiftMotionCorrectionMethod(PSMotionCorrectionMethod::AUTO),
2567     pixelShiftEperIso(0.0),
2568     pixelShiftSigma(1.0),
2569     pixelShiftShowMotion(false),
2570     pixelShiftShowMotionMaskOnly(false),
2571     pixelShiftHoleFill(true),
2572     pixelShiftMedian(false),
2573     pixelShiftGreen(true),
2574     pixelShiftBlur(true),
2575     pixelShiftSmoothFactor(0.7),
2576     pixelShiftEqualBright(false),
2577     pixelShiftEqualBrightChannel(false),
2578     pixelShiftNonGreenCross(true),
2579     pixelShiftDemosaicMethod(getPSDemosaicMethodString(PSDemosaicMethod::AMAZE)),
2580     dcb_enhance(true),
2581     pdafLinesFilter(false)
2582 {
2583 }
2584 
operator ==(const BayerSensor & other) const2585 bool RAWParams::BayerSensor::operator ==(const BayerSensor& other) const
2586 {
2587     return
2588         method == other.method
2589         && border == other.border
2590         && imageNum == other.imageNum
2591         && ccSteps == other.ccSteps
2592         && black0 == other.black0
2593         && black1 == other.black1
2594         && black2 == other.black2
2595         && black3 == other.black3
2596         && twogreen == other.twogreen
2597         && linenoise == other.linenoise
2598         && linenoiseDirection == other.linenoiseDirection
2599         && greenthresh == other.greenthresh
2600         && dcb_iterations == other.dcb_iterations
2601         && lmmse_iterations == other.lmmse_iterations
2602         && dualDemosaicAutoContrast == other.dualDemosaicAutoContrast
2603         && dualDemosaicContrast == other.dualDemosaicContrast
2604         && pixelShiftMotionCorrectionMethod == other.pixelShiftMotionCorrectionMethod
2605         && pixelShiftEperIso == other.pixelShiftEperIso
2606         && pixelShiftSigma == other.pixelShiftSigma
2607         && pixelShiftShowMotion == other.pixelShiftShowMotion
2608         && pixelShiftShowMotionMaskOnly == other.pixelShiftShowMotionMaskOnly
2609         && pixelShiftHoleFill == other.pixelShiftHoleFill
2610         && pixelShiftMedian == other.pixelShiftMedian
2611         && pixelShiftGreen == other.pixelShiftGreen
2612         && pixelShiftBlur == other.pixelShiftBlur
2613         && pixelShiftSmoothFactor == other.pixelShiftSmoothFactor
2614         && pixelShiftEqualBright == other.pixelShiftEqualBright
2615         && pixelShiftEqualBrightChannel == other.pixelShiftEqualBrightChannel
2616         && pixelShiftNonGreenCross == other.pixelShiftNonGreenCross
2617         && pixelShiftDemosaicMethod == other.pixelShiftDemosaicMethod
2618         && dcb_enhance == other.dcb_enhance
2619         && pdafLinesFilter == other.pdafLinesFilter;
2620 }
2621 
operator !=(const BayerSensor & other) const2622 bool RAWParams::BayerSensor::operator !=(const BayerSensor& other) const
2623 {
2624     return !(*this == other);
2625 }
2626 
setPixelShiftDefaults()2627 void RAWParams::BayerSensor::setPixelShiftDefaults()
2628 {
2629     pixelShiftMotionCorrectionMethod = RAWParams::BayerSensor::PSMotionCorrectionMethod::AUTO;
2630     pixelShiftEperIso = 0.0;
2631     pixelShiftSigma = 1.0;
2632     pixelShiftHoleFill = true;
2633     pixelShiftMedian = false;
2634     pixelShiftGreen = true;
2635     pixelShiftBlur = true;
2636     pixelShiftSmoothFactor = 0.7;
2637     pixelShiftEqualBright = false;
2638     pixelShiftEqualBrightChannel = false;
2639     pixelShiftNonGreenCross = true;
2640     pixelShiftDemosaicMethod = getPSDemosaicMethodString(PSDemosaicMethod::AMAZE);
2641 }
2642 
getMethodStrings()2643 const std::vector<const char*>& RAWParams::BayerSensor::getMethodStrings()
2644 {
2645     static const std::vector<const char*> method_strings {
2646         "amaze",
2647         "amazevng4",
2648         "rcd",
2649         "rcdvng4",
2650         "dcb",
2651         "dcbvng4",
2652         "lmmse",
2653         "igv",
2654         "ahd",
2655         "eahd",
2656         "hphd",
2657         "vng4",
2658         "fast",
2659         "mono",
2660         "pixelshift",
2661         "none"
2662     };
2663     return method_strings;
2664 }
2665 
getMethodString(Method method)2666 Glib::ustring RAWParams::BayerSensor::getMethodString(Method method)
2667 {
2668     return getMethodStrings()[toUnderlying(method)];
2669 }
2670 
getPSDemosaicMethodStrings()2671 const std::vector<const char*>& RAWParams::BayerSensor::getPSDemosaicMethodStrings()
2672 {
2673     static const std::vector<const char*> method_strings {
2674         "amaze",
2675         "amazevng4",
2676         "rcdvng4",
2677         "lmmse"
2678     };
2679     return method_strings;
2680 }
2681 
getPSDemosaicMethodString(PSDemosaicMethod method)2682 Glib::ustring RAWParams::BayerSensor::getPSDemosaicMethodString(PSDemosaicMethod method)
2683 {
2684     return getPSDemosaicMethodStrings()[toUnderlying(method)];
2685 }
2686 
2687 
2688 
XTransSensor()2689 RAWParams::XTransSensor::XTransSensor() :
2690     method(getMethodString(Method::THREE_PASS)),
2691     dualDemosaicAutoContrast(true),
2692     dualDemosaicContrast(20),
2693     border(7),
2694     ccSteps(0),
2695     blackred(0.0),
2696     blackgreen(0.0),
2697     blackblue(0.0)
2698 {
2699 }
2700 
operator ==(const XTransSensor & other) const2701 bool RAWParams::XTransSensor::operator ==(const XTransSensor& other) const
2702 {
2703     return
2704         method == other.method
2705         && dualDemosaicAutoContrast == other.dualDemosaicAutoContrast
2706         && dualDemosaicContrast == other.dualDemosaicContrast
2707         && border == other.border
2708         && ccSteps == other.ccSteps
2709         && blackred == other.blackred
2710         && blackgreen == other.blackgreen
2711         && blackblue == other.blackblue;
2712 }
2713 
operator !=(const XTransSensor & other) const2714 bool RAWParams::XTransSensor::operator !=(const XTransSensor& other) const
2715 {
2716     return !(*this == other);
2717 }
2718 
getMethodStrings()2719 const std::vector<const char*>& RAWParams::XTransSensor::getMethodStrings()
2720 {
2721     static const std::vector<const char*> method_strings {
2722         "4-pass",
2723         "3-pass (best)",
2724         "2-pass",
2725         "1-pass (medium)",
2726         "fast",
2727         "mono",
2728         "none"
2729     };
2730     return method_strings;
2731 }
2732 
getMethodString(Method method)2733 Glib::ustring RAWParams::XTransSensor::getMethodString(Method method)
2734 {
2735     return getMethodStrings()[toUnderlying(method)];
2736 }
2737 
RAWParams()2738 RAWParams::RAWParams() :
2739     df_autoselect(false),
2740     ff_AutoSelect(false),
2741     ff_BlurRadius(32),
2742     ff_BlurType(getFlatFieldBlurTypeString(FlatFieldBlurType::AREA)),
2743     ff_AutoClipControl(false),
2744     ff_clipControl(0),
2745     ca_autocorrect(false),
2746     ca_avoidcolourshift(true),
2747     caautoiterations(2),
2748     cared(0.0),
2749     cablue(0.0),
2750     expos(1.0),
2751     hotPixelFilter(false),
2752     deadPixelFilter(false),
2753     hotdeadpix_thresh(100)
2754 {
2755 }
2756 
operator ==(const RAWParams & other) const2757 bool RAWParams::operator ==(const RAWParams& other) const
2758 {
2759     return
2760         bayersensor == other.bayersensor
2761         && xtranssensor == other.xtranssensor
2762         && dark_frame == other.dark_frame
2763         && df_autoselect == other.df_autoselect
2764         && ff_file == other.ff_file
2765         && ff_AutoSelect == other.ff_AutoSelect
2766         && ff_BlurRadius == other.ff_BlurRadius
2767         && ff_BlurType == other.ff_BlurType
2768         && ff_AutoClipControl == other.ff_AutoClipControl
2769         && ff_clipControl == other.ff_clipControl
2770         && ca_autocorrect == other.ca_autocorrect
2771         && ca_avoidcolourshift == other.ca_avoidcolourshift
2772         && caautoiterations == other.caautoiterations
2773         && cared == other.cared
2774         && cablue == other.cablue
2775         && expos == other.expos
2776         && hotPixelFilter == other.hotPixelFilter
2777         && deadPixelFilter == other.deadPixelFilter
2778         && hotdeadpix_thresh == other.hotdeadpix_thresh;
2779 }
2780 
operator !=(const RAWParams & other) const2781 bool RAWParams::operator !=(const RAWParams& other) const
2782 {
2783     return !(*this == other);
2784 }
2785 
getFlatFieldBlurTypeStrings()2786 const std::vector<const char*>& RAWParams::getFlatFieldBlurTypeStrings()
2787 {
2788     static const std::vector<const char*> blur_type_strings {
2789         "Area Flatfield",
2790         "Vertical Flatfield",
2791         "Horizontal Flatfield",
2792         "V+H Flatfield"
2793     };
2794     return blur_type_strings;
2795 }
2796 
getFlatFieldBlurTypeString(FlatFieldBlurType type)2797 Glib::ustring RAWParams::getFlatFieldBlurTypeString(FlatFieldBlurType type)
2798 {
2799     return getFlatFieldBlurTypeStrings()[toUnderlying(type)];
2800 }
2801 
2802 
MetaDataParams()2803 MetaDataParams::MetaDataParams():
2804     mode(MetaDataParams::TUNNEL)
2805 {
2806 }
2807 
operator ==(const MetaDataParams & other) const2808 bool MetaDataParams::operator==(const MetaDataParams &other) const
2809 {
2810     return mode == other.mode;
2811 }
2812 
operator !=(const MetaDataParams & other) const2813 bool MetaDataParams::operator!=(const MetaDataParams &other) const
2814 {
2815     return !(*this == other);
2816 }
2817 
FilmNegativeParams()2818 FilmNegativeParams::FilmNegativeParams() :
2819     enabled(false),
2820     redRatio(1.36),
2821     greenExp(1.5),
2822     blueRatio(0.86)
2823 {
2824 }
2825 
operator ==(const FilmNegativeParams & other) const2826 bool FilmNegativeParams::operator ==(const FilmNegativeParams& other) const
2827 {
2828     return
2829         enabled == other.enabled
2830         && redRatio   == other.redRatio
2831         && greenExp == other.greenExp
2832         && blueRatio  == other.blueRatio;
2833 }
2834 
operator !=(const FilmNegativeParams & other) const2835 bool FilmNegativeParams::operator !=(const FilmNegativeParams& other) const
2836 {
2837     return !(*this == other);
2838 }
2839 
ProcParams()2840 ProcParams::ProcParams()
2841 {
2842     setDefaults();
2843 }
2844 
setDefaults()2845 void ProcParams::setDefaults()
2846 {
2847     toneCurve = {};
2848 
2849     labCurve = {};
2850 
2851     rgbCurves = {};
2852 
2853     localContrast = {};
2854 
2855     colorToning = {};
2856 
2857     sharpenEdge = {};
2858 
2859     sharpenMicro = {};
2860 
2861     sharpening = {};
2862 
2863     prsharpening = {};
2864     prsharpening.contrast = 15.0;
2865     prsharpening.method = "rld";
2866     prsharpening.deconvamount = 100;
2867     prsharpening.deconvradius = 0.45;
2868     prsharpening.deconviter = 100;
2869     prsharpening.deconvdamping = 0;
2870 
2871     pdsharpening = {};
2872 
2873     vibrance = {};
2874 
2875     wb = {};
2876 
2877     colorappearance = {};
2878 
2879     defringe = {};
2880 
2881     impulseDenoise = {};
2882 
2883     dirpyrDenoise = {};
2884 
2885     epd = {};
2886 
2887     fattal = {};
2888 
2889     sh = {};
2890 
2891     crop = {};
2892 
2893     coarse = {};
2894 
2895     commonTrans = {};
2896 
2897     rotate = {};
2898 
2899     distortion = {};
2900 
2901     lensProf = {};
2902 
2903     perspective = {};
2904 
2905     gradient = {};
2906 
2907     pcvignette = {};
2908 
2909     vignetting = {};
2910 
2911     chmixer = {};
2912 
2913     blackwhite = {};
2914 
2915     cacorrection = {};
2916 
2917     resize = {};
2918 
2919     icm = {};
2920 
2921     wavelet = {};
2922 
2923     dirpyrequalizer = {};
2924 
2925     hsvequalizer = {};
2926 
2927     filmSimulation = {};
2928 
2929     softlight = {};
2930 
2931     dehaze = {};
2932 
2933     raw = {};
2934 
2935     metadata = {};
2936     exif.clear();
2937     iptc.clear();
2938 
2939     // -1 means that there's no pp3 data with rank yet. In this case, the
2940     // embedded Rating metadata should take precedence. -1 should never be
2941     // written to pp3 on disk.
2942     rank = -1;
2943     colorlabel = 0;
2944     inTrash = false;
2945 
2946     ppVersion = PPVERSION;
2947 }
2948 
save(const Glib::ustring & fname,const Glib::ustring & fname2,bool fnameAbsolute,ParamsEdited * pedited)2949 int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bool fnameAbsolute, ParamsEdited* pedited)
2950 {
2951     if (fname.empty() && fname2.empty()) {
2952         return 0;
2953     }
2954 
2955     Glib::ustring sPParams;
2956 
2957     try {
2958         Glib::KeyFile keyFile;
2959 
2960 // Version
2961         keyFile.set_string("Version", "AppVersion", RTVERSION);
2962         keyFile.set_integer("Version", "Version", PPVERSION);
2963 
2964         saveToKeyfile(!pedited || pedited->general.rank, "General", "Rank", rank, keyFile);
2965         saveToKeyfile(!pedited || pedited->general.colorlabel, "General", "ColorLabel", colorlabel, keyFile);
2966         saveToKeyfile(!pedited || pedited->general.intrash, "General", "InTrash", inTrash, keyFile);
2967 
2968 // Tone curve
2969         saveToKeyfile(!pedited || pedited->toneCurve.autoexp, "Exposure", "Auto", toneCurve.autoexp, keyFile);
2970         saveToKeyfile(!pedited || pedited->toneCurve.clip, "Exposure", "Clip", toneCurve.clip, keyFile);
2971         saveToKeyfile(!pedited || pedited->toneCurve.expcomp, "Exposure", "Compensation", toneCurve.expcomp, keyFile);
2972         saveToKeyfile(!pedited || pedited->toneCurve.brightness, "Exposure", "Brightness", toneCurve.brightness, keyFile);
2973         saveToKeyfile(!pedited || pedited->toneCurve.contrast, "Exposure", "Contrast", toneCurve.contrast, keyFile);
2974         saveToKeyfile(!pedited || pedited->toneCurve.saturation, "Exposure", "Saturation", toneCurve.saturation, keyFile);
2975         saveToKeyfile(!pedited || pedited->toneCurve.black, "Exposure", "Black", toneCurve.black, keyFile);
2976         saveToKeyfile(!pedited || pedited->toneCurve.hlcompr, "Exposure", "HighlightCompr", toneCurve.hlcompr, keyFile);
2977         saveToKeyfile(!pedited || pedited->toneCurve.hlcomprthresh, "Exposure", "HighlightComprThreshold", toneCurve.hlcomprthresh, keyFile);
2978         saveToKeyfile(!pedited || pedited->toneCurve.shcompr, "Exposure", "ShadowCompr", toneCurve.shcompr, keyFile);
2979         saveToKeyfile(!pedited || pedited->toneCurve.histmatching, "Exposure", "HistogramMatching", toneCurve.histmatching, keyFile);
2980         saveToKeyfile(!pedited || pedited->toneCurve.fromHistMatching, "Exposure", "CurveFromHistogramMatching", toneCurve.fromHistMatching, keyFile);
2981         saveToKeyfile(!pedited || pedited->toneCurve.clampOOG, "Exposure", "ClampOOG", toneCurve.clampOOG, keyFile);
2982 
2983 // Highlight recovery
2984         saveToKeyfile(!pedited || pedited->toneCurve.hrenabled, "HLRecovery", "Enabled", toneCurve.hrenabled, keyFile);
2985         saveToKeyfile(!pedited || pedited->toneCurve.method, "HLRecovery", "Method", toneCurve.method, keyFile);
2986 
2987         const std::map<ToneCurveMode, const char*> tc_mapping = {
2988             {ToneCurveMode::STD, "Standard"},
2989             {ToneCurveMode::FILMLIKE, "FilmLike"},
2990             {ToneCurveMode::SATANDVALBLENDING, "SatAndValueBlending"},
2991             {ToneCurveMode::WEIGHTEDSTD, "WeightedStd"},
2992             {ToneCurveMode::LUMINANCE, "Luminance"},
2993             {ToneCurveMode::PERCEPTUAL, "Perceptual"}
2994         };
2995 
2996         saveToKeyfile(!pedited || pedited->toneCurve.curveMode, "Exposure", "CurveMode", tc_mapping, toneCurve.curveMode, keyFile);
2997         saveToKeyfile(!pedited || pedited->toneCurve.curveMode2, "Exposure", "CurveMode2", tc_mapping, toneCurve.curveMode2, keyFile);
2998 
2999         saveToKeyfile(!pedited || pedited->toneCurve.curve, "Exposure", "Curve", toneCurve.curve, keyFile);
3000         saveToKeyfile(!pedited || pedited->toneCurve.curve2, "Exposure", "Curve2", toneCurve.curve2, keyFile);
3001 
3002 // Retinex
3003         saveToKeyfile(!pedited || pedited->retinex.enabled, "Retinex", "Enabled", retinex.enabled, keyFile);
3004         saveToKeyfile(!pedited || pedited->retinex.str, "Retinex", "Str", retinex.str, keyFile);
3005         saveToKeyfile(!pedited || pedited->retinex.scal, "Retinex", "Scal", retinex.scal, keyFile);
3006         saveToKeyfile(!pedited || pedited->retinex.iter, "Retinex", "Iter", retinex.iter, keyFile);
3007         saveToKeyfile(!pedited || pedited->retinex.grad, "Retinex", "Grad", retinex.grad, keyFile);
3008         saveToKeyfile(!pedited || pedited->retinex.grads, "Retinex", "Grads", retinex.grads, keyFile);
3009         saveToKeyfile(!pedited || pedited->retinex.gam, "Retinex", "Gam", retinex.gam, keyFile);
3010         saveToKeyfile(!pedited || pedited->retinex.slope, "Retinex", "Slope", retinex.slope, keyFile);
3011         saveToKeyfile(!pedited || pedited->retinex.medianmap, "Retinex", "Median", retinex.medianmap, keyFile);
3012 
3013         saveToKeyfile(!pedited || pedited->retinex.neigh, "Retinex", "Neigh", retinex.neigh, keyFile);
3014         saveToKeyfile(!pedited || pedited->retinex.offs, "Retinex", "Offs", retinex.offs, keyFile);
3015         saveToKeyfile(!pedited || pedited->retinex.vart, "Retinex", "Vart", retinex.vart, keyFile);
3016         saveToKeyfile(!pedited || pedited->retinex.limd, "Retinex", "Limd", retinex.limd, keyFile);
3017         saveToKeyfile(!pedited || pedited->retinex.highl, "Retinex", "highl", retinex.highl, keyFile);
3018         saveToKeyfile(!pedited || pedited->retinex.skal, "Retinex", "skal", retinex.skal, keyFile);
3019         saveToKeyfile(!pedited || pedited->retinex.retinexMethod, "Retinex", "RetinexMethod", retinex.retinexMethod, keyFile);
3020         saveToKeyfile(!pedited || pedited->retinex.mapMethod, "Retinex", "mapMethod", retinex.mapMethod, keyFile);
3021         saveToKeyfile(!pedited || pedited->retinex.viewMethod, "Retinex", "viewMethod", retinex.viewMethod, keyFile);
3022         saveToKeyfile(!pedited || pedited->retinex.retinexcolorspace, "Retinex", "Retinexcolorspace", retinex.retinexcolorspace, keyFile);
3023         saveToKeyfile(!pedited || pedited->retinex.gammaretinex, "Retinex", "Gammaretinex", retinex.gammaretinex, keyFile);
3024         saveToKeyfile(!pedited || pedited->retinex.cdcurve, "Retinex", "CDCurve", retinex.cdcurve, keyFile);
3025         saveToKeyfile(!pedited || pedited->retinex.mapcurve, "Retinex", "MAPCurve", retinex.mapcurve, keyFile);
3026         saveToKeyfile(!pedited || pedited->retinex.cdHcurve, "Retinex", "CDHCurve", retinex.cdHcurve, keyFile);
3027         saveToKeyfile(!pedited || pedited->retinex.lhcurve, "Retinex", "LHCurve", retinex.lhcurve, keyFile);
3028         saveToKeyfile(!pedited || pedited->retinex.highlights, "Retinex", "Highlights", retinex.highlights, keyFile);
3029         saveToKeyfile(!pedited || pedited->retinex.htonalwidth, "Retinex", "HighlightTonalWidth", retinex.htonalwidth, keyFile);
3030         saveToKeyfile(!pedited || pedited->retinex.shadows, "Retinex", "Shadows", retinex.shadows, keyFile);
3031         saveToKeyfile(!pedited || pedited->retinex.stonalwidth, "Retinex", "ShadowTonalWidth", retinex.stonalwidth, keyFile);
3032         saveToKeyfile(!pedited || pedited->retinex.radius, "Retinex", "Radius", retinex.radius, keyFile);
3033         saveToKeyfile(!pedited || pedited->retinex.transmissionCurve, "Retinex", "TransmissionCurve", retinex.transmissionCurve, keyFile);
3034         saveToKeyfile(!pedited || pedited->retinex.gaintransmissionCurve, "Retinex", "GainTransmissionCurve", retinex.gaintransmissionCurve, keyFile);
3035 
3036 // Local contrast
3037         saveToKeyfile(!pedited || pedited->localContrast.enabled, "Local Contrast", "Enabled", localContrast.enabled, keyFile);
3038         saveToKeyfile(!pedited || pedited->localContrast.radius, "Local Contrast", "Radius", localContrast.radius, keyFile);
3039         saveToKeyfile(!pedited || pedited->localContrast.amount, "Local Contrast", "Amount", localContrast.amount, keyFile);
3040         saveToKeyfile(!pedited || pedited->localContrast.darkness, "Local Contrast", "Darkness", localContrast.darkness, keyFile);
3041         saveToKeyfile(!pedited || pedited->localContrast.lightness, "Local Contrast", "Lightness", localContrast.lightness, keyFile);
3042 
3043 
3044 // Channel mixer
3045         saveToKeyfile(!pedited || pedited->chmixer.enabled, "Channel Mixer", "Enabled", chmixer.enabled, keyFile);
3046 
3047         if (!pedited || pedited->chmixer.red[0] || pedited->chmixer.red[1] || pedited->chmixer.red[2]) {
3048             Glib::ArrayHandle<int> rmix(chmixer.red, 3, Glib::OWNERSHIP_NONE);
3049             keyFile.set_integer_list("Channel Mixer", "Red", rmix);
3050         }
3051 
3052         if (!pedited || pedited->chmixer.green[0] || pedited->chmixer.green[1] || pedited->chmixer.green[2]) {
3053             Glib::ArrayHandle<int> gmix(chmixer.green, 3, Glib::OWNERSHIP_NONE);
3054             keyFile.set_integer_list("Channel Mixer", "Green", gmix);
3055         }
3056 
3057         if (!pedited || pedited->chmixer.blue[0] || pedited->chmixer.blue[1] || pedited->chmixer.blue[2]) {
3058             Glib::ArrayHandle<int> bmix(chmixer.blue, 3, Glib::OWNERSHIP_NONE);
3059             keyFile.set_integer_list("Channel Mixer", "Blue", bmix);
3060         }
3061 
3062 // Black & White
3063         saveToKeyfile(!pedited || pedited->blackwhite.enabled, "Black & White", "Enabled", blackwhite.enabled, keyFile);
3064         saveToKeyfile(!pedited || pedited->blackwhite.method, "Black & White", "Method", blackwhite.method, keyFile);
3065         saveToKeyfile(!pedited || pedited->blackwhite.autoc, "Black & White", "Auto", blackwhite.autoc, keyFile);
3066         saveToKeyfile(!pedited || pedited->blackwhite.enabledcc, "Black & White", "ComplementaryColors", blackwhite.enabledcc, keyFile);
3067         saveToKeyfile(!pedited || pedited->blackwhite.setting, "Black & White", "Setting", blackwhite.setting, keyFile);
3068         saveToKeyfile(!pedited || pedited->blackwhite.filter, "Black & White", "Filter", blackwhite.filter, keyFile);
3069         saveToKeyfile(!pedited || pedited->blackwhite.mixerRed, "Black & White", "MixerRed", blackwhite.mixerRed, keyFile);
3070         saveToKeyfile(!pedited || pedited->blackwhite.mixerOrange, "Black & White", "MixerOrange", blackwhite.mixerOrange, keyFile);
3071         saveToKeyfile(!pedited || pedited->blackwhite.mixerYellow, "Black & White", "MixerYellow", blackwhite.mixerYellow, keyFile);
3072         saveToKeyfile(!pedited || pedited->blackwhite.mixerGreen, "Black & White", "MixerGreen", blackwhite.mixerGreen, keyFile);
3073         saveToKeyfile(!pedited || pedited->blackwhite.mixerCyan, "Black & White", "MixerCyan", blackwhite.mixerCyan, keyFile);
3074         saveToKeyfile(!pedited || pedited->blackwhite.mixerBlue, "Black & White", "MixerBlue", blackwhite.mixerBlue, keyFile);
3075         saveToKeyfile(!pedited || pedited->blackwhite.mixerMagenta, "Black & White", "MixerMagenta", blackwhite.mixerMagenta, keyFile);
3076         saveToKeyfile(!pedited || pedited->blackwhite.mixerPurple, "Black & White", "MixerPurple", blackwhite.mixerPurple, keyFile);
3077         saveToKeyfile(!pedited || pedited->blackwhite.gammaRed, "Black & White", "GammaRed", blackwhite.gammaRed, keyFile);
3078         saveToKeyfile(!pedited || pedited->blackwhite.gammaGreen, "Black & White", "GammaGreen", blackwhite.gammaGreen, keyFile);
3079         saveToKeyfile(!pedited || pedited->blackwhite.gammaBlue, "Black & White", "GammaBlue", blackwhite.gammaBlue, keyFile);
3080         saveToKeyfile(!pedited || pedited->blackwhite.algo, "Black & White", "Algorithm", blackwhite.algo, keyFile);
3081         saveToKeyfile(!pedited || pedited->blackwhite.luminanceCurve, "Black & White", "LuminanceCurve", blackwhite.luminanceCurve, keyFile);
3082         saveToKeyfile(
3083             !pedited || pedited->blackwhite.beforeCurveMode,
3084             "Black & White",
3085             "BeforeCurveMode",
3086             {
3087                 {BlackWhiteParams::TcMode::STD_BW, "Standard"},
3088                 {BlackWhiteParams::TcMode::FILMLIKE_BW, "FilmLike"},
3089                 {BlackWhiteParams::TcMode::SATANDVALBLENDING_BW, "SatAndValueBlending"},
3090                 {BlackWhiteParams::TcMode::WEIGHTEDSTD_BW, "WeightedStd"}
3091 
3092             },
3093             blackwhite.beforeCurveMode,
3094             keyFile
3095         );
3096         saveToKeyfile(
3097             !pedited || pedited->blackwhite.afterCurveMode,
3098             "Black & White",
3099             "AfterCurveMode",
3100             {
3101                 {BlackWhiteParams::TcMode::STD_BW, "Standard"},
3102                 {BlackWhiteParams::TcMode::WEIGHTEDSTD_BW, "WeightedStd"}
3103 
3104             },
3105             blackwhite.afterCurveMode,
3106             keyFile
3107         );
3108         saveToKeyfile(!pedited || pedited->blackwhite.beforeCurve, "Black & White", "BeforeCurve", blackwhite.beforeCurve, keyFile);
3109         saveToKeyfile(!pedited || pedited->blackwhite.afterCurve, "Black & White", "AfterCurve", blackwhite.afterCurve, keyFile);
3110 
3111 // Luma curve
3112         saveToKeyfile(!pedited || pedited->labCurve.enabled, "Luminance Curve", "Enabled", labCurve.enabled, keyFile);
3113         saveToKeyfile(!pedited || pedited->labCurve.brightness, "Luminance Curve", "Brightness", labCurve.brightness, keyFile);
3114         saveToKeyfile(!pedited || pedited->labCurve.contrast, "Luminance Curve", "Contrast", labCurve.contrast, keyFile);
3115         saveToKeyfile(!pedited || pedited->labCurve.chromaticity, "Luminance Curve", "Chromaticity", labCurve.chromaticity, keyFile);
3116         saveToKeyfile(!pedited || pedited->labCurve.avoidcolorshift, "Luminance Curve", "AvoidColorShift", labCurve.avoidcolorshift, keyFile);
3117         saveToKeyfile(!pedited || pedited->labCurve.rstprotection, "Luminance Curve", "RedAndSkinTonesProtection", labCurve.rstprotection, keyFile);
3118         saveToKeyfile(!pedited || pedited->labCurve.lcredsk, "Luminance Curve", "LCredsk", labCurve.lcredsk, keyFile);
3119         saveToKeyfile(!pedited || pedited->labCurve.lcurve, "Luminance Curve", "LCurve", labCurve.lcurve, keyFile);
3120         saveToKeyfile(!pedited || pedited->labCurve.acurve, "Luminance Curve", "aCurve", labCurve.acurve, keyFile);
3121         saveToKeyfile(!pedited || pedited->labCurve.bcurve, "Luminance Curve", "bCurve", labCurve.bcurve, keyFile);
3122         saveToKeyfile(!pedited || pedited->labCurve.cccurve, "Luminance Curve", "ccCurve", labCurve.cccurve, keyFile);
3123         saveToKeyfile(!pedited || pedited->labCurve.chcurve, "Luminance Curve", "chCurve", labCurve.chcurve, keyFile);
3124         saveToKeyfile(!pedited || pedited->labCurve.lhcurve, "Luminance Curve", "lhCurve", labCurve.lhcurve, keyFile);
3125         saveToKeyfile(!pedited || pedited->labCurve.hhcurve, "Luminance Curve", "hhCurve", labCurve.hhcurve, keyFile);
3126         saveToKeyfile(!pedited || pedited->labCurve.lccurve, "Luminance Curve", "LcCurve", labCurve.lccurve, keyFile);
3127         saveToKeyfile(!pedited || pedited->labCurve.clcurve, "Luminance Curve", "ClCurve", labCurve.clcurve, keyFile);
3128 
3129 // Sharpening
3130         saveToKeyfile(!pedited || pedited->sharpening.enabled, "Sharpening", "Enabled", sharpening.enabled, keyFile);
3131         saveToKeyfile(!pedited || pedited->sharpening.contrast, "Sharpening", "Contrast", sharpening.contrast, keyFile);
3132         saveToKeyfile(!pedited || pedited->sharpening.method, "Sharpening", "Method", sharpening.method, keyFile);
3133         saveToKeyfile(!pedited || pedited->sharpening.radius, "Sharpening", "Radius", sharpening.radius, keyFile);
3134         saveToKeyfile(!pedited || pedited->sharpening.blurradius, "Sharpening", "BlurRadius", sharpening.blurradius, keyFile);
3135         saveToKeyfile(!pedited || pedited->sharpening.amount, "Sharpening", "Amount", sharpening.amount, keyFile);
3136         saveToKeyfile(!pedited || pedited->sharpening.threshold, "Sharpening", "Threshold", sharpening.threshold.toVector(), keyFile);
3137         saveToKeyfile(!pedited || pedited->sharpening.edgesonly, "Sharpening", "OnlyEdges", sharpening.edgesonly, keyFile);
3138         saveToKeyfile(!pedited || pedited->sharpening.edges_radius, "Sharpening", "EdgedetectionRadius", sharpening.edges_radius, keyFile);
3139         saveToKeyfile(!pedited || pedited->sharpening.edges_tolerance, "Sharpening", "EdgeTolerance", sharpening.edges_tolerance, keyFile);
3140         saveToKeyfile(!pedited || pedited->sharpening.halocontrol, "Sharpening", "HalocontrolEnabled", sharpening.halocontrol, keyFile);
3141         saveToKeyfile(!pedited || pedited->sharpening.halocontrol_amount, "Sharpening", "HalocontrolAmount", sharpening.halocontrol_amount, keyFile);
3142         saveToKeyfile(!pedited || pedited->sharpening.deconvradius, "Sharpening", "DeconvRadius", sharpening.deconvradius, keyFile);
3143         saveToKeyfile(!pedited || pedited->sharpening.deconvamount, "Sharpening", "DeconvAmount", sharpening.deconvamount, keyFile);
3144         saveToKeyfile(!pedited || pedited->sharpening.deconvdamping, "Sharpening", "DeconvDamping", sharpening.deconvdamping, keyFile);
3145         saveToKeyfile(!pedited || pedited->sharpening.deconviter, "Sharpening", "DeconvIterations", sharpening.deconviter, keyFile);
3146 
3147 // Vibrance
3148         saveToKeyfile(!pedited || pedited->vibrance.enabled, "Vibrance", "Enabled", vibrance.enabled, keyFile);
3149         saveToKeyfile(!pedited || pedited->vibrance.pastels, "Vibrance", "Pastels", vibrance.pastels, keyFile);
3150         saveToKeyfile(!pedited || pedited->vibrance.saturated, "Vibrance", "Saturated", vibrance.saturated, keyFile);
3151         saveToKeyfile(!pedited || pedited->vibrance.psthreshold, "Vibrance", "PSThreshold", vibrance.psthreshold.toVector(), keyFile);
3152         saveToKeyfile(!pedited || pedited->vibrance.protectskins, "Vibrance", "ProtectSkins", vibrance.protectskins, keyFile);
3153         saveToKeyfile(!pedited || pedited->vibrance.avoidcolorshift, "Vibrance", "AvoidColorShift", vibrance.avoidcolorshift, keyFile);
3154         saveToKeyfile(!pedited || pedited->vibrance.pastsattog, "Vibrance", "PastSatTog", vibrance.pastsattog, keyFile);
3155         saveToKeyfile(!pedited || pedited->vibrance.skintonescurve, "Vibrance", "SkinTonesCurve", vibrance.skintonescurve, keyFile);
3156 
3157 // Edge sharpening
3158         saveToKeyfile(!pedited || pedited->sharpenEdge.enabled, "SharpenEdge", "Enabled", sharpenEdge.enabled, keyFile);
3159         saveToKeyfile(!pedited || pedited->sharpenEdge.passes, "SharpenEdge", "Passes", sharpenEdge.passes, keyFile);
3160         saveToKeyfile(!pedited || pedited->sharpenEdge.amount, "SharpenEdge", "Strength", sharpenEdge.amount, keyFile);
3161         saveToKeyfile(!pedited || pedited->sharpenEdge.threechannels, "SharpenEdge", "ThreeChannels", sharpenEdge.threechannels, keyFile);
3162 
3163 // Micro-contrast sharpening
3164         saveToKeyfile(!pedited || pedited->sharpenMicro.enabled, "SharpenMicro", "Enabled", sharpenMicro.enabled, keyFile);
3165         saveToKeyfile(!pedited || pedited->sharpenMicro.matrix, "SharpenMicro", "Matrix", sharpenMicro.matrix, keyFile);
3166         saveToKeyfile(!pedited || pedited->sharpenMicro.amount, "SharpenMicro", "Strength", sharpenMicro.amount, keyFile);
3167         saveToKeyfile(!pedited || pedited->sharpenMicro.contrast, "SharpenMicro", "Contrast", sharpenMicro.contrast, keyFile);
3168         saveToKeyfile(!pedited || pedited->sharpenMicro.uniformity, "SharpenMicro", "Uniformity", sharpenMicro.uniformity, keyFile);
3169 
3170 // WB
3171         saveToKeyfile(!pedited || pedited->wb.enabled, "White Balance", "Enabled", wb.enabled, keyFile);
3172         saveToKeyfile(!pedited || pedited->wb.method, "White Balance", "Setting", wb.method, keyFile);
3173         saveToKeyfile(!pedited || pedited->wb.temperature, "White Balance", "Temperature", wb.temperature, keyFile);
3174         saveToKeyfile(!pedited || pedited->wb.green, "White Balance", "Green", wb.green, keyFile);
3175         saveToKeyfile(!pedited || pedited->wb.equal, "White Balance", "Equal", wb.equal, keyFile);
3176         saveToKeyfile(!pedited || pedited->wb.tempBias, "White Balance", "TemperatureBias", wb.tempBias, keyFile);
3177 
3178 // Colorappearance
3179         saveToKeyfile(!pedited || pedited->colorappearance.enabled, "Color appearance", "Enabled", colorappearance.enabled, keyFile);
3180         saveToKeyfile(!pedited || pedited->colorappearance.degree, "Color appearance", "Degree", colorappearance.degree, keyFile);
3181         saveToKeyfile(!pedited || pedited->colorappearance.autodegree, "Color appearance", "AutoDegree", colorappearance.autodegree, keyFile);
3182         saveToKeyfile(!pedited || pedited->colorappearance.degreeout, "Color appearance", "Degreeout",        colorappearance.degreeout, keyFile);
3183         saveToKeyfile(!pedited || pedited->colorappearance.autodegreeout, "Color appearance", "AutoDegreeout",    colorappearance.autodegreeout, keyFile);
3184         saveToKeyfile(!pedited || pedited->colorappearance.surround, "Color appearance", "Surround", colorappearance.surround, keyFile);
3185         saveToKeyfile(!pedited || pedited->colorappearance.surrsrc, "Color appearance", "Surrsrc", colorappearance.surrsrc, keyFile);
3186         saveToKeyfile(!pedited || pedited->colorappearance.adaplum, "Color appearance", "AdaptLum", colorappearance.adaplum, keyFile);
3187         saveToKeyfile(!pedited || pedited->colorappearance.badpixsl, "Color appearance", "Badpixsl", colorappearance.badpixsl, keyFile);
3188         saveToKeyfile(!pedited || pedited->colorappearance.wbmodel, "Color appearance", "Model", colorappearance.wbmodel, keyFile);
3189         saveToKeyfile(!pedited || pedited->colorappearance.algo, "Color appearance", "Algorithm", colorappearance.algo, keyFile);
3190         saveToKeyfile(!pedited || pedited->colorappearance.jlight, "Color appearance", "J-Light", colorappearance.jlight, keyFile);
3191         saveToKeyfile(!pedited || pedited->colorappearance.qbright, "Color appearance", "Q-Bright", colorappearance.qbright, keyFile);
3192         saveToKeyfile(!pedited || pedited->colorappearance.chroma, "Color appearance", "C-Chroma", colorappearance.chroma, keyFile);
3193         saveToKeyfile(!pedited || pedited->colorappearance.schroma, "Color appearance", "S-Chroma", colorappearance.schroma, keyFile);
3194         saveToKeyfile(!pedited || pedited->colorappearance.mchroma, "Color appearance", "M-Chroma", colorappearance.mchroma, keyFile);
3195         saveToKeyfile(!pedited || pedited->colorappearance.contrast, "Color appearance", "J-Contrast", colorappearance.contrast, keyFile);
3196         saveToKeyfile(!pedited || pedited->colorappearance.qcontrast, "Color appearance", "Q-Contrast", colorappearance.qcontrast, keyFile);
3197         saveToKeyfile(!pedited || pedited->colorappearance.colorh, "Color appearance", "H-Hue", colorappearance.colorh, keyFile);
3198         saveToKeyfile(!pedited || pedited->colorappearance.rstprotection, "Color appearance", "RSTProtection", colorappearance.rstprotection, keyFile);
3199         saveToKeyfile(!pedited || pedited->colorappearance.adapscen, "Color appearance", "AdaptScene", colorappearance.adapscen, keyFile);
3200         saveToKeyfile(!pedited || pedited->colorappearance.autoadapscen, "Color appearance", "AutoAdapscen", colorappearance.autoadapscen, keyFile);
3201         saveToKeyfile(!pedited || pedited->colorappearance.ybscen, "Color appearance", "YbScene", colorappearance.ybscen, keyFile);
3202         saveToKeyfile(!pedited || pedited->colorappearance.autoybscen, "Color appearance", "Autoybscen", colorappearance.autoybscen, keyFile);
3203         saveToKeyfile(!pedited || pedited->colorappearance.surrsource, "Color appearance", "SurrSource", colorappearance.surrsource, keyFile);
3204         saveToKeyfile(!pedited || pedited->colorappearance.gamut, "Color appearance", "Gamut", colorappearance.gamut, keyFile);
3205         saveToKeyfile(!pedited || pedited->colorappearance.tempout, "Color appearance", "Tempout", colorappearance.tempout, keyFile);
3206         saveToKeyfile(!pedited || pedited->colorappearance.greenout, "Color appearance", "Greenout", colorappearance.greenout, keyFile);
3207         saveToKeyfile(!pedited || pedited->colorappearance.tempsc, "Color appearance", "Tempsc", colorappearance.tempsc, keyFile);
3208         saveToKeyfile(!pedited || pedited->colorappearance.greensc, "Color appearance", "Greensc", colorappearance.greensc, keyFile);
3209         saveToKeyfile(!pedited || pedited->colorappearance.ybout, "Color appearance", "Ybout", colorappearance.ybout, keyFile);
3210         saveToKeyfile(!pedited || pedited->colorappearance.datacie, "Color appearance", "Datacie", colorappearance.datacie, keyFile);
3211         saveToKeyfile(!pedited || pedited->colorappearance.tonecie, "Color appearance", "Tonecie", colorappearance.tonecie, keyFile);
3212 
3213         const std::map<ColorAppearanceParams::TcMode, const char*> ca_mapping = {
3214             {ColorAppearanceParams::TcMode::LIGHT, "Lightness"},
3215             {ColorAppearanceParams::TcMode::BRIGHT, "Brightness"}
3216         };
3217 
3218         saveToKeyfile(!pedited || pedited->colorappearance.curveMode, "Color appearance", "CurveMode", ca_mapping, colorappearance.curveMode, keyFile);
3219         saveToKeyfile(!pedited || pedited->colorappearance.curveMode2, "Color appearance", "CurveMode2", ca_mapping, colorappearance.curveMode2, keyFile);
3220         saveToKeyfile(
3221             !pedited || pedited->colorappearance.curveMode3,
3222             "Color appearance",
3223             "CurveMode3",
3224             {
3225                 {ColorAppearanceParams::CtcMode::CHROMA, "Chroma"},
3226                 {ColorAppearanceParams::CtcMode::SATUR, "Saturation"},
3227                 {ColorAppearanceParams::CtcMode::COLORF, "Colorfullness"}
3228 
3229             },
3230             colorappearance.curveMode3,
3231             keyFile
3232         );
3233         saveToKeyfile(!pedited || pedited->colorappearance.curve, "Color appearance", "Curve", colorappearance.curve, keyFile);
3234         saveToKeyfile(!pedited || pedited->colorappearance.curve2, "Color appearance", "Curve2", colorappearance.curve2, keyFile);
3235         saveToKeyfile(!pedited || pedited->colorappearance.curve3, "Color appearance", "Curve3", colorappearance.curve3, keyFile);
3236 
3237 // Impulse denoise
3238         saveToKeyfile(!pedited || pedited->impulseDenoise.enabled, "Impulse Denoising", "Enabled", impulseDenoise.enabled, keyFile);
3239         saveToKeyfile(!pedited || pedited->impulseDenoise.thresh, "Impulse Denoising", "Threshold", impulseDenoise.thresh, keyFile);
3240 
3241 // Defringe
3242         saveToKeyfile(!pedited || pedited->defringe.enabled, "Defringing", "Enabled", defringe.enabled, keyFile);
3243         saveToKeyfile(!pedited || pedited->defringe.radius, "Defringing", "Radius", defringe.radius, keyFile);
3244         saveToKeyfile(!pedited || pedited->defringe.threshold, "Defringing", "Threshold", defringe.threshold, keyFile);
3245         saveToKeyfile(!pedited || pedited->defringe.huecurve, "Defringing", "HueCurve", defringe.huecurve, keyFile);
3246 
3247 // Dehaze
3248         saveToKeyfile(!pedited || pedited->dehaze.enabled, "Dehaze", "Enabled", dehaze.enabled, keyFile);
3249         saveToKeyfile(!pedited || pedited->dehaze.strength, "Dehaze", "Strength", dehaze.strength, keyFile);
3250         saveToKeyfile(!pedited || pedited->dehaze.showDepthMap, "Dehaze", "ShowDepthMap", dehaze.showDepthMap, keyFile);
3251         saveToKeyfile(!pedited || pedited->dehaze.depth, "Dehaze", "Depth", dehaze.depth, keyFile);
3252         saveToKeyfile(!pedited || pedited->dehaze.depth, "Dehaze", "Luminance", dehaze.luminance, keyFile);
3253 
3254 // Directional pyramid denoising
3255         saveToKeyfile(!pedited || pedited->dirpyrDenoise.enabled, "Directional Pyramid Denoising", "Enabled", dirpyrDenoise.enabled, keyFile);
3256         saveToKeyfile(!pedited || pedited->dirpyrDenoise.enhance, "Directional Pyramid Denoising", "Enhance", dirpyrDenoise.enhance, keyFile);
3257         saveToKeyfile(!pedited || pedited->dirpyrDenoise.median, "Directional Pyramid Denoising", "Median", dirpyrDenoise.median, keyFile);
3258         saveToKeyfile(!pedited || pedited->dirpyrDenoise.luma, "Directional Pyramid Denoising", "Luma", dirpyrDenoise.luma, keyFile);
3259         saveToKeyfile(!pedited || pedited->dirpyrDenoise.Ldetail, "Directional Pyramid Denoising", "Ldetail", dirpyrDenoise.Ldetail, keyFile);
3260         saveToKeyfile(!pedited || pedited->dirpyrDenoise.chroma, "Directional Pyramid Denoising", "Chroma", dirpyrDenoise.chroma, keyFile);
3261         saveToKeyfile(!pedited || pedited->dirpyrDenoise.dmethod, "Directional Pyramid Denoising", "Method", dirpyrDenoise.dmethod, keyFile);
3262         saveToKeyfile(!pedited || pedited->dirpyrDenoise.Lmethod, "Directional Pyramid Denoising", "LMethod", dirpyrDenoise.Lmethod, keyFile);
3263 
3264         if (dirpyrDenoise.Cmethod == "PRE") {
3265             dirpyrDenoise.Cmethod = "MAN"; // Never save 'auto chroma preview mode' to pp3
3266         }
3267 
3268         saveToKeyfile(!pedited || pedited->dirpyrDenoise.Cmethod, "Directional Pyramid Denoising", "CMethod", dirpyrDenoise.Cmethod, keyFile);
3269 
3270         if (dirpyrDenoise.C2method == "PREV") {
3271             dirpyrDenoise.C2method = "MANU";
3272         }
3273 
3274         saveToKeyfile(!pedited || pedited->dirpyrDenoise.C2method, "Directional Pyramid Denoising", "C2Method", dirpyrDenoise.C2method, keyFile);
3275         saveToKeyfile(!pedited || pedited->dirpyrDenoise.smethod, "Directional Pyramid Denoising", "SMethod", dirpyrDenoise.smethod, keyFile);
3276         saveToKeyfile(!pedited || pedited->dirpyrDenoise.medmethod, "Directional Pyramid Denoising", "MedMethod", dirpyrDenoise.medmethod, keyFile);
3277         saveToKeyfile(!pedited || pedited->dirpyrDenoise.rgbmethod, "Directional Pyramid Denoising", "RGBMethod", dirpyrDenoise.rgbmethod, keyFile);
3278         saveToKeyfile(!pedited || pedited->dirpyrDenoise.methodmed, "Directional Pyramid Denoising", "MethodMed", dirpyrDenoise.methodmed, keyFile);
3279         saveToKeyfile(!pedited || pedited->dirpyrDenoise.redchro, "Directional Pyramid Denoising", "Redchro", dirpyrDenoise.redchro, keyFile);
3280         saveToKeyfile(!pedited || pedited->dirpyrDenoise.bluechro, "Directional Pyramid Denoising", "Bluechro", dirpyrDenoise.bluechro, keyFile);
3281         saveToKeyfile(!pedited || pedited->dirpyrDenoise.gamma, "Directional Pyramid Denoising", "Gamma", dirpyrDenoise.gamma, keyFile);
3282         saveToKeyfile(!pedited || pedited->dirpyrDenoise.passes, "Directional Pyramid Denoising", "Passes", dirpyrDenoise.passes, keyFile);
3283         saveToKeyfile(!pedited || pedited->dirpyrDenoise.lcurve, "Directional Pyramid Denoising", "LCurve", dirpyrDenoise.lcurve, keyFile);
3284         saveToKeyfile(!pedited || pedited->dirpyrDenoise.cccurve, "Directional Pyramid Denoising", "CCCurve", dirpyrDenoise.cccurve, keyFile);
3285 
3286 // EPD
3287         saveToKeyfile(!pedited || pedited->epd.enabled, "EPD", "Enabled", epd.enabled, keyFile);
3288         saveToKeyfile(!pedited || pedited->epd.strength, "EPD", "Strength", epd.strength, keyFile);
3289         saveToKeyfile(!pedited || pedited->epd.gamma, "EPD", "Gamma", epd.gamma, keyFile);
3290         saveToKeyfile(!pedited || pedited->epd.edgeStopping, "EPD", "EdgeStopping", epd.edgeStopping, keyFile);
3291         saveToKeyfile(!pedited || pedited->epd.scale, "EPD", "Scale", epd.scale, keyFile);
3292         saveToKeyfile(!pedited || pedited->epd.reweightingIterates, "EPD", "ReweightingIterates", epd.reweightingIterates, keyFile);
3293 
3294 // Fattal
3295         saveToKeyfile(!pedited || pedited->fattal.enabled, "FattalToneMapping", "Enabled", fattal.enabled, keyFile);
3296         saveToKeyfile(!pedited || pedited->fattal.threshold, "FattalToneMapping", "Threshold", fattal.threshold, keyFile);
3297         saveToKeyfile(!pedited || pedited->fattal.amount, "FattalToneMapping", "Amount", fattal.amount, keyFile);
3298         saveToKeyfile(!pedited || pedited->fattal.anchor, "FattalToneMapping", "Anchor", fattal.anchor, keyFile);
3299 
3300 // Shadows & highlights
3301         saveToKeyfile(!pedited || pedited->sh.enabled, "Shadows & Highlights", "Enabled", sh.enabled, keyFile);
3302         saveToKeyfile(!pedited || pedited->sh.highlights, "Shadows & Highlights", "Highlights", sh.highlights, keyFile);
3303         saveToKeyfile(!pedited || pedited->sh.htonalwidth, "Shadows & Highlights", "HighlightTonalWidth", sh.htonalwidth, keyFile);
3304         saveToKeyfile(!pedited || pedited->sh.shadows, "Shadows & Highlights", "Shadows", sh.shadows, keyFile);
3305         saveToKeyfile(!pedited || pedited->sh.stonalwidth, "Shadows & Highlights", "ShadowTonalWidth", sh.stonalwidth, keyFile);
3306         saveToKeyfile(!pedited || pedited->sh.radius, "Shadows & Highlights", "Radius", sh.radius, keyFile);
3307         saveToKeyfile(!pedited || pedited->sh.lab, "Shadows & Highlights", "Lab", sh.lab, keyFile);
3308 
3309 // Crop
3310         saveToKeyfile(!pedited || pedited->crop.enabled, "Crop", "Enabled", crop.enabled, keyFile);
3311         saveToKeyfile(!pedited || pedited->crop.x, "Crop", "X", crop.x, keyFile);
3312         saveToKeyfile(!pedited || pedited->crop.y, "Crop", "Y", crop.y, keyFile);
3313         saveToKeyfile(!pedited || pedited->crop.w, "Crop", "W", crop.w, keyFile);
3314         saveToKeyfile(!pedited || pedited->crop.h, "Crop", "H", crop.h, keyFile);
3315         saveToKeyfile(!pedited || pedited->crop.fixratio, "Crop", "FixedRatio", crop.fixratio, keyFile);
3316         saveToKeyfile(!pedited || pedited->crop.ratio, "Crop", "Ratio", crop.ratio, keyFile);
3317         saveToKeyfile(!pedited || pedited->crop.orientation, "Crop", "Orientation", crop.orientation, keyFile);
3318         saveToKeyfile(!pedited || pedited->crop.guide, "Crop", "Guide", crop.guide, keyFile);
3319 
3320 // Coarse transformation
3321         saveToKeyfile(!pedited || pedited->coarse.rotate, "Coarse Transformation", "Rotate", coarse.rotate, keyFile);
3322         saveToKeyfile(!pedited || pedited->coarse.hflip, "Coarse Transformation", "HorizontalFlip", coarse.hflip, keyFile);
3323         saveToKeyfile(!pedited || pedited->coarse.vflip, "Coarse Transformation", "VerticalFlip", coarse.vflip, keyFile);
3324 
3325 // Common properties for transformations
3326         saveToKeyfile(!pedited || pedited->commonTrans.method, "Common Properties for Transformations", "Method", commonTrans.method, keyFile);
3327         saveToKeyfile(!pedited || pedited->commonTrans.autofill, "Common Properties for Transformations", "AutoFill", commonTrans.autofill, keyFile);
3328 
3329 // Rotation
3330         saveToKeyfile(!pedited || pedited->rotate.degree, "Rotation", "Degree", rotate.degree, keyFile);
3331 
3332 // Distortion
3333         saveToKeyfile(!pedited || pedited->distortion.amount, "Distortion", "Amount", distortion.amount, keyFile);
3334 
3335 // Lens profile
3336         saveToKeyfile(!pedited || pedited->lensProf.lcMode, "LensProfile", "LcMode", lensProf.getMethodString(lensProf.lcMode), keyFile);
3337         saveToKeyfile(!pedited || pedited->lensProf.lcpFile, "LensProfile", "LCPFile", relativePathIfInside(fname, fnameAbsolute, lensProf.lcpFile), keyFile);
3338         saveToKeyfile(!pedited || pedited->lensProf.useDist, "LensProfile", "UseDistortion", lensProf.useDist, keyFile);
3339         saveToKeyfile(!pedited || pedited->lensProf.useVign, "LensProfile", "UseVignette", lensProf.useVign, keyFile);
3340         saveToKeyfile(!pedited || pedited->lensProf.useCA, "LensProfile", "UseCA", lensProf.useCA, keyFile);
3341         saveToKeyfile(!pedited || pedited->lensProf.lfCameraMake, "LensProfile", "LFCameraMake", lensProf.lfCameraMake, keyFile);
3342         saveToKeyfile(!pedited || pedited->lensProf.lfCameraModel, "LensProfile", "LFCameraModel", lensProf.lfCameraModel, keyFile);
3343         saveToKeyfile(!pedited || pedited->lensProf.lfLens, "LensProfile", "LFLens", lensProf.lfLens, keyFile);
3344 
3345 // Perspective correction
3346         saveToKeyfile(!pedited || pedited->perspective.horizontal, "Perspective", "Horizontal", perspective.horizontal, keyFile);
3347         saveToKeyfile(!pedited || pedited->perspective.vertical, "Perspective", "Vertical", perspective.vertical, keyFile);
3348 
3349 // Gradient
3350         saveToKeyfile(!pedited || pedited->gradient.enabled, "Gradient", "Enabled", gradient.enabled, keyFile);
3351         saveToKeyfile(!pedited || pedited->gradient.degree, "Gradient", "Degree", gradient.degree, keyFile);
3352         saveToKeyfile(!pedited || pedited->gradient.feather, "Gradient", "Feather", gradient.feather, keyFile);
3353         saveToKeyfile(!pedited || pedited->gradient.strength, "Gradient", "Strength", gradient.strength, keyFile);
3354         saveToKeyfile(!pedited || pedited->gradient.centerX, "Gradient", "CenterX", gradient.centerX, keyFile);
3355         saveToKeyfile(!pedited || pedited->gradient.centerY, "Gradient", "CenterY", gradient.centerY, keyFile);
3356 
3357 // Post-crop vignette
3358         saveToKeyfile(!pedited || pedited->pcvignette.enabled, "PCVignette", "Enabled", pcvignette.enabled, keyFile);
3359         saveToKeyfile(!pedited || pedited->pcvignette.strength, "PCVignette", "Strength", pcvignette.strength, keyFile);
3360         saveToKeyfile(!pedited || pedited->pcvignette.feather, "PCVignette", "Feather", pcvignette.feather, keyFile);
3361         saveToKeyfile(!pedited || pedited->pcvignette.roundness, "PCVignette", "Roundness", pcvignette.roundness, keyFile);
3362 
3363 // C/A correction
3364         saveToKeyfile(!pedited || pedited->cacorrection.red, "CACorrection", "Red", cacorrection.red, keyFile);
3365         saveToKeyfile(!pedited || pedited->cacorrection.blue, "CACorrection", "Blue", cacorrection.blue, keyFile);
3366 
3367 // Vignetting correction
3368         saveToKeyfile(!pedited || pedited->vignetting.amount, "Vignetting Correction", "Amount", vignetting.amount, keyFile);
3369         saveToKeyfile(!pedited || pedited->vignetting.radius, "Vignetting Correction", "Radius", vignetting.radius, keyFile);
3370         saveToKeyfile(!pedited || pedited->vignetting.strength, "Vignetting Correction", "Strength", vignetting.strength, keyFile);
3371         saveToKeyfile(!pedited || pedited->vignetting.centerX, "Vignetting Correction", "CenterX", vignetting.centerX, keyFile);
3372         saveToKeyfile(!pedited || pedited->vignetting.centerY, "Vignetting Correction", "CenterY", vignetting.centerY, keyFile);
3373 
3374 // Resize
3375         saveToKeyfile(!pedited || pedited->resize.enabled, "Resize", "Enabled", resize.enabled, keyFile);
3376         saveToKeyfile(!pedited || pedited->resize.scale, "Resize", "Scale", resize.scale, keyFile);
3377         saveToKeyfile(!pedited || pedited->resize.appliesTo, "Resize", "AppliesTo", resize.appliesTo, keyFile);
3378         saveToKeyfile(!pedited || pedited->resize.method, "Resize", "Method", resize.method, keyFile);
3379         saveToKeyfile(!pedited || pedited->resize.dataspec, "Resize", "DataSpecified", resize.dataspec, keyFile);
3380         saveToKeyfile(!pedited || pedited->resize.width, "Resize", "Width", resize.width, keyFile);
3381         saveToKeyfile(!pedited || pedited->resize.height, "Resize", "Height", resize.height, keyFile);
3382         saveToKeyfile(!pedited || pedited->resize.allowUpscaling, "Resize", "AllowUpscaling", resize.allowUpscaling, keyFile);
3383 
3384 // Post demosaic sharpening
3385         saveToKeyfile(!pedited || pedited->pdsharpening.enabled, "PostDemosaicSharpening", "Enabled", pdsharpening.enabled, keyFile);
3386         saveToKeyfile(!pedited || pedited->pdsharpening.contrast, "PostDemosaicSharpening", "Contrast", pdsharpening.contrast, keyFile);
3387         saveToKeyfile(!pedited || pedited->pdsharpening.autoContrast, "PostDemosaicSharpening", "AutoContrast", pdsharpening.autoContrast, keyFile);
3388         saveToKeyfile(!pedited || pedited->pdsharpening.autoRadius, "PostDemosaicSharpening", "AutoRadius", pdsharpening.autoRadius, keyFile);
3389         saveToKeyfile(!pedited || pedited->pdsharpening.deconvradius, "PostDemosaicSharpening", "DeconvRadius", pdsharpening.deconvradius, keyFile);
3390         saveToKeyfile(!pedited || pedited->pdsharpening.deconvradiusOffset, "PostDemosaicSharpening", "DeconvRadiusOffset", pdsharpening.deconvradiusOffset, keyFile);
3391         saveToKeyfile(!pedited || pedited->pdsharpening.deconvitercheck, "PostDemosaicSharpening", "DeconvIterCheck", pdsharpening.deconvitercheck, keyFile);
3392         saveToKeyfile(!pedited || pedited->pdsharpening.deconviter, "PostDemosaicSharpening", "DeconvIterations", pdsharpening.deconviter, keyFile);
3393 
3394 // Post resize sharpening
3395         saveToKeyfile(!pedited || pedited->prsharpening.enabled, "PostResizeSharpening", "Enabled", prsharpening.enabled, keyFile);
3396         saveToKeyfile(!pedited || pedited->prsharpening.contrast, "PostResizeSharpening", "Contrast", prsharpening.contrast, keyFile);
3397         saveToKeyfile(!pedited || pedited->prsharpening.method, "PostResizeSharpening", "Method", prsharpening.method, keyFile);
3398         saveToKeyfile(!pedited || pedited->prsharpening.radius, "PostResizeSharpening", "Radius", prsharpening.radius, keyFile);
3399         saveToKeyfile(!pedited || pedited->prsharpening.amount, "PostResizeSharpening", "Amount", prsharpening.amount, keyFile);
3400         saveToKeyfile(!pedited || pedited->prsharpening.threshold, "PostResizeSharpening", "Threshold", prsharpening.threshold.toVector(), keyFile);
3401         saveToKeyfile(!pedited || pedited->prsharpening.edgesonly, "PostResizeSharpening", "OnlyEdges", prsharpening.edgesonly, keyFile);
3402         saveToKeyfile(!pedited || pedited->prsharpening.edges_radius, "PostResizeSharpening", "EdgedetectionRadius", prsharpening.edges_radius, keyFile);
3403         saveToKeyfile(!pedited || pedited->prsharpening.edges_tolerance, "PostResizeSharpening", "EdgeTolerance", prsharpening.edges_tolerance, keyFile);
3404         saveToKeyfile(!pedited || pedited->prsharpening.halocontrol, "PostResizeSharpening", "HalocontrolEnabled", prsharpening.halocontrol, keyFile);
3405         saveToKeyfile(!pedited || pedited->prsharpening.halocontrol_amount, "PostResizeSharpening", "HalocontrolAmount", prsharpening.halocontrol_amount, keyFile);
3406         saveToKeyfile(!pedited || pedited->prsharpening.deconvradius, "PostResizeSharpening", "DeconvRadius", prsharpening.deconvradius, keyFile);
3407         saveToKeyfile(!pedited || pedited->prsharpening.deconvamount, "PostResizeSharpening", "DeconvAmount", prsharpening.deconvamount, keyFile);
3408         saveToKeyfile(!pedited || pedited->prsharpening.deconvdamping, "PostResizeSharpening", "DeconvDamping", prsharpening.deconvdamping, keyFile);
3409         saveToKeyfile(!pedited || pedited->prsharpening.deconviter, "PostResizeSharpening", "DeconvIterations", prsharpening.deconviter, keyFile);
3410 
3411 // Color management
3412         saveToKeyfile(!pedited || pedited->icm.inputProfile, "Color Management", "InputProfile", relativePathIfInside(fname, fnameAbsolute, icm.inputProfile), keyFile);
3413         saveToKeyfile(!pedited || pedited->icm.toneCurve, "Color Management", "ToneCurve", icm.toneCurve, keyFile);
3414         saveToKeyfile(!pedited || pedited->icm.applyLookTable, "Color Management", "ApplyLookTable", icm.applyLookTable, keyFile);
3415         saveToKeyfile(!pedited || pedited->icm.applyBaselineExposureOffset, "Color Management", "ApplyBaselineExposureOffset", icm.applyBaselineExposureOffset, keyFile);
3416         saveToKeyfile(!pedited || pedited->icm.applyHueSatMap, "Color Management", "ApplyHueSatMap", icm.applyHueSatMap, keyFile);
3417         saveToKeyfile(!pedited || pedited->icm.dcpIlluminant, "Color Management", "DCPIlluminant", icm.dcpIlluminant, keyFile);
3418         saveToKeyfile(!pedited || pedited->icm.workingProfile, "Color Management", "WorkingProfile", icm.workingProfile, keyFile);
3419         saveToKeyfile(!pedited || pedited->icm.workingTRC, "Color Management", "WorkingTRC", icm.workingTRC, keyFile);
3420         saveToKeyfile(!pedited || pedited->icm.workingTRCGamma, "Color Management", "WorkingTRCGamma", icm.workingTRCGamma, keyFile);
3421         saveToKeyfile(!pedited || pedited->icm.workingTRCSlope, "Color Management", "WorkingTRCSlope", icm.workingTRCSlope, keyFile);
3422         saveToKeyfile(!pedited || pedited->icm.outputProfile, "Color Management", "OutputProfile", icm.outputProfile, keyFile);
3423         saveToKeyfile(
3424             !pedited || pedited->icm.outputIntent,
3425             "Color Management",
3426             "OutputProfileIntent",
3427             {
3428                 {RI_PERCEPTUAL, "Perceptual"},
3429                 {RI_RELATIVE, "Relative"},
3430                 {RI_SATURATION, "Saturation"},
3431                 {RI_ABSOLUTE, "Absolute"}
3432 
3433             },
3434             icm.outputIntent,
3435             keyFile
3436         );
3437         saveToKeyfile(!pedited || pedited->icm.outputBPC, "Color Management", "OutputBPC", icm.outputBPC, keyFile);
3438 
3439 // Wavelet
3440         saveToKeyfile(!pedited || pedited->wavelet.enabled, "Wavelet", "Enabled", wavelet.enabled, keyFile);
3441         saveToKeyfile(!pedited || pedited->wavelet.strength, "Wavelet", "Strength", wavelet.strength, keyFile);
3442         saveToKeyfile(!pedited || pedited->wavelet.balance, "Wavelet", "Balance", wavelet.balance, keyFile);
3443         saveToKeyfile(!pedited || pedited->wavelet.iter, "Wavelet", "Iter", wavelet.iter, keyFile);
3444         saveToKeyfile(!pedited || pedited->wavelet.thres, "Wavelet", "MaxLev", wavelet.thres, keyFile);
3445         saveToKeyfile(!pedited || pedited->wavelet.Tilesmethod, "Wavelet", "TilesMethod", wavelet.Tilesmethod, keyFile);
3446         saveToKeyfile(!pedited || pedited->wavelet.daubcoeffmethod, "Wavelet", "DaubMethod", wavelet.daubcoeffmethod, keyFile);
3447         saveToKeyfile(!pedited || pedited->wavelet.CLmethod, "Wavelet", "ChoiceLevMethod", wavelet.CLmethod, keyFile);
3448         saveToKeyfile(!pedited || pedited->wavelet.Backmethod, "Wavelet", "BackMethod", wavelet.Backmethod, keyFile);
3449         saveToKeyfile(!pedited || pedited->wavelet.Lmethod, "Wavelet", "LevMethod", wavelet.Lmethod, keyFile);
3450         saveToKeyfile(!pedited || pedited->wavelet.Dirmethod, "Wavelet", "DirMethod", wavelet.Dirmethod, keyFile);
3451         saveToKeyfile(!pedited || pedited->wavelet.greenhigh, "Wavelet", "CBgreenhigh", wavelet.greenhigh, keyFile);
3452         saveToKeyfile(!pedited || pedited->wavelet.greenmed, "Wavelet", "CBgreenmed", wavelet.greenmed, keyFile);
3453         saveToKeyfile(!pedited || pedited->wavelet.greenlow, "Wavelet", "CBgreenlow", wavelet.greenlow, keyFile);
3454         saveToKeyfile(!pedited || pedited->wavelet.bluehigh, "Wavelet", "CBbluehigh", wavelet.bluehigh, keyFile);
3455         saveToKeyfile(!pedited || pedited->wavelet.bluemed, "Wavelet", "CBbluemed", wavelet.bluemed, keyFile);
3456         saveToKeyfile(!pedited || pedited->wavelet.bluelow, "Wavelet", "CBbluelow", wavelet.bluelow, keyFile);
3457         saveToKeyfile(!pedited || pedited->wavelet.expcontrast, "Wavelet", "Expcontrast", wavelet.expcontrast, keyFile);
3458         saveToKeyfile(!pedited || pedited->wavelet.expchroma, "Wavelet", "Expchroma", wavelet.expchroma, keyFile);
3459         saveToKeyfile(!pedited || pedited->wavelet.expedge, "Wavelet", "Expedge", wavelet.expedge, keyFile);
3460         saveToKeyfile(!pedited || pedited->wavelet.expresid, "Wavelet", "Expresid", wavelet.expresid, keyFile);
3461         saveToKeyfile(!pedited || pedited->wavelet.expfinal, "Wavelet", "Expfinal", wavelet.expfinal, keyFile);
3462         saveToKeyfile(!pedited || pedited->wavelet.exptoning, "Wavelet", "Exptoning", wavelet.exptoning, keyFile);
3463         saveToKeyfile(!pedited || pedited->wavelet.expnoise, "Wavelet", "Expnoise", wavelet.expnoise, keyFile);
3464 
3465         for (int i = 0; i < 9; i++) {
3466             std::stringstream ss;
3467             ss << "Contrast" << (i + 1);
3468 
3469             saveToKeyfile(!pedited || pedited->wavelet.c[i], "Wavelet", ss.str(), wavelet.c[i], keyFile);
3470         }
3471 
3472         for (int i = 0; i < 9; i++) {
3473             std::stringstream ss;
3474             ss << "Chroma" << (i + 1);
3475 
3476             saveToKeyfile(!pedited || pedited->wavelet.ch[i], "Wavelet", ss.str(), wavelet.ch[i], keyFile);
3477         }
3478 
3479         saveToKeyfile(!pedited || pedited->wavelet.sup, "Wavelet", "ContExtra", wavelet.sup, keyFile);
3480         saveToKeyfile(!pedited || pedited->wavelet.HSmethod, "Wavelet", "HSMethod", wavelet.HSmethod, keyFile);
3481         saveToKeyfile(!pedited || pedited->wavelet.hllev, "Wavelet", "HLRange", wavelet.hllev.toVector(), keyFile);
3482         saveToKeyfile(!pedited || pedited->wavelet.bllev, "Wavelet", "SHRange", wavelet.bllev.toVector(), keyFile);
3483         saveToKeyfile(!pedited || pedited->wavelet.edgcont, "Wavelet", "Edgcont", wavelet.edgcont.toVector(), keyFile);
3484         saveToKeyfile(!pedited || pedited->wavelet.level0noise, "Wavelet", "Level0noise", wavelet.level0noise.toVector(), keyFile);
3485         saveToKeyfile(!pedited || pedited->wavelet.level1noise, "Wavelet", "Level1noise", wavelet.level1noise.toVector(), keyFile);
3486         saveToKeyfile(!pedited || pedited->wavelet.level2noise, "Wavelet", "Level2noise", wavelet.level2noise.toVector(), keyFile);
3487         saveToKeyfile(!pedited || pedited->wavelet.level3noise, "Wavelet", "Level3noise", wavelet.level3noise.toVector(), keyFile);
3488         saveToKeyfile(!pedited || pedited->wavelet.threshold, "Wavelet", "ThresholdHighlight", wavelet.threshold, keyFile);
3489         saveToKeyfile(!pedited || pedited->wavelet.threshold2, "Wavelet", "ThresholdShadow", wavelet.threshold2, keyFile);
3490         saveToKeyfile(!pedited || pedited->wavelet.edgedetect, "Wavelet", "Edgedetect", wavelet.edgedetect, keyFile);
3491         saveToKeyfile(!pedited || pedited->wavelet.edgedetectthr, "Wavelet", "Edgedetectthr", wavelet.edgedetectthr, keyFile);
3492         saveToKeyfile(!pedited || pedited->wavelet.edgedetectthr2, "Wavelet", "EdgedetectthrHi", wavelet.edgedetectthr2, keyFile);
3493         saveToKeyfile(!pedited || pedited->wavelet.edgesensi, "Wavelet", "Edgesensi", wavelet.edgesensi, keyFile);
3494         saveToKeyfile(!pedited || pedited->wavelet.edgeampli, "Wavelet", "Edgeampli", wavelet.edgeampli, keyFile);
3495         saveToKeyfile(!pedited || pedited->wavelet.chroma, "Wavelet", "ThresholdChroma", wavelet.chroma, keyFile);
3496         saveToKeyfile(!pedited || pedited->wavelet.CHmethod, "Wavelet", "CHromaMethod", wavelet.CHmethod, keyFile);
3497         saveToKeyfile(!pedited || pedited->wavelet.Medgreinf, "Wavelet", "Medgreinf", wavelet.Medgreinf, keyFile);
3498         saveToKeyfile(!pedited || pedited->wavelet.CHSLmethod, "Wavelet", "CHSLromaMethod", wavelet.CHSLmethod, keyFile);
3499         saveToKeyfile(!pedited || pedited->wavelet.EDmethod, "Wavelet", "EDMethod", wavelet.EDmethod, keyFile);
3500         saveToKeyfile(!pedited || pedited->wavelet.NPmethod, "Wavelet", "NPMethod", wavelet.NPmethod, keyFile);
3501         saveToKeyfile(!pedited || pedited->wavelet.BAmethod, "Wavelet", "BAMethod", wavelet.BAmethod, keyFile);
3502         saveToKeyfile(!pedited || pedited->wavelet.TMmethod, "Wavelet", "TMMethod", wavelet.TMmethod, keyFile);
3503         saveToKeyfile(!pedited || pedited->wavelet.chro, "Wavelet", "ChromaLink", wavelet.chro, keyFile);
3504         saveToKeyfile(!pedited || pedited->wavelet.ccwcurve, "Wavelet", "ContrastCurve", wavelet.ccwcurve, keyFile);
3505         saveToKeyfile(!pedited || pedited->wavelet.pastlev, "Wavelet", "Pastlev", wavelet.pastlev.toVector(), keyFile);
3506         saveToKeyfile(!pedited || pedited->wavelet.satlev, "Wavelet", "Satlev", wavelet.satlev.toVector(), keyFile);
3507         saveToKeyfile(!pedited || pedited->wavelet.opacityCurveRG, "Wavelet", "OpacityCurveRG", wavelet.opacityCurveRG, keyFile);
3508         saveToKeyfile(!pedited || pedited->wavelet.opacityCurveBY, "Wavelet", "OpacityCurveBY", wavelet.opacityCurveBY, keyFile);
3509         saveToKeyfile(!pedited || pedited->wavelet.opacityCurveW, "Wavelet", "OpacityCurveW", wavelet.opacityCurveW, keyFile);
3510         saveToKeyfile(!pedited || pedited->wavelet.opacityCurveWL, "Wavelet", "OpacityCurveWL", wavelet.opacityCurveWL, keyFile);
3511         saveToKeyfile(!pedited || pedited->wavelet.hhcurve, "Wavelet", "HHcurve", wavelet.hhcurve, keyFile);
3512         saveToKeyfile(!pedited || pedited->wavelet.Chcurve, "Wavelet", "CHcurve", wavelet.Chcurve, keyFile);
3513         saveToKeyfile(!pedited || pedited->wavelet.wavclCurve, "Wavelet", "WavclCurve", wavelet.wavclCurve, keyFile);
3514         saveToKeyfile(!pedited || pedited->wavelet.median, "Wavelet", "Median", wavelet.median, keyFile);
3515         saveToKeyfile(!pedited || pedited->wavelet.medianlev, "Wavelet", "Medianlev", wavelet.medianlev, keyFile);
3516         saveToKeyfile(!pedited || pedited->wavelet.linkedg, "Wavelet", "Linkedg", wavelet.linkedg, keyFile);
3517         saveToKeyfile(!pedited || pedited->wavelet.cbenab, "Wavelet", "CBenab", wavelet.cbenab, keyFile);
3518         saveToKeyfile(!pedited || pedited->wavelet.lipst, "Wavelet", "Lipst", wavelet.lipst, keyFile);
3519         saveToKeyfile(!pedited || pedited->wavelet.skinprotect, "Wavelet", "Skinprotect", wavelet.skinprotect, keyFile);
3520         saveToKeyfile(!pedited || pedited->wavelet.hueskin, "Wavelet", "Hueskin", wavelet.hueskin.toVector(), keyFile);
3521         saveToKeyfile(!pedited || pedited->wavelet.edgrad, "Wavelet", "Edgrad", wavelet.edgrad, keyFile);
3522         saveToKeyfile(!pedited || pedited->wavelet.edgval, "Wavelet", "Edgval", wavelet.edgval, keyFile);
3523         saveToKeyfile(!pedited || pedited->wavelet.edgthresh, "Wavelet", "ThrEdg", wavelet.edgthresh, keyFile);
3524         saveToKeyfile(!pedited || pedited->wavelet.avoid, "Wavelet", "AvoidColorShift", wavelet.avoid, keyFile);
3525         saveToKeyfile(!pedited || pedited->wavelet.tmr, "Wavelet", "TMr", wavelet.tmr, keyFile);
3526         saveToKeyfile(!pedited || pedited->wavelet.rescon, "Wavelet", "ResidualcontShadow", wavelet.rescon, keyFile);
3527         saveToKeyfile(!pedited || pedited->wavelet.resconH, "Wavelet", "ResidualcontHighlight", wavelet.resconH, keyFile);
3528         saveToKeyfile(!pedited || pedited->wavelet.thr, "Wavelet", "ThresholdResidShadow", wavelet.thr, keyFile);
3529         saveToKeyfile(!pedited || pedited->wavelet.thrH, "Wavelet", "ThresholdResidHighLight", wavelet.thrH, keyFile);
3530         saveToKeyfile(!pedited || pedited->wavelet.reschro, "Wavelet", "Residualchroma", wavelet.reschro, keyFile);
3531         saveToKeyfile(!pedited || pedited->wavelet.tmrs, "Wavelet", "ResidualTM", wavelet.tmrs, keyFile);
3532         saveToKeyfile(!pedited || pedited->wavelet.gamma, "Wavelet", "Residualgamma", wavelet.gamma, keyFile);
3533         saveToKeyfile(!pedited || pedited->wavelet.sky, "Wavelet", "HueRangeResidual", wavelet.sky, keyFile);
3534         saveToKeyfile(!pedited || pedited->wavelet.hueskin2, "Wavelet", "HueRange", wavelet.hueskin2.toVector(), keyFile);
3535         saveToKeyfile(!pedited || pedited->wavelet.contrast, "Wavelet", "Contrast", wavelet.contrast, keyFile);
3536 
3537 // Directional pyramid equalizer
3538         saveToKeyfile(!pedited || pedited->dirpyrequalizer.enabled, "Directional Pyramid Equalizer", "Enabled", dirpyrequalizer.enabled, keyFile);
3539         saveToKeyfile(!pedited || pedited->dirpyrequalizer.gamutlab, "Directional Pyramid Equalizer", "Gamutlab", dirpyrequalizer.gamutlab, keyFile);
3540         saveToKeyfile(!pedited || pedited->dirpyrequalizer.cbdlMethod, "Directional Pyramid Equalizer", "cbdlMethod", dirpyrequalizer.cbdlMethod, keyFile);
3541 
3542         for (int i = 0; i < 6; i++) {
3543             std::stringstream ss;
3544             ss << "Mult" << i;
3545 
3546             saveToKeyfile(!pedited || pedited->dirpyrequalizer.mult[i], "Directional Pyramid Equalizer", ss.str(), dirpyrequalizer.mult[i], keyFile);
3547         }
3548 
3549         saveToKeyfile(!pedited || pedited->dirpyrequalizer.threshold, "Directional Pyramid Equalizer", "Threshold", dirpyrequalizer.threshold, keyFile);
3550         saveToKeyfile(!pedited || pedited->dirpyrequalizer.skinprotect, "Directional Pyramid Equalizer", "Skinprotect", dirpyrequalizer.skinprotect, keyFile);
3551         saveToKeyfile(!pedited || pedited->dirpyrequalizer.hueskin, "Directional Pyramid Equalizer", "Hueskin", dirpyrequalizer.hueskin.toVector(), keyFile);
3552 
3553 // HSV Equalizer
3554         saveToKeyfile(!pedited || pedited->hsvequalizer.enabled, "HSV Equalizer", "Enabled", hsvequalizer.enabled, keyFile);
3555         saveToKeyfile(!pedited || pedited->hsvequalizer.hcurve, "HSV Equalizer", "HCurve", hsvequalizer.hcurve, keyFile);
3556         saveToKeyfile(!pedited || pedited->hsvequalizer.scurve, "HSV Equalizer", "SCurve", hsvequalizer.scurve, keyFile);
3557         saveToKeyfile(!pedited || pedited->hsvequalizer.vcurve, "HSV Equalizer", "VCurve", hsvequalizer.vcurve, keyFile);
3558 
3559 // Soft Light
3560         saveToKeyfile(!pedited || pedited->softlight.enabled, "SoftLight", "Enabled", softlight.enabled, keyFile);
3561         saveToKeyfile(!pedited || pedited->softlight.strength, "SoftLight", "Strength", softlight.strength, keyFile);
3562 
3563 // Film simulation
3564         saveToKeyfile(!pedited || pedited->filmSimulation.enabled, "Film Simulation", "Enabled", filmSimulation.enabled, keyFile);
3565         saveToKeyfile(!pedited || pedited->filmSimulation.clutFilename, "Film Simulation", "ClutFilename", filmSimulation.clutFilename, keyFile);
3566         saveToKeyfile(!pedited || pedited->filmSimulation.strength, "Film Simulation", "Strength", filmSimulation.strength, keyFile);
3567 
3568         saveToKeyfile(!pedited || pedited->rgbCurves.enabled, "RGB Curves", "Enabled", rgbCurves.enabled, keyFile);
3569         saveToKeyfile(!pedited || pedited->rgbCurves.lumamode, "RGB Curves", "LumaMode", rgbCurves.lumamode, keyFile);
3570         saveToKeyfile(!pedited || pedited->rgbCurves.rcurve, "RGB Curves", "rCurve", rgbCurves.rcurve, keyFile);
3571         saveToKeyfile(!pedited || pedited->rgbCurves.gcurve, "RGB Curves", "gCurve", rgbCurves.gcurve, keyFile);
3572         saveToKeyfile(!pedited || pedited->rgbCurves.bcurve, "RGB Curves", "bCurve", rgbCurves.bcurve, keyFile);
3573 
3574 // Color toning
3575         saveToKeyfile(!pedited || pedited->colorToning.enabled, "ColorToning", "Enabled", colorToning.enabled, keyFile);
3576         saveToKeyfile(!pedited || pedited->colorToning.method, "ColorToning", "Method", colorToning.method, keyFile);
3577         saveToKeyfile(!pedited || pedited->colorToning.lumamode, "ColorToning", "Lumamode", colorToning.lumamode, keyFile);
3578         saveToKeyfile(!pedited || pedited->colorToning.twocolor, "ColorToning", "Twocolor", colorToning.twocolor, keyFile);
3579         saveToKeyfile(!pedited || pedited->colorToning.redlow, "ColorToning", "Redlow", colorToning.redlow, keyFile);
3580         saveToKeyfile(!pedited || pedited->colorToning.greenlow, "ColorToning", "Greenlow", colorToning.greenlow, keyFile);
3581         saveToKeyfile(!pedited || pedited->colorToning.bluelow, "ColorToning", "Bluelow", colorToning.bluelow, keyFile);
3582         saveToKeyfile(!pedited || pedited->colorToning.satlow, "ColorToning", "Satlow", colorToning.satlow, keyFile);
3583         saveToKeyfile(!pedited || pedited->colorToning.balance, "ColorToning", "Balance", colorToning.balance, keyFile);
3584         saveToKeyfile(!pedited || pedited->colorToning.sathigh, "ColorToning", "Sathigh", colorToning.sathigh, keyFile);
3585         saveToKeyfile(!pedited || pedited->colorToning.redmed, "ColorToning", "Redmed", colorToning.redmed, keyFile);
3586         saveToKeyfile(!pedited || pedited->colorToning.greenmed, "ColorToning", "Greenmed", colorToning.greenmed, keyFile);
3587         saveToKeyfile(!pedited || pedited->colorToning.bluemed, "ColorToning", "Bluemed", colorToning.bluemed, keyFile);
3588         saveToKeyfile(!pedited || pedited->colorToning.redhigh, "ColorToning", "Redhigh", colorToning.redhigh, keyFile);
3589         saveToKeyfile(!pedited || pedited->colorToning.greenhigh, "ColorToning", "Greenhigh", colorToning.greenhigh, keyFile);
3590         saveToKeyfile(!pedited || pedited->colorToning.bluehigh, "ColorToning", "Bluehigh", colorToning.bluehigh, keyFile);
3591         saveToKeyfile(!pedited || pedited->colorToning.autosat, "ColorToning", "Autosat", colorToning.autosat, keyFile);
3592         saveToKeyfile(!pedited || pedited->colorToning.opacityCurve, "ColorToning", "OpacityCurve", colorToning.opacityCurve, keyFile);
3593         saveToKeyfile(!pedited || pedited->colorToning.colorCurve, "ColorToning", "ColorCurve", colorToning.colorCurve, keyFile);
3594         saveToKeyfile(!pedited || pedited->colorToning.satprotectionthreshold, "ColorToning", "SatProtectionThreshold", colorToning.satProtectionThreshold, keyFile);
3595         saveToKeyfile(!pedited || pedited->colorToning.saturatedopacity, "ColorToning", "SaturatedOpacity", colorToning.saturatedOpacity, keyFile);
3596         saveToKeyfile(!pedited || pedited->colorToning.strength, "ColorToning", "Strength", colorToning.strength, keyFile);
3597         saveToKeyfile(!pedited || pedited->colorToning.hlColSat, "ColorToning", "HighlightsColorSaturation", colorToning.hlColSat.toVector(), keyFile);
3598         saveToKeyfile(!pedited || pedited->colorToning.shadowsColSat, "ColorToning", "ShadowsColorSaturation", colorToning.shadowsColSat.toVector(), keyFile);
3599         saveToKeyfile(!pedited || pedited->colorToning.clcurve, "ColorToning", "ClCurve", colorToning.clcurve, keyFile);
3600         saveToKeyfile(!pedited || pedited->colorToning.cl2curve, "ColorToning", "Cl2Curve", colorToning.cl2curve, keyFile);
3601         saveToKeyfile(!pedited || pedited->colorToning.labgridALow, "ColorToning", "LabGridALow", colorToning.labgridALow, keyFile);
3602         saveToKeyfile(!pedited || pedited->colorToning.labgridBLow, "ColorToning", "LabGridBLow", colorToning.labgridBLow, keyFile);
3603         saveToKeyfile(!pedited || pedited->colorToning.labgridAHigh, "ColorToning", "LabGridAHigh", colorToning.labgridAHigh, keyFile);
3604         saveToKeyfile(!pedited || pedited->colorToning.labgridBHigh, "ColorToning", "LabGridBHigh", colorToning.labgridBHigh, keyFile);
3605         if (!pedited || pedited->colorToning.labregions) {
3606             for (size_t j = 0; j < colorToning.labregions.size(); ++j) {
3607                 std::string n = std::to_string(j+1);
3608                 auto &l = colorToning.labregions[j];
3609                 putToKeyfile("ColorToning", Glib::ustring("LabRegionA_") + n, l.a, keyFile);
3610                 putToKeyfile("ColorToning", Glib::ustring("LabRegionB_") + n, l.b, keyFile);
3611                 putToKeyfile("ColorToning", Glib::ustring("LabRegionSaturation_") + n, l.saturation, keyFile);
3612                 putToKeyfile("ColorToning", Glib::ustring("LabRegionSlope_") + n, l.slope, keyFile);
3613                 putToKeyfile("ColorToning", Glib::ustring("LabRegionOffset_") + n, l.offset, keyFile);
3614                 putToKeyfile("ColorToning", Glib::ustring("LabRegionPower_") + n, l.power, keyFile);
3615                 putToKeyfile("ColorToning", Glib::ustring("LabRegionHueMask_") + n, l.hueMask, keyFile);
3616                 putToKeyfile("ColorToning", Glib::ustring("LabRegionChromaticityMask_") + n, l.chromaticityMask, keyFile);
3617                 putToKeyfile("ColorToning", Glib::ustring("LabRegionLightnessMask_") + n, l.lightnessMask, keyFile);
3618                 putToKeyfile("ColorToning", Glib::ustring("LabRegionMaskBlur_") + n, l.maskBlur, keyFile);
3619                 putToKeyfile("ColorToning", Glib::ustring("LabRegionChannel_") + n, l.channel, keyFile);
3620             }
3621         }
3622         saveToKeyfile(!pedited || pedited->colorToning.labregionsShowMask, "ColorToning", "LabRegionsShowMask", colorToning.labregionsShowMask, keyFile);
3623 
3624 // Raw
3625         saveToKeyfile(!pedited || pedited->raw.darkFrame, "RAW", "DarkFrame", relativePathIfInside(fname, fnameAbsolute, raw.dark_frame), keyFile);
3626         saveToKeyfile(!pedited || pedited->raw.df_autoselect, "RAW", "DarkFrameAuto", raw.df_autoselect, keyFile);
3627         saveToKeyfile(!pedited || pedited->raw.ff_file, "RAW", "FlatFieldFile", relativePathIfInside(fname, fnameAbsolute, raw.ff_file), keyFile);
3628         saveToKeyfile(!pedited || pedited->raw.ff_AutoSelect, "RAW", "FlatFieldAutoSelect", raw.ff_AutoSelect, keyFile);
3629         saveToKeyfile(!pedited || pedited->raw.ff_BlurRadius, "RAW", "FlatFieldBlurRadius", raw.ff_BlurRadius, keyFile);
3630         saveToKeyfile(!pedited || pedited->raw.ff_BlurType, "RAW", "FlatFieldBlurType", raw.ff_BlurType, keyFile);
3631         saveToKeyfile(!pedited || pedited->raw.ff_AutoClipControl, "RAW", "FlatFieldAutoClipControl", raw.ff_AutoClipControl, keyFile);
3632         saveToKeyfile(!pedited || pedited->raw.ff_clipControl, "RAW", "FlatFieldClipControl", raw.ff_clipControl, keyFile);
3633         saveToKeyfile(!pedited || pedited->raw.ca_autocorrect, "RAW", "CA", raw.ca_autocorrect, keyFile);
3634         saveToKeyfile(!pedited || pedited->raw.ca_avoidcolourshift, "RAW", "CAAvoidColourshift", raw.ca_avoidcolourshift, keyFile);
3635         saveToKeyfile(!pedited || pedited->raw.caautoiterations, "RAW", "CAAutoIterations", raw.caautoiterations, keyFile);
3636         saveToKeyfile(!pedited || pedited->raw.cared, "RAW", "CARed", raw.cared, keyFile);
3637         saveToKeyfile(!pedited || pedited->raw.cablue, "RAW", "CABlue", raw.cablue, keyFile);
3638         saveToKeyfile(!pedited || pedited->raw.hotPixelFilter, "RAW", "HotPixelFilter", raw.hotPixelFilter, keyFile);
3639         saveToKeyfile(!pedited || pedited->raw.deadPixelFilter, "RAW", "DeadPixelFilter", raw.deadPixelFilter, keyFile);
3640         saveToKeyfile(!pedited || pedited->raw.hotdeadpix_thresh, "RAW", "HotDeadPixelThresh", raw.hotdeadpix_thresh, keyFile);
3641         saveToKeyfile(!pedited || pedited->raw.bayersensor.method, "RAW Bayer", "Method", raw.bayersensor.method, keyFile);
3642         saveToKeyfile(!pedited || pedited->raw.bayersensor.border, "RAW Bayer", "Border", raw.bayersensor.border, keyFile);
3643         saveToKeyfile(!pedited || pedited->raw.bayersensor.imageNum, "RAW Bayer", "ImageNum", raw.bayersensor.imageNum + 1, keyFile);
3644         saveToKeyfile(!pedited || pedited->raw.bayersensor.ccSteps, "RAW Bayer", "CcSteps", raw.bayersensor.ccSteps, keyFile);
3645         saveToKeyfile(!pedited || pedited->raw.bayersensor.exBlack0, "RAW Bayer", "PreBlack0", raw.bayersensor.black0, keyFile);
3646         saveToKeyfile(!pedited || pedited->raw.bayersensor.exBlack1, "RAW Bayer", "PreBlack1", raw.bayersensor.black1, keyFile);
3647         saveToKeyfile(!pedited || pedited->raw.bayersensor.exBlack2, "RAW Bayer", "PreBlack2", raw.bayersensor.black2, keyFile);
3648         saveToKeyfile(!pedited || pedited->raw.bayersensor.exBlack3, "RAW Bayer", "PreBlack3", raw.bayersensor.black3, keyFile);
3649         saveToKeyfile(!pedited || pedited->raw.bayersensor.exTwoGreen, "RAW Bayer", "PreTwoGreen", raw.bayersensor.twogreen, keyFile);
3650         saveToKeyfile(!pedited || pedited->raw.bayersensor.linenoise, "RAW Bayer", "LineDenoise", raw.bayersensor.linenoise, keyFile);
3651         saveToKeyfile(!pedited || pedited->raw.bayersensor.linenoise, "RAW Bayer", "LineDenoiseDirection", toUnderlying(raw.bayersensor.linenoiseDirection), keyFile);
3652         saveToKeyfile(!pedited || pedited->raw.bayersensor.greenEq, "RAW Bayer", "GreenEqThreshold", raw.bayersensor.greenthresh, keyFile);
3653         saveToKeyfile(!pedited || pedited->raw.bayersensor.dcbIterations, "RAW Bayer", "DCBIterations", raw.bayersensor.dcb_iterations, keyFile);
3654         saveToKeyfile(!pedited || pedited->raw.bayersensor.dcbEnhance, "RAW Bayer", "DCBEnhance", raw.bayersensor.dcb_enhance, keyFile);
3655         saveToKeyfile(!pedited || pedited->raw.bayersensor.lmmseIterations, "RAW Bayer", "LMMSEIterations", raw.bayersensor.lmmse_iterations, keyFile);
3656         saveToKeyfile(!pedited || pedited->raw.bayersensor.dualDemosaicAutoContrast, "RAW Bayer", "DualDemosaicAutoContrast", raw.bayersensor.dualDemosaicAutoContrast, keyFile);
3657         saveToKeyfile(!pedited || pedited->raw.bayersensor.dualDemosaicContrast, "RAW Bayer", "DualDemosaicContrast", raw.bayersensor.dualDemosaicContrast, keyFile);
3658         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftMotionCorrectionMethod, "RAW Bayer", "PixelShiftMotionCorrectionMethod", toUnderlying(raw.bayersensor.pixelShiftMotionCorrectionMethod), keyFile);
3659         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftEperIso, "RAW Bayer", "PixelShiftEperIso", raw.bayersensor.pixelShiftEperIso, keyFile);
3660         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftSigma, "RAW Bayer", "PixelShiftSigma", raw.bayersensor.pixelShiftSigma, keyFile);
3661         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftShowMotion, "RAW Bayer", "PixelShiftShowMotion", raw.bayersensor.pixelShiftShowMotion, keyFile);
3662         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftShowMotionMaskOnly, "RAW Bayer", "PixelShiftShowMotionMaskOnly", raw.bayersensor.pixelShiftShowMotionMaskOnly, keyFile);
3663         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftHoleFill, "RAW Bayer", "pixelShiftHoleFill", raw.bayersensor.pixelShiftHoleFill, keyFile);
3664         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftMedian, "RAW Bayer", "pixelShiftMedian", raw.bayersensor.pixelShiftMedian, keyFile);
3665         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftGreen, "RAW Bayer", "pixelShiftGreen", raw.bayersensor.pixelShiftGreen, keyFile);
3666         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftBlur, "RAW Bayer", "pixelShiftBlur", raw.bayersensor.pixelShiftBlur, keyFile);
3667         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftSmooth, "RAW Bayer", "pixelShiftSmoothFactor", raw.bayersensor.pixelShiftSmoothFactor, keyFile);
3668         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftEqualBright, "RAW Bayer", "pixelShiftEqualBright", raw.bayersensor.pixelShiftEqualBright, keyFile);
3669         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftEqualBrightChannel, "RAW Bayer", "pixelShiftEqualBrightChannel", raw.bayersensor.pixelShiftEqualBrightChannel, keyFile);
3670         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftNonGreenCross, "RAW Bayer", "pixelShiftNonGreenCross", raw.bayersensor.pixelShiftNonGreenCross, keyFile);
3671         saveToKeyfile(!pedited || pedited->raw.bayersensor.pixelShiftDemosaicMethod, "RAW Bayer", "pixelShiftDemosaicMethod", raw.bayersensor.pixelShiftDemosaicMethod, keyFile);
3672         saveToKeyfile(!pedited || pedited->raw.bayersensor.pdafLinesFilter, "RAW Bayer", "PDAFLinesFilter", raw.bayersensor.pdafLinesFilter, keyFile);
3673         saveToKeyfile(!pedited || pedited->raw.xtranssensor.method, "RAW X-Trans", "Method", raw.xtranssensor.method, keyFile);
3674         saveToKeyfile(!pedited || pedited->raw.xtranssensor.dualDemosaicAutoContrast, "RAW X-Trans", "DualDemosaicAutoContrast", raw.xtranssensor.dualDemosaicAutoContrast, keyFile);
3675         saveToKeyfile(!pedited || pedited->raw.xtranssensor.dualDemosaicContrast, "RAW X-Trans", "DualDemosaicContrast", raw.xtranssensor.dualDemosaicContrast, keyFile);
3676         saveToKeyfile(!pedited || pedited->raw.xtranssensor.border, "RAW X-Trans", "Border", raw.xtranssensor.border, keyFile);
3677         saveToKeyfile(!pedited || pedited->raw.xtranssensor.ccSteps, "RAW X-Trans", "CcSteps", raw.xtranssensor.ccSteps, keyFile);
3678         saveToKeyfile(!pedited || pedited->raw.xtranssensor.exBlackRed, "RAW X-Trans", "PreBlackRed", raw.xtranssensor.blackred, keyFile);
3679         saveToKeyfile(!pedited || pedited->raw.xtranssensor.exBlackGreen, "RAW X-Trans", "PreBlackGreen", raw.xtranssensor.blackgreen, keyFile);
3680         saveToKeyfile(!pedited || pedited->raw.xtranssensor.exBlackBlue, "RAW X-Trans", "PreBlackBlue", raw.xtranssensor.blackblue, keyFile);
3681 
3682 // Raw exposition
3683         saveToKeyfile(!pedited || pedited->raw.exPos, "RAW", "PreExposure", raw.expos, keyFile);
3684 
3685 // MetaData
3686         saveToKeyfile(!pedited || pedited->metadata.mode, "MetaData", "Mode", metadata.mode, keyFile);
3687 
3688 // Film negative
3689         saveToKeyfile(!pedited || pedited->filmNegative.enabled, "Film Negative", "Enabled", filmNegative.enabled, keyFile);
3690         saveToKeyfile(!pedited || pedited->filmNegative.redRatio, "Film Negative", "RedRatio", filmNegative.redRatio, keyFile);
3691         saveToKeyfile(!pedited || pedited->filmNegative.greenExp, "Film Negative", "GreenExponent", filmNegative.greenExp, keyFile);
3692         saveToKeyfile(!pedited || pedited->filmNegative.blueRatio, "Film Negative", "BlueRatio", filmNegative.blueRatio, keyFile);
3693 
3694 // EXIF change list
3695         if (!pedited || pedited->exif) {
3696             for (ExifPairs::const_iterator i = exif.begin(); i != exif.end(); ++i) {
3697                 keyFile.set_string("Exif", i->first, i->second);
3698             }
3699         }
3700 
3701 // IPTC change list
3702         if (!pedited || pedited->iptc) {
3703             for (IPTCPairs::const_iterator i = iptc.begin(); i != iptc.end(); ++i) {
3704                 Glib::ArrayHandle<Glib::ustring> values = i->second;
3705                 keyFile.set_string_list("IPTC", i->first, values);
3706             }
3707         }
3708 
3709         sPParams = keyFile.to_data();
3710 
3711     } catch (Glib::KeyFileError&) {}
3712 
3713     if (sPParams.empty()) {
3714         return 1;
3715     }
3716 
3717     int error1, error2;
3718     error1 = write(fname, sPParams);
3719 
3720     if (!fname2.empty()) {
3721 
3722         error2 = write(fname2, sPParams);
3723         // If at least one file has been saved, it's a success
3724         return error1 & error2;
3725     } else {
3726         return error1;
3727     }
3728 }
3729 
load(const Glib::ustring & fname,ParamsEdited * pedited)3730 int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
3731 {
3732     setlocale(LC_NUMERIC, "C");  // to set decimal point to "."
3733 
3734     if (fname.empty()) {
3735         return 1;
3736     }
3737 
3738     Glib::KeyFile keyFile;
3739 
3740     try {
3741         if (pedited) {
3742             pedited->set(false);
3743         }
3744 
3745         if (!Glib::file_test(fname, Glib::FILE_TEST_EXISTS) ||
3746                 !keyFile.load_from_file(fname)) {
3747             return 1;
3748         }
3749 
3750         ppVersion = PPVERSION;
3751         appVersion = RTVERSION;
3752 
3753         if (keyFile.has_group("Version")) {
3754             if (keyFile.has_key("Version", "AppVersion")) {
3755                 appVersion = keyFile.get_string("Version", "AppVersion");
3756             }
3757 
3758             if (keyFile.has_key("Version", "Version")) {
3759                 ppVersion = keyFile.get_integer("Version", "Version");
3760             }
3761         }
3762 
3763         if (keyFile.has_group("General")) {
3764             assignFromKeyfile(keyFile, "General", "Rank", pedited, rank, pedited->general.rank);
3765             assignFromKeyfile(keyFile, "General", "ColorLabel", pedited, colorlabel, pedited->general.colorlabel);
3766             assignFromKeyfile(keyFile, "General", "InTrash", pedited, inTrash, pedited->general.intrash);
3767         }
3768 
3769         if (keyFile.has_group("Exposure")) {
3770             if (ppVersion < PPVERSION_AEXP) {
3771                 toneCurve.autoexp = false; // prevent execution of autoexp when opening file created with earlier versions of autoexp algorithm
3772             } else {
3773                 assignFromKeyfile(keyFile, "Exposure", "Auto", pedited, toneCurve.autoexp, pedited->toneCurve.autoexp);
3774             }
3775 
3776             assignFromKeyfile(keyFile, "Exposure", "Clip", pedited, toneCurve.clip, pedited->toneCurve.clip);
3777             assignFromKeyfile(keyFile, "Exposure", "Compensation", pedited, toneCurve.expcomp, pedited->toneCurve.expcomp);
3778             assignFromKeyfile(keyFile, "Exposure", "Brightness", pedited, toneCurve.brightness, pedited->toneCurve.brightness);
3779             assignFromKeyfile(keyFile, "Exposure", "Contrast", pedited, toneCurve.contrast, pedited->toneCurve.contrast);
3780             assignFromKeyfile(keyFile, "Exposure", "Saturation", pedited, toneCurve.saturation, pedited->toneCurve.saturation);
3781             assignFromKeyfile(keyFile, "Exposure", "Black", pedited, toneCurve.black, pedited->toneCurve.black);
3782             assignFromKeyfile(keyFile, "Exposure", "HighlightCompr", pedited, toneCurve.hlcompr, pedited->toneCurve.hlcompr);
3783             assignFromKeyfile(keyFile, "Exposure", "HighlightComprThreshold", pedited, toneCurve.hlcomprthresh, pedited->toneCurve.hlcomprthresh);
3784             assignFromKeyfile(keyFile, "Exposure", "ShadowCompr", pedited, toneCurve.shcompr, pedited->toneCurve.shcompr);
3785 
3786             if (toneCurve.shcompr > 100) {
3787                 toneCurve.shcompr = 100; // older pp3 files can have values above 100.
3788             }
3789 
3790             const std::map<std::string, ToneCurveMode> tc_mapping = {
3791                 {"Standard", ToneCurveMode::STD},
3792                 {"FilmLike", ToneCurveMode::FILMLIKE},
3793                 {"SatAndValueBlending", ToneCurveMode::SATANDVALBLENDING},
3794                 {"WeightedStd", ToneCurveMode::WEIGHTEDSTD},
3795                 {"Luminance", ToneCurveMode::LUMINANCE},
3796                 {"Perceptual", ToneCurveMode::PERCEPTUAL}
3797             };
3798 
3799             assignFromKeyfile(keyFile, "Exposure", "CurveMode", pedited, tc_mapping, toneCurve.curveMode, pedited->toneCurve.curveMode);
3800             assignFromKeyfile(keyFile, "Exposure", "CurveMode2", pedited, tc_mapping, toneCurve.curveMode2, pedited->toneCurve.curveMode2);
3801 
3802             if (ppVersion > 200) {
3803                 assignFromKeyfile(keyFile, "Exposure", "Curve", pedited, toneCurve.curve, pedited->toneCurve.curve);
3804                 assignFromKeyfile(keyFile, "Exposure", "Curve2", pedited, toneCurve.curve2, pedited->toneCurve.curve2);
3805             }
3806 
3807             assignFromKeyfile(keyFile, "Exposure", "HistogramMatching", pedited, toneCurve.histmatching, pedited->toneCurve.histmatching);
3808             if (ppVersion < 340) {
3809                 toneCurve.fromHistMatching = false;
3810                 if (pedited) {
3811                     pedited->toneCurve.fromHistMatching = true;
3812                 }
3813             } else {
3814                 assignFromKeyfile(keyFile, "Exposure", "CurveFromHistogramMatching", pedited, toneCurve.fromHistMatching, pedited->toneCurve.fromHistMatching);
3815             }
3816             assignFromKeyfile(keyFile, "Exposure", "ClampOOG", pedited, toneCurve.clampOOG, pedited->toneCurve.clampOOG);
3817         }
3818 
3819         if (keyFile.has_group("HLRecovery")) {
3820             assignFromKeyfile(keyFile, "HLRecovery", "Enabled", pedited, toneCurve.hrenabled, pedited->toneCurve.hrenabled);
3821             assignFromKeyfile(keyFile, "HLRecovery", "Method", pedited, toneCurve.method, pedited->toneCurve.method);
3822         }
3823 
3824         if (keyFile.has_group("Channel Mixer")) {
3825             if (ppVersion >= 329) {
3826                 assignFromKeyfile(keyFile, "Channel Mixer", "Enabled", pedited, chmixer.enabled, pedited->chmixer.enabled);
3827             } else {
3828                 chmixer.enabled = true;
3829 
3830                 if (pedited) {
3831                     pedited->chmixer.enabled = true;
3832                 }
3833             }
3834 
3835             if (keyFile.has_key("Channel Mixer", "Red") && keyFile.has_key("Channel Mixer", "Green") && keyFile.has_key("Channel Mixer", "Blue")) {
3836                 const std::vector<int> rmix = keyFile.get_integer_list("Channel Mixer", "Red");
3837                 const std::vector<int> gmix = keyFile.get_integer_list("Channel Mixer", "Green");
3838                 const std::vector<int> bmix = keyFile.get_integer_list("Channel Mixer", "Blue");
3839 
3840                 if (rmix.size() == 3 && gmix.size() == 3 && bmix.size() == 3) {
3841                     memcpy(chmixer.red,   rmix.data(), 3 * sizeof(int));
3842                     memcpy(chmixer.green, gmix.data(), 3 * sizeof(int));
3843                     memcpy(chmixer.blue,  bmix.data(), 3 * sizeof(int));
3844                 }
3845                 if (ppVersion < 338) {
3846                     for (int i = 0; i < 3; ++i) {
3847                         chmixer.red[i] *= 10;
3848                         chmixer.green[i] *= 10;
3849                         chmixer.blue[i] *= 10;
3850                     }
3851                 }
3852 
3853                 if (pedited) {
3854                     pedited->chmixer.red[0] =   pedited->chmixer.red[1] =   pedited->chmixer.red[2] = true;
3855                     pedited->chmixer.green[0] = pedited->chmixer.green[1] = pedited->chmixer.green[2] = true;
3856                     pedited->chmixer.blue[0] =  pedited->chmixer.blue[1] =  pedited->chmixer.blue[2] = true;
3857                 }
3858             }
3859         }
3860 
3861         if (keyFile.has_group("Black & White")) {
3862             assignFromKeyfile(keyFile, "Black & White", "Enabled", pedited, blackwhite.enabled, pedited->blackwhite.enabled);
3863             assignFromKeyfile(keyFile, "Black & White", "Method", pedited, blackwhite.method, pedited->blackwhite.method);
3864             assignFromKeyfile(keyFile, "Black & White", "Auto", pedited, blackwhite.autoc, pedited->blackwhite.autoc);
3865             assignFromKeyfile(keyFile, "Black & White", "ComplementaryColors", pedited, blackwhite.enabledcc, pedited->blackwhite.enabledcc);
3866             assignFromKeyfile(keyFile, "Black & White", "MixerRed", pedited, blackwhite.mixerRed, pedited->blackwhite.mixerRed);
3867             assignFromKeyfile(keyFile, "Black & White", "MixerOrange", pedited, blackwhite.mixerOrange, pedited->blackwhite.mixerOrange);
3868             assignFromKeyfile(keyFile, "Black & White", "MixerYellow", pedited, blackwhite.mixerYellow, pedited->blackwhite.mixerYellow);
3869             assignFromKeyfile(keyFile, "Black & White", "MixerGreen", pedited, blackwhite.mixerGreen, pedited->blackwhite.mixerGreen);
3870             assignFromKeyfile(keyFile, "Black & White", "MixerCyan", pedited, blackwhite.mixerCyan, pedited->blackwhite.mixerCyan);
3871             assignFromKeyfile(keyFile, "Black & White", "MixerBlue", pedited, blackwhite.mixerBlue, pedited->blackwhite.mixerBlue);
3872             assignFromKeyfile(keyFile, "Black & White", "MixerMagenta", pedited, blackwhite.mixerMagenta, pedited->blackwhite.mixerMagenta);
3873             assignFromKeyfile(keyFile, "Black & White", "MixerPurple", pedited, blackwhite.mixerPurple, pedited->blackwhite.mixerPurple);
3874             assignFromKeyfile(keyFile, "Black & White", "GammaRed", pedited, blackwhite.gammaRed, pedited->blackwhite.gammaRed);
3875             assignFromKeyfile(keyFile, "Black & White", "GammaGreen", pedited, blackwhite.gammaGreen, pedited->blackwhite.gammaGreen);
3876             assignFromKeyfile(keyFile, "Black & White", "GammaBlue", pedited, blackwhite.gammaBlue, pedited->blackwhite.gammaBlue);
3877             assignFromKeyfile(keyFile, "Black & White", "Filter", pedited, blackwhite.filter, pedited->blackwhite.filter);
3878             assignFromKeyfile(keyFile, "Black & White", "Setting", pedited, blackwhite.setting, pedited->blackwhite.setting);
3879             assignFromKeyfile(keyFile, "Black & White", "LuminanceCurve", pedited, blackwhite.luminanceCurve, pedited->blackwhite.luminanceCurve);
3880 
3881             assignFromKeyfile(keyFile, "Black & White", "BeforeCurve", pedited, blackwhite.beforeCurve, pedited->blackwhite.beforeCurve);
3882 
3883             assignFromKeyfile(keyFile, "Black & White", "Algorithm", pedited, blackwhite.algo, pedited->blackwhite.algo);
3884             assignFromKeyfile(
3885                 keyFile,
3886                 "Black & White",
3887                 "BeforeCurveMode",
3888                 pedited,
3889                 {
3890                     {"Standard", BlackWhiteParams::TcMode::STD_BW},
3891                     {"FilmLike", BlackWhiteParams::TcMode::FILMLIKE_BW},
3892                     {"SatAndValueBlending", BlackWhiteParams::TcMode::SATANDVALBLENDING_BW},
3893                     {"WeightedStd", BlackWhiteParams::TcMode::WEIGHTEDSTD_BW}
3894                 },
3895                 blackwhite.beforeCurveMode,
3896                 pedited->blackwhite.beforeCurveMode
3897             );
3898 
3899             assignFromKeyfile(keyFile, "Black & White", "AfterCurve", pedited, blackwhite.afterCurve, pedited->blackwhite.afterCurve);
3900             assignFromKeyfile(
3901                 keyFile,
3902                 "Black & White",
3903                 "AfterCurveMode",
3904                 pedited,
3905                 {
3906                     {"Standard", BlackWhiteParams::TcMode::STD_BW},
3907                     {"WeightedStd", BlackWhiteParams::TcMode::WEIGHTEDSTD_BW}
3908                 },
3909                 blackwhite.afterCurveMode,
3910                 pedited->blackwhite.afterCurveMode
3911             );
3912         }
3913 
3914         if (keyFile.has_group("Retinex")) {
3915             assignFromKeyfile(keyFile, "Retinex", "Median", pedited, retinex.medianmap, pedited->retinex.medianmap);
3916             assignFromKeyfile(keyFile, "Retinex", "RetinexMethod", pedited, retinex.retinexMethod, pedited->retinex.retinexMethod);
3917             assignFromKeyfile(keyFile, "Retinex", "mapMethod", pedited, retinex.mapMethod, pedited->retinex.mapMethod);
3918             assignFromKeyfile(keyFile, "Retinex", "viewMethod", pedited, retinex.viewMethod, pedited->retinex.viewMethod);
3919 
3920             assignFromKeyfile(keyFile, "Retinex", "Retinexcolorspace", pedited, retinex.retinexcolorspace, pedited->retinex.retinexcolorspace);
3921             assignFromKeyfile(keyFile, "Retinex", "Gammaretinex", pedited, retinex.gammaretinex, pedited->retinex.gammaretinex);
3922             assignFromKeyfile(keyFile, "Retinex", "Enabled", pedited, retinex.enabled, pedited->retinex.enabled);
3923             assignFromKeyfile(keyFile, "Retinex", "Neigh", pedited, retinex.neigh, pedited->retinex.neigh);
3924             assignFromKeyfile(keyFile, "Retinex", "Str", pedited, retinex.str, pedited->retinex.str);
3925             assignFromKeyfile(keyFile, "Retinex", "Scal", pedited, retinex.scal, pedited->retinex.scal);
3926             assignFromKeyfile(keyFile, "Retinex", "Iter", pedited, retinex.iter, pedited->retinex.iter);
3927             assignFromKeyfile(keyFile, "Retinex", "Grad", pedited, retinex.grad, pedited->retinex.grad);
3928             assignFromKeyfile(keyFile, "Retinex", "Grads", pedited, retinex.grads, pedited->retinex.grads);
3929             assignFromKeyfile(keyFile, "Retinex", "Gam", pedited, retinex.gam, pedited->retinex.gam);
3930             assignFromKeyfile(keyFile, "Retinex", "Slope", pedited, retinex.slope, pedited->retinex.slope);
3931             assignFromKeyfile(keyFile, "Retinex", "Offs", pedited, retinex.offs, pedited->retinex.offs);
3932             assignFromKeyfile(keyFile, "Retinex", "Vart", pedited, retinex.vart, pedited->retinex.vart);
3933             assignFromKeyfile(keyFile, "Retinex", "Limd", pedited, retinex.limd, pedited->retinex.limd);
3934             assignFromKeyfile(keyFile, "Retinex", "highl", pedited, retinex.highl, pedited->retinex.highl);
3935             assignFromKeyfile(keyFile, "Retinex", "skal", pedited, retinex.skal, pedited->retinex.skal);
3936             assignFromKeyfile(keyFile, "Retinex", "CDCurve", pedited, retinex.cdcurve, pedited->retinex.cdcurve);
3937 
3938             assignFromKeyfile(keyFile, "Retinex", "MAPCurve", pedited, retinex.mapcurve, pedited->retinex.mapcurve);
3939 
3940             assignFromKeyfile(keyFile, "Retinex", "CDHCurve", pedited, retinex.cdHcurve, pedited->retinex.cdHcurve);
3941 
3942             assignFromKeyfile(keyFile, "Retinex", "LHCurve", pedited, retinex.lhcurve, pedited->retinex.lhcurve);
3943 
3944             assignFromKeyfile(keyFile, "Retinex", "Highlights", pedited, retinex.highlights, pedited->retinex.highlights);
3945             assignFromKeyfile(keyFile, "Retinex", "HighlightTonalWidth", pedited, retinex.htonalwidth, pedited->retinex.htonalwidth);
3946             assignFromKeyfile(keyFile, "Retinex", "Shadows", pedited, retinex.shadows, pedited->retinex.shadows);
3947             assignFromKeyfile(keyFile, "Retinex", "ShadowTonalWidth", pedited, retinex.stonalwidth, pedited->retinex.stonalwidth);
3948 
3949             assignFromKeyfile(keyFile, "Retinex", "Radius", pedited, retinex.radius, pedited->retinex.radius);
3950 
3951             assignFromKeyfile(keyFile, "Retinex", "TransmissionCurve", pedited, retinex.transmissionCurve, pedited->retinex.transmissionCurve);
3952 
3953             assignFromKeyfile(keyFile, "Retinex", "GainTransmissionCurve", pedited, retinex.gaintransmissionCurve, pedited->retinex.gaintransmissionCurve);
3954         }
3955 
3956         if (keyFile.has_group("Local Contrast")) {
3957             assignFromKeyfile(keyFile, "Local Contrast", "Enabled", pedited, localContrast.enabled, pedited->localContrast.enabled);
3958             assignFromKeyfile(keyFile, "Local Contrast", "Radius", pedited, localContrast.radius, pedited->localContrast.radius);
3959             assignFromKeyfile(keyFile, "Local Contrast", "Amount", pedited, localContrast.amount, pedited->localContrast.amount);
3960             assignFromKeyfile(keyFile, "Local Contrast", "Darkness", pedited, localContrast.darkness, pedited->localContrast.darkness);
3961             assignFromKeyfile(keyFile, "Local Contrast", "Lightness", pedited, localContrast.lightness, pedited->localContrast.lightness);
3962         }
3963 
3964         if (keyFile.has_group("Luminance Curve")) {
3965             if (ppVersion >= 329) {
3966                 assignFromKeyfile(keyFile, "Luminance Curve", "Enabled", pedited, labCurve.enabled, pedited->labCurve.enabled);
3967             } else {
3968                 labCurve.enabled = true;
3969 
3970                 if (pedited) {
3971                     pedited->labCurve.enabled = true;
3972                 }
3973             }
3974 
3975             assignFromKeyfile(keyFile, "Luminance Curve", "Brightness", pedited, labCurve.brightness, pedited->labCurve.brightness);
3976             assignFromKeyfile(keyFile, "Luminance Curve", "Contrast", pedited, labCurve.contrast, pedited->labCurve.contrast);
3977 
3978             if (ppVersion < 303) {
3979                 // transform Saturation into Chromaticity
3980                 // if Saturation == 0, should we set BWToning on?
3981                 assignFromKeyfile(keyFile, "Luminance Curve", "Saturation", pedited, labCurve.chromaticity, pedited->labCurve.chromaticity);
3982                 // transform AvoidColorClipping into AvoidColorShift
3983                 assignFromKeyfile(keyFile, "Luminance Curve", "AvoidColorClipping", pedited, labCurve.avoidcolorshift, pedited->labCurve.avoidcolorshift);
3984             } else {
3985                 if (keyFile.has_key("Luminance Curve", "Chromaticity")) {
3986                     labCurve.chromaticity = keyFile.get_integer("Luminance Curve", "Chromaticity");
3987 
3988                     if (ppVersion >= 303 && ppVersion < 314 && labCurve.chromaticity == -100) {
3989                         blackwhite.enabled = true;
3990                     }
3991 
3992                     if (pedited) {
3993                         pedited->labCurve.chromaticity = true;
3994                     }
3995                 }
3996 
3997                 assignFromKeyfile(keyFile, "Luminance Curve", "AvoidColorShift", pedited, labCurve.avoidcolorshift, pedited->labCurve.avoidcolorshift);
3998                 assignFromKeyfile(keyFile, "Luminance Curve", "RedAndSkinTonesProtection", pedited, labCurve.rstprotection, pedited->labCurve.rstprotection);
3999             }
4000 
4001             assignFromKeyfile(keyFile, "Luminance Curve", "LCredsk", pedited, labCurve.lcredsk, pedited->labCurve.lcredsk);
4002 
4003             if (ppVersion < 314) {
4004                 // Backward compatibility: If BWtoning is true, Chromaticity has to be set to -100, which will produce the same effect
4005                 // and will enable the b&w toning mode ('a' & 'b' curves)
4006                 if (keyFile.has_key("Luminance Curve", "BWtoning")) {
4007                     if (keyFile.get_boolean("Luminance Curve", "BWtoning")) {
4008                         labCurve.chromaticity = -100;
4009 
4010                         if (pedited) {
4011                             pedited->labCurve.chromaticity = true;
4012                         }
4013                     }
4014                 }
4015             }
4016 
4017             assignFromKeyfile(keyFile, "Luminance Curve", "LCurve", pedited, labCurve.lcurve, pedited->labCurve.lcurve);
4018             assignFromKeyfile(keyFile, "Luminance Curve", "aCurve", pedited, labCurve.acurve, pedited->labCurve.acurve);
4019             assignFromKeyfile(keyFile, "Luminance Curve", "bCurve", pedited, labCurve.bcurve, pedited->labCurve.bcurve);
4020             assignFromKeyfile(keyFile, "Luminance Curve", "ccCurve", pedited, labCurve.cccurve, pedited->labCurve.cccurve);
4021             assignFromKeyfile(keyFile, "Luminance Curve", "chCurve", pedited, labCurve.chcurve, pedited->labCurve.chcurve);
4022             assignFromKeyfile(keyFile, "Luminance Curve", "lhCurve", pedited, labCurve.lhcurve, pedited->labCurve.lhcurve);
4023             assignFromKeyfile(keyFile, "Luminance Curve", "hhCurve", pedited, labCurve.hhcurve, pedited->labCurve.hhcurve);
4024             assignFromKeyfile(keyFile, "Luminance Curve", "LcCurve", pedited, labCurve.lccurve, pedited->labCurve.lccurve);
4025             assignFromKeyfile(keyFile, "Luminance Curve", "ClCurve", pedited, labCurve.clcurve, pedited->labCurve.clcurve);
4026         }
4027 
4028         if (keyFile.has_group("Sharpening")) {
4029             assignFromKeyfile(keyFile, "Sharpening", "Enabled", pedited, sharpening.enabled, pedited->sharpening.enabled);
4030             if (ppVersion >= 334) {
4031                 assignFromKeyfile(keyFile, "Sharpening", "Contrast", pedited, sharpening.contrast, pedited->sharpening.contrast);
4032             } else {
4033                 sharpening.contrast = 0;
4034                 if (pedited) {
4035                     pedited->sharpening.contrast = true;
4036                 }
4037             }
4038             assignFromKeyfile(keyFile, "Sharpening", "Radius", pedited, sharpening.radius, pedited->sharpening.radius);
4039             assignFromKeyfile(keyFile, "Sharpening", "BlurRadius", pedited, sharpening.blurradius, pedited->sharpening.blurradius);
4040             assignFromKeyfile(keyFile, "Sharpening", "Amount", pedited, sharpening.amount, pedited->sharpening.amount);
4041 
4042             if (keyFile.has_key("Sharpening", "Threshold")) {
4043                 if (ppVersion < 302) {
4044                     int thresh = min(keyFile.get_integer("Sharpening", "Threshold"), 2000);
4045                     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
4046                 } else {
4047                     const std::vector<int> thresh = keyFile.get_integer_list("Sharpening", "Threshold");
4048 
4049                     if (thresh.size() >= 4) {
4050                         sharpening.threshold.setValues(thresh[0], thresh[1], min(thresh[2], 2000), min(thresh[3], 2000));
4051                     }
4052                 }
4053 
4054                 if (pedited) {
4055                     pedited->sharpening.threshold = true;
4056                 }
4057             }
4058 
4059             assignFromKeyfile(keyFile, "Sharpening", "OnlyEdges", pedited, sharpening.edgesonly, pedited->sharpening.edgesonly);
4060             assignFromKeyfile(keyFile, "Sharpening", "EdgedetectionRadius", pedited, sharpening.edges_radius, pedited->sharpening.edges_radius);
4061             assignFromKeyfile(keyFile, "Sharpening", "EdgeTolerance", pedited, sharpening.edges_tolerance, pedited->sharpening.edges_tolerance);
4062             assignFromKeyfile(keyFile, "Sharpening", "HalocontrolEnabled", pedited, sharpening.halocontrol, pedited->sharpening.halocontrol);
4063             assignFromKeyfile(keyFile, "Sharpening", "HalocontrolAmount", pedited, sharpening.halocontrol_amount, pedited->sharpening.halocontrol_amount);
4064             assignFromKeyfile(keyFile, "Sharpening", "Method", pedited, sharpening.method, pedited->sharpening.method);
4065             assignFromKeyfile(keyFile, "Sharpening", "DeconvRadius", pedited, sharpening.deconvradius, pedited->sharpening.deconvradius);
4066             assignFromKeyfile(keyFile, "Sharpening", "DeconvAmount", pedited, sharpening.deconvamount, pedited->sharpening.deconvamount);
4067             assignFromKeyfile(keyFile, "Sharpening", "DeconvDamping", pedited, sharpening.deconvdamping, pedited->sharpening.deconvdamping);
4068             assignFromKeyfile(keyFile, "Sharpening", "DeconvIterations", pedited, sharpening.deconviter, pedited->sharpening.deconviter);
4069         }
4070 
4071         if (keyFile.has_group("SharpenEdge")) {
4072             assignFromKeyfile(keyFile, "SharpenEdge", "Enabled", pedited, sharpenEdge.enabled, pedited->sharpenEdge.enabled);
4073             assignFromKeyfile(keyFile, "SharpenEdge", "Passes", pedited, sharpenEdge.passes, pedited->sharpenEdge.passes);
4074             assignFromKeyfile(keyFile, "SharpenEdge", "Strength", pedited, sharpenEdge.amount, pedited->sharpenEdge.amount);
4075             assignFromKeyfile(keyFile, "SharpenEdge", "ThreeChannels", pedited, sharpenEdge.threechannels, pedited->sharpenEdge.threechannels);
4076         }
4077 
4078         if (keyFile.has_group("SharpenMicro")) {
4079             assignFromKeyfile(keyFile, "SharpenMicro", "Enabled", pedited, sharpenMicro.enabled, pedited->sharpenMicro.enabled);
4080             assignFromKeyfile(keyFile, "SharpenMicro", "Matrix", pedited, sharpenMicro.matrix, pedited->sharpenMicro.matrix);
4081             assignFromKeyfile(keyFile, "SharpenMicro", "Strength", pedited, sharpenMicro.amount, pedited->sharpenMicro.amount);
4082             if (ppVersion >= 334) {
4083                 assignFromKeyfile(keyFile, "SharpenMicro", "Contrast", pedited, sharpenMicro.contrast, pedited->sharpenMicro.contrast);
4084             } else {
4085                 sharpenMicro.contrast = 0;
4086                 if (pedited) {
4087                     pedited->sharpenMicro.contrast = true;
4088                 }
4089             }
4090             if (ppVersion >= 346) {
4091                 assignFromKeyfile(keyFile, "SharpenMicro", "Uniformity", pedited, sharpenMicro.uniformity, pedited->sharpenMicro.uniformity);
4092             } else {
4093                 double temp = 50.0;
4094                 assignFromKeyfile(keyFile, "SharpenMicro", "Uniformity", pedited, temp, pedited->sharpenMicro.uniformity);
4095                 sharpenMicro.uniformity = temp / 10;
4096             }
4097         }
4098 
4099         if (keyFile.has_group("Vibrance")) {
4100             assignFromKeyfile(keyFile, "Vibrance", "Enabled", pedited, vibrance.enabled, pedited->vibrance.enabled);
4101             assignFromKeyfile(keyFile, "Vibrance", "Pastels", pedited, vibrance.pastels, pedited->vibrance.pastels);
4102             assignFromKeyfile(keyFile, "Vibrance", "Saturated", pedited, vibrance.saturated, pedited->vibrance.saturated);
4103 
4104             if (keyFile.has_key("Vibrance", "PSThreshold")) {
4105                 if (ppVersion < 302) {
4106                     int thresh = keyFile.get_integer("Vibrance", "PSThreshold");
4107                     vibrance.psthreshold.setValues(thresh, thresh);
4108                 } else {
4109                     const std::vector<int> thresh = keyFile.get_integer_list("Vibrance", "PSThreshold");
4110 
4111                     if (thresh.size() >= 2) {
4112                         vibrance.psthreshold.setValues(thresh[0], thresh[1]);
4113                     }
4114                 }
4115 
4116                 if (pedited) {
4117                     pedited->vibrance.psthreshold = true;
4118                 }
4119             }
4120 
4121             assignFromKeyfile(keyFile, "Vibrance", "ProtectSkins", pedited, vibrance.protectskins, pedited->vibrance.protectskins);
4122             assignFromKeyfile(keyFile, "Vibrance", "AvoidColorShift", pedited, vibrance.avoidcolorshift, pedited->vibrance.avoidcolorshift);
4123             assignFromKeyfile(keyFile, "Vibrance", "PastSatTog", pedited, vibrance.pastsattog, pedited->vibrance.pastsattog);
4124             assignFromKeyfile(keyFile, "Vibrance", "SkinTonesCurve", pedited, vibrance.skintonescurve, pedited->vibrance.skintonescurve);
4125         }
4126 
4127         if (keyFile.has_group("White Balance")) {
4128             assignFromKeyfile(keyFile, "White Balance", "Enabled", pedited, wb.enabled, pedited->wb.enabled);
4129             assignFromKeyfile(keyFile, "White Balance", "Setting", pedited, wb.method, pedited->wb.method);
4130             assignFromKeyfile(keyFile, "White Balance", "Temperature", pedited, wb.temperature, pedited->wb.temperature);
4131             assignFromKeyfile(keyFile, "White Balance", "Green", pedited, wb.green, pedited->wb.green);
4132             assignFromKeyfile(keyFile, "White Balance", "Equal", pedited, wb.equal, pedited->wb.equal);
4133             assignFromKeyfile(keyFile, "White Balance", "TemperatureBias", pedited, wb.tempBias, pedited->wb.tempBias);
4134         }
4135 
4136         if (keyFile.has_group("Defringing")) {
4137             assignFromKeyfile(keyFile, "Defringing", "Enabled", pedited, defringe.enabled, pedited->defringe.enabled);
4138             assignFromKeyfile(keyFile, "Defringing", "Radius", pedited, defringe.radius, pedited->defringe.radius);
4139 
4140             if (keyFile.has_key("Defringing", "Threshold")) {
4141                 defringe.threshold = (float)keyFile.get_integer("Defringing", "Threshold");
4142 
4143                 if (pedited) {
4144                     pedited->defringe.threshold = true;
4145                 }
4146             }
4147 
4148             if (ppVersion < 310) {
4149                 defringe.threshold = sqrt(defringe.threshold * 33.f / 5.f);
4150             }
4151 
4152             assignFromKeyfile(keyFile, "Defringing", "HueCurve", pedited, defringe.huecurve, pedited->defringe.huecurve);
4153         }
4154 
4155         if (keyFile.has_group("Color appearance")) {
4156             assignFromKeyfile(keyFile, "Color appearance", "Enabled", pedited, colorappearance.enabled, pedited->colorappearance.enabled);
4157             assignFromKeyfile(keyFile, "Color appearance", "Degree", pedited, colorappearance.degree, pedited->colorappearance.degree);
4158             assignFromKeyfile(keyFile, "Color appearance", "AutoDegree", pedited, colorappearance.autodegree, pedited->colorappearance.autodegree);
4159             assignFromKeyfile(keyFile, "Color appearance", "Degreeout", pedited, colorappearance.degreeout, pedited->colorappearance.degreeout);
4160 
4161             assignFromKeyfile(keyFile, "Color appearance", "AutoDegreeout", pedited, colorappearance.autodegreeout, pedited->colorappearance.autodegreeout);
4162 
4163             assignFromKeyfile(keyFile, "Color appearance", "Surround", pedited, colorappearance.surround, pedited->colorappearance.surround);
4164             assignFromKeyfile(keyFile, "Color appearance", "Surrsrc", pedited, colorappearance.surrsrc, pedited->colorappearance.surrsrc);
4165             assignFromKeyfile(keyFile, "Color appearance", "AdaptLum", pedited, colorappearance.adaplum, pedited->colorappearance.adaplum);
4166             assignFromKeyfile(keyFile, "Color appearance", "Badpixsl", pedited, colorappearance.badpixsl, pedited->colorappearance.badpixsl);
4167             assignFromKeyfile(keyFile, "Color appearance", "Model", pedited, colorappearance.wbmodel, pedited->colorappearance.wbmodel);
4168             assignFromKeyfile(keyFile, "Color appearance", "Algorithm", pedited, colorappearance.algo, pedited->colorappearance.algo);
4169             assignFromKeyfile(keyFile, "Color appearance", "J-Light", pedited, colorappearance.jlight, pedited->colorappearance.jlight);
4170             assignFromKeyfile(keyFile, "Color appearance", "Q-Bright", pedited, colorappearance.qbright, pedited->colorappearance.qbright);
4171             assignFromKeyfile(keyFile, "Color appearance", "C-Chroma", pedited, colorappearance.chroma, pedited->colorappearance.chroma);
4172             assignFromKeyfile(keyFile, "Color appearance", "S-Chroma", pedited, colorappearance.schroma, pedited->colorappearance.schroma);
4173             assignFromKeyfile(keyFile, "Color appearance", "M-Chroma", pedited, colorappearance.mchroma, pedited->colorappearance.mchroma);
4174             assignFromKeyfile(keyFile, "Color appearance", "RSTProtection", pedited, colorappearance.rstprotection, pedited->colorappearance.rstprotection);
4175             assignFromKeyfile(keyFile, "Color appearance", "J-Contrast", pedited, colorappearance.contrast, pedited->colorappearance.contrast);
4176             assignFromKeyfile(keyFile, "Color appearance", "Q-Contrast", pedited, colorappearance.qcontrast, pedited->colorappearance.qcontrast);
4177             assignFromKeyfile(keyFile, "Color appearance", "H-Hue", pedited, colorappearance.colorh, pedited->colorappearance.colorh);
4178             assignFromKeyfile(keyFile, "Color appearance", "AdaptScene", pedited, colorappearance.adapscen, pedited->colorappearance.adapscen);
4179             assignFromKeyfile(keyFile, "Color appearance", "AutoAdapscen", pedited, colorappearance.autoadapscen, pedited->colorappearance.autoadapscen);
4180             assignFromKeyfile(keyFile, "Color appearance", "YbScene", pedited, colorappearance.ybscen, pedited->colorappearance.ybscen);
4181             assignFromKeyfile(keyFile, "Color appearance", "Autoybscen", pedited, colorappearance.autoybscen, pedited->colorappearance.autoybscen);
4182             assignFromKeyfile(keyFile, "Color appearance", "SurrSource", pedited, colorappearance.surrsource, pedited->colorappearance.surrsource);
4183             assignFromKeyfile(keyFile, "Color appearance", "Gamut", pedited, colorappearance.gamut, pedited->colorappearance.gamut);
4184             assignFromKeyfile(keyFile, "Color appearance", "Tempout", pedited, colorappearance.tempout, pedited->colorappearance.tempout);
4185             assignFromKeyfile(keyFile, "Color appearance", "Greenout", pedited, colorappearance.greenout, pedited->colorappearance.greenout);
4186             assignFromKeyfile(keyFile, "Color appearance", "Tempsc", pedited, colorappearance.tempsc, pedited->colorappearance.tempsc);
4187             assignFromKeyfile(keyFile, "Color appearance", "Greensc", pedited, colorappearance.greensc, pedited->colorappearance.greensc);
4188             assignFromKeyfile(keyFile, "Color appearance", "Ybout", pedited, colorappearance.ybout, pedited->colorappearance.ybout);
4189             assignFromKeyfile(keyFile, "Color appearance", "Datacie", pedited, colorappearance.datacie, pedited->colorappearance.datacie);
4190             assignFromKeyfile(keyFile, "Color appearance", "Tonecie", pedited, colorappearance.tonecie, pedited->colorappearance.tonecie);
4191 
4192             const std::map<std::string, ColorAppearanceParams::TcMode> tc_mapping = {
4193                 {"Lightness", ColorAppearanceParams::TcMode::LIGHT},
4194                 {"Brightness", ColorAppearanceParams::TcMode::BRIGHT}
4195             };
4196             assignFromKeyfile(keyFile, "Color appearance", "CurveMode", pedited, tc_mapping, colorappearance.curveMode, pedited->colorappearance.curveMode);
4197             assignFromKeyfile(keyFile, "Color appearance", "CurveMode2", pedited, tc_mapping, colorappearance.curveMode2, pedited->colorappearance.curveMode2);
4198 
4199             assignFromKeyfile(
4200                 keyFile,
4201                 "Color appearance",
4202                 "CurveMode3",
4203                 pedited,
4204                 {
4205                     {"Chroma", ColorAppearanceParams::CtcMode::CHROMA},
4206                     {"Saturation", ColorAppearanceParams::CtcMode::SATUR},
4207                     {"Colorfullness", ColorAppearanceParams::CtcMode::COLORF}
4208                 },
4209                 colorappearance.curveMode3,
4210                 pedited->colorappearance.curveMode3
4211             );
4212 
4213             if (ppVersion > 200) {
4214                 assignFromKeyfile(keyFile, "Color appearance", "Curve", pedited, colorappearance.curve, pedited->colorappearance.curve);
4215                 assignFromKeyfile(keyFile, "Color appearance", "Curve2", pedited, colorappearance.curve2, pedited->colorappearance.curve2);
4216                 assignFromKeyfile(keyFile, "Color appearance", "Curve3", pedited, colorappearance.curve3, pedited->colorappearance.curve3);
4217             }
4218 
4219         }
4220 
4221         if (keyFile.has_group("Impulse Denoising")) {
4222             assignFromKeyfile(keyFile, "Impulse Denoising", "Enabled", pedited, impulseDenoise.enabled, pedited->impulseDenoise.enabled);
4223             assignFromKeyfile(keyFile, "Impulse Denoising", "Threshold", pedited, impulseDenoise.thresh, pedited->impulseDenoise.thresh);
4224         }
4225 
4226         if (keyFile.has_group("Directional Pyramid Denoising")) { //TODO: No longer an accurate description for FT denoise
4227             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Enabled", pedited, dirpyrDenoise.enabled, pedited->dirpyrDenoise.enabled);
4228             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Enhance", pedited, dirpyrDenoise.enhance, pedited->dirpyrDenoise.enhance);
4229             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Median", pedited, dirpyrDenoise.median, pedited->dirpyrDenoise.median);
4230             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Luma", pedited, dirpyrDenoise.luma, pedited->dirpyrDenoise.luma);
4231             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Ldetail", pedited, dirpyrDenoise.Ldetail, pedited->dirpyrDenoise.Ldetail);
4232             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Chroma", pedited, dirpyrDenoise.chroma, pedited->dirpyrDenoise.chroma);
4233             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Method", pedited, dirpyrDenoise.dmethod, pedited->dirpyrDenoise.dmethod);
4234             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "LMethod", pedited, dirpyrDenoise.Lmethod, pedited->dirpyrDenoise.Lmethod);
4235             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "CMethod", pedited, dirpyrDenoise.Cmethod, pedited->dirpyrDenoise.Cmethod);
4236 
4237             if (dirpyrDenoise.Cmethod == "PRE") {
4238                 dirpyrDenoise.Cmethod = "MAN"; // Never load 'auto chroma preview mode' from pp3
4239             }
4240 
4241             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "C2Method", pedited, dirpyrDenoise.C2method, pedited->dirpyrDenoise.C2method);
4242 
4243             if (dirpyrDenoise.C2method == "PREV") {
4244                 dirpyrDenoise.C2method = "MANU";
4245             }
4246 
4247             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "SMethod", pedited, dirpyrDenoise.smethod, pedited->dirpyrDenoise.smethod);
4248             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "MedMethod", pedited, dirpyrDenoise.medmethod, pedited->dirpyrDenoise.medmethod);
4249             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "MethodMed", pedited, dirpyrDenoise.methodmed, pedited->dirpyrDenoise.methodmed);
4250             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "RGBMethod", pedited, dirpyrDenoise.rgbmethod, pedited->dirpyrDenoise.rgbmethod);
4251             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "LCurve", pedited, dirpyrDenoise.lcurve, pedited->dirpyrDenoise.lcurve);
4252 
4253             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "CCCurve", pedited, dirpyrDenoise.cccurve, pedited->dirpyrDenoise.cccurve);
4254 
4255             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Redchro", pedited, dirpyrDenoise.redchro, pedited->dirpyrDenoise.redchro);
4256             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Bluechro", pedited, dirpyrDenoise.bluechro, pedited->dirpyrDenoise.bluechro);
4257             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Gamma", pedited, dirpyrDenoise.gamma, pedited->dirpyrDenoise.gamma);
4258             assignFromKeyfile(keyFile, "Directional Pyramid Denoising", "Passes", pedited, dirpyrDenoise.passes, pedited->dirpyrDenoise.passes);
4259         }
4260 
4261         if (keyFile.has_group("EPD")) {
4262             assignFromKeyfile(keyFile, "EPD", "Enabled", pedited, epd.enabled, pedited->epd.enabled);
4263             assignFromKeyfile(keyFile, "EPD", "Strength", pedited, epd.strength, pedited->epd.strength);
4264             assignFromKeyfile(keyFile, "EPD", "Gamma", pedited, epd.gamma, pedited->epd.gamma);
4265             assignFromKeyfile(keyFile, "EPD", "EdgeStopping", pedited, epd.edgeStopping, pedited->epd.edgeStopping);
4266             assignFromKeyfile(keyFile, "EPD", "Scale", pedited, epd.scale, pedited->epd.scale);
4267             assignFromKeyfile(keyFile, "EPD", "ReweightingIterates", pedited, epd.reweightingIterates, pedited->epd.reweightingIterates);
4268         }
4269 
4270         if (keyFile.has_group("FattalToneMapping")) {
4271             assignFromKeyfile(keyFile, "FattalToneMapping", "Enabled", pedited, fattal.enabled, pedited->fattal.enabled);
4272             assignFromKeyfile(keyFile, "FattalToneMapping", "Threshold", pedited, fattal.threshold, pedited->fattal.threshold);
4273             assignFromKeyfile(keyFile, "FattalToneMapping", "Amount", pedited, fattal.amount, pedited->fattal.amount);
4274             assignFromKeyfile(keyFile, "FattalToneMapping", "Anchor", pedited, fattal.anchor, pedited->fattal.anchor);
4275         }
4276 
4277         if (keyFile.has_group ("Shadows & Highlights") && ppVersion >= 333) {
4278             assignFromKeyfile(keyFile, "Shadows & Highlights", "Enabled", pedited, sh.enabled, pedited->sh.enabled);
4279             assignFromKeyfile(keyFile, "Shadows & Highlights", "Highlights", pedited, sh.highlights, pedited->sh.highlights);
4280             assignFromKeyfile(keyFile, "Shadows & Highlights", "HighlightTonalWidth", pedited, sh.htonalwidth, pedited->sh.htonalwidth);
4281             assignFromKeyfile(keyFile, "Shadows & Highlights", "Shadows", pedited, sh.shadows, pedited->sh.shadows);
4282             assignFromKeyfile(keyFile, "Shadows & Highlights", "ShadowTonalWidth", pedited, sh.stonalwidth, pedited->sh.stonalwidth);
4283             assignFromKeyfile(keyFile, "Shadows & Highlights", "Radius", pedited, sh.radius, pedited->sh.radius);
4284             if (ppVersion >= 344) {
4285                 assignFromKeyfile(keyFile, "Shadows & Highlights", "Lab", pedited, sh.lab, pedited->sh.lab);
4286             } else {
4287                 sh.lab = true;
4288             }
4289 
4290             if (keyFile.has_key("Shadows & Highlights", "LocalContrast") && ppVersion < 329) {
4291                 int lc = keyFile.get_integer("Shadows & Highlights", "LocalContrast");
4292                 localContrast.amount = float(lc) / 30.;
4293 
4294                 if (pedited) {
4295                     pedited->localContrast.amount = true;
4296                 }
4297 
4298                 localContrast.enabled = sh.enabled;
4299 
4300                 if (pedited) {
4301                     pedited->localContrast.enabled = true;
4302                 }
4303 
4304                 localContrast.radius = sh.radius;
4305 
4306                 if (pedited) {
4307                     pedited->localContrast.radius = true;
4308                 }
4309             }
4310         }
4311 
4312         if (keyFile.has_group("Crop")) {
4313             assignFromKeyfile(keyFile, "Crop", "Enabled", pedited, crop.enabled, pedited->crop.enabled);
4314             assignFromKeyfile(keyFile, "Crop", "X", pedited, crop.x, pedited->crop.x);
4315             assignFromKeyfile(keyFile, "Crop", "Y", pedited, crop.y, pedited->crop.y);
4316 
4317             if (keyFile.has_key("Crop", "W")) {
4318                 crop.w = std::max(keyFile.get_integer("Crop", "W"), 1);
4319 
4320                 if (pedited) {
4321                     pedited->crop.w = true;
4322                 }
4323             }
4324 
4325             if (keyFile.has_key("Crop", "H")) {
4326                 crop.h = std::max(keyFile.get_integer("Crop", "H"), 1);
4327 
4328                 if (pedited) {
4329                     pedited->crop.h = true;
4330                 }
4331             }
4332 
4333             assignFromKeyfile(keyFile, "Crop", "FixedRatio", pedited, crop.fixratio, pedited->crop.fixratio);
4334 
4335             if (assignFromKeyfile(keyFile, "Crop", "Ratio", pedited, crop.ratio, pedited->crop.ratio)) {
4336                 //backwards compatibility for crop.ratio
4337                 if (crop.ratio == "DIN") {
4338                     crop.ratio = "1.414 - DIN EN ISO 216";
4339                 }
4340 
4341                 if (crop.ratio == "8.5:11") {
4342                     crop.ratio = "8.5:11 - US Letter";
4343                 }
4344 
4345                 if (crop.ratio == "11:17") {
4346                     crop.ratio = "11:17 - Tabloid";
4347                 }
4348             }
4349 
4350             assignFromKeyfile(keyFile, "Crop", "Orientation", pedited, crop.orientation, pedited->crop.orientation);
4351             assignFromKeyfile(keyFile, "Crop", "Guide", pedited, crop.guide, pedited->crop.guide);
4352         }
4353 
4354         if (keyFile.has_group("Coarse Transformation")) {
4355             assignFromKeyfile(keyFile, "Coarse Transformation", "Rotate", pedited, coarse.rotate, pedited->coarse.rotate);
4356             assignFromKeyfile(keyFile, "Coarse Transformation", "HorizontalFlip", pedited, coarse.hflip, pedited->coarse.hflip);
4357             assignFromKeyfile(keyFile, "Coarse Transformation", "VerticalFlip", pedited, coarse.vflip, pedited->coarse.vflip);
4358         }
4359 
4360         if (keyFile.has_group("Rotation")) {
4361             assignFromKeyfile(keyFile, "Rotation", "Degree", pedited, rotate.degree, pedited->rotate.degree);
4362         }
4363 
4364         if (keyFile.has_group("Common Properties for Transformations")) {
4365             if (keyFile.has_key("Common Properties for Transformations", "Method")) {
4366                 assignFromKeyfile(keyFile, "Common Properties for Transformations", "Method", pedited, commonTrans.method, pedited->commonTrans.method);
4367             } else {
4368                 commonTrans.method = "lin";
4369             }
4370             assignFromKeyfile(keyFile, "Common Properties for Transformations", "AutoFill", pedited, commonTrans.autofill, pedited->commonTrans.autofill);
4371         }
4372 
4373         if (keyFile.has_group("Distortion")) {
4374             assignFromKeyfile(keyFile, "Distortion", "Amount", pedited, distortion.amount, pedited->distortion.amount);
4375         }
4376 
4377         if (keyFile.has_group("LensProfile")) {
4378             if (keyFile.has_key("LensProfile", "LcMode")) {
4379                 lensProf.lcMode = lensProf.getMethodNumber(keyFile.get_string("LensProfile", "LcMode"));
4380 
4381                 if (pedited) {
4382                     pedited->lensProf.lcMode = true;
4383                 }
4384             }
4385 
4386             if (keyFile.has_key("LensProfile", "LCPFile")) {
4387                 lensProf.lcpFile = expandRelativePath(fname, "", keyFile.get_string("LensProfile", "LCPFile"));
4388 
4389                 if (pedited) {
4390                     pedited->lensProf.lcpFile = true;
4391                 }
4392 
4393                 if (ppVersion < 327 && !lensProf.lcpFile.empty()) {
4394                     lensProf.lcMode = LensProfParams::LcMode::LCP;
4395                 }
4396             }
4397 
4398             assignFromKeyfile(keyFile, "LensProfile", "UseDistortion", pedited, lensProf.useDist, pedited->lensProf.useDist);
4399             assignFromKeyfile(keyFile, "LensProfile", "UseVignette", pedited, lensProf.useVign, pedited->lensProf.useVign);
4400             assignFromKeyfile(keyFile, "LensProfile", "UseCA", pedited, lensProf.useCA, pedited->lensProf.useCA);
4401 
4402             if (keyFile.has_key("LensProfile", "LFCameraMake")) {
4403                 lensProf.lfCameraMake = keyFile.get_string("LensProfile", "LFCameraMake");
4404 
4405                 if (pedited) {
4406                     pedited->lensProf.lfCameraMake = true;
4407                 }
4408             }
4409 
4410             if (keyFile.has_key("LensProfile", "LFCameraModel")) {
4411                 lensProf.lfCameraModel = keyFile.get_string("LensProfile", "LFCameraModel");
4412 
4413                 if (pedited) {
4414                     pedited->lensProf.lfCameraModel = true;
4415                 }
4416             }
4417 
4418             if (keyFile.has_key("LensProfile", "LFLens")) {
4419                 lensProf.lfLens = keyFile.get_string("LensProfile", "LFLens");
4420 
4421                 if (pedited) {
4422                     pedited->lensProf.lfLens = true;
4423                 }
4424             }
4425         }
4426 
4427         if (keyFile.has_group("Perspective")) {
4428             assignFromKeyfile(keyFile, "Perspective", "Horizontal", pedited, perspective.horizontal, pedited->perspective.horizontal);
4429             assignFromKeyfile(keyFile, "Perspective", "Vertical", pedited, perspective.vertical, pedited->perspective.vertical);
4430         }
4431 
4432         if (keyFile.has_group("Gradient")) {
4433             assignFromKeyfile(keyFile, "Gradient", "Enabled", pedited, gradient.enabled, pedited->gradient.enabled);
4434             assignFromKeyfile(keyFile, "Gradient", "Degree", pedited, gradient.degree, pedited->gradient.degree);
4435             assignFromKeyfile(keyFile, "Gradient", "Feather", pedited, gradient.feather, pedited->gradient.feather);
4436             assignFromKeyfile(keyFile, "Gradient", "Strength", pedited, gradient.strength, pedited->gradient.strength);
4437             assignFromKeyfile(keyFile, "Gradient", "CenterX", pedited, gradient.centerX, pedited->gradient.centerX);
4438             assignFromKeyfile(keyFile, "Gradient", "CenterY", pedited, gradient.centerY, pedited->gradient.centerY);
4439         }
4440 
4441         if (keyFile.has_group("PCVignette")) {
4442             assignFromKeyfile(keyFile, "PCVignette", "Enabled", pedited, pcvignette.enabled, pedited->pcvignette.enabled);
4443             assignFromKeyfile(keyFile, "PCVignette", "Strength", pedited, pcvignette.strength, pedited->pcvignette.strength);
4444             assignFromKeyfile(keyFile, "PCVignette", "Feather", pedited, pcvignette.feather, pedited->pcvignette.feather);
4445             assignFromKeyfile(keyFile, "PCVignette", "Roundness", pedited, pcvignette.roundness, pedited->pcvignette.roundness);
4446         }
4447 
4448         if (keyFile.has_group("CACorrection")) {
4449             assignFromKeyfile(keyFile, "CACorrection", "Red", pedited, cacorrection.red, pedited->cacorrection.red);
4450             assignFromKeyfile(keyFile, "CACorrection", "Blue", pedited, cacorrection.blue, pedited->cacorrection.blue);
4451         }
4452 
4453         if (keyFile.has_group("Vignetting Correction")) {
4454             assignFromKeyfile(keyFile, "Vignetting Correction", "Amount", pedited, vignetting.amount, pedited->vignetting.amount);
4455             assignFromKeyfile(keyFile, "Vignetting Correction", "Radius", pedited, vignetting.radius, pedited->vignetting.radius);
4456             assignFromKeyfile(keyFile, "Vignetting Correction", "Strength", pedited, vignetting.strength, pedited->vignetting.strength);
4457             assignFromKeyfile(keyFile, "Vignetting Correction", "CenterX", pedited, vignetting.centerX, pedited->vignetting.centerX);
4458             assignFromKeyfile(keyFile, "Vignetting Correction", "CenterY", pedited, vignetting.centerY, pedited->vignetting.centerY);
4459         }
4460 
4461         if (keyFile.has_group("Resize")) {
4462             assignFromKeyfile(keyFile, "Resize", "Enabled", pedited, resize.enabled, pedited->resize.enabled);
4463             assignFromKeyfile(keyFile, "Resize", "Scale", pedited, resize.scale, pedited->resize.scale);
4464             assignFromKeyfile(keyFile, "Resize", "AppliesTo", pedited, resize.appliesTo, pedited->resize.appliesTo);
4465             assignFromKeyfile(keyFile, "Resize", "Method", pedited, resize.method, pedited->resize.method);
4466             assignFromKeyfile(keyFile, "Resize", "DataSpecified", pedited, resize.dataspec, pedited->resize.dataspec);
4467             assignFromKeyfile(keyFile, "Resize", "Width", pedited, resize.width, pedited->resize.width);
4468             assignFromKeyfile(keyFile, "Resize", "Height", pedited, resize.height, pedited->resize.height);
4469             if (ppVersion >= 339) {
4470                 assignFromKeyfile(keyFile, "Resize", "AllowUpscaling", pedited, resize.allowUpscaling, pedited->resize.allowUpscaling);
4471             } else {
4472                 resize.allowUpscaling = false;
4473                 if (pedited) {
4474                     pedited->resize.allowUpscaling = true;
4475                 }
4476             }
4477         }
4478 
4479         if (keyFile.has_group("PostDemosaicSharpening")) {
4480             assignFromKeyfile(keyFile, "PostDemosaicSharpening", "Enabled", pedited, pdsharpening.enabled, pedited->pdsharpening.enabled);
4481             assignFromKeyfile(keyFile, "PostDemosaicSharpening", "Contrast", pedited, pdsharpening.contrast, pedited->pdsharpening.contrast);
4482             assignFromKeyfile(keyFile, "PostDemosaicSharpening", "AutoContrast", pedited, pdsharpening.autoContrast, pedited->pdsharpening.autoContrast);
4483             assignFromKeyfile(keyFile, "PostDemosaicSharpening", "AutoRadius", pedited, pdsharpening.autoRadius, pedited->pdsharpening.autoRadius);
4484             assignFromKeyfile(keyFile, "PostDemosaicSharpening", "DeconvRadius", pedited, pdsharpening.deconvradius, pedited->pdsharpening.deconvradius);
4485             assignFromKeyfile(keyFile, "PostDemosaicSharpening", "DeconvRadiusOffset", pedited, pdsharpening.deconvradiusOffset, pedited->pdsharpening.deconvradiusOffset);
4486             assignFromKeyfile(keyFile, "PostDemosaicSharpening", "DeconvIterCheck", pedited, pdsharpening.deconvitercheck, pedited->pdsharpening.deconvitercheck);
4487             assignFromKeyfile(keyFile, "PostDemosaicSharpening", "DeconvIterations", pedited, pdsharpening.deconviter, pedited->pdsharpening.deconviter);
4488         }
4489 
4490         if (keyFile.has_group("PostResizeSharpening")) {
4491             assignFromKeyfile(keyFile, "PostResizeSharpening", "Enabled", pedited, prsharpening.enabled, pedited->prsharpening.enabled);
4492             assignFromKeyfile(keyFile, "PostResizeSharpening", "Contrast", pedited, prsharpening.contrast, pedited->prsharpening.contrast);
4493             assignFromKeyfile(keyFile, "PostResizeSharpening", "Radius", pedited, prsharpening.radius, pedited->prsharpening.radius);
4494             assignFromKeyfile(keyFile, "PostResizeSharpening", "Amount", pedited, prsharpening.amount, pedited->prsharpening.amount);
4495 
4496             if (keyFile.has_key("PostResizeSharpening", "Threshold")) {
4497                 if (ppVersion < 302) {
4498                     int thresh = min(keyFile.get_integer("PostResizeSharpening", "Threshold"), 2000);
4499                     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
4500                 } else {
4501                     const std::vector<int> thresh = keyFile.get_integer_list("PostResizeSharpening", "Threshold");
4502 
4503                     if (thresh.size() >= 4) {
4504                         prsharpening.threshold.setValues(thresh[0], thresh[1], min(thresh[2], 2000), min(thresh[3], 2000));
4505                     }
4506                 }
4507 
4508                 if (pedited) {
4509                     pedited->prsharpening.threshold = true;
4510                 }
4511             }
4512 
4513             assignFromKeyfile(keyFile, "PostResizeSharpening", "OnlyEdges", pedited, prsharpening.edgesonly, pedited->prsharpening.edgesonly);
4514             assignFromKeyfile(keyFile, "PostResizeSharpening", "EdgedetectionRadius", pedited, prsharpening.edges_radius, pedited->prsharpening.edges_radius);
4515             assignFromKeyfile(keyFile, "PostResizeSharpening", "EdgeTolerance", pedited, prsharpening.edges_tolerance, pedited->prsharpening.edges_tolerance);
4516             assignFromKeyfile(keyFile, "PostResizeSharpening", "HalocontrolEnabled", pedited, prsharpening.halocontrol, pedited->prsharpening.halocontrol);
4517             assignFromKeyfile(keyFile, "PostResizeSharpening", "HalocontrolAmount", pedited, prsharpening.halocontrol_amount, pedited->prsharpening.halocontrol_amount);
4518             assignFromKeyfile(keyFile, "PostResizeSharpening", "Method", pedited, prsharpening.method, pedited->prsharpening.method);
4519             assignFromKeyfile(keyFile, "PostResizeSharpening", "DeconvRadius", pedited, prsharpening.deconvradius, pedited->prsharpening.deconvradius);
4520             assignFromKeyfile(keyFile, "PostResizeSharpening", "DeconvAmount", pedited, prsharpening.deconvamount, pedited->prsharpening.deconvamount);
4521             assignFromKeyfile(keyFile, "PostResizeSharpening", "DeconvDamping", pedited, prsharpening.deconvdamping, pedited->prsharpening.deconvdamping);
4522             assignFromKeyfile(keyFile, "PostResizeSharpening", "DeconvIterations", pedited, prsharpening.deconviter, pedited->prsharpening.deconviter);
4523         }
4524 
4525         if (keyFile.has_group("Color Management")) {
4526             if (keyFile.has_key("Color Management", "InputProfile")) {
4527                 icm.inputProfile = expandRelativePath(fname, "file:", keyFile.get_string("Color Management", "InputProfile"));
4528 
4529                 if (pedited) {
4530                     pedited->icm.inputProfile = true;
4531                 }
4532             }
4533 
4534             assignFromKeyfile(keyFile, "Color Management", "ToneCurve", pedited, icm.toneCurve, pedited->icm.toneCurve);
4535             assignFromKeyfile(keyFile, "Color Management", "ApplyLookTable", pedited, icm.applyLookTable, pedited->icm.applyLookTable);
4536             assignFromKeyfile(keyFile, "Color Management", "ApplyBaselineExposureOffset", pedited, icm.applyBaselineExposureOffset, pedited->icm.applyBaselineExposureOffset);
4537             assignFromKeyfile(keyFile, "Color Management", "ApplyHueSatMap", pedited, icm.applyHueSatMap, pedited->icm.applyHueSatMap);
4538             assignFromKeyfile(keyFile, "Color Management", "DCPIlluminant", pedited, icm.dcpIlluminant, pedited->icm.dcpIlluminant);
4539             assignFromKeyfile(keyFile, "Color Management", "WorkingProfile", pedited, icm.workingProfile, pedited->icm.workingProfile);
4540             assignFromKeyfile(keyFile, "Color Management", "WorkingTRC", pedited, icm.workingTRC, pedited->icm.workingTRC);
4541             assignFromKeyfile(keyFile, "Color Management", "WorkingTRCGamma", pedited, icm.workingTRCGamma, pedited->icm.workingTRCGamma);
4542             assignFromKeyfile(keyFile, "Color Management", "WorkingTRCSlope", pedited, icm.workingTRCSlope, pedited->icm.workingTRCSlope);
4543 
4544             assignFromKeyfile(keyFile, "Color Management", "OutputProfile", pedited, icm.outputProfile, pedited->icm.outputProfile);
4545             if (ppVersion < 341) {
4546                 if (icm.outputProfile == "RT_Medium_gsRGB") {
4547                     icm.outputProfile = "RTv4_Medium";
4548                 } else if (icm.outputProfile == "RT_Large_gBT709" || icm.outputProfile == "RT_Large_g10" || icm.outputProfile == "RT_Large_gsRGB") {
4549                     icm.outputProfile = "RTv4_Large";
4550                 } else if (icm.outputProfile == "WideGamutRGB") {
4551                     icm.outputProfile = "RTv4_Wide";
4552                 } else if (icm.outputProfile == "RT_sRGB_gBT709" || icm.outputProfile == "RT_sRGB_g10" || icm.outputProfile == "RT_sRGB") {
4553                     icm.outputProfile = "RTv4_sRGB";
4554                 } else if (icm.outputProfile == "BetaRGB") { // Have we ever provided this profile ? Should we convert this filename ?
4555                     icm.outputProfile = "RTv4_Beta";
4556                 } else if (icm.outputProfile == "BestRGB") { // Have we ever provided this profile ? Should we convert this filename ?
4557                     icm.outputProfile = "RTv4_Best";
4558                 } else if (icm.outputProfile == "Rec2020") {
4559                     icm.outputProfile = "RTv4_Rec2020";
4560                 } else if (icm.outputProfile == "Bruce") { // Have we ever provided this profile ? Should we convert this filename ?
4561                     icm.outputProfile = "RTv4_Bruce";
4562                 } else if (icm.outputProfile == "ACES") {
4563                     icm.outputProfile = "RTv4_ACES-AP0";
4564                 }
4565             }
4566             if (keyFile.has_key("Color Management", "OutputProfileIntent")) {
4567                 Glib::ustring intent = keyFile.get_string("Color Management", "OutputProfileIntent");
4568 
4569                 if (intent == "Perceptual") {
4570                     icm.outputIntent = RI_PERCEPTUAL;
4571                 } else if (intent == "Relative") {
4572                     icm.outputIntent = RI_RELATIVE;
4573                 } else if (intent == "Saturation") {
4574                     icm.outputIntent = RI_SATURATION;
4575                 } else if (intent == "Absolute") {
4576                     icm.outputIntent = RI_ABSOLUTE;
4577                 }
4578 
4579                 if (pedited) {
4580                     pedited->icm.outputIntent = true;
4581                 }
4582             }
4583             assignFromKeyfile(keyFile, "Color Management", "OutputBPC", pedited, icm.outputBPC, pedited->icm.outputBPC);
4584         }
4585 
4586         if (keyFile.has_group("Wavelet")) {
4587             assignFromKeyfile(keyFile, "Wavelet", "Enabled", pedited, wavelet.enabled, pedited->wavelet.enabled);
4588             assignFromKeyfile(keyFile, "Wavelet", "Strength", pedited, wavelet.strength, pedited->wavelet.strength);
4589             assignFromKeyfile(keyFile, "Wavelet", "Balance", pedited, wavelet.balance, pedited->wavelet.balance);
4590             assignFromKeyfile(keyFile, "Wavelet", "Iter", pedited, wavelet.iter, pedited->wavelet.iter);
4591             assignFromKeyfile(keyFile, "Wavelet", "Median", pedited, wavelet.median, pedited->wavelet.median);
4592             assignFromKeyfile(keyFile, "Wavelet", "Medianlev", pedited, wavelet.medianlev, pedited->wavelet.medianlev);
4593             assignFromKeyfile(keyFile, "Wavelet", "Linkedg", pedited, wavelet.linkedg, pedited->wavelet.linkedg);
4594             assignFromKeyfile(keyFile, "Wavelet", "CBenab", pedited, wavelet.cbenab, pedited->wavelet.cbenab);
4595             assignFromKeyfile(keyFile, "Wavelet", "CBgreenhigh", pedited, wavelet.greenhigh, pedited->wavelet.greenhigh);
4596             assignFromKeyfile(keyFile, "Wavelet", "CBgreenmed", pedited, wavelet.greenmed, pedited->wavelet.greenmed);
4597             assignFromKeyfile(keyFile, "Wavelet", "CBgreenlow", pedited, wavelet.greenlow, pedited->wavelet.greenlow);
4598             assignFromKeyfile(keyFile, "Wavelet", "CBbluehigh", pedited, wavelet.bluehigh, pedited->wavelet.bluehigh);
4599             assignFromKeyfile(keyFile, "Wavelet", "CBbluemed", pedited, wavelet.bluemed, pedited->wavelet.bluemed);
4600             assignFromKeyfile(keyFile, "Wavelet", "CBbluelow", pedited, wavelet.bluelow, pedited->wavelet.bluelow);
4601             assignFromKeyfile(keyFile, "Wavelet", "Lipst", pedited, wavelet.lipst, pedited->wavelet.lipst);
4602             assignFromKeyfile(keyFile, "Wavelet", "AvoidColorShift", pedited, wavelet.avoid, pedited->wavelet.avoid);
4603             assignFromKeyfile(keyFile, "Wavelet", "TMr", pedited, wavelet.tmr, pedited->wavelet.tmr);
4604 
4605             if (ppVersion < 331) { // wavelet.Lmethod was a string before version 331
4606                 Glib::ustring temp;
4607                 assignFromKeyfile(keyFile, "Wavelet", "LevMethod", pedited, temp, pedited->wavelet.Lmethod);
4608 
4609                 if (!temp.empty()) {
4610                     wavelet.Lmethod = std::stoi(temp);
4611                 }
4612             } else {
4613                 assignFromKeyfile(keyFile, "Wavelet", "LevMethod", pedited, wavelet.Lmethod, pedited->wavelet.Lmethod);
4614             }
4615 
4616             assignFromKeyfile(keyFile, "Wavelet", "ChoiceLevMethod", pedited, wavelet.CLmethod, pedited->wavelet.CLmethod);
4617             assignFromKeyfile(keyFile, "Wavelet", "BackMethod", pedited, wavelet.Backmethod, pedited->wavelet.Backmethod);
4618             assignFromKeyfile(keyFile, "Wavelet", "TilesMethod", pedited, wavelet.Tilesmethod, pedited->wavelet.Tilesmethod);
4619             assignFromKeyfile(keyFile, "Wavelet", "DaubMethod", pedited, wavelet.daubcoeffmethod, pedited->wavelet.daubcoeffmethod);
4620             assignFromKeyfile(keyFile, "Wavelet", "CHromaMethod", pedited, wavelet.CHmethod, pedited->wavelet.CHmethod);
4621             assignFromKeyfile(keyFile, "Wavelet", "Medgreinf", pedited, wavelet.Medgreinf, pedited->wavelet.Medgreinf);
4622             assignFromKeyfile(keyFile, "Wavelet", "CHSLromaMethod", pedited, wavelet.CHSLmethod, pedited->wavelet.CHSLmethod);
4623             assignFromKeyfile(keyFile, "Wavelet", "EDMethod", pedited, wavelet.EDmethod, pedited->wavelet.EDmethod);
4624             assignFromKeyfile(keyFile, "Wavelet", "NPMethod", pedited, wavelet.NPmethod, pedited->wavelet.NPmethod);
4625             assignFromKeyfile(keyFile, "Wavelet", "BAMethod", pedited, wavelet.BAmethod, pedited->wavelet.BAmethod);
4626             assignFromKeyfile(keyFile, "Wavelet", "TMMethod", pedited, wavelet.TMmethod, pedited->wavelet.TMmethod);
4627             assignFromKeyfile(keyFile, "Wavelet", "HSMethod", pedited, wavelet.HSmethod, pedited->wavelet.HSmethod);
4628             assignFromKeyfile(keyFile, "Wavelet", "DirMethod", pedited, wavelet.Dirmethod, pedited->wavelet.Dirmethod);
4629             assignFromKeyfile(keyFile, "Wavelet", "ResidualcontShadow", pedited, wavelet.rescon, pedited->wavelet.rescon);
4630             assignFromKeyfile(keyFile, "Wavelet", "ResidualcontHighlight", pedited, wavelet.resconH, pedited->wavelet.resconH);
4631             assignFromKeyfile(keyFile, "Wavelet", "Residualchroma", pedited, wavelet.reschro, pedited->wavelet.reschro);
4632             assignFromKeyfile(keyFile, "Wavelet", "ResidualTM", pedited, wavelet.tmrs, pedited->wavelet.tmrs);
4633             assignFromKeyfile(keyFile, "Wavelet", "Residualgamma", pedited, wavelet.gamma, pedited->wavelet.gamma);
4634             assignFromKeyfile(keyFile, "Wavelet", "ContExtra", pedited, wavelet.sup, pedited->wavelet.sup);
4635             assignFromKeyfile(keyFile, "Wavelet", "HueRangeResidual", pedited, wavelet.sky, pedited->wavelet.sky);
4636             assignFromKeyfile(keyFile, "Wavelet", "MaxLev", pedited, wavelet.thres, pedited->wavelet.thres);
4637             assignFromKeyfile(keyFile, "Wavelet", "ThresholdHighlight", pedited, wavelet.threshold, pedited->wavelet.threshold);
4638             assignFromKeyfile(keyFile, "Wavelet", "ThresholdShadow", pedited, wavelet.threshold2, pedited->wavelet.threshold2);
4639             assignFromKeyfile(keyFile, "Wavelet", "Edgedetect", pedited, wavelet.edgedetect, pedited->wavelet.edgedetect);
4640             assignFromKeyfile(keyFile, "Wavelet", "Edgedetectthr", pedited, wavelet.edgedetectthr, pedited->wavelet.edgedetectthr);
4641             assignFromKeyfile(keyFile, "Wavelet", "EdgedetectthrHi", pedited, wavelet.edgedetectthr2, pedited->wavelet.edgedetectthr2);
4642             assignFromKeyfile(keyFile, "Wavelet", "Edgesensi", pedited, wavelet.edgesensi, pedited->wavelet.edgesensi);
4643             assignFromKeyfile(keyFile, "Wavelet", "Edgeampli", pedited, wavelet.edgeampli, pedited->wavelet.edgeampli);
4644             assignFromKeyfile(keyFile, "Wavelet", "ThresholdChroma", pedited, wavelet.chroma, pedited->wavelet.chroma);
4645             assignFromKeyfile(keyFile, "Wavelet", "ChromaLink", pedited, wavelet.chro, pedited->wavelet.chro);
4646             assignFromKeyfile(keyFile, "Wavelet", "Contrast", pedited, wavelet.contrast, pedited->wavelet.contrast);
4647             assignFromKeyfile(keyFile, "Wavelet", "Edgrad", pedited, wavelet.edgrad, pedited->wavelet.edgrad);
4648             assignFromKeyfile(keyFile, "Wavelet", "Edgval", pedited, wavelet.edgval, pedited->wavelet.edgval);
4649             assignFromKeyfile(keyFile, "Wavelet", "ThrEdg", pedited, wavelet.edgthresh, pedited->wavelet.edgthresh);
4650             assignFromKeyfile(keyFile, "Wavelet", "ThresholdResidShadow", pedited, wavelet.thr, pedited->wavelet.thr);
4651             assignFromKeyfile(keyFile, "Wavelet", "ThresholdResidHighLight", pedited, wavelet.thrH, pedited->wavelet.thrH);
4652             assignFromKeyfile(keyFile, "Wavelet", "ContrastCurve", pedited, wavelet.ccwcurve, pedited->wavelet.ccwcurve);
4653             assignFromKeyfile(keyFile, "Wavelet", "OpacityCurveRG", pedited, wavelet.opacityCurveRG, pedited->wavelet.opacityCurveRG);
4654             assignFromKeyfile(keyFile, "Wavelet", "OpacityCurveBY", pedited, wavelet.opacityCurveBY, pedited->wavelet.opacityCurveBY);
4655             assignFromKeyfile(keyFile, "Wavelet", "OpacityCurveW", pedited, wavelet.opacityCurveW, pedited->wavelet.opacityCurveW);
4656             assignFromKeyfile(keyFile, "Wavelet", "OpacityCurveWL", pedited, wavelet.opacityCurveWL, pedited->wavelet.opacityCurveWL);
4657             assignFromKeyfile(keyFile, "Wavelet", "HHcurve", pedited, wavelet.hhcurve, pedited->wavelet.hhcurve);
4658             assignFromKeyfile(keyFile, "Wavelet", "CHcurve", pedited, wavelet.Chcurve, pedited->wavelet.Chcurve);
4659             assignFromKeyfile(keyFile, "Wavelet", "WavclCurve", pedited, wavelet.wavclCurve, pedited->wavelet.wavclCurve);
4660 
4661             if (keyFile.has_key("Wavelet", "Hueskin")) {
4662                 const std::vector<int> thresh = keyFile.get_integer_list("Wavelet", "Hueskin");
4663 
4664                 if (thresh.size() >= 4) {
4665                     wavelet.hueskin.setValues(thresh[0], thresh[1], min(thresh[2], 300), min(thresh[3], 300));
4666                 }
4667 
4668                 if (pedited) {
4669                     pedited->wavelet.hueskin = true;
4670                 }
4671             }
4672 
4673             if (keyFile.has_key("Wavelet", "HueRange")) {
4674                 const std::vector<int> thresh = keyFile.get_integer_list("Wavelet", "HueRange");
4675 
4676                 if (thresh.size() >= 4) {
4677                     wavelet.hueskin2.setValues(thresh[0], thresh[1], min(thresh[2], 300), min(thresh[3], 300));
4678                 }
4679 
4680                 if (pedited) {
4681                     pedited->wavelet.hueskin2 = true;
4682                 }
4683             }
4684 
4685             if (keyFile.has_key("Wavelet", "HLRange")) {
4686                 const std::vector<int> thresh = keyFile.get_integer_list("Wavelet", "HLRange");
4687 
4688                 if (thresh.size() >= 4) {
4689                     wavelet.hllev.setValues(thresh[0], thresh[1], min(thresh[2], 300), min(thresh[3], 300));
4690                 }
4691 
4692                 if (pedited) {
4693                     pedited->wavelet.hllev = true;
4694                 }
4695             }
4696 
4697             if (keyFile.has_key("Wavelet", "SHRange")) {
4698                 const std::vector<int> thresh = keyFile.get_integer_list("Wavelet", "SHRange");
4699 
4700                 if (thresh.size() >= 4) {
4701                     wavelet.bllev.setValues(thresh[0], thresh[1], min(thresh[2], 300), min(thresh[3], 300));
4702                 }
4703 
4704                 if (pedited) {
4705                     pedited->wavelet.bllev = true;
4706                 }
4707             }
4708 
4709             if (keyFile.has_key("Wavelet", "Edgcont")) {
4710                 const std::vector<int> thresh = keyFile.get_integer_list("Wavelet", "Edgcont");
4711 
4712                 if (thresh.size() >= 4) {
4713                     wavelet.edgcont.setValues(thresh[0], thresh[1], min(thresh[2], 300), min(thresh[3], 300));
4714                 }
4715 
4716                 if (pedited) {
4717                     pedited->wavelet.edgcont = true;
4718                 }
4719             }
4720 
4721             if (keyFile.has_key("Wavelet", "Level0noise")) {
4722                 const std::vector<double> thresh = keyFile.get_double_list("Wavelet", "Level0noise");
4723 
4724                 if (thresh.size() >= 2) {
4725                     wavelet.level0noise.setValues(thresh[0], thresh[1]);
4726                 }
4727 
4728                 if (pedited) {
4729                     pedited->wavelet.level0noise = true;
4730                 }
4731             }
4732 
4733             if (keyFile.has_key("Wavelet", "Level1noise")) {
4734                 const std::vector<double> thresh = keyFile.get_double_list("Wavelet", "Level1noise");
4735 
4736                 if (thresh.size() >= 2) {
4737                     wavelet.level1noise.setValues(thresh[0], thresh[1]);
4738                 }
4739 
4740                 if (pedited) {
4741                     pedited->wavelet.level1noise = true;
4742                 }
4743             }
4744 
4745             if (keyFile.has_key("Wavelet", "Level2noise")) {
4746                 const std::vector<double> thresh = keyFile.get_double_list("Wavelet", "Level2noise");
4747 
4748                 if (thresh.size() >= 2) {
4749                     wavelet.level2noise.setValues(thresh[0], thresh[1]);
4750                 }
4751 
4752                 if (pedited) {
4753                     pedited->wavelet.level2noise = true;
4754                 }
4755             }
4756 
4757             if (keyFile.has_key("Wavelet", "Level3noise")) {
4758                 const std::vector<double> thresh = keyFile.get_double_list("Wavelet", "Level3noise");
4759 
4760                 if (thresh.size() >= 2) {
4761                     wavelet.level3noise.setValues(thresh[0], thresh[1]);
4762                 }
4763 
4764                 if (pedited) {
4765                     pedited->wavelet.level3noise = true;
4766                 }
4767             }
4768 
4769             if (keyFile.has_key("Wavelet", "Pastlev")) {
4770                 const std::vector<int> thresh = keyFile.get_integer_list("Wavelet", "Pastlev");
4771 
4772                 if (thresh.size() >= 4) {
4773                     wavelet.pastlev.setValues(thresh[0], thresh[1], min(thresh[2], 300), min(thresh[3], 300));
4774                 }
4775 
4776                 if (pedited) {
4777                     pedited->wavelet.pastlev = true;
4778                 }
4779             }
4780 
4781             if (keyFile.has_key("Wavelet", "Satlev")) {
4782                 const std::vector<int> thresh = keyFile.get_integer_list("Wavelet", "Satlev");
4783 
4784                 if (thresh.size() >= 4) {
4785                     wavelet.satlev.setValues(thresh[0], thresh[1], min(thresh[2], 300), min(thresh[3], 300));
4786                 }
4787 
4788                 if (pedited) {
4789                     pedited->wavelet.satlev = true;
4790                 }
4791             }
4792 
4793             assignFromKeyfile(keyFile, "Wavelet", "Skinprotect", pedited, wavelet.skinprotect, pedited->wavelet.skinprotect);
4794             assignFromKeyfile(keyFile, "Wavelet", "Expcontrast", pedited, wavelet.expcontrast, pedited->wavelet.expcontrast);
4795             assignFromKeyfile(keyFile, "Wavelet", "Expchroma", pedited, wavelet.expchroma, pedited->wavelet.expchroma);
4796 
4797             for (int i = 0; i < 9; ++i) {
4798                 std::stringstream ss;
4799                 ss << "Contrast" << (i + 1);
4800 
4801                 if (keyFile.has_key("Wavelet", ss.str())) {
4802                     wavelet.c[i] = keyFile.get_integer("Wavelet", ss.str());
4803 
4804                     if (pedited) {
4805                         pedited->wavelet.c[i] = true;
4806                     }
4807                 }
4808             }
4809 
4810             for (int i = 0; i < 9; ++i) {
4811                 std::stringstream ss;
4812                 ss << "Chroma" << (i + 1);
4813 
4814                 if (keyFile.has_key("Wavelet", ss.str())) {
4815                     wavelet.ch[i] = keyFile.get_integer("Wavelet", ss.str());
4816 
4817                     if (pedited) {
4818                         pedited->wavelet.ch[i] = true;
4819                     }
4820                 }
4821             }
4822 
4823             assignFromKeyfile(keyFile, "Wavelet", "Expedge", pedited, wavelet.expedge, pedited->wavelet.expedge);
4824             assignFromKeyfile(keyFile, "Wavelet", "Expresid", pedited, wavelet.expresid, pedited->wavelet.expresid);
4825             assignFromKeyfile(keyFile, "Wavelet", "Expfinal", pedited, wavelet.expfinal, pedited->wavelet.expfinal);
4826             assignFromKeyfile(keyFile, "Wavelet", "Exptoning", pedited, wavelet.exptoning, pedited->wavelet.exptoning);
4827             assignFromKeyfile(keyFile, "Wavelet", "Expnoise", pedited, wavelet.expnoise, pedited->wavelet.expnoise);
4828         }
4829 
4830         if (keyFile.has_group("Directional Pyramid Equalizer")) {
4831             assignFromKeyfile(keyFile, "Directional Pyramid Equalizer", "Enabled", pedited, dirpyrequalizer.enabled, pedited->dirpyrequalizer.enabled);
4832             assignFromKeyfile(keyFile, "Directional Pyramid Equalizer", "Gamutlab", pedited, dirpyrequalizer.gamutlab, pedited->dirpyrequalizer.gamutlab);
4833             assignFromKeyfile(keyFile, "Directional Pyramid Equalizer", "cbdlMethod", pedited, dirpyrequalizer.cbdlMethod, pedited->dirpyrequalizer.cbdlMethod);
4834 
4835             if (keyFile.has_key("Directional Pyramid Equalizer", "Hueskin")) {
4836                 const std::vector<int> thresh = keyFile.get_integer_list("Directional Pyramid Equalizer", "Hueskin");
4837 
4838                 if (thresh.size() >= 4) {
4839                     dirpyrequalizer.hueskin.setValues(thresh[0], thresh[1], min(thresh[2], 300), min(thresh[3], 300));
4840                 }
4841 
4842                 if (pedited) {
4843                     pedited->dirpyrequalizer.hueskin = true;
4844                 }
4845             }
4846 
4847             if (ppVersion < 316) {
4848                 for (int i = 0; i < 5; i ++) {
4849                     std::stringstream ss;
4850                     ss << "Mult" << i;
4851 
4852                     if (keyFile.has_key("Directional Pyramid Equalizer", ss.str())) {
4853                         if (i == 4) {
4854                             dirpyrequalizer.threshold = keyFile.get_double("Directional Pyramid Equalizer", ss.str());
4855 
4856                             if (pedited) {
4857                                 pedited->dirpyrequalizer.threshold = true;
4858                             }
4859                         } else {
4860                             dirpyrequalizer.mult[i] = keyFile.get_double("Directional Pyramid Equalizer", ss.str());
4861 
4862                             if (pedited) {
4863                                 pedited->dirpyrequalizer.mult[i] = true;
4864                             }
4865                         }
4866                     }
4867                 }
4868 
4869                 dirpyrequalizer.mult[4] = 1.0;
4870             } else {
4871                 // 5 level wavelet + dedicated threshold parameter
4872                 for (int i = 0; i < 6; i ++) {
4873                     std::stringstream ss;
4874                     ss << "Mult" << i;
4875 
4876                     if (keyFile.has_key("Directional Pyramid Equalizer", ss.str())) {
4877                         dirpyrequalizer.mult[i] = keyFile.get_double("Directional Pyramid Equalizer", ss.str());
4878 
4879                         if (pedited) {
4880                             pedited->dirpyrequalizer.mult[i] = true;
4881                         }
4882                     }
4883                 }
4884 
4885                 assignFromKeyfile(keyFile, "Directional Pyramid Equalizer", "Threshold", pedited, dirpyrequalizer.threshold, pedited->dirpyrequalizer.threshold);
4886                 assignFromKeyfile(keyFile, "Directional Pyramid Equalizer", "Skinprotect", pedited, dirpyrequalizer.skinprotect, pedited->dirpyrequalizer.skinprotect);
4887             }
4888         }
4889 
4890         if (keyFile.has_group("SoftLight")) {
4891             assignFromKeyfile(keyFile, "SoftLight", "Enabled", pedited, softlight.enabled, pedited->softlight.enabled);
4892             assignFromKeyfile(keyFile, "SoftLight", "Strength", pedited, softlight.strength, pedited->softlight.strength);
4893         }
4894 
4895         if (keyFile.has_group("Dehaze")) {
4896             assignFromKeyfile(keyFile, "Dehaze", "Enabled", pedited, dehaze.enabled, pedited->dehaze.enabled);
4897             assignFromKeyfile(keyFile, "Dehaze", "Strength", pedited, dehaze.strength, pedited->dehaze.strength);
4898             assignFromKeyfile(keyFile, "Dehaze", "ShowDepthMap", pedited, dehaze.showDepthMap, pedited->dehaze.showDepthMap);
4899             assignFromKeyfile(keyFile, "Dehaze", "Depth", pedited, dehaze.depth, pedited->dehaze.depth);
4900             assignFromKeyfile(keyFile, "Dehaze", "Luminance", pedited, dehaze.luminance, pedited->dehaze.luminance);
4901         }
4902 
4903         if (keyFile.has_group("Film Simulation")) {
4904             assignFromKeyfile(keyFile, "Film Simulation", "Enabled", pedited, filmSimulation.enabled, pedited->filmSimulation.enabled);
4905             assignFromKeyfile(keyFile, "Film Simulation", "ClutFilename", pedited, filmSimulation.clutFilename, pedited->filmSimulation.clutFilename);
4906 
4907             if (keyFile.has_key("Film Simulation", "Strength")) {
4908                 if (ppVersion < 321) {
4909                     filmSimulation.strength = keyFile.get_double("Film Simulation", "Strength") * 100 + 0.1;
4910                 } else {
4911                     filmSimulation.strength = keyFile.get_integer("Film Simulation", "Strength");
4912                 }
4913 
4914                 if (pedited) {
4915                     pedited->filmSimulation.strength = true;
4916                 }
4917             }
4918         }
4919 
4920         if (keyFile.has_group("HSV Equalizer")) {
4921             if (ppVersion >= 329) {
4922                 assignFromKeyfile(keyFile, "HSV Equalizer", "Enabled", pedited, hsvequalizer.enabled, pedited->hsvequalizer.enabled);
4923             } else {
4924                 hsvequalizer.enabled = true;
4925 
4926                 if (pedited) {
4927                     pedited->hsvequalizer.enabled = true;
4928                 }
4929             }
4930 
4931             if (ppVersion >= 300) {
4932                 assignFromKeyfile(keyFile, "HSV Equalizer", "HCurve", pedited, hsvequalizer.hcurve, pedited->hsvequalizer.hcurve);
4933                 assignFromKeyfile(keyFile, "HSV Equalizer", "SCurve", pedited, hsvequalizer.scurve, pedited->hsvequalizer.scurve);
4934                 assignFromKeyfile(keyFile, "HSV Equalizer", "VCurve", pedited, hsvequalizer.vcurve, pedited->hsvequalizer.vcurve);
4935             }
4936         }
4937 
4938         if (keyFile.has_group("RGB Curves")) {
4939             if (ppVersion >= 329) {
4940                 assignFromKeyfile(keyFile, "RGB Curves", "Enabled", pedited, rgbCurves.enabled, pedited->rgbCurves.enabled);
4941             } else {
4942                 rgbCurves.enabled = true;
4943 
4944                 if (pedited) {
4945                     pedited->rgbCurves.enabled = true;
4946                 }
4947             }
4948 
4949             assignFromKeyfile(keyFile, "RGB Curves", "LumaMode", pedited, rgbCurves.lumamode, pedited->rgbCurves.lumamode);
4950             assignFromKeyfile(keyFile, "RGB Curves", "rCurve", pedited, rgbCurves.rcurve, pedited->rgbCurves.rcurve);
4951             assignFromKeyfile(keyFile, "RGB Curves", "gCurve", pedited, rgbCurves.gcurve, pedited->rgbCurves.gcurve);
4952             assignFromKeyfile(keyFile, "RGB Curves", "bCurve", pedited, rgbCurves.bcurve, pedited->rgbCurves.bcurve);
4953         }
4954 
4955         if (keyFile.has_group("ColorToning")) {
4956             assignFromKeyfile(keyFile, "ColorToning", "Enabled", pedited, colorToning.enabled, pedited->colorToning.enabled);
4957             assignFromKeyfile(keyFile, "ColorToning", "Method", pedited, colorToning.method, pedited->colorToning.method);
4958             assignFromKeyfile(keyFile, "ColorToning", "Lumamode", pedited, colorToning.lumamode, pedited->colorToning.lumamode);
4959             assignFromKeyfile(keyFile, "ColorToning", "Twocolor", pedited, colorToning.twocolor, pedited->colorToning.twocolor);
4960             assignFromKeyfile(keyFile, "ColorToning", "OpacityCurve", pedited, colorToning.opacityCurve, pedited->colorToning.opacityCurve);
4961             assignFromKeyfile(keyFile, "ColorToning", "ColorCurve", pedited, colorToning.colorCurve, pedited->colorToning.colorCurve);
4962             assignFromKeyfile(keyFile, "ColorToning", "Autosat", pedited, colorToning.autosat, pedited->colorToning.autosat);
4963             assignFromKeyfile(keyFile, "ColorToning", "SatProtectionThreshold", pedited, colorToning.satProtectionThreshold, pedited->colorToning.satprotectionthreshold);
4964             assignFromKeyfile(keyFile, "ColorToning", "SaturatedOpacity", pedited, colorToning.saturatedOpacity, pedited->colorToning.saturatedopacity);
4965             assignFromKeyfile(keyFile, "ColorToning", "Strength", pedited, colorToning.strength, pedited->colorToning.strength);
4966 
4967             if (keyFile.has_key("ColorToning", "HighlightsColorSaturation")) {
4968                 const std::vector<int> thresh = keyFile.get_integer_list("ColorToning", "HighlightsColorSaturation");
4969 
4970                 if (thresh.size() >= 2) {
4971                     colorToning.hlColSat.setValues(thresh[0], thresh[1]);
4972                 }
4973 
4974                 if (pedited) {
4975                     pedited->colorToning.hlColSat = true;
4976                 }
4977             }
4978 
4979             if (keyFile.has_key("ColorToning", "ShadowsColorSaturation")) {
4980                 const std::vector<int> thresh = keyFile.get_integer_list("ColorToning", "ShadowsColorSaturation");
4981 
4982                 if (thresh.size() >= 2) {
4983                     colorToning.shadowsColSat.setValues(thresh[0], thresh[1]);
4984                 }
4985 
4986                 if (pedited) {
4987                     pedited->colorToning.shadowsColSat = true;
4988                 }
4989             }
4990 
4991             assignFromKeyfile(keyFile, "ColorToning", "ClCurve", pedited, colorToning.clcurve, pedited->colorToning.clcurve);
4992             assignFromKeyfile(keyFile, "ColorToning", "Cl2Curve", pedited, colorToning.cl2curve, pedited->colorToning.cl2curve);
4993             assignFromKeyfile(keyFile, "ColorToning", "Redlow", pedited, colorToning.redlow, pedited->colorToning.redlow);
4994             assignFromKeyfile(keyFile, "ColorToning", "Greenlow", pedited, colorToning.greenlow, pedited->colorToning.greenlow);
4995             assignFromKeyfile(keyFile, "ColorToning", "Bluelow", pedited, colorToning.bluelow, pedited->colorToning.bluelow);
4996             assignFromKeyfile(keyFile, "ColorToning", "Satlow", pedited, colorToning.satlow, pedited->colorToning.satlow);
4997             assignFromKeyfile(keyFile, "ColorToning", "Balance", pedited, colorToning.balance, pedited->colorToning.balance);
4998             assignFromKeyfile(keyFile, "ColorToning", "Sathigh", pedited, colorToning.sathigh, pedited->colorToning.sathigh);
4999             assignFromKeyfile(keyFile, "ColorToning", "Redmed", pedited, colorToning.redmed, pedited->colorToning.redmed);
5000             assignFromKeyfile(keyFile, "ColorToning", "Greenmed", pedited, colorToning.greenmed, pedited->colorToning.greenmed);
5001             assignFromKeyfile(keyFile, "ColorToning", "Bluemed", pedited, colorToning.bluemed, pedited->colorToning.bluemed);
5002             assignFromKeyfile(keyFile, "ColorToning", "Redhigh", pedited, colorToning.redhigh, pedited->colorToning.redhigh);
5003             assignFromKeyfile(keyFile, "ColorToning", "Greenhigh", pedited, colorToning.greenhigh, pedited->colorToning.greenhigh);
5004             assignFromKeyfile(keyFile, "ColorToning", "Bluehigh", pedited, colorToning.bluehigh, pedited->colorToning.bluehigh);
5005 
5006             assignFromKeyfile(keyFile, "ColorToning", "LabGridALow", pedited, colorToning.labgridALow, pedited->colorToning.labgridALow);
5007             assignFromKeyfile(keyFile, "ColorToning", "LabGridBLow", pedited, colorToning.labgridBLow, pedited->colorToning.labgridBLow);
5008             assignFromKeyfile(keyFile, "ColorToning", "LabGridAHigh", pedited, colorToning.labgridAHigh, pedited->colorToning.labgridAHigh);
5009             assignFromKeyfile(keyFile, "ColorToning", "LabGridBHigh", pedited, colorToning.labgridBHigh, pedited->colorToning.labgridBHigh);
5010             if (ppVersion < 337) {
5011                 const double scale = ColorToningParams::LABGRID_CORR_SCALE;
5012                 colorToning.labgridALow *= scale;
5013                 colorToning.labgridAHigh *= scale;
5014                 colorToning.labgridBLow *= scale;
5015                 colorToning.labgridBHigh *= scale;
5016             }
5017             std::vector<ColorToningParams::LabCorrectionRegion> lg;
5018             bool found = false;
5019             bool done = false;
5020             for (int i = 1; !done; ++i) {
5021                 ColorToningParams::LabCorrectionRegion cur;
5022                 done = true;
5023                 std::string n = std::to_string(i);
5024                 if (assignFromKeyfile(keyFile, "ColorToning", Glib::ustring("LabRegionA_") + n, pedited, cur.a, pedited->colorToning.labregions)) {
5025                     found = true;
5026                     done = false;
5027                 }
5028                 if (assignFromKeyfile(keyFile, "ColorToning", Glib::ustring("LabRegionB_") + n, pedited, cur.b, pedited->colorToning.labregions)) {
5029                     found = true;
5030                     done = false;
5031                 }
5032                 if (assignFromKeyfile(keyFile, "ColorToning", Glib::ustring("LabRegionSaturation_") + n, pedited, cur.saturation, pedited->colorToning.labregions)) {
5033                     found = true;
5034                     done = false;
5035                 }
5036                 if (assignFromKeyfile(keyFile, "ColorToning", Glib::ustring("LabRegionSlope_") + n, pedited, cur.slope, pedited->colorToning.labregions)) {
5037                     found = true;
5038                     done = false;
5039                 }
5040                 if (assignFromKeyfile(keyFile, "ColorToning", Glib::ustring("LabRegionOffset_") + n, pedited, cur.offset, pedited->colorToning.labregions)) {
5041                     found = true;
5042                     done = false;
5043                 }
5044                 if (assignFromKeyfile(keyFile, "ColorToning", Glib::ustring("LabRegionPower_") + n, pedited, cur.power, pedited->colorToning.labregions)) {
5045                     found = true;
5046                     done = false;
5047                 }
5048                 if (assignFromKeyfile(keyFile, "ColorToning", Glib::ustring("LabRegionHueMask_") + n, pedited, cur.hueMask, pedited->colorToning.labregions)) {
5049                     found = true;
5050                     done = false;
5051                 }
5052                 if (assignFromKeyfile(keyFile, "ColorToning", Glib::ustring("LabRegionChromaticityMask_") + n, pedited, cur.chromaticityMask, pedited->colorToning.labregions)) {
5053                     found = true;
5054                     done = false;
5055                 }
5056                 if (assignFromKeyfile(keyFile, "ColorToning", Glib::ustring("LabRegionLightnessMask_") + n, pedited, cur.lightnessMask, pedited->colorToning.labregions)) {
5057                     found = true;
5058                     done = false;
5059                 }
5060                 if (assignFromKeyfile(keyFile, "ColorToning", Glib::ustring("LabRegionMaskBlur_") + n, pedited, cur.maskBlur, pedited->colorToning.labregions)) {
5061                     found = true;
5062                     done = false;
5063                 }
5064                 if (assignFromKeyfile(keyFile, "ColorToning", Glib::ustring("LabRegionChannel_") + n, pedited, cur.channel, pedited->colorToning.labregions)) {
5065                     found = true;
5066                     done = false;
5067                 }
5068                 if (!done) {
5069                     lg.emplace_back(cur);
5070                 }
5071             }
5072             if (found) {
5073                 colorToning.labregions = std::move(lg);
5074             }
5075             assignFromKeyfile(keyFile, "ColorToning", "LabRegionsShowMask", pedited, colorToning.labregionsShowMask, pedited->colorToning.labregionsShowMask);
5076         }
5077 
5078         if (keyFile.has_group("RAW")) {
5079             if (keyFile.has_key("RAW", "DarkFrame")) {
5080                 raw.dark_frame = expandRelativePath(fname, "", keyFile.get_string("RAW", "DarkFrame"));
5081 
5082                 if (pedited) {
5083                     pedited->raw.darkFrame = true;
5084                 }
5085             }
5086 
5087             assignFromKeyfile(keyFile, "RAW", "DarkFrameAuto", pedited, raw.df_autoselect, pedited->raw.df_autoselect);
5088 
5089             if (keyFile.has_key("RAW", "FlatFieldFile")) {
5090                 raw.ff_file = expandRelativePath(fname, "", keyFile.get_string("RAW", "FlatFieldFile"));
5091 
5092                 if (pedited) {
5093                     pedited->raw.ff_file = true;
5094                 }
5095             }
5096 
5097             assignFromKeyfile(keyFile, "RAW", "FlatFieldAutoSelect", pedited, raw.ff_AutoSelect, pedited->raw.ff_AutoSelect);
5098             assignFromKeyfile(keyFile, "RAW", "FlatFieldBlurRadius", pedited, raw.ff_BlurRadius, pedited->raw.ff_BlurRadius);
5099             assignFromKeyfile(keyFile, "RAW", "FlatFieldBlurType", pedited, raw.ff_BlurType, pedited->raw.ff_BlurType);
5100             assignFromKeyfile(keyFile, "RAW", "FlatFieldAutoClipControl", pedited, raw.ff_AutoClipControl, pedited->raw.ff_AutoClipControl);
5101 
5102             if (ppVersion < 328) {
5103                 // With ppversion < 328 this value was stored as a boolean, which is nonsense.
5104                 // To avoid annoying warnings we skip reading and assume 0.
5105                 raw.ff_clipControl = 0;
5106             } else {
5107                 assignFromKeyfile(keyFile, "RAW", "FlatFieldClipControl", pedited, raw.ff_clipControl, pedited->raw.ff_clipControl);
5108             }
5109 
5110             assignFromKeyfile(keyFile, "RAW", "CA", pedited, raw.ca_autocorrect, pedited->raw.ca_autocorrect);
5111             if (ppVersion >= 342) {
5112                 assignFromKeyfile(keyFile, "RAW", "CAAutoIterations", pedited, raw.caautoiterations, pedited->raw.caautoiterations);
5113             } else {
5114                 raw.caautoiterations = 1;
5115             }
5116 
5117             if (ppVersion >= 343) {
5118                 assignFromKeyfile(keyFile, "RAW", "CAAvoidColourshift", pedited, raw.ca_avoidcolourshift, pedited->raw.ca_avoidcolourshift);
5119             } else {
5120                 raw.ca_avoidcolourshift = false;
5121             }
5122             assignFromKeyfile(keyFile, "RAW", "CARed", pedited, raw.cared, pedited->raw.cared);
5123             assignFromKeyfile(keyFile, "RAW", "CABlue", pedited, raw.cablue, pedited->raw.cablue);
5124             // For compatibility to elder pp3 versions
5125             assignFromKeyfile(keyFile, "RAW", "HotDeadPixels", pedited, raw.hotPixelFilter, pedited->raw.hotPixelFilter);
5126             raw.deadPixelFilter = raw.hotPixelFilter;
5127 
5128             if (pedited) {
5129                 pedited->raw.deadPixelFilter = pedited->raw.hotPixelFilter;
5130             }
5131 
5132             assignFromKeyfile(keyFile, "RAW", "HotPixelFilter", pedited, raw.hotPixelFilter, pedited->raw.hotPixelFilter);
5133             assignFromKeyfile(keyFile, "RAW", "DeadPixelFilter", pedited, raw.deadPixelFilter, pedited->raw.deadPixelFilter);
5134             assignFromKeyfile(keyFile, "RAW", "HotDeadPixelThresh", pedited, raw.hotdeadpix_thresh, pedited->raw.hotdeadpix_thresh);
5135             assignFromKeyfile(keyFile, "RAW", "PreExposure", pedited, raw.expos, pedited->raw.exPos);
5136 
5137             if (ppVersion < 320) {
5138                 assignFromKeyfile(keyFile, "RAW", "Method", pedited, raw.bayersensor.method, pedited->raw.bayersensor.method);
5139                 assignFromKeyfile(keyFile, "RAW", "CcSteps", pedited, raw.bayersensor.ccSteps, pedited->raw.bayersensor.ccSteps);
5140                 assignFromKeyfile(keyFile, "RAW", "LineDenoise", pedited, raw.bayersensor.linenoise, pedited->raw.bayersensor.linenoise);
5141                 assignFromKeyfile(keyFile, "RAW", "GreenEqThreshold", pedited, raw.bayersensor.greenthresh, pedited->raw.bayersensor.greenEq);
5142                 assignFromKeyfile(keyFile, "RAW", "DCBIterations", pedited, raw.bayersensor.dcb_iterations, pedited->raw.bayersensor.dcbIterations);
5143                 assignFromKeyfile(keyFile, "RAW", "DCBEnhance", pedited, raw.bayersensor.dcb_enhance, pedited->raw.bayersensor.dcbEnhance);
5144                 assignFromKeyfile(keyFile, "RAW", "LMMSEIterations", pedited, raw.bayersensor.lmmse_iterations, pedited->raw.bayersensor.lmmseIterations);
5145                 assignFromKeyfile(keyFile, "RAW", "PreBlackzero", pedited, raw.bayersensor.black0, pedited->raw.bayersensor.exBlack0);
5146                 assignFromKeyfile(keyFile, "RAW", "PreBlackone", pedited, raw.bayersensor.black1, pedited->raw.bayersensor.exBlack1);
5147                 assignFromKeyfile(keyFile, "RAW", "PreBlacktwo", pedited, raw.bayersensor.black2, pedited->raw.bayersensor.exBlack2);
5148                 assignFromKeyfile(keyFile, "RAW", "PreBlackthree", pedited, raw.bayersensor.black3, pedited->raw.bayersensor.exBlack3);
5149                 assignFromKeyfile(keyFile, "RAW", "PreTwoGreen", pedited, raw.bayersensor.twogreen, pedited->raw.bayersensor.exTwoGreen);
5150             }
5151         }
5152 
5153         if (keyFile.has_group("RAW Bayer")) {
5154             assignFromKeyfile(keyFile, "RAW Bayer", "Method", pedited, raw.bayersensor.method, pedited->raw.bayersensor.method);
5155             assignFromKeyfile(keyFile, "RAW Bayer", "Border", pedited, raw.bayersensor.border, pedited->raw.bayersensor.border);
5156 
5157             if (keyFile.has_key("RAW Bayer", "ImageNum")) {
5158                 raw.bayersensor.imageNum = keyFile.get_integer("RAW Bayer", "ImageNum") - 1;
5159 
5160                 if (pedited) {
5161                     pedited->raw.bayersensor.imageNum = true;
5162                 }
5163             }
5164 
5165             assignFromKeyfile(keyFile, "RAW Bayer", "CcSteps", pedited, raw.bayersensor.ccSteps, pedited->raw.bayersensor.ccSteps);
5166             assignFromKeyfile(keyFile, "RAW Bayer", "PreBlack0", pedited, raw.bayersensor.black0, pedited->raw.bayersensor.exBlack0);
5167             assignFromKeyfile(keyFile, "RAW Bayer", "PreBlack1", pedited, raw.bayersensor.black1, pedited->raw.bayersensor.exBlack1);
5168             assignFromKeyfile(keyFile, "RAW Bayer", "PreBlack2", pedited, raw.bayersensor.black2, pedited->raw.bayersensor.exBlack2);
5169             assignFromKeyfile(keyFile, "RAW Bayer", "PreBlack3", pedited, raw.bayersensor.black3, pedited->raw.bayersensor.exBlack3);
5170             assignFromKeyfile(keyFile, "RAW Bayer", "PreTwoGreen", pedited, raw.bayersensor.twogreen, pedited->raw.bayersensor.exTwoGreen);
5171             assignFromKeyfile(keyFile, "RAW Bayer", "LineDenoise", pedited, raw.bayersensor.linenoise, pedited->raw.bayersensor.linenoise);
5172 
5173             if (keyFile.has_key("RAW Bayer", "LineDenoiseDirection")) {
5174                 raw.bayersensor.linenoiseDirection = RAWParams::BayerSensor::LineNoiseDirection(keyFile.get_integer("RAW Bayer", "LineDenoiseDirection"));
5175 
5176                 if (pedited) {
5177                     pedited->raw.bayersensor.linenoiseDirection = true;
5178                 }
5179             }
5180 
5181             assignFromKeyfile(keyFile, "RAW Bayer", "GreenEqThreshold", pedited, raw.bayersensor.greenthresh, pedited->raw.bayersensor.greenEq);
5182             assignFromKeyfile(keyFile, "RAW Bayer", "DCBIterations", pedited, raw.bayersensor.dcb_iterations, pedited->raw.bayersensor.dcbIterations);
5183             assignFromKeyfile(keyFile, "RAW Bayer", "DCBEnhance", pedited, raw.bayersensor.dcb_enhance, pedited->raw.bayersensor.dcbEnhance);
5184             assignFromKeyfile(keyFile, "RAW Bayer", "LMMSEIterations", pedited, raw.bayersensor.lmmse_iterations, pedited->raw.bayersensor.lmmseIterations);
5185             assignFromKeyfile(keyFile, "RAW Bayer", "DualDemosaicAutoContrast", pedited, raw.bayersensor.dualDemosaicAutoContrast, pedited->raw.bayersensor.dualDemosaicAutoContrast);
5186             if (ppVersion < 345) {
5187                 raw.bayersensor.dualDemosaicAutoContrast = false;
5188                 if (pedited) {
5189                     pedited->raw.bayersensor.dualDemosaicAutoContrast = true;
5190                 }
5191             }
5192             assignFromKeyfile(keyFile, "RAW Bayer", "DualDemosaicContrast", pedited, raw.bayersensor.dualDemosaicContrast, pedited->raw.bayersensor.dualDemosaicContrast);
5193 
5194             if (keyFile.has_key("RAW Bayer", "PixelShiftMotionCorrectionMethod")) {
5195                 raw.bayersensor.pixelShiftMotionCorrectionMethod = (RAWParams::BayerSensor::PSMotionCorrectionMethod)keyFile.get_integer("RAW Bayer", "PixelShiftMotionCorrectionMethod");
5196 
5197                 if (pedited) {
5198                     pedited->raw.bayersensor.pixelShiftMotionCorrectionMethod = true;
5199                 }
5200             }
5201 
5202             assignFromKeyfile(keyFile, "RAW Bayer", "PixelShiftEperIso", pedited, raw.bayersensor.pixelShiftEperIso, pedited->raw.bayersensor.pixelShiftEperIso);
5203             if (ppVersion < 332) {
5204                 raw.bayersensor.pixelShiftEperIso += 1.0;
5205             }
5206             assignFromKeyfile(keyFile, "RAW Bayer", "PixelShiftSigma", pedited, raw.bayersensor.pixelShiftSigma, pedited->raw.bayersensor.pixelShiftSigma);
5207             assignFromKeyfile(keyFile, "RAW Bayer", "PixelShiftShowMotion", pedited, raw.bayersensor.pixelShiftShowMotion, pedited->raw.bayersensor.pixelShiftShowMotion);
5208             assignFromKeyfile(keyFile, "RAW Bayer", "PixelShiftShowMotionMaskOnly", pedited, raw.bayersensor.pixelShiftShowMotionMaskOnly, pedited->raw.bayersensor.pixelShiftShowMotionMaskOnly);
5209             assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftHoleFill", pedited, raw.bayersensor.pixelShiftHoleFill, pedited->raw.bayersensor.pixelShiftHoleFill);
5210             assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftMedian", pedited, raw.bayersensor.pixelShiftMedian, pedited->raw.bayersensor.pixelShiftMedian);
5211             assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftGreen", pedited, raw.bayersensor.pixelShiftGreen, pedited->raw.bayersensor.pixelShiftGreen);
5212             assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftBlur", pedited, raw.bayersensor.pixelShiftBlur, pedited->raw.bayersensor.pixelShiftBlur);
5213             assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftSmoothFactor", pedited, raw.bayersensor.pixelShiftSmoothFactor, pedited->raw.bayersensor.pixelShiftSmooth);
5214             assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftEqualBright", pedited, raw.bayersensor.pixelShiftEqualBright, pedited->raw.bayersensor.pixelShiftEqualBright);
5215             assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftEqualBrightChannel", pedited, raw.bayersensor.pixelShiftEqualBrightChannel, pedited->raw.bayersensor.pixelShiftEqualBrightChannel);
5216             assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftNonGreenCross", pedited, raw.bayersensor.pixelShiftNonGreenCross, pedited->raw.bayersensor.pixelShiftNonGreenCross);
5217 
5218             if (ppVersion < 336) {
5219                 if (keyFile.has_key("RAW Bayer", "pixelShiftLmmse")) {
5220                     bool useLmmse = keyFile.get_boolean ("RAW Bayer", "pixelShiftLmmse");
5221                     if (useLmmse) {
5222                         raw.bayersensor.pixelShiftDemosaicMethod = raw.bayersensor.getPSDemosaicMethodString(RAWParams::BayerSensor::PSDemosaicMethod::LMMSE);
5223                     } else {
5224                         raw.bayersensor.pixelShiftDemosaicMethod = raw.bayersensor.getPSDemosaicMethodString(RAWParams::BayerSensor::PSDemosaicMethod::AMAZE);
5225                     }
5226                     if (pedited) {
5227                         pedited->raw.bayersensor.pixelShiftDemosaicMethod = true;
5228                     }
5229                 }
5230             } else {
5231                 assignFromKeyfile(keyFile, "RAW Bayer", "pixelShiftDemosaicMethod", pedited, raw.bayersensor.pixelShiftDemosaicMethod, pedited->raw.bayersensor.pixelShiftDemosaicMethod);
5232             }
5233 
5234             assignFromKeyfile(keyFile, "RAW Bayer", "PDAFLinesFilter", pedited, raw.bayersensor.pdafLinesFilter, pedited->raw.bayersensor.pdafLinesFilter);
5235         }
5236 
5237         if (keyFile.has_group("RAW X-Trans")) {
5238             assignFromKeyfile(keyFile, "RAW X-Trans", "Method", pedited, raw.xtranssensor.method, pedited->raw.xtranssensor.method);
5239             assignFromKeyfile(keyFile, "RAW X-Trans", "DualDemosaicAutoContrast", pedited, raw.xtranssensor.dualDemosaicAutoContrast, pedited->raw.xtranssensor.dualDemosaicAutoContrast);
5240             if (ppVersion < 345) {
5241                 raw.xtranssensor.dualDemosaicAutoContrast = false;
5242                 if (pedited) {
5243                     pedited->raw.xtranssensor.dualDemosaicAutoContrast = true;
5244                 }
5245             }
5246             assignFromKeyfile(keyFile, "RAW X-Trans", "DualDemosaicContrast", pedited, raw.xtranssensor.dualDemosaicContrast, pedited->raw.xtranssensor.dualDemosaicContrast);
5247             assignFromKeyfile(keyFile, "RAW X-Trans", "Border", pedited, raw.xtranssensor.border, pedited->raw.xtranssensor.border);
5248             assignFromKeyfile(keyFile, "RAW X-Trans", "CcSteps", pedited, raw.xtranssensor.ccSteps, pedited->raw.xtranssensor.ccSteps);
5249             assignFromKeyfile(keyFile, "RAW X-Trans", "PreBlackRed", pedited, raw.xtranssensor.blackred, pedited->raw.xtranssensor.exBlackRed);
5250             assignFromKeyfile(keyFile, "RAW X-Trans", "PreBlackGreen", pedited, raw.xtranssensor.blackgreen, pedited->raw.xtranssensor.exBlackGreen);
5251             assignFromKeyfile(keyFile, "RAW X-Trans", "PreBlackBlue", pedited, raw.xtranssensor.blackblue, pedited->raw.xtranssensor.exBlackBlue);
5252         }
5253 
5254         if (keyFile.has_group("Film Negative")) {
5255             assignFromKeyfile(keyFile, "Film Negative", "Enabled", pedited, filmNegative.enabled, pedited->filmNegative.enabled);
5256             assignFromKeyfile(keyFile, "Film Negative", "RedRatio", pedited, filmNegative.redRatio, pedited->filmNegative.redRatio);
5257             assignFromKeyfile(keyFile, "Film Negative", "GreenExponent", pedited, filmNegative.greenExp, pedited->filmNegative.greenExp);
5258             assignFromKeyfile(keyFile, "Film Negative", "BlueRatio", pedited, filmNegative.blueRatio, pedited->filmNegative.blueRatio);
5259         }
5260 
5261         if (keyFile.has_group("MetaData")) {
5262             int mode = int(MetaDataParams::TUNNEL);
5263             assignFromKeyfile(keyFile, "MetaData", "Mode", pedited, mode, pedited->metadata.mode);
5264 
5265             if (mode >= int(MetaDataParams::TUNNEL) && mode <= int(MetaDataParams::STRIP)) {
5266                 metadata.mode = static_cast<MetaDataParams::Mode>(mode);
5267             }
5268         }
5269 
5270         if (keyFile.has_group("Exif")) {
5271             for (const auto& key : keyFile.get_keys("Exif")) {
5272                 exif[key] = keyFile.get_string("Exif", key);
5273 
5274                 if (pedited) {
5275                     pedited->exif = true;
5276                 }
5277             }
5278         }
5279 
5280         /*
5281          * Load iptc change settings
5282          *
5283          * Existing values are preserved, and the stored values
5284          * are added to the list. To reset a field, the user has to
5285          * save the profile with the field leaved empty, but still
5286          * terminated by a semi-column ";"
5287          *
5288          * Please note that the old Keywords and SupplementalCategories
5289          * tag content is fully replaced by the new one,
5290          * i.e. they don't merge
5291          */
5292         if (keyFile.has_group("IPTC")) {
5293             for (const auto& key : keyFile.get_keys("IPTC")) {
5294                 // does this key already exist?
5295                 const IPTCPairs::iterator element = iptc.find(key);
5296 
5297                 if (element != iptc.end()) {
5298                     // it already exist so we cleanup the values
5299                     element->second.clear();
5300                 }
5301 
5302                 // TODO: look out if merging Keywords and SupplementalCategories from the procparams chain would be interesting
5303                 for (const auto& currLoadedTagValue : keyFile.get_string_list("IPTC", key)) {
5304                     iptc[key].push_back(currLoadedTagValue);
5305                 }
5306 
5307                 if (pedited) {
5308                     pedited->iptc = true;
5309                 }
5310             }
5311         }
5312 
5313         return 0;
5314     } catch (const Glib::Error& e) {
5315         printf("-->%s\n", e.what().c_str());
5316         setDefaults();
5317         return 1;
5318     } catch (...) {
5319         printf("-->unknown exception!\n");
5320         setDefaults();
5321         return 1;
5322     }
5323 
5324     return 0;
5325 }
5326 
create()5327 ProcParams* ProcParams::create()
5328 {
5329     return new ProcParams();
5330 }
5331 
destroy(ProcParams * pp)5332 void ProcParams::destroy(ProcParams* pp)
5333 {
5334     delete pp;
5335 }
5336 
operator ==(const ProcParams & other) const5337 bool ProcParams::operator ==(const ProcParams& other) const
5338 {
5339     return
5340         toneCurve == other.toneCurve
5341         && retinex == other.retinex
5342         && localContrast == other.localContrast
5343         && labCurve == other.labCurve
5344         && sharpenEdge == other.sharpenEdge
5345         && sharpenMicro == other.sharpenMicro
5346         && sharpening == other.sharpening
5347         && prsharpening == other.prsharpening
5348         && vibrance == other.vibrance
5349         && wb == other.wb
5350         && colorappearance == other.colorappearance
5351         && impulseDenoise == other.impulseDenoise
5352         && dirpyrDenoise == other.dirpyrDenoise
5353         && epd == other.epd
5354         && fattal == other.fattal
5355         && defringe == other.defringe
5356         && sh == other.sh
5357         && crop == other.crop
5358         && coarse == other.coarse
5359         && rotate == other.rotate
5360         && commonTrans == other.commonTrans
5361         && distortion == other.distortion
5362         && lensProf == other.lensProf
5363         && perspective == other.perspective
5364         && gradient == other.gradient
5365         && pcvignette == other.pcvignette
5366         && cacorrection == other.cacorrection
5367         && vignetting == other.vignetting
5368         && chmixer == other.chmixer
5369         && blackwhite == other.blackwhite
5370         && resize == other.resize
5371         && raw == other.raw
5372         && icm == other.icm
5373         && wavelet == other.wavelet
5374         && dirpyrequalizer == other.dirpyrequalizer
5375         && hsvequalizer == other.hsvequalizer
5376         && filmSimulation == other.filmSimulation
5377         && softlight == other.softlight
5378         && rgbCurves == other.rgbCurves
5379         && colorToning == other.colorToning
5380         && metadata == other.metadata
5381         && exif == other.exif
5382         && iptc == other.iptc
5383         && dehaze == other.dehaze
5384         && filmNegative == other.filmNegative;
5385 }
5386 
operator !=(const ProcParams & other) const5387 bool ProcParams::operator !=(const ProcParams& other) const
5388 {
5389     return !(*this == other);
5390 }
5391 
init()5392 void ProcParams::init()
5393 {
5394 }
5395 
cleanup()5396 void ProcParams::cleanup()
5397 {
5398 }
5399 
write(const Glib::ustring & fname,const Glib::ustring & content) const5400 int ProcParams::write(const Glib::ustring& fname, const Glib::ustring& content) const
5401 {
5402     int error = 0;
5403 
5404     if (fname.length()) {
5405         FILE *f;
5406         f = g_fopen(fname.c_str(), "wt");
5407 
5408         if (f == nullptr) {
5409             error = 1;
5410         } else {
5411             fprintf(f, "%s", content.c_str());
5412             fclose(f);
5413         }
5414     }
5415 
5416     return error;
5417 }
5418 
PartialProfile(bool createInstance,bool paramsEditedValue)5419 PartialProfile::PartialProfile(bool createInstance, bool paramsEditedValue)
5420 {
5421     if (createInstance) {
5422         pparams = new ProcParams();
5423         pedited = new ParamsEdited(paramsEditedValue);
5424     } else {
5425         pparams = nullptr;
5426         pedited = nullptr;
5427     }
5428 }
5429 
PartialProfile(ProcParams * pp,ParamsEdited * pe,bool fullCopy)5430 PartialProfile::PartialProfile(ProcParams* pp, ParamsEdited* pe, bool fullCopy)
5431 {
5432     if (fullCopy && pp) {
5433         pparams = new ProcParams(*pp);
5434     } else {
5435         pparams = pp;
5436     }
5437 
5438     if (fullCopy && pe) {
5439         pedited = new ParamsEdited(*pe);
5440     } else {
5441         pedited = pe;
5442     }
5443 }
5444 
PartialProfile(const ProcParams * pp,const ParamsEdited * pe)5445 PartialProfile::PartialProfile(const ProcParams* pp, const ParamsEdited* pe)
5446 {
5447     if (pp) {
5448         pparams = new ProcParams(*pp);
5449     } else {
5450         pparams = nullptr;
5451     }
5452 
5453     if (pe) {
5454         pedited = new ParamsEdited(*pe);
5455     } else {
5456         pedited = nullptr;
5457     }
5458 }
5459 
deleteInstance()5460 void PartialProfile::deleteInstance()
5461 {
5462     if (pparams) {
5463         delete pparams;
5464         pparams = nullptr;
5465     }
5466 
5467     if (pedited) {
5468         delete pedited;
5469         pedited = nullptr;
5470     }
5471 }
5472 
clearGeneral()5473 void PartialProfile::clearGeneral()
5474 {
5475     if (pedited) {
5476         pedited->general.colorlabel = false;
5477         pedited->general.intrash = false;
5478         pedited->general.rank = false;
5479     }
5480 }
5481 
load(const Glib::ustring & fName)5482 int PartialProfile::load(const Glib::ustring& fName)
5483 {
5484     if (!pparams) {
5485         pparams = new ProcParams();
5486     }
5487 
5488     if (!pedited) {
5489         pedited = new ParamsEdited();
5490     }
5491 
5492     if (fName == DEFPROFILE_INTERNAL) {
5493         return 0;
5494     } else if (fName == DEFPROFILE_DYNAMIC) {
5495         return -1; // should not happen here
5496     } else {
5497         return pparams->load(fName, pedited);
5498     }
5499 }
5500 
5501 /*
5502  * Set the all values of the General section to false
5503  * in order to preserve them in applyTo
5504  */
set(bool v)5505 void PartialProfile::set(bool v)
5506 {
5507     if (pedited) {
5508         pedited->set(v);
5509     }
5510 }
5511 
applyTo(ProcParams * destParams,bool fromLastSave) const5512 void PartialProfile::applyTo(ProcParams* destParams, bool fromLastSave) const
5513 {
5514     if (destParams && pparams && pedited) {
5515         bool fromHistMatching = fromLastSave && destParams->toneCurve.histmatching && pparams->toneCurve.histmatching;
5516         pedited->combine(*destParams, *pparams, true);
5517         if (!fromLastSave) {
5518             destParams->toneCurve.fromHistMatching = fromHistMatching;
5519         }
5520     }
5521 }
5522 
AutoPartialProfile()5523 AutoPartialProfile::AutoPartialProfile() :
5524     PartialProfile(true)
5525 {
5526 }
5527 
~AutoPartialProfile()5528 AutoPartialProfile::~AutoPartialProfile()
5529 {
5530     deleteInstance();
5531 }
5532 
5533 }
5534 
5535 }
5536