File indexing completed on 2025-01-19 03:53:17

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2008-08-11
0007  * Description : Raw import settings box
0008  *
0009  * SPDX-FileCopyrightText: 2008-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "rawsettingsbox.h"
0016 
0017 // Qt includes
0018 
0019 #include <QButtonGroup>
0020 #include <QLabel>
0021 #include <QLayout>
0022 #include <QPushButton>
0023 #include <QString>
0024 #include <QToolBox>
0025 #include <QToolButton>
0026 #include <QIcon>
0027 #include <QTabWidget>
0028 
0029 // KDE includes
0030 
0031 #include <kconfiggroup.h>
0032 #include <ksharedconfig.h>
0033 #include <klocalizedstring.h>
0034 
0035 // Local includes
0036 
0037 #include "dlayoutbox.h"
0038 #include "dexpanderbox.h"
0039 #include "dnuminput.h"
0040 #include "colorgradientwidget.h"
0041 #include "histogrambox.h"
0042 #include "histogramwidget.h"
0043 #include "iccpreviewwidget.h"
0044 #include "imagecurves.h"
0045 #include "imagedialog.h"
0046 #include "imagehistogram.h"
0047 #include "digikam_globals.h"
0048 #include "digikam_debug.h"
0049 #include "drawdecoderwidget.h"
0050 
0051 namespace DigikamRawImportNativePlugin
0052 {
0053 
0054 class Q_DECL_HIDDEN RawSettingsBox::Private
0055 {
0056 public:
0057 
0058     enum AllColorsColorType
0059     {
0060         AllColorsRed = 0,
0061         AllColorsGreen,
0062         AllColorsBlue
0063     };
0064 
0065 public:
0066 
0067     explicit Private()
0068       : optionGroupName                 (QLatin1String("RAW Import Settings")),
0069         optionHistogramChannelEntry     (QLatin1String("Histogram Channel")),
0070         optionHistogramScaleEntry       (QLatin1String("Histogram Scale")),
0071         optionBrightnessEntry           (QLatin1String("Brightness")),
0072         optionContrastEntry             (QLatin1String("Contrast")),
0073         optionGammaEntry                (QLatin1String("Gamma")),
0074         optionSaturationEntry           (QLatin1String("Saturation")),
0075         optionMainExposureEntry         (QLatin1String("MainExposure")),
0076         optionCurvePrefix               (QLatin1String("RawCurve")),
0077         optionSettingsPageEntry         (QLatin1String("Settings Page")),
0078         optionDecodingSettingsTabEntry  (QLatin1String("Decoding Settings Tab"))
0079     {
0080         infoBox                = nullptr;
0081         advExposureBox         = nullptr;
0082         gammaLabel             = nullptr;
0083         gammaInput             = nullptr;
0084         saturationLabel        = nullptr;
0085         saturationInput        = nullptr;
0086         fineExposureLabel      = nullptr;
0087         mainExposureInput      = nullptr;
0088         contrastInput          = nullptr;
0089         contrastLabel          = nullptr;
0090         curveBox               = nullptr;
0091         curveWidget            = nullptr;
0092         resetCurveBtn          = nullptr;
0093         decodingSettingsBox    = nullptr;
0094         postProcessSettingsBox = nullptr;
0095         tabView                = nullptr;
0096         abortBtn               = nullptr;
0097         updateBtn              = nullptr;
0098         rawdecodingBox         = nullptr;
0099         brightnessLabel        = nullptr;
0100         brightnessInput        = nullptr;
0101     }
0102 
0103     const QString        optionGroupName;
0104     const QString        optionHistogramChannelEntry;
0105     const QString        optionHistogramScaleEntry;
0106     const QString        optionBrightnessEntry;
0107     const QString        optionContrastEntry;
0108     const QString        optionGammaEntry;
0109     const QString        optionSaturationEntry;
0110     const QString        optionMainExposureEntry;
0111     const QString        optionCurvePrefix;
0112     const QString        optionSettingsPageEntry;
0113     const QString        optionDecodingSettingsTabEntry;
0114 
0115     QWidget*             advExposureBox;
0116     QWidget*             curveBox;
0117     QWidget*             rawdecodingBox;
0118 
0119     QLabel*              brightnessLabel;
0120     QLabel*              contrastLabel;
0121     QLabel*              gammaLabel;
0122     QLabel*              saturationLabel;
0123     QLabel*              fineExposureLabel;
0124 
0125     QPushButton*         abortBtn;
0126     QPushButton*         updateBtn;
0127     QPushButton*         resetCurveBtn;
0128 
0129     QTabWidget*          tabView;
0130 
0131     CurvesWidget*        curveWidget;
0132 
0133     ImageDialogPreview*  infoBox;
0134 
0135     DExpanderBox*        postProcessSettingsBox;
0136 
0137     DIntNumInput*        contrastInput;
0138     DIntNumInput*        brightnessInput;
0139 
0140     DDoubleNumInput*     gammaInput;
0141     DDoubleNumInput*     saturationInput;
0142     DDoubleNumInput*     mainExposureInput;
0143 
0144     DRawDecoderWidget*   decodingSettingsBox;
0145 };
0146 
0147 RawSettingsBox::RawSettingsBox(const QUrl& url, QWidget* const parent)
0148     : EditorToolSettings(parent),
0149       d                 (new Private)
0150 {
0151     setButtons(Default | Ok | Cancel);
0152     setTools(Histogram);
0153     setHistogramType(LRGBC);
0154 
0155     QGridLayout* const gridSettings = new QGridLayout(plainPage());
0156     d->tabView                      = new QTabWidget(plainPage());
0157 
0158     // - RAW Decoding view --------------------------------------------------------------
0159 
0160     d->rawdecodingBox               = new QWidget(d->tabView);
0161     QGridLayout* const rawGrid      = new QGridLayout(d->rawdecodingBox);
0162     d->decodingSettingsBox          = new DRawDecoderWidget(d->rawdecodingBox,
0163                                                             DRawDecoderWidget::SIXTEENBITS |
0164                                                             DRawDecoderWidget::COLORSPACE);
0165     d->decodingSettingsBox->setObjectName(QLatin1String("RawSettingsBox Expander"));
0166 
0167     // Note: do not touch the url edit's fileDialog() here.
0168     // This creates the file dialog, which involved an event loop, which is evil.
0169     // Adjust file dialog in slotFileDialogAboutToOpen
0170 
0171     d->abortBtn  = new QPushButton(d->rawdecodingBox);
0172     d->abortBtn->setText(i18n("Abort"));
0173     d->abortBtn->setIcon(QIcon::fromTheme(QLatin1String("dialog-cancel")));
0174     d->abortBtn->setEnabled(false);
0175     d->abortBtn->setToolTip(i18n("Abort the current Raw image preview."));
0176 
0177     d->updateBtn = new QPushButton(d->rawdecodingBox);
0178     d->updateBtn->setText(i18nc("@action: refresh RAW preview", "Update"));
0179     d->updateBtn->setIcon(QIcon::fromTheme(QLatin1String("view-refresh")));
0180     d->updateBtn->setEnabled(false);
0181     d->updateBtn->setToolTip(i18n("Generate a Raw image preview using current settings."));
0182 
0183     const int spacing = spacingHint();
0184 
0185     rawGrid->addWidget(d->decodingSettingsBox, 0, 0, 1, 3);
0186     rawGrid->addWidget(d->abortBtn,            1, 0, 1, 1);
0187     rawGrid->addWidget(d->updateBtn,           1, 2, 1, 1);
0188     rawGrid->setColumnStretch(1, 10);
0189     rawGrid->setContentsMargins(spacing, spacing, spacing, spacing);
0190     rawGrid->setSpacing(spacing);
0191 
0192     // - Post-processing view --------------------------------------------------------------
0193 
0194     d->postProcessSettingsBox            = new DExpanderBox(d->tabView);
0195     d->postProcessSettingsBox->setObjectName(QLatin1String("PostProcessingSettingsBox Expander"));
0196 
0197     d->advExposureBox                    = new QWidget(d->postProcessSettingsBox);
0198     QGridLayout* const advExposureLayout = new QGridLayout(d->advExposureBox);
0199 
0200     d->brightnessLabel = new QLabel(i18n("Brightness:"), d->advExposureBox);
0201     d->brightnessInput = new DIntNumInput(d->advExposureBox);
0202     d->brightnessInput->setRange(-100, 100, 1);
0203     d->brightnessInput->setDefaultValue(0);
0204     d->brightnessInput->setWhatsThis(i18n("Set here the brightness adjustment of the image."));
0205 
0206     d->contrastLabel = new QLabel(i18n("Contrast:"), d->advExposureBox);
0207     d->contrastInput = new DIntNumInput(d->advExposureBox);
0208     d->contrastInput->setRange(-100, 100, 1);
0209     d->contrastInput->setDefaultValue(0);
0210     d->contrastInput->setWhatsThis(i18n("Set here the contrast adjustment of the image."));
0211 
0212     d->gammaLabel = new QLabel(i18n("Gamma:"), d->advExposureBox);
0213     d->gammaInput = new DDoubleNumInput(d->advExposureBox);
0214     d->gammaInput->setDecimals(2);
0215     d->gammaInput->setRange(0.1, 3.0, 0.01);
0216     d->gammaInput->setDefaultValue(1.0);
0217     d->gammaInput->setWhatsThis(i18n("Set here the gamma adjustment of the image"));
0218 
0219     d->saturationLabel = new QLabel(i18n("Saturation:"), d->advExposureBox);
0220     d->saturationInput = new DDoubleNumInput(d->advExposureBox);
0221     d->saturationInput->setDecimals(2);
0222     d->saturationInput->setRange(0.0, 2.0, 0.01);
0223     d->saturationInput->setDefaultValue(1.0);
0224     d->saturationInput->setWhatsThis(i18n("Set here the color saturation correction."));
0225 
0226     d->fineExposureLabel = new QLabel(i18n("Exposure (E.V):"), d->advExposureBox);
0227     d->mainExposureInput = new DDoubleNumInput(d->advExposureBox);
0228     d->mainExposureInput->setDecimals(2);
0229     d->mainExposureInput->setRange(-3.0, 3.0, 0.1);
0230     d->mainExposureInput->setDefaultValue(0.0);
0231     d->mainExposureInput->setWhatsThis(i18n("This value in E.V will be used to perform "
0232                                             "an exposure compensation of the image."));
0233 
0234     advExposureLayout->addWidget(d->brightnessLabel,   0, 0, 1, 1);
0235     advExposureLayout->addWidget(d->brightnessInput,   0, 1, 1, 2);
0236     advExposureLayout->addWidget(d->contrastLabel,     1, 0, 1, 1);
0237     advExposureLayout->addWidget(d->contrastInput,     1, 1, 1, 2);
0238     advExposureLayout->addWidget(d->gammaLabel,        2, 0, 1, 1);
0239     advExposureLayout->addWidget(d->gammaInput,        2, 1, 1, 2);
0240     advExposureLayout->addWidget(d->saturationLabel,   3, 0, 1, 1);
0241     advExposureLayout->addWidget(d->saturationInput,   3, 1, 1, 2);
0242     advExposureLayout->addWidget(d->fineExposureLabel, 4, 0, 1, 1);
0243     advExposureLayout->addWidget(d->mainExposureInput, 4, 1, 1, 2);
0244     advExposureLayout->setRowStretch(5, 10);
0245     advExposureLayout->setContentsMargins(spacing, spacing, spacing, spacing);
0246     advExposureLayout->setSpacing(0);
0247 
0248     // ---------------------------------------------------------------
0249 
0250     d->curveBox                          = new QWidget(d->postProcessSettingsBox);
0251     QGridLayout* const curveLayout       = new QGridLayout(d->curveBox);
0252 
0253     ColorGradientWidget* const vGradient = new ColorGradientWidget(Qt::Vertical, 10, d->curveBox);
0254     vGradient->setColors(QColor("white"), QColor("black"));
0255 
0256     QLabel* const spacev                 = new QLabel(d->curveBox);
0257     spacev->setFixedWidth(1);
0258 
0259     d->curveWidget     = new CurvesWidget(256, 192, d->curveBox);
0260     d->curveWidget->setWhatsThis(i18n("This is the curve adjustment of the image luminosity"));
0261 
0262     d->resetCurveBtn   = new QPushButton(i18n("Reset"), d->curveBox);
0263     d->resetCurveBtn->setIcon(QIcon::fromTheme(QLatin1String("document-revert")));
0264     d->resetCurveBtn->setToolTip(i18n("Reset curve to linear"));
0265 
0266     QLabel* const spaceh                 = new QLabel(d->curveBox);
0267     spaceh->setFixedHeight(1);
0268 
0269     ColorGradientWidget* const hGradient = new ColorGradientWidget(Qt::Horizontal, 10, d->curveBox);
0270     hGradient->setColors(QColor("black"), QColor("white"));
0271 
0272     curveLayout->addWidget(vGradient,        0, 0, 1, 1);
0273     curveLayout->addWidget(spacev,           0, 1, 1, 1);
0274     curveLayout->addWidget(d->curveWidget,   0, 2, 1, 2);
0275     curveLayout->addWidget(spaceh,           1, 2, 1, 2);
0276     curveLayout->addWidget(hGradient,        2, 2, 1, 2);
0277     curveLayout->addWidget(d->resetCurveBtn, 3, 3, 1, 1);
0278     curveLayout->setRowStretch(4, 10);
0279     curveLayout->setColumnStretch(2, 10);
0280     curveLayout->setContentsMargins(spacing, spacing, spacing, spacing);
0281     curveLayout->setSpacing(0);
0282 
0283     // ---------------------------------------------------------------
0284 
0285     d->postProcessSettingsBox->addItem(d->advExposureBox, i18n("Exposure"),         QLatin1String("exposure"), true);
0286     d->postProcessSettingsBox->addItem(d->curveBox,       i18n("Luminosity Curve"), QLatin1String("luminositycurve"), false);
0287     d->postProcessSettingsBox->setItemIcon(0, QIcon::fromTheme(QLatin1String("contrast")));
0288     d->postProcessSettingsBox->setItemIcon(1, QIcon::fromTheme(QLatin1String("adjustcurves")));
0289     d->postProcessSettingsBox->addStretch();
0290 
0291     // - Image info view --------------------------------------------------------------
0292 
0293     d->infoBox = new ImageDialogPreview(d->postProcessSettingsBox);
0294     d->infoBox->slotShowPreview(url);
0295 
0296     // ---------------------------------------------------------------
0297 
0298     d->decodingSettingsBox->setItemIcon(DRawDecoderWidget::DEMOSAICING,
0299                                         QIcon::fromTheme(QLatin1String("image-x-adobe-dng")));
0300     d->decodingSettingsBox->setItemIcon(DRawDecoderWidget::WHITEBALANCE,
0301                                         QIcon::fromTheme(QLatin1String("bordertool")));
0302     d->decodingSettingsBox->setItemIcon(DRawDecoderWidget::CORRECTIONS,
0303                                         QIcon::fromTheme(QLatin1String("zoom-draw")));
0304     d->decodingSettingsBox->setItemIcon(DRawDecoderWidget::COLORMANAGEMENT,
0305                                         QIcon::fromTheme(QLatin1String("preferences-desktop-display-color")));
0306     d->decodingSettingsBox->updateMinimumWidth();
0307 
0308     d->tabView->insertTab(0, d->rawdecodingBox,         i18n("Raw Decoding"));
0309     d->tabView->insertTab(1, d->postProcessSettingsBox, i18n("Post Processing"));
0310     d->tabView->insertTab(2, d->infoBox,                i18n("Info"));
0311 
0312     // ---------------------------------------------------------------
0313 
0314     button(Default)->setText(i18n("Reset"));
0315     button(Default)->setIcon(QIcon::fromTheme(QLatin1String("document-revert")));
0316     button(Default)->setToolTip(i18n("Reset all settings to default values."));
0317 
0318     button(Ok)->setText(i18n("Import"));
0319     button(Ok)->setIcon(QIcon::fromTheme(QLatin1String("dialog-ok-apply")));
0320     button(Ok)->setToolTip(i18n("Import image to editor using current settings."));
0321 
0322     button(Cancel)->setText(i18n("Use Default"));
0323     button(Cancel)->setIcon(QIcon::fromTheme(QLatin1String("go-home")));
0324     button(Cancel)->setToolTip(i18n("Use general Raw decoding settings to load this image in editor."));
0325 
0326     // ---------------------------------------------------------------
0327 
0328     gridSettings->addWidget(d->tabView, 0, 0, 1, 5);
0329     gridSettings->setColumnStretch(2, 10);
0330     gridSettings->setContentsMargins(QMargins());
0331     gridSettings->setSpacing(spacing);
0332 
0333     // ---------------------------------------------------------------
0334 
0335     connect(d->resetCurveBtn, SIGNAL(clicked()),
0336             this, SLOT(slotResetCurve()));
0337 
0338     connect(d->updateBtn, SIGNAL(clicked()),
0339             this, SIGNAL(signalUpdatePreview()));
0340 
0341     connect(d->abortBtn, SIGNAL(clicked()),
0342             this, SIGNAL(signalAbortPreview()));
0343 
0344     connect(d->decodingSettingsBox, SIGNAL(signalSettingsChanged()),
0345             this, SLOT(slotDemosaicingChanged()));
0346 
0347     connect(d->curveWidget, SIGNAL(signalCurvesChanged()),
0348             this, SIGNAL(signalPostProcessingChanged()));
0349 
0350     connect(d->brightnessInput, SIGNAL(valueChanged(int)),
0351             this, SIGNAL(signalPostProcessingChanged()));
0352 
0353     connect(d->contrastInput, SIGNAL(valueChanged(int)),
0354             this, SIGNAL(signalPostProcessingChanged()));
0355 
0356     connect(d->gammaInput, SIGNAL(valueChanged(double)),
0357             this, SIGNAL(signalPostProcessingChanged()));
0358 
0359     connect(d->saturationInput, SIGNAL(valueChanged(double)),
0360             this, SIGNAL(signalPostProcessingChanged()));
0361 
0362     connect(d->mainExposureInput, SIGNAL(valueChanged(double)),
0363             this, SIGNAL(signalPostProcessingChanged()));
0364 
0365     connect(d->decodingSettingsBox->inputProfileUrlEdit(), SIGNAL(signalOpenFileDialog()),
0366             this, SLOT(slotFileDialogAboutToOpen()));
0367 
0368     connect(d->decodingSettingsBox->outputProfileUrlEdit(), SIGNAL(signalOpenFileDialog()),
0369             this, SLOT(slotFileDialogAboutToOpen()));
0370 }
0371 
0372 RawSettingsBox::~RawSettingsBox()
0373 {
0374     delete d->curveWidget;
0375     delete d;
0376 }
0377 
0378 void RawSettingsBox::slotDemosaicingChanged()
0379 {
0380     enableUpdateBtn(true);
0381 }
0382 
0383 void RawSettingsBox::enableUpdateBtn(bool b)
0384 {
0385     d->updateBtn->setEnabled(b);
0386 }
0387 
0388 bool RawSettingsBox::updateBtnEnabled() const
0389 {
0390     return d->updateBtn->isEnabled();
0391 }
0392 
0393 void RawSettingsBox::setBusy(bool b)
0394 {
0395     d->decodingSettingsBox->setEnabled(!b);
0396     d->abortBtn->setEnabled(b);
0397 }
0398 
0399 void RawSettingsBox::setDemosaicedImage(DImg& img)
0400 {
0401     d->curveWidget->stopHistogramComputation();
0402     d->curveWidget->updateData(img);
0403 }
0404 
0405 void RawSettingsBox::setPostProcessedImage(const DImg& img)
0406 {
0407     histogramBox()->histogram()->stopHistogramComputation();
0408     histogramBox()->histogram()->updateData(img);
0409 }
0410 
0411 void RawSettingsBox::resetSettings()
0412 {
0413     d->decodingSettingsBox->resetToDefault();
0414     d->brightnessInput->slotReset();
0415     d->contrastInput->slotReset();
0416     d->gammaInput->slotReset();
0417     d->saturationInput->slotReset();
0418     d->mainExposureInput->slotReset();
0419     slotResetCurve();
0420 }
0421 
0422 void RawSettingsBox::slotResetCurve()
0423 {
0424     d->curveWidget->reset();
0425     Q_EMIT signalPostProcessingChanged();
0426 }
0427 
0428 CurvesWidget* RawSettingsBox::curvesWidget() const
0429 {
0430     return d->curveWidget;
0431 }
0432 
0433 void RawSettingsBox::readSettings()
0434 {
0435     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0436     KConfigGroup group        = config->group(d->optionGroupName);
0437 
0438     histogramBox()->setChannel((ChannelType)group.readEntry(d->optionHistogramChannelEntry,
0439                                                             (int) LuminosityChannel));
0440     histogramBox()->setScale((HistogramScale)group.readEntry(d->optionHistogramScaleEntry,
0441                                                              (int) LogScaleHistogram));
0442     curvesWidget()->setScaleType((HistogramScale)group.readEntry(d->optionHistogramScaleEntry,
0443                                                                  (int) LogScaleHistogram));
0444 
0445     d->decodingSettingsBox->readSettings(group);
0446 
0447     d->brightnessInput->setValue(group.readEntry(d->optionBrightnessEntry, 0));
0448     d->contrastInput->setValue(group.readEntry(d->optionContrastEntry, 0));
0449     d->gammaInput->setValue(group.readEntry(d->optionGammaEntry, 1.0));
0450     d->saturationInput->setValue(group.readEntry(d->optionSaturationEntry, 1.0));
0451     d->mainExposureInput->setValue(group.readEntry(d->optionMainExposureEntry, 0.0));
0452 
0453     d->curveWidget->restoreCurve(group, d->optionCurvePrefix);
0454 
0455     d->tabView->setCurrentIndex(group.readEntry(d->optionSettingsPageEntry, 0));
0456 
0457     d->postProcessSettingsBox->readSettings(group);
0458 }
0459 
0460 void RawSettingsBox::writeSettings()
0461 {
0462     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0463     KConfigGroup group        = config->group(d->optionGroupName);
0464 
0465     group.writeEntry(d->optionHistogramChannelEntry, (int)histogramBox()->channel());
0466     group.writeEntry(d->optionHistogramScaleEntry,   (int)histogramBox()->scale());
0467 
0468     d->decodingSettingsBox->writeSettings(group);
0469 
0470     group.writeEntry(d->optionBrightnessEntry,   d->brightnessInput->value());
0471     group.writeEntry(d->optionContrastEntry,     d->contrastInput->value());
0472     group.writeEntry(d->optionGammaEntry,        d->gammaInput->value());
0473     group.writeEntry(d->optionSaturationEntry,   d->saturationInput->value());
0474     group.writeEntry(d->optionMainExposureEntry, d->mainExposureInput->value());
0475 
0476     d->curveWidget->saveCurve(group, d->optionCurvePrefix);
0477 
0478     group.writeEntry(d->optionSettingsPageEntry, d->tabView->currentIndex());
0479 
0480     d->postProcessSettingsBox->writeSettings(group);
0481 
0482     group.sync();
0483 }
0484 
0485 DRawDecoding RawSettingsBox::settings() const
0486 {
0487     DRawDecoding settings(d->decodingSettingsBox->settings());
0488 
0489     settings.bcg.brightness    = (double)d->brightnessInput->value() / 250.0;
0490     settings.bcg.contrast      = (double)(d->contrastInput->value()  / 100.0) + 1.00;
0491     settings.bcg.gamma         = d->gammaInput->value();
0492     settings.wb.saturation     = d->saturationInput->value();
0493     settings.wb.expositionMain = d->mainExposureInput->value();
0494 
0495     if (d->curveWidget->curves()->isDirty())
0496     {
0497         d->curveWidget->curves()->curvesCalculateAllCurves();
0498         settings.curvesAdjust = d->curveWidget->curves()->getContainer();
0499     }
0500 
0501     return settings;
0502 }
0503 
0504 void RawSettingsBox::slotFileDialogAboutToOpen()
0505 {
0506     //TODO : port to Qt5
0507     //requester->fileDialog()->setPreviewWidget(new ICCPreviewWidget(requester));
0508 }
0509 
0510 } // namespace DigikamRawImportNativePlugin
0511 
0512 #include "moc_rawsettingsbox.cpp"