File indexing completed on 2025-04-27 03:58:22

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2007-08-02
0007  * Description : a stack of widgets to set image file save
0008  *               options into image editor.
0009  *
0010  * SPDX-FileCopyrightText: 2007-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "filesaveoptionsbox.h"
0017 
0018 // Qt includes
0019 
0020 #include <QCheckBox>
0021 #include <QGridLayout>
0022 #include <QImageReader>
0023 #include <QLabel>
0024 #include <QWidget>
0025 #include <QApplication>
0026 #include <QStyle>
0027 
0028 // KDE includes
0029 
0030 #include <kconfiggroup.h>
0031 #include <ksharedconfig.h>
0032 #include <klocalizedstring.h>
0033 
0034 // Local includes
0035 
0036 #include "digikam_debug.h"
0037 #include "dpluginloader.h"
0038 
0039 namespace Digikam
0040 {
0041 
0042 class Q_DECL_HIDDEN FileSaveOptionsBox::Private
0043 {
0044 
0045 public:
0046 
0047     explicit Private()
0048       : noneOptions     (nullptr),
0049         noneGrid        (nullptr),
0050         labelNone       (nullptr),
0051         JPEGOptions     (nullptr),
0052         PNGOptions      (nullptr),
0053         TIFFOptions     (nullptr),
0054 
0055 #ifdef HAVE_JASPER
0056 
0057         JPEG2000Options (nullptr),
0058 
0059 #endif // HAVE_JASPER
0060 
0061 #ifdef HAVE_X265
0062 
0063         HEIFOptions     (nullptr),
0064 
0065 #endif // HAVE_X265
0066 
0067         PGFOptions      (nullptr),
0068         JXLOptions      (nullptr),
0069         WEBPOptions     (nullptr),
0070         AVIFOptions     (nullptr)
0071     {
0072     }
0073 
0074     QWidget*            noneOptions;
0075 
0076     QGridLayout*        noneGrid;
0077 
0078     QLabel*             labelNone;
0079 
0080     DImgLoaderSettings* JPEGOptions;
0081     DImgLoaderSettings* PNGOptions;
0082     DImgLoaderSettings* TIFFOptions;
0083 
0084 #ifdef HAVE_JASPER
0085 
0086     DImgLoaderSettings* JPEG2000Options;
0087 
0088 #endif // HAVE_JASPER
0089 
0090 #ifdef HAVE_X265
0091 
0092     DImgLoaderSettings* HEIFOptions;
0093 
0094 #endif // HAVE_X265
0095 
0096     DImgLoaderSettings* PGFOptions;
0097     DImgLoaderSettings* JXLOptions;
0098     DImgLoaderSettings* WEBPOptions;
0099     DImgLoaderSettings* AVIFOptions;
0100 };
0101 
0102 FileSaveOptionsBox::FileSaveOptionsBox(QWidget* const parent)
0103     : QStackedWidget(parent),
0104       d             (new Private)
0105 {
0106     setAttribute(Qt::WA_DeleteOnClose);
0107 
0108     //-- NONE Settings ------------------------------------------------------
0109 
0110     d->noneOptions               = new QWidget(this);
0111     d->noneGrid                  = new QGridLayout(d->noneOptions);
0112     d->noneGrid->setSpacing(qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0113                                  QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing)));
0114     d->noneOptions->setLayout(d->noneGrid);
0115     d->labelNone                 = new QLabel(i18n("No options available"), d->noneOptions);
0116     d->noneGrid->addWidget(d->labelNone, 0, 0, 0, 1);
0117     DPluginLoader* const ploader = DPluginLoader::instance();
0118 
0119     //-- JPEG Settings ------------------------------------------------------
0120 
0121     d->JPEGOptions     = ploader->exportWidget(QLatin1String("JPEG"));
0122     d->JPEGOptions->setParent(this);
0123 
0124     //-- PNG Settings -------------------------------------------------------
0125 
0126     d->PNGOptions      = ploader->exportWidget(QLatin1String("PNG"));
0127     d->PNGOptions->setParent(this);
0128 
0129     //-- TIFF Settings ------------------------------------------------------
0130 
0131     d->TIFFOptions     = ploader->exportWidget(QLatin1String("TIFF"));
0132     d->TIFFOptions->setParent(this);
0133 
0134     //-- JPEG 2000 Settings -------------------------------------------------
0135 
0136 #ifdef HAVE_JASPER
0137 
0138     d->JPEG2000Options = ploader->exportWidget(QLatin1String("JP2"));
0139     d->JPEG2000Options->setParent(this);
0140 
0141 #endif // HAVE_JASPER
0142 
0143     //-- PGF Settings -------------------------------------------------
0144 
0145     d->PGFOptions      = ploader->exportWidget(QLatin1String("PGF"));
0146     d->PGFOptions->setParent(this);
0147 
0148     //-- JXL Settings -------------------------------------------------
0149 
0150     // NOTE: JXL support depend of JXL QImage loader plugin availability.
0151 
0152     d->JXLOptions      = ploader->exportWidget(QLatin1String("JXL"));
0153 
0154     if (d->JXLOptions)
0155     {
0156         d->JXLOptions->setParent(this);
0157     }
0158 
0159     //-- WEBP Settings -------------------------------------------------
0160 
0161     // NOTE: WEBP support depend of WEBP QImage loader plugin availability.
0162 
0163     d->WEBPOptions     = ploader->exportWidget(QLatin1String("WEBP"));
0164 
0165     if (d->WEBPOptions)
0166     {
0167         d->WEBPOptions->setParent(this);
0168     }
0169 
0170     //-- AVIF Settings -------------------------------------------------
0171 
0172     // NOTE: AVIF support depend of JXL QImage loader plugin availability.
0173 
0174     d->AVIFOptions     = ploader->exportWidget(QLatin1String("AVIF"));
0175 
0176     if (d->AVIFOptions)
0177     {
0178         d->AVIFOptions->setParent(this);
0179     }
0180 
0181     //-- HEIF Settings -------------------------------------------------
0182 
0183 #ifdef HAVE_X265
0184 
0185     d->HEIFOptions     = ploader->exportWidget(QLatin1String("HEIF"));
0186     d->HEIFOptions->setParent(this);
0187 
0188 #endif // HAVE_X265
0189 
0190     //-----------------------------------------------------------------------
0191 
0192     insertWidget(NONE,        d->noneOptions);
0193     insertWidget(JPEG,        d->JPEGOptions);
0194     insertWidget(PNG,         d->PNGOptions);
0195     insertWidget(TIFF,        d->TIFFOptions);
0196 
0197 #ifdef HAVE_JASPER
0198 
0199     insertWidget(JP2K,        d->JPEG2000Options);
0200 
0201 #endif // HAVE_JASPER
0202 
0203     insertWidget(PGF,         d->PGFOptions);
0204 
0205 #ifdef HAVE_X265
0206 
0207     insertWidget(HEIF,        d->HEIFOptions);
0208 
0209 #endif // HAVE_X265
0210 
0211     if (d->JXLOptions)
0212     {
0213         insertWidget(JXL,     d->JXLOptions);
0214     }
0215 
0216     if (d->WEBPOptions)
0217     {
0218         insertWidget(WEBP,    d->WEBPOptions);
0219     }
0220 
0221     if (d->AVIFOptions)
0222     {
0223         insertWidget(AVIF,    d->AVIFOptions);
0224     }
0225 
0226     //-----------------------------------------------------------------------
0227 
0228     readSettings();
0229 }
0230 
0231 FileSaveOptionsBox::~FileSaveOptionsBox()
0232 {
0233     delete d;
0234 }
0235 
0236 void FileSaveOptionsBox::setImageFileFormat(const QString& ext)
0237 {
0238     qCDebug(DIGIKAM_WIDGETS_LOG) << "Format selected: " << ext;
0239     setCurrentIndex(discoverFormat(ext, NONE));
0240 }
0241 
0242 FileSaveOptionsBox::FORMAT FileSaveOptionsBox::discoverFormat(const QString& filename,
0243                                                               FileSaveOptionsBox::FORMAT fallback)
0244 {
0245     qCDebug(DIGIKAM_WIDGETS_LOG) << "Trying to discover format based on filename '" << filename
0246                                  << "', fallback = " << fallback;
0247 
0248     QStringList splitParts = filename.split(QLatin1Char('.'));
0249     QString ext;
0250 
0251     if (splitParts.size() < 2)
0252     {
0253         qCDebug(DIGIKAM_WIDGETS_LOG) << "filename '" << filename
0254                                      << "' does not contain an extension separated by a point.";
0255         ext = filename;
0256     }
0257     else
0258     {
0259         ext = splitParts.at(splitParts.size() - 1);
0260     }
0261 
0262     ext = ext.toUpper();
0263 
0264     FORMAT format = fallback;
0265 
0266     if      (ext.contains(QLatin1String("JPEG")) || ext.contains(QLatin1String("JPG")) || ext.contains(QLatin1String("JPE")))
0267     {
0268         format = JPEG;
0269     }
0270     else if (ext.contains(QLatin1String("PNG")))
0271     {
0272         format = PNG;
0273     }
0274     else if (ext.contains(QLatin1String("TIFF")) || ext.contains(QLatin1String("TIF")))
0275     {
0276         format = TIFF;
0277     }
0278 
0279 #ifdef HAVE_JASPER
0280 
0281     else if (ext.contains(QLatin1String("JP2")) || ext.contains(QLatin1String("JPX")) || ext.contains(QLatin1String("JPC")) ||
0282              ext.contains(QLatin1String("PGX")) || ext.contains(QLatin1String("J2K")))
0283     {
0284         format = JP2K;
0285     }
0286 
0287 #endif // HAVE_JASPER
0288 
0289 #ifdef HAVE_X265
0290 
0291     else if (ext.contains(QLatin1String("HEIC")) || ext.contains(QLatin1String("HEIF")) || ext.contains(QLatin1String("HIF")))
0292     {
0293         format = HEIF;
0294     }
0295 
0296 #endif // HAVE_X265
0297 
0298     else if (ext.contains(QLatin1String("PGF")))
0299     {
0300         format = PGF;
0301     }
0302     else if (ext.contains(QLatin1String("JXL")))
0303     {
0304         format = JXL;
0305     }
0306     else if (ext.contains(QLatin1String("WEBP")))
0307     {
0308         format = WEBP;
0309     }
0310     else if (ext.contains(QLatin1String("AVIF")))
0311     {
0312         format = AVIF;
0313     }
0314     else
0315     {
0316         qCWarning(DIGIKAM_WIDGETS_LOG) << "Using fallback format " << fallback;
0317     }
0318 
0319     qCDebug(DIGIKAM_WIDGETS_LOG) << "Discovered format: " << format;
0320 
0321     return format;
0322 }
0323 
0324 void FileSaveOptionsBox::applySettings()
0325 {
0326     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0327     KConfigGroup group        = config->group(QLatin1String("ImageViewer Settings"));
0328     group.writeEntry(QLatin1String("JPEGCompression"),     d->JPEGOptions->settings()[QLatin1String("quality")].toInt());
0329     group.writeEntry(QLatin1String("JPEGSubSampling"),     d->JPEGOptions->settings()[QLatin1String("subsampling")].toInt());
0330 
0331     // ---
0332 
0333     group.writeEntry(QLatin1String("PNGCompression"),      d->PNGOptions->settings()[QLatin1String("quality")].toInt());
0334 
0335     // ---
0336 
0337     group.writeEntry(QLatin1String("TIFFCompression"),     d->TIFFOptions->settings()[QLatin1String("compress")].toBool());
0338 
0339 #ifdef HAVE_JASPER
0340 
0341     group.writeEntry(QLatin1String("JPEG2000Compression"), d->JPEG2000Options->settings()[QLatin1String("quality")].toInt());
0342     group.writeEntry(QLatin1String("JPEG2000LossLess"),    d->JPEG2000Options->settings()[QLatin1String("lossless")].toBool());
0343 
0344 #endif // HAVE_JASPER
0345 
0346     group.writeEntry(QLatin1String("PGFCompression"),      d->PGFOptions->settings()[QLatin1String("quality")].toInt());
0347     group.writeEntry(QLatin1String("PGFLossLess"),         d->PGFOptions->settings()[QLatin1String("lossless")].toBool());
0348 
0349 #ifdef HAVE_X265
0350 
0351     group.writeEntry(QLatin1String("HEIFCompression"),     d->HEIFOptions->settings()[QLatin1String("quality")].toInt());
0352     group.writeEntry(QLatin1String("HEIFLossLess"),        d->HEIFOptions->settings()[QLatin1String("lossless")].toBool());
0353 
0354 #endif // HAVE_X265
0355 
0356     if (d->JXLOptions)
0357     {
0358         group.writeEntry(QLatin1String("JXLCompression"),  d->JXLOptions->settings()[QLatin1String("quality")].toInt());
0359         group.writeEntry(QLatin1String("JXLLossLess"),     d->JXLOptions->settings()[QLatin1String("lossless")].toBool());
0360     }
0361 
0362     if (d->WEBPOptions)
0363     {
0364         group.writeEntry(QLatin1String("WEBPCompression"), d->WEBPOptions->settings()[QLatin1String("quality")].toInt());
0365         group.writeEntry(QLatin1String("WEBPLossLess"),    d->WEBPOptions->settings()[QLatin1String("lossless")].toBool());
0366     }
0367 
0368     if (d->AVIFOptions)
0369     {
0370         group.writeEntry(QLatin1String("AVIFCompression"),  d->AVIFOptions->settings()[QLatin1String("quality")].toInt());
0371         group.writeEntry(QLatin1String("AVIFLossLess"),     d->AVIFOptions->settings()[QLatin1String("lossless")].toBool());
0372     }
0373 
0374     config->sync();
0375 }
0376 
0377 void FileSaveOptionsBox::readSettings()
0378 {
0379     DImgLoaderPrms set;
0380 
0381     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0382     KConfigGroup group        = config->group(QLatin1String("ImageViewer Settings"));
0383 
0384     set.clear();
0385     set.insert(QLatin1String("quality"),     group.readEntry(QLatin1String("JPEGCompression"),     75));
0386     set.insert(QLatin1String("subsampling"), group.readEntry(QLatin1String("JPEGSubSampling"),     1));  ///< Medium subsampling
0387     d->JPEGOptions->setSettings(set);
0388 
0389     // ---
0390 
0391     set.clear();
0392     set.insert(QLatin1String("quality"),  group.readEntry(QLatin1String("PNGCompression"),         9));
0393     d->PNGOptions->setSettings(set);
0394 
0395     // ---
0396 
0397     set.clear();
0398     set.insert(QLatin1String("compress"), group.readEntry(QLatin1String("TIFFCompression"),        false));
0399     d->TIFFOptions->setSettings(set);
0400 
0401 #ifdef HAVE_JASPER
0402 
0403     set.clear();
0404     set.insert(QLatin1String("quality"),  group.readEntry(QLatin1String("JPEG2000Compression"),    75));
0405     set.insert(QLatin1String("lossless"), group.readEntry(QLatin1String("JPEG2000LossLess"),       true));
0406     d->JPEG2000Options->setSettings(set);
0407 
0408 #endif // HAVE_JASPER
0409 
0410     set.clear();
0411     set.insert(QLatin1String("quality"),  group.readEntry(QLatin1String("PGFCompression"),         3));
0412     set.insert(QLatin1String("lossless"), group.readEntry(QLatin1String("PGFLossLess"),            true));
0413     d->PGFOptions->setSettings(set);
0414 
0415 #ifdef HAVE_X265
0416 
0417     set.clear();
0418     set.insert(QLatin1String("quality"),  group.readEntry(QLatin1String("HEIFCompression"),        75));
0419     set.insert(QLatin1String("lossless"), group.readEntry(QLatin1String("HEIFLossLess"),           true));
0420     d->HEIFOptions->setSettings(set);
0421 
0422 #endif // HAVE_X265
0423 
0424     if (d->JXLOptions)
0425     {
0426         set.clear();
0427         set.insert(QLatin1String("quality"),  group.readEntry(QLatin1String("JXLCompression"),     75));
0428         set.insert(QLatin1String("lossless"), group.readEntry(QLatin1String("JXLLossLess"),        true));
0429         d->JXLOptions->setSettings(set);
0430     }
0431 
0432     if (d->WEBPOptions)
0433     {
0434         set.clear();
0435         set.insert(QLatin1String("quality"),  group.readEntry(QLatin1String("WEBPCompression"),     75));
0436         set.insert(QLatin1String("lossless"), group.readEntry(QLatin1String("WEBPLossLess"),        true));
0437         d->WEBPOptions->setSettings(set);
0438     }
0439 
0440     if (d->AVIFOptions)
0441     {
0442         set.clear();
0443         set.insert(QLatin1String("quality"),  group.readEntry(QLatin1String("AVIFCompression"),     75));
0444         set.insert(QLatin1String("lossless"), group.readEntry(QLatin1String("AVIFLossLess"),        true));
0445         d->AVIFOptions->setSettings(set);
0446     }
0447 }
0448 
0449 } // namespace Digikam
0450 
0451 #include "moc_filesaveoptionsbox.cpp"