File indexing completed on 2025-03-09 03:50:50
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-11-13 0007 * Description : a tool to blend bracketed images. 0008 * 0009 * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2015 by Benjamin Girault <benjamin dot girault at gmail dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "enfusesettings.h" 0017 0018 // Qt includes 0019 0020 #include <QCheckBox> 0021 #include <QGridLayout> 0022 #include <QLabel> 0023 #include <QStyle> 0024 #include <QApplication> 0025 #include <QSpinBox> 0026 #include <QDoubleSpinBox> 0027 0028 // KDE includes 0029 0030 #include <klocalizedstring.h> 0031 #include <kconfiggroup.h> 0032 0033 namespace DigikamGenericExpoBlendingPlugin 0034 { 0035 0036 QString EnfuseSettings::asCommentString() const 0037 { 0038 QString ret; 0039 0040 ret.append(hardMask ? i18nc("@info", "Hardmask: enabled") : i18nc("@info", "Hardmask: disabled")); 0041 ret.append(QLatin1Char('\n')); 0042 ret.append(ciecam02 ? i18nc("@info", "CIECAM02: enabled") : i18nc("@info", "CIECAM02: disabled")); 0043 ret.append(QLatin1Char('\n')); 0044 ret.append(autoLevels ? i18nc("@info", "Levels: auto") : i18nc("@info", "Levels: <numid>%1</numid>", levels)); 0045 ret.append(QLatin1Char('\n')); 0046 ret.append(i18nc("@info", "Exposure: <numid>%1</numid>", exposure)); 0047 ret.append(QLatin1Char('\n')); 0048 ret.append(i18nc("@info", "Saturation: <numid>%1</numid>", saturation)); 0049 ret.append(QLatin1Char('\n')); 0050 ret.append(i18nc("@info", "Contrast: <numid>%1</numid>", contrast)); 0051 0052 return ret; 0053 } 0054 0055 QString EnfuseSettings::inputImagesList() const 0056 { 0057 QString ret; 0058 0059 Q_FOREACH (const QUrl& url, inputUrls) 0060 { 0061 ret.append(url.fileName() + QLatin1String(" ; ")); 0062 } 0063 0064 ret.truncate(ret.length() - 3); 0065 0066 return ret; 0067 } 0068 0069 class Q_DECL_HIDDEN EnfuseSettingsWidget::Private 0070 { 0071 public: 0072 0073 explicit Private() 0074 : autoLevelsCB (nullptr), 0075 hardMaskCB (nullptr), 0076 ciecam02CB (nullptr), 0077 levelsLabel (nullptr), 0078 exposureLabel (nullptr), 0079 saturationLabel (nullptr), 0080 contrastLabel (nullptr), 0081 levelsInput (nullptr), 0082 exposureInput (nullptr), 0083 saturationInput (nullptr), 0084 contrastInput (nullptr) 0085 { 0086 } 0087 0088 public: 0089 0090 QCheckBox* autoLevelsCB; 0091 QCheckBox* hardMaskCB; 0092 QCheckBox* ciecam02CB; 0093 0094 QLabel* levelsLabel; 0095 QLabel* exposureLabel; 0096 QLabel* saturationLabel; 0097 QLabel* contrastLabel; 0098 0099 QSpinBox* levelsInput; 0100 0101 QDoubleSpinBox* exposureInput; 0102 QDoubleSpinBox* saturationInput; 0103 QDoubleSpinBox* contrastInput; 0104 }; 0105 0106 EnfuseSettingsWidget::EnfuseSettingsWidget(QWidget* const parent) 0107 : QWidget(parent), 0108 d (new Private) 0109 { 0110 setAttribute(Qt::WA_DeleteOnClose); 0111 0112 const int spacing = qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing), 0113 QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing)); 0114 0115 QGridLayout* const grid = new QGridLayout(this); 0116 0117 // ------------------------------------------------------------------------ 0118 0119 d->autoLevelsCB = new QCheckBox(i18nc("@option:check Enfuse setting", "Automatic Local/Global Image Features Balance (Levels)"), this); 0120 d->autoLevelsCB->setToolTip(i18nc("@info:tooltip", 0121 "Optimize image features (contrast, saturation, . . .) to be as global as possible.")); 0122 d->autoLevelsCB->setWhatsThis(i18nc("@info:whatsthis", 0123 "Set automatic level selection (maximized) for pyramid blending, " 0124 "i.e. optimize image features (contrast, saturation, . . .) to be as global as possible.")); 0125 0126 d->levelsLabel = new QLabel(i18nc("@label:slider Enfuse settings", "Image Features Balance:")); 0127 d->levelsInput = new QSpinBox(this); 0128 d->levelsInput->setRange(1, 29); 0129 d->levelsInput->setSingleStep(1); 0130 d->levelsInput->setToolTip(i18nc("@info:tooltip", 0131 "Balances between local features (small number) or global features (high number).")); 0132 d->levelsInput->setWhatsThis(i18nc("@info:whatsthis", 0133 "Set the number of levels for pyramid blending. " 0134 "Balances towards local features (small number) or global features (high number). " 0135 "Additionally, a low number trades off quality of results for faster " 0136 "execution time and lower memory usage.")); 0137 0138 d->hardMaskCB = new QCheckBox(i18nc("@option:check", "Hard Mask"), this); 0139 d->hardMaskCB->setToolTip(i18nc("@info:tooltip", 0140 "Useful only for focus stack to improve sharpness.")); 0141 d->hardMaskCB->setWhatsThis(i18nc("@info:whatsthis", 0142 "Force hard blend masks without averaging on finest " 0143 "scale. This is only useful for focus " 0144 "stacks with thin and high contrast features. " 0145 "It improves sharpness at the expense of increased noise.")); 0146 0147 d->exposureLabel = new QLabel(i18nc("@label:slider Enfuse settings", "Well-Exposedness Contribution:")); 0148 d->exposureInput = new QDoubleSpinBox(this); 0149 d->exposureInput->setRange(0.0, 1.0); 0150 d->exposureInput->setSingleStep(0.01); 0151 d->exposureInput->setToolTip(i18nc("@info:tooltip", 0152 "Contribution of well exposed pixels to the blending process.")); 0153 d->exposureInput->setWhatsThis(i18nc("@info:whatsthis", 0154 "Set the well-exposedness criterion contribution for the blending process. " 0155 "Higher values will favor well-exposed pixels.")); 0156 0157 d->saturationLabel = new QLabel(i18nc("@label:slider enfuse settings", "High-Saturation Contribution:")); 0158 d->saturationInput = new QDoubleSpinBox(this); 0159 d->saturationInput->setDecimals(2); 0160 d->saturationInput->setRange(0.0, 1.0); 0161 d->saturationInput->setSingleStep(0.01); 0162 d->saturationInput->setToolTip(i18nc("@info:tooltip", 0163 "Contribution of highly saturated pixels to the blending process.")); 0164 d->saturationInput->setWhatsThis(i18nc("@info:whatsthis", 0165 "Increasing this value makes pixels with high " 0166 "saturation contribute more to the final output.")); 0167 0168 d->contrastLabel = new QLabel(i18nc("@label:slider enfuse settings", "High-Contrast Contribution:")); 0169 d->contrastInput = new QDoubleSpinBox(this); 0170 d->contrastInput->setDecimals(2); 0171 d->contrastInput->setRange(0.0, 1.0); 0172 d->contrastInput->setSingleStep(0.01); 0173 d->contrastInput->setToolTip(i18nc("@info:tooltip", 0174 "Contribution of highly contrasted pixels to the blending process.")); 0175 d->contrastInput->setWhatsThis(i18nc("@info:whatsthis", 0176 "Sets the relative weight of high-contrast pixels. " 0177 "Increasing this weight makes pixels with neighboring differently colored " 0178 "pixels contribute more to the final output. Particularly useful for focus stacks.")); 0179 0180 d->ciecam02CB = new QCheckBox(i18nc("@option:check", "Use Color Appearance Model (CIECAM02)"), this); 0181 d->ciecam02CB->setToolTip(i18nc("@info:tooltip", 0182 "Convert to CIECAM02 color appearance model during the blending process instead of RGB.")); 0183 d->ciecam02CB->setWhatsThis(i18nc("@info:whatsthis", 0184 "Use Color Appearance Modelling (CIECAM02) to render detailed colors. " 0185 "Your input files should have embedded ICC profiles. If no ICC profile is present, " 0186 "sRGB color space will be assumed. The difference between using this option " 0187 "and default color blending algorithm is very slight, and will be most noticeable " 0188 "when you need to blend areas of different primary colors together.")); 0189 0190 // ------------------------------------------------------------------------ 0191 0192 grid->addWidget(d->autoLevelsCB, 0, 0, 1, 2); 0193 grid->addWidget(d->levelsLabel, 1, 0, 1, 1); 0194 grid->addWidget(d->levelsInput, 1, 1, 1, 1); 0195 grid->addWidget(d->hardMaskCB, 2, 0, 1, 2); 0196 grid->addWidget(d->exposureLabel, 3, 0, 1, 1); 0197 grid->addWidget(d->exposureInput, 3, 1, 1, 1); 0198 grid->addWidget(d->saturationLabel, 4, 0, 1, 1); 0199 grid->addWidget(d->saturationInput, 4, 1, 1, 1); 0200 grid->addWidget(d->contrastLabel, 5, 0, 1, 1); 0201 grid->addWidget(d->contrastInput, 5, 1, 1, 1); 0202 grid->addWidget(d->ciecam02CB, 6, 0, 1, 2); 0203 grid->setRowStretch(7, 10); 0204 grid->setContentsMargins(spacing, spacing, spacing, spacing); 0205 grid->setSpacing(spacing); 0206 0207 // ------------------------------------------------------------------------ 0208 0209 connect(d->autoLevelsCB, SIGNAL(toggled(bool)), 0210 d->levelsLabel, SLOT(setDisabled(bool))); 0211 0212 connect(d->autoLevelsCB, SIGNAL(toggled(bool)), 0213 d->levelsInput, SLOT(setDisabled(bool))); 0214 } 0215 0216 EnfuseSettingsWidget::~EnfuseSettingsWidget() 0217 { 0218 delete d; 0219 } 0220 0221 void EnfuseSettingsWidget::resetToDefault() 0222 { 0223 d->autoLevelsCB->setChecked(true); 0224 d->levelsInput->setValue(20); 0225 d->hardMaskCB->setChecked(false); 0226 d->exposureInput->setValue(1.0); 0227 d->saturationInput->setValue(0.2); 0228 d->contrastInput->setValue(0.0); 0229 d->ciecam02CB->setChecked(false); 0230 } 0231 0232 void EnfuseSettingsWidget::setSettings(const EnfuseSettings& settings) 0233 { 0234 d->autoLevelsCB->setChecked(settings.autoLevels); 0235 d->levelsInput->setValue(settings.levels); 0236 d->hardMaskCB->setChecked(settings.hardMask); 0237 d->exposureInput->setValue(settings.exposure); 0238 d->saturationInput->setValue(settings.saturation); 0239 d->contrastInput->setValue(settings.contrast); 0240 d->ciecam02CB->setChecked(settings.ciecam02); 0241 } 0242 0243 EnfuseSettings EnfuseSettingsWidget::settings() const 0244 { 0245 EnfuseSettings settings; 0246 settings.autoLevels = d->autoLevelsCB->isChecked(); 0247 settings.levels = d->levelsInput->value(); 0248 settings.hardMask = d->hardMaskCB->isChecked(); 0249 settings.exposure = d->exposureInput->value(); 0250 settings.saturation = d->saturationInput->value(); 0251 settings.contrast = d->contrastInput->value(); 0252 settings.ciecam02 = d->ciecam02CB->isChecked(); 0253 0254 return settings; 0255 } 0256 0257 void EnfuseSettingsWidget::readSettings(const KConfigGroup& group) 0258 { 0259 d->autoLevelsCB->setChecked(group.readEntry("Auto Levels", true)); 0260 d->levelsInput->setValue(group.readEntry("Levels Value", 20)); 0261 d->hardMaskCB->setChecked(group.readEntry("Hard Mask", false)); 0262 d->exposureInput->setValue(group.readEntry("Exposure Value", 1.0)); 0263 d->saturationInput->setValue(group.readEntry("Saturation Value", 0.2)); 0264 d->contrastInput->setValue(group.readEntry("Contrast Value", 0.0)); 0265 d->ciecam02CB->setChecked(group.readEntry("CIECAM02", false)); 0266 } 0267 0268 void EnfuseSettingsWidget::writeSettings(KConfigGroup& group) 0269 { 0270 group.writeEntry("Auto Levels", d->autoLevelsCB->isChecked()); 0271 group.writeEntry("Levels Value", d->levelsInput->value()); 0272 group.writeEntry("Hard Mask", d->hardMaskCB->isChecked()); 0273 group.writeEntry("Exposure Value", d->exposureInput->value()); 0274 group.writeEntry("Saturation Value", d->saturationInput->value()); 0275 group.writeEntry("Contrast Value", d->contrastInput->value()); 0276 group.writeEntry("CIECAM02", d->ciecam02CB->isChecked()); 0277 } 0278 0279 } // namespace DigikamGenericExpoBlendingPlugin 0280 0281 #include "moc_enfusesettings.cpp"