File indexing completed on 2025-01-05 03:56:18

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2013-08-19
0007  * Description : Image Quality settings widget
0008  *
0009  * SPDX-FileCopyrightText: 2013-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2013-2014 by Gowtham Ashok <gwty93 at gmail dot com>
0011  * SPDX-FileCopyrightText: 2021-2022 by Phuoc Khanh Le <phuockhanhnk94 at gmail dot com>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "imagequalitysettings.h"
0018 
0019 // Qt includes
0020 
0021 #include <QCheckBox>
0022 #include <QRadioButton>
0023 #include <QButtonGroup>
0024 #include <QGroupBox>
0025 #include <QGridLayout>
0026 #include <QLabel>
0027 #include <QVBoxLayout>
0028 #include <QIcon>
0029 #include <QApplication>
0030 #include <QStyle>
0031 #include <QPushButton>
0032 
0033 // KDE includes
0034 
0035 #include <klocalizedstring.h>
0036 
0037 // Local includes
0038 
0039 #include "dlayoutbox.h"
0040 #include "picklabelwidget.h"
0041 #include "dnuminput.h"
0042 
0043 namespace Digikam
0044 {
0045 
0046 class Q_DECL_HIDDEN ImageQualitySettings::Private
0047 {
0048 public:
0049 
0050     enum DetectMethod
0051     {
0052         AESTHETIC = 0,
0053         BASICFACTORS
0054     };
0055 
0056 public:
0057 
0058     explicit Private()
0059       : detectBlur          (nullptr),
0060         detectNoise         (nullptr),
0061         detectCompression   (nullptr),
0062         detectExposure      (nullptr),
0063         detectButtonGroup   (nullptr),
0064         detectAesthetic     (nullptr),
0065         detectBasicFactors  (nullptr),
0066         setRejected         (nullptr),
0067         setPending          (nullptr),
0068         setAccepted         (nullptr),
0069         lbl2                (nullptr),
0070         lbl3                (nullptr),
0071         lbl4                (nullptr),
0072         lbl5                (nullptr),
0073         lbl6                (nullptr),
0074         lbl7                (nullptr),
0075         setRejectedThreshold(nullptr),
0076         setPendingThreshold (nullptr),
0077         setAcceptedThreshold(nullptr),
0078         setBlurWeight       (nullptr),
0079         setNoiseWeight      (nullptr),
0080         setCompressionWeight(nullptr)
0081     {
0082     }
0083 
0084     QCheckBox*    detectBlur;
0085     QCheckBox*    detectNoise;
0086     QCheckBox*    detectCompression;
0087     QCheckBox*    detectExposure;
0088 
0089     QButtonGroup* detectButtonGroup;
0090     QRadioButton* detectAesthetic;
0091     QRadioButton* detectBasicFactors;
0092 
0093     QCheckBox*    setRejected;
0094     QCheckBox*    setPending;
0095     QCheckBox*    setAccepted;
0096 
0097     QLabel*       lbl2;
0098     QLabel*       lbl3;
0099     QLabel*       lbl4;
0100     QLabel*       lbl5;
0101     QLabel*       lbl6;
0102     QLabel*       lbl7;
0103 
0104     DIntNumInput* setRejectedThreshold;
0105     DIntNumInput* setPendingThreshold;
0106     DIntNumInput* setAcceptedThreshold;
0107     DIntNumInput* setBlurWeight;
0108     DIntNumInput* setNoiseWeight;
0109     DIntNumInput* setCompressionWeight;
0110 };
0111 
0112 // --------------------------------------------------------
0113 
0114 ImageQualitySettings::ImageQualitySettings(QWidget* const parent)
0115     : QWidget(parent),
0116       d      (new Private)
0117 {
0118     const int spacing         = qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0119                                      QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing));
0120 
0121     DHBox* const hlay1        = new DHBox(this);
0122 
0123     d->setRejected            = new QCheckBox(i18nc("@option:check", "Assign 'Rejected' Label to Low Quality Pictures"), hlay1);
0124     d->setRejected->setToolTip(i18nc("@info:tooltip", "Low quality images detected by blur, noise, and compression analysis will be assigned to Rejected label."));
0125 
0126     QWidget* const hspace1    = new QWidget(hlay1);
0127     hlay1->setStretchFactor(hspace1, 10);
0128 
0129     QLabel* const workIcon1   = new QLabel(hlay1);
0130     workIcon1->setPixmap(QIcon::fromTheme(QLatin1String("flag-red")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize)));
0131 
0132     // ------------------------------------------------------------------------------
0133 
0134     DHBox* const hlay2        = new DHBox(this);
0135 
0136     d->setPending             = new QCheckBox(i18nc("@option:check", "Assign 'Pending' Label to Medium Quality Pictures"), hlay2);
0137     d->setPending->setToolTip(i18nc("@info:tooltip", "Medium quality images detected by blur, noise, and compression analysis will be assigned to Pending label."));
0138 
0139     QWidget* const hspace2    = new QWidget(hlay2);
0140     hlay2->setStretchFactor(hspace2, 10);
0141 
0142     QLabel* const workIcon2   = new QLabel(hlay2);
0143     workIcon2->setPixmap(QIcon::fromTheme(QLatin1String("flag-yellow")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize)));
0144 
0145     // ------------------------------------------------------------------------------
0146 
0147     DHBox* const hlay3        = new DHBox(this);
0148 
0149     d->setAccepted            = new QCheckBox(i18nc("@option:check", "Assign 'Accepted' Label to High Quality Pictures"), hlay3);
0150     d->setAccepted->setToolTip(i18nc("@info:tooltip", "High quality images detected by blur, noise, and compression analysis will be assigned to Accepted label."));
0151 
0152     QWidget* const hspace3    = new QWidget(hlay3);
0153     hlay3->setStretchFactor(hspace3, 10);
0154 
0155     QLabel* const workIcon3   = new QLabel(hlay3);
0156     workIcon3->setPixmap(QIcon::fromTheme(QLatin1String("flag-green")).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize)));
0157 
0158     // ------------------------------------------------------------------------------
0159 
0160     d->detectButtonGroup      = new QButtonGroup(this);
0161     d->detectButtonGroup->setExclusive(true);
0162 
0163     d->detectAesthetic        = new QRadioButton(i18nc("@option:radio", "Detect Aesthetic Image using Deep Learning"),
0164                                                  this);
0165     d->detectAesthetic->setToolTip(i18nc("@info:tooltip", "Detect if the image has aesthetic value.\n"
0166                                          "The aesthetic detection engine use deep learning model to classify images"));
0167 
0168     d->detectButtonGroup->addButton(d->detectAesthetic, Private::AESTHETIC);
0169 
0170     d->detectBasicFactors     = new QRadioButton(i18nc("@option:radio", "Detect Quality Using Basic Factors"),
0171                                                  this);
0172     d->detectBasicFactors->setToolTip(i18nc("@info:tooltip", "Detect if the image is sabotaging by four basic factors "
0173                                             "(blur, noise, exposure, and compression)."));
0174 
0175     d->detectButtonGroup->addButton(d->detectBasicFactors, Private::BASICFACTORS);
0176     d->detectAesthetic->setChecked(true);
0177 
0178     // ------------------------------------------------------------------------------
0179 
0180     QWidget* const basicView  = new QWidget(this);
0181     QGridLayout* const grid1  = new QGridLayout(basicView);
0182 
0183     d->lbl2                   = new QLabel(i18nc("@label", "Rejected threshold:"), basicView);
0184     d->lbl2->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0185     d->setRejectedThreshold   = new DIntNumInput(basicView);
0186     d->setRejectedThreshold->setDefaultValue(10);
0187     d->setRejectedThreshold->setRange(1, 100, 1);
0188     d->setRejectedThreshold->setToolTip(i18nc("@info:tooltip", "Threshold below which all pictures are assigned Rejected Label"));
0189 
0190     d->lbl3                   = new QLabel(i18nc("@label", "Pending threshold:"), basicView);
0191     d->lbl3->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0192     d->setPendingThreshold    = new DIntNumInput(basicView);
0193     d->setPendingThreshold->setDefaultValue(40);
0194     d->setPendingThreshold->setRange(1, 100, 1);
0195     d->setPendingThreshold->setToolTip(i18nc("@info:tooltip", "Threshold below which all pictures are assigned Pending Label"));
0196 
0197     d->lbl4                   = new QLabel(i18nc("@label", "Accepted threshold:"), basicView);
0198     d->lbl4->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0199     d->setAcceptedThreshold   = new DIntNumInput(basicView);
0200     d->setAcceptedThreshold->setDefaultValue(60);
0201     d->setAcceptedThreshold->setRange(1, 100, 1);
0202     d->setAcceptedThreshold->setToolTip(i18nc("@info:tooltip", "Threshold above which all pictures are assigned Accepted Label"));
0203 
0204     d->detectBlur             = new QCheckBox(i18nc("@option:check", "Detect Blur"), basicView);
0205     d->detectBlur->setToolTip(i18nc("@info:tooltip", "Detect the amount of blur in the images passed to it"));
0206 
0207     d->lbl5                   = new QLabel(i18nc("@label", "Weight:"), basicView);
0208     d->lbl5->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0209     d->setBlurWeight          = new DIntNumInput(basicView);
0210     d->setBlurWeight->setDefaultValue(100);
0211     d->setBlurWeight->setRange(1, 100, 1);
0212     d->setBlurWeight->setToolTip(i18nc("@info:tooltip", "Weight to assign to Blur Algorithm"));
0213 
0214     d->detectNoise            = new QCheckBox(i18nc("@option:check", "Detect Noise"), basicView);
0215     d->detectNoise->setToolTip(i18nc("@info:tooltip", "Detect the amount of noise in the images passed to it"));
0216 
0217     d->lbl6                   = new QLabel(i18nc("@label", "Weight:"), basicView);
0218     d->lbl6->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0219     d->setNoiseWeight         = new DIntNumInput(basicView);
0220     d->setNoiseWeight->setDefaultValue(100);
0221     d->setNoiseWeight->setRange(1, 100, 1);
0222     d->setNoiseWeight->setToolTip(i18nc("@info:tooltip", "Weight to assign to Noise Algorithm"));
0223 
0224     d->detectCompression      = new QCheckBox(i18nc("@option:check", "Detect Compression"), basicView);
0225     d->detectCompression->setToolTip(i18nc("@info:tooltip", "Detect the amount of compression in the images passed to it"));
0226 
0227     d->lbl7                   = new QLabel(i18nc("@label", "Weight:"), basicView);
0228     d->lbl7->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0229     d->setCompressionWeight   = new DIntNumInput(basicView);
0230     d->setCompressionWeight->setDefaultValue(100);
0231     d->setCompressionWeight->setRange(1, 100, 1);
0232     d->setCompressionWeight->setToolTip(i18nc("@info:tooltip", "Weight to assign to Compression Algorithm"));
0233 
0234     d->detectExposure         = new QCheckBox(i18nc("@option:check", "Detect Under and Over Exposure"), basicView);
0235     d->detectExposure->setToolTip(i18nc("@info:tooltip", "Detect if the images are under-exposed or over-exposed"));
0236 
0237     grid1->addWidget(d->lbl2,                  0, 0, 1, 2);
0238     grid1->addWidget(d->setRejectedThreshold,  0, 2, 1, 1);
0239     grid1->addWidget(d->lbl3,                  1, 0, 1, 2);
0240     grid1->addWidget(d->setPendingThreshold,   1, 2, 1, 1);
0241     grid1->addWidget(d->lbl4,                  2, 0, 1, 2);
0242     grid1->addWidget(d->setAcceptedThreshold,  2, 2, 1, 1);
0243 
0244     grid1->addWidget(d->detectBlur,            3, 0, 1, 1);
0245     grid1->addWidget(d->lbl5,                  3, 1, 1, 1);
0246     grid1->addWidget(d->setBlurWeight,         3, 2, 1, 1);
0247 
0248     grid1->addWidget(d->detectNoise,           4, 0, 1, 1);
0249     grid1->addWidget(d->lbl6,                  4, 1, 1, 1);
0250     grid1->addWidget(d->setNoiseWeight,        4, 2, 1, 1);
0251 
0252     grid1->addWidget(d->detectCompression,     5, 0, 1, 1);
0253     grid1->addWidget(d->lbl7,                  5, 1, 1, 1);
0254     grid1->addWidget(d->setCompressionWeight,  5, 2, 1, 1);
0255 
0256     grid1->addWidget(d->detectExposure,        6, 0, 1, 3);
0257     grid1->setContentsMargins(2 * spacing, spacing, spacing, spacing);
0258     grid1->setColumnStretch(0, 1);
0259     grid1->setColumnStretch(1, 1);
0260     grid1->setColumnStretch(2, 100);
0261     grid1->setRowStretch(7, 10);
0262 
0263     // ------------------------------------------------------------------------------
0264 
0265     QGridLayout* const glay = new QGridLayout(this);
0266     glay->addWidget(hlay1,                 0, 1, 1, 1);
0267     glay->addWidget(hlay2,                 1, 1, 1, 1);
0268     glay->addWidget(hlay3,                 2, 1, 1, 1);
0269     glay->addWidget(d->detectAesthetic,    3, 1, 1, 1);
0270     glay->addWidget(d->detectBasicFactors, 4, 1, 1, 1);
0271     glay->addWidget(basicView,             5, 1, 1, 1);
0272     glay->setColumnStretch(1, 10);
0273     glay->setContentsMargins(2 * spacing, spacing, spacing, spacing);
0274 
0275     // ------------------------------------------------------------------------------
0276 
0277     connect(d->detectBlur, SIGNAL(toggled(bool)),
0278             this, SIGNAL(signalSettingsChanged()));
0279 
0280     connect(d->detectNoise, SIGNAL(toggled(bool)),
0281             this, SIGNAL(signalSettingsChanged()));
0282 
0283     connect(d->detectCompression, SIGNAL(toggled(bool)),
0284             this, SIGNAL(signalSettingsChanged()));
0285 
0286     connect(d->detectExposure, SIGNAL(toggled(bool)),
0287             this, SIGNAL(signalSettingsChanged()));
0288 
0289     connect(d->setRejected, SIGNAL(toggled(bool)),
0290             this, SIGNAL(signalSettingsChanged()));
0291 
0292     connect(d->setPending, SIGNAL(toggled(bool)),
0293             this, SIGNAL(signalSettingsChanged()));
0294 
0295     connect(d->setAccepted, SIGNAL(toggled(bool)),
0296             this, SIGNAL(signalSettingsChanged()));
0297 
0298     connect(d->setRejectedThreshold, SIGNAL(valueChanged(int)),
0299             this, SIGNAL(signalSettingsChanged()));
0300 
0301     connect(d->setPendingThreshold, SIGNAL(valueChanged(int)),
0302             this, SIGNAL(signalSettingsChanged()));
0303 
0304     connect(d->setAcceptedThreshold, SIGNAL(valueChanged(int)),
0305             this, SIGNAL(signalSettingsChanged()));
0306 
0307     connect(d->setBlurWeight, SIGNAL(valueChanged(int)),
0308             this, SIGNAL(signalSettingsChanged()));
0309 
0310     connect(d->setNoiseWeight, SIGNAL(valueChanged(int)),
0311             this, SIGNAL(signalSettingsChanged()));
0312 
0313     connect(d->setCompressionWeight, SIGNAL(valueChanged(int)),
0314             this, SIGNAL(signalSettingsChanged()));
0315 
0316     // ------------------------------------------------------------------------------
0317 
0318     connect(d->detectBlur, SIGNAL(toggled(bool)),
0319             d->lbl5, SLOT(setEnabled(bool)));
0320 
0321     connect(d->detectBlur, SIGNAL(toggled(bool)),
0322             d->setBlurWeight, SLOT(setEnabled(bool)));
0323 
0324     connect(d->detectNoise, SIGNAL(toggled(bool)),
0325             d->lbl6, SLOT(setEnabled(bool)));
0326 
0327     connect(d->detectNoise, SIGNAL(toggled(bool)),
0328             d->setNoiseWeight, SLOT(setEnabled(bool)));
0329 
0330     connect(d->detectCompression, SIGNAL(toggled(bool)),
0331             d->lbl7, SLOT(setEnabled(bool)));
0332 
0333     connect(d->detectCompression, SIGNAL(toggled(bool)),
0334             d->setCompressionWeight, SLOT(setEnabled(bool)));
0335 
0336 #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
0337 
0338     connect(d->detectButtonGroup, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::idClicked),
0339             this, &ImageQualitySettings::slotDisableOptionViews);
0340 
0341 #else
0342 
0343     connect(d->detectButtonGroup, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonClicked),
0344             this, &ImageQualitySettings::slotDisableOptionViews);
0345 
0346 #endif
0347 
0348     slotDisableOptionViews();
0349 }
0350 
0351 ImageQualitySettings::~ImageQualitySettings()
0352 {
0353     delete d;
0354 }
0355 
0356 void ImageQualitySettings::applySettings()
0357 {
0358     ImageQualityContainer imq = getImageQualityContainer();
0359     imq.writeToConfig();
0360 }
0361 
0362 void ImageQualitySettings::applySettings(KConfigGroup& group)
0363 {
0364     ImageQualityContainer imq = getImageQualityContainer();
0365     imq.writeToConfig(group);
0366 }
0367 
0368 void ImageQualitySettings::readSettings()
0369 {
0370     ImageQualityContainer imq;
0371     imq.readFromConfig();
0372     setImageQualityContainer(imq);
0373 }
0374 
0375 void ImageQualitySettings::readSettings(const KConfigGroup& group)
0376 {
0377     ImageQualityContainer imq;
0378     imq.readFromConfig(group);
0379     setImageQualityContainer(imq);
0380 }
0381 
0382 void ImageQualitySettings::setImageQualityContainer(const ImageQualityContainer& imq)
0383 {
0384     d->detectBlur->setChecked(imq.detectBlur);
0385     d->detectNoise->setChecked(imq.detectNoise);
0386     d->detectCompression->setChecked(imq.detectCompression);
0387     d->detectExposure->setChecked(imq.detectExposure);
0388 
0389     if (imq.detectAesthetic)
0390     {
0391         d->detectAesthetic->setChecked(true);
0392     }
0393     else
0394     {
0395         d->detectBasicFactors->setChecked(true);
0396     }
0397 
0398     d->setRejected->setChecked(imq.lowQRejected);
0399     d->setPending->setChecked(imq.mediumQPending);
0400     d->setAccepted->setChecked(imq.highQAccepted);
0401     d->setRejectedThreshold->setValue(imq.rejectedThreshold);
0402     d->setPendingThreshold->setValue(imq.pendingThreshold);
0403     d->setAcceptedThreshold->setValue(imq.acceptedThreshold);
0404     d->setBlurWeight->setValue(imq.blurWeight);
0405     d->setNoiseWeight->setValue(imq.noiseWeight);
0406     d->setCompressionWeight->setValue(imq.compressionWeight);
0407 
0408     d->lbl5->setEnabled(imq.detectBlur);
0409     d->setBlurWeight->setEnabled(imq.detectBlur);
0410     d->lbl6->setEnabled(imq.detectNoise);
0411     d->setNoiseWeight->setEnabled(imq.detectNoise);
0412     d->lbl7->setEnabled(imq.detectCompression);
0413     d->setCompressionWeight->setEnabled(imq.detectCompression);
0414 
0415     slotDisableOptionViews();
0416 }
0417 
0418 ImageQualityContainer ImageQualitySettings::getImageQualityContainer() const
0419 {
0420     ImageQualityContainer imq;
0421 
0422     imq.detectBlur        = d->detectBlur->isChecked();
0423     imq.detectNoise       = d->detectNoise->isChecked();
0424     imq.detectCompression = d->detectCompression->isChecked();
0425     imq.detectExposure    = d->detectExposure->isChecked();
0426     imq.detectAesthetic   = d->detectAesthetic->isChecked();
0427     imq.lowQRejected      = d->setRejected->isChecked();
0428     imq.mediumQPending    = d->setPending->isChecked();
0429     imq.highQAccepted     = d->setAccepted->isChecked();
0430     imq.rejectedThreshold = d->setRejectedThreshold->value();
0431     imq.pendingThreshold  = d->setPendingThreshold->value();
0432     imq.acceptedThreshold = d->setAcceptedThreshold->value();
0433     imq.blurWeight        = d->setBlurWeight->value();
0434     imq.noiseWeight       = d->setNoiseWeight->value();
0435     imq.compressionWeight = d->setCompressionWeight->value();
0436 
0437     return imq;
0438 }
0439 
0440 void ImageQualitySettings::slotDisableOptionViews()
0441 {
0442     bool b = d->detectBasicFactors->isChecked();
0443 
0444     d->lbl2->setEnabled(b);
0445     d->lbl3->setEnabled(b);
0446     d->lbl4->setEnabled(b);
0447     d->detectBlur->setEnabled(b);
0448     d->detectNoise->setEnabled(b);
0449     d->detectCompression->setEnabled(b);
0450     d->detectExposure->setEnabled(b);
0451     d->setRejectedThreshold->setEnabled(b);
0452     d->setPendingThreshold->setEnabled(b);
0453     d->setAcceptedThreshold->setEnabled(b);
0454 
0455     d->lbl5->setEnabled(b && d->detectBlur->isChecked());
0456     d->setBlurWeight->setEnabled(b && d->detectBlur->isChecked());
0457     d->lbl6->setEnabled(b && d->detectNoise->isChecked());
0458     d->setNoiseWeight->setEnabled(b && d->detectNoise->isChecked());
0459     d->lbl7->setEnabled(b && d->detectCompression->isChecked());
0460     d->setCompressionWeight->setEnabled(b && d->detectCompression->isChecked());
0461 
0462     Q_EMIT signalSettingsChanged();
0463 }
0464 
0465 void ImageQualitySettings::resetToDefault()
0466 {
0467     blockSignals(true);
0468 
0469     ImageQualityContainer prm;
0470     setImageQualityContainer(prm);
0471 
0472     blockSignals(false);
0473 }
0474 
0475 ImageQualityContainer ImageQualitySettings::defaultSettings() const
0476 {
0477     ImageQualityContainer prm;
0478 
0479     return prm;
0480 }
0481 
0482 } // namespace Digikam
0483 
0484 #include "moc_imagequalitysettings.cpp"