File indexing completed on 2024-12-22 04:15:44

0001 /*
0002  * SPDX-FileCopyrightText: 2022 L. E. Segovia <amy@amyspark.me>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_wdg_options_jpegxl.h"
0008 
0009 #include <tuple>
0010 
0011 #include <KoColorModelStandardIds.h>
0012 
0013 KisWdgOptionsJPEGXL::KisWdgOptionsJPEGXL(QWidget *parent)
0014     : KisConfigWidget(parent)
0015 {
0016     setupUi(this);
0017 
0018     {
0019         resampling->addItem(i18nc("JPEG-XL encoder options", "Default (only for low quality)"), -1);
0020         resampling->addItem(i18nc("JPEG-XL encoder options", "No downsampling"), 1);
0021         resampling->addItem(i18nc("JPEG-XL encoder options", "2x2 downsampling"), 2);
0022         resampling->addItem(i18nc("JPEG-XL encoder options", "4x4 downsampling"), 4);
0023         resampling->addItem(i18nc("JPEG-XL encoder options", "8x8 downsampling"), 8);
0024 
0025         extraChannelResampling->addItem(i18nc("JPEG-XL encoder options", "Default (only for low quality)"), -1);
0026         extraChannelResampling->addItem(i18nc("JPEG-XL encoder options", "No downsampling"), 1);
0027         extraChannelResampling->addItem(i18nc("JPEG-XL encoder options", "2x2 downsampling"), 2);
0028         extraChannelResampling->addItem(i18nc("JPEG-XL encoder options", "4x4 downsampling"), 4);
0029         extraChannelResampling->addItem(i18nc("JPEG-XL encoder options", "8x8 downsampling"), 8);
0030     }
0031 
0032     {
0033         dots->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0034         dots->addItem(i18nc("JPEG-XL encoder options", "Disabled"), 0);
0035         dots->addItem(i18nc("JPEG-XL encoder options", "Enabled"), 1);
0036     }
0037 
0038     {
0039         patches->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0040         patches->addItem(i18nc("JPEG-XL encoder options", "Disabled"), 0);
0041         patches->addItem(i18nc("JPEG-XL encoder options", "Enabled"), 1);
0042     }
0043 
0044     {
0045         gaborish->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0046         gaborish->addItem(i18nc("JPEG-XL encoder options", "Disabled"), 0);
0047         gaborish->addItem(i18nc("JPEG-XL encoder options", "Enabled"), 1);
0048     }
0049 
0050     {
0051         modular->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0052         modular->addItem(i18nc("JPEG-XL encoder options", "VarDCT mode (e.g. for photographic images)"), 0);
0053         modular->addItem(i18nc("JPEG-XL encoder options", "Modular mode (e.g. for lossless images)"), -1);
0054     }
0055 
0056     {
0057         keepInvisible->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0058         keepInvisible->addItem(i18nc("JPEG-XL encoder options", "Disabled"), 0);
0059         keepInvisible->addItem(i18nc("JPEG-XL encoder options", "Enabled"), 1);
0060     }
0061 
0062     {
0063         groupOrder->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0064         groupOrder->addItem(i18nc("JPEG-XL encoder options", "Scanline order"), 0);
0065         groupOrder->addItem(i18nc("JPEG-XL encoder options", "Center-first order"), -1);
0066     }
0067 
0068     {
0069         responsive->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0070         responsive->addItem(i18nc("JPEG-XL encoder options", "Disabled"), 0);
0071         responsive->addItem(i18nc("JPEG-XL encoder options", "Enabled"), 1);
0072     }
0073 
0074     {
0075         progressiveAC->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0076         progressiveAC->addItem(i18nc("JPEG-XL encoder options", "Disabled"), 0);
0077         progressiveAC->addItem(i18nc("JPEG-XL encoder options", "Enabled"), 1);
0078     }
0079 
0080     {
0081         qProgressiveAC->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0082         qProgressiveAC->addItem(i18nc("JPEG-XL encoder options", "Disabled"), 0);
0083         qProgressiveAC->addItem(i18nc("JPEG-XL encoder options", "Enabled"), 1);
0084     }
0085 
0086     {
0087         progressiveDC->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0088         progressiveDC->addItem(i18nc("JPEG-XL encoder options", "Disabled"), 0);
0089         progressiveDC->addItem(i18nc("JPEG-XL encoder options", "64x64 lower resolution pass"), 1);
0090         progressiveDC->addItem(i18nc("JPEG-XL encoder options", "512x512 + 64x64 lower resolution passes"), 2);
0091     }
0092 
0093     {
0094         lossyPalette->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0095         lossyPalette->addItem(i18nc("JPEG-XL encoder options", "Disabled"), 0);
0096         lossyPalette->addItem(i18nc("JPEG-XL encoder options", "Enabled"), 1);
0097     }
0098 
0099     {
0100         modularGroupSize->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0101         modularGroupSize->addItem(i18nc("JPEG-XL encoder options", "128"), 0);
0102         modularGroupSize->addItem(i18nc("JPEG-XL encoder options", "256"), 1);
0103         modularGroupSize->addItem(i18nc("JPEG-XL encoder options", "512"), 2);
0104         modularGroupSize->addItem(i18nc("JPEG-XL encoder options", "1024"), 3);
0105     }
0106 
0107     {
0108         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0109         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Zero"), 0);
0110         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Left"), 1);
0111         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Top"), 2);
0112         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Avg0"), 3);
0113         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Select"), 4);
0114         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Gradient"), 5);
0115         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Weighted"), 6);
0116         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Top right"), 7);
0117         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Top left"), 8);
0118         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Left left"), 9);
0119         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Avg1"), 10);
0120         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Avg2"), 11);
0121         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Avg3"), 12);
0122         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Toptop predictive average"), 13);
0123         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Gradient + Weighted"), 14);
0124         modularPredictor->addItem(i18nc("JPEG-XL encoder options", "Use all predictors"), 15);
0125     }
0126 
0127     {
0128         jpegReconCFL->addItem(i18nc("JPEG-XL encoder options", "Default (encoder chooses)"), -1);
0129         jpegReconCFL->addItem(i18nc("JPEG-XL encoder options", "Disabled"), 0);
0130         jpegReconCFL->addItem(i18nc("JPEG-XL encoder options", "Enabled"), 1);
0131     }
0132 
0133     metaDataFilters->setModel(&m_filterRegistryModel);
0134 
0135     connect(cmbConversionPolicy,
0136             qOverload<int>(&QComboBox::currentIndexChanged),
0137             this,
0138             &KisWdgOptionsJPEGXL::toggleExtraHDROptions);
0139 
0140     connect(modular, qOverload<int>(&QComboBox::currentIndexChanged), this, &KisWdgOptionsJPEGXL::toggleModularTabs);
0141 }
0142 
0143 void KisWdgOptionsJPEGXL::toggleExtraHDROptions(int index)
0144 {
0145     const QString option = cmbConversionPolicy->itemData(index).value<QString>();
0146     chkHLGOOTF->setEnabled(option.contains("HLG"));
0147 }
0148 
0149 void KisWdgOptionsJPEGXL::toggleModularTabs(int index)
0150 {
0151     const int id = modular->itemData(index, Qt::UserRole).value<int>();
0152     advancedParameters->setTabEnabled(1, id == -1 || id == 0); // vardct
0153     advancedParameters->setTabEnabled(2, id == -1 || id == 1); // modular
0154 }
0155 
0156 void KisWdgOptionsJPEGXL::setConfiguration(const KisPropertiesConfigurationSP cfg)
0157 {
0158     using SpaceList = QList<std::tuple<QString, QString, QString>>;
0159 
0160     haveAnimation->setChecked(cfg->getBool("haveAnimation", true));
0161     flattenLayers->setChecked(cfg->getBool("flattenLayers", true));
0162     lossyEncoding->setChecked(!cfg->getBool("lossless", true));
0163     effort->setValue(cfg->getInt("effort", 7));
0164     decodingSpeed->setValue(cfg->getInt("decodingSpeed", 0));
0165     lossyQuality->setValue(cfg->getInt("lossyQuality", 100));
0166     forceModular->setChecked(cfg->getBool("forceModular", false));
0167 
0168     const int CicpPrimaries = cfg->getInt(KisImportExportFilter::CICPPrimariesTag, PRIMARIES_UNSPECIFIED);
0169     tabWidget->setTabEnabled(1, cfg->getBool(KisImportExportFilter::HDRTag, false)
0170                                    && cfg->getString(KisImportExportFilter::ColorModelIDTag) != GrayAColorModelID.id());
0171     SpaceList conversionOptionsList = {
0172         {i18nc("Color space option", "Save as is"),
0173          i18nc("@tooltip",
0174                "The image will be stored without conversion, the ICC profile will be converted to CICP or embedded if "
0175                "it was not possible."),
0176          "KeepSame"},
0177         {i18nc("Color space name", "Rec 2100 PQ"),
0178          i18nc("@tooltip",
0179                "The image will be converted to Rec 2020 linear first, and then encoded with a perceptual quantizer "
0180                "curve"
0181                " (also known as SMPTE 2048 curve). Recommended for HDR images where the absolute brightness is "
0182                "important."),
0183          "Rec2100PQ"},
0184         {i18nc("Color space name", "Rec 2100 HLG"),
0185          i18nc("@tooltip",
0186                "The image will be converted to Rec 2020 linear first, and then encoded with a Hybrid Log Gamma curve."
0187                " Recommended for HDR images where the display may not understand HDR."),
0188          "Rec2100HLG"}};
0189 
0190     if (cfg->getString(KisImportExportFilter::ColorModelIDTag) == RGBAColorModelID.id()) {
0191         if (CicpPrimaries != PRIMARIES_UNSPECIFIED) {
0192             conversionOptionsList << std::make_tuple<QString, QString, QString>(
0193                 i18nc("Color space option plus transfer function name", "Keep colorants, encode PQ"),
0194                 i18nc("@tooltip",
0195                       "The image will be linearized first, and then encoded with a perceptual quantizer curve"
0196                       " (also known as the SMPTE 2048 curve). Recommended for images where the absolute brightness is "
0197                       "important."),
0198                 "ApplyPQ");
0199 
0200             conversionOptionsList << std::make_tuple<QString, QString, QString>(
0201                 i18nc("Color space option plus transfer function name", "Keep colorants, encode HLG"),
0202                 i18nc("@tooltip",
0203                       "The image will be linearized first, and then encoded with a Hybrid Log Gamma curve."
0204                       " Recommended for images intended for screens which cannot understand PQ"),
0205                 "ApplyHLG");
0206 
0207             conversionOptionsList << std::make_tuple<QString, QString, QString>(
0208                 i18nc("Color space option plus transfer function name", "Keep colorants, encode SMPTE ST 428"),
0209                 i18nc("@tooltip",
0210                       "The image will be linearized first, and then encoded with SMPTE ST 428."
0211                       " Krita always opens images like these as linear floating point, this option is there to reverse "
0212                       "that"),
0213                 "ApplySMPTE428");
0214         }
0215     }
0216     for (int i = 0; i < conversionOptionsList.size(); i++) {
0217         const auto &option = conversionOptionsList.at(i);
0218         cmbConversionPolicy->addItem(std::get<0>(option), std::get<2>(option));
0219         cmbConversionPolicy->setItemData(i, std::get<1>(option), Qt::ToolTipRole);
0220     }
0221     const QString optionName = cfg->getString("floatingPointConversionOption", "Rec2100PQ");
0222     cmbConversionPolicy->setCurrentIndex(cmbConversionPolicy->findData(optionName, Qt::UserRole));
0223     spnNits->setValue(cfg->getDouble("HLGnominalPeak", 1000.0));
0224     spnGamma->setValue(cfg->getDouble("HLGgamma", 1.2));
0225     chkHLGOOTF->setChecked(cfg->getBool("removeHGLOOTF", true));
0226 
0227     resampling->setCurrentIndex(resampling->findData(cfg->getInt("resampling", -1)));
0228     extraChannelResampling->setCurrentIndex(
0229         extraChannelResampling->findData(cfg->getInt("extraChannelResampling", -1)));
0230     photonNoise->setValue(cfg->getInt("photonNoise", 0));
0231     dots->setCurrentIndex(dots->findData(cfg->getInt("dots", -1)));
0232     patches->setCurrentIndex(patches->findData(cfg->getInt("patches", -1)));
0233     epf->setValue(cfg->getInt("epf", -1));
0234     gaborish->setCurrentIndex(gaborish->findData(cfg->getInt("gaborish", -1)));
0235     modular->setCurrentIndex(modular->findData(cfg->getInt("modularSetVal", -1)));
0236     keepInvisible->setCurrentIndex(keepInvisible->findData(cfg->getInt("keepInvisible", -1)));
0237     groupOrder->setCurrentIndex(groupOrder->findData(cfg->getInt("groupOrder", -1)));
0238     responsive->setCurrentIndex(responsive->findData(cfg->getInt("responsive", -1)));
0239     progressiveAC->setCurrentIndex(progressiveAC->findData(cfg->getInt("progressiveAC", -1)));
0240     qProgressiveAC->setCurrentIndex(qProgressiveAC->findData(cfg->getInt("qProgressiveAC", -1)));
0241     progressiveDC->setCurrentIndex(progressiveDC->findData(cfg->getInt("progressiveDC", -1)));
0242     channelColorsGlobalPercent->setValue(cfg->getInt("channelColorsGlobalPercent", -1));
0243     channelColorsGroupPercent->setValue(cfg->getInt("channelColorsGroupPercent", -1));
0244     paletteColors->setValue(cfg->getInt("paletteColors", -1));
0245     lossyPalette->setCurrentIndex(lossyPalette->findData(cfg->getInt("lossyPalette", -1)));
0246     modularGroupSize->setCurrentIndex(modularGroupSize->findData(cfg->getInt("modularGroupSize", -1)));
0247     modularPredictor->setCurrentIndex(modularPredictor->findData(cfg->getInt("modularPredictor", -1)));
0248     modularMATreeLearningPercent->setValue(cfg->getInt("modularMATreeLearningPercent", -1));
0249     jpegReconCFL->setCurrentIndex(jpegReconCFL->findData(cfg->getInt("jpegReconCFL", -1)));
0250 
0251     chkAuthor->setChecked(cfg->getBool("storeAuthor", false));
0252     exif->setChecked(cfg->getBool("exif", true));
0253     xmp->setChecked(cfg->getBool("xmp", true));
0254     iptc->setChecked(cfg->getBool("iptc", true));
0255     chkMetadata->setChecked(cfg->getBool("storeMetaData", true));
0256     m_filterRegistryModel.setEnabledFilters(cfg->getString("filters").split(','));
0257 }
0258 
0259 KisPropertiesConfigurationSP KisWdgOptionsJPEGXL::configuration() const
0260 {
0261     KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
0262 
0263     cfg->setProperty("haveAnimation", haveAnimation->isChecked());
0264     cfg->setProperty("flattenLayers", flattenLayers->isChecked());
0265     cfg->setProperty("lossless", !lossyEncoding->isChecked());
0266     cfg->setProperty("effort", effort->value());
0267     cfg->setProperty("decodingSpeed", decodingSpeed->value());
0268     cfg->setProperty("lossyQuality", lossyQuality->value());
0269     cfg->setProperty("forceModular", forceModular->isChecked());
0270     cfg->setProperty("modularSetVal", modular->currentData());
0271 
0272     cfg->setProperty("floatingPointConversionOption", cmbConversionPolicy->currentData(Qt::UserRole).toString());
0273     cfg->setProperty("HLGnominalPeak", spnNits->value());
0274     cfg->setProperty("HLGgamma", spnGamma->value());
0275     cfg->setProperty("removeHGLOOTF", chkHLGOOTF->isChecked());
0276 
0277     cfg->setProperty("resampling", resampling->currentData());
0278     cfg->setProperty("extraChannelResampling", extraChannelResampling->currentData());
0279     cfg->setProperty("photonNoise", photonNoise->value());
0280     cfg->setProperty("dots", dots->currentData());
0281     cfg->setProperty("patches", patches->currentData());
0282     cfg->setProperty("epf", epf->value());
0283     cfg->setProperty("gaborish", gaborish->currentData());
0284     // force modular encoding without overriding value in advanced tab
0285     if (forceModular->isChecked() && lossyEncoding->isChecked()) {
0286         cfg->setProperty("modular", 1);
0287     } else {
0288         cfg->setProperty("modular", modular->currentData());
0289     }
0290     cfg->setProperty("keepInvisible", keepInvisible->currentData());
0291     cfg->setProperty("groupOrder", groupOrder->currentData());
0292     cfg->setProperty("responsive", responsive->currentData());
0293     cfg->setProperty("progressiveAC", progressiveAC->currentData());
0294     cfg->setProperty("qProgressiveAC", qProgressiveAC->currentData());
0295     cfg->setProperty("progressiveDC", progressiveDC->currentData());
0296     cfg->setProperty("channelColorsGlobalPercent", channelColorsGlobalPercent->value());
0297     cfg->setProperty("channelColorsGroupPercent", channelColorsGroupPercent->value());
0298     cfg->setProperty("paletteColors", paletteColors->value());
0299     cfg->setProperty("lossyPalette", lossyPalette->currentData());
0300     cfg->setProperty("modularGroupSize", modularGroupSize->currentData());
0301     cfg->setProperty("modularPredictor", modularPredictor->currentData());
0302     cfg->setProperty("modularMATreeLearningPercent", modularMATreeLearningPercent->value());
0303     cfg->setProperty("jpegReconCFL", jpegReconCFL->currentData());
0304 
0305     cfg->setProperty("storeAuthor", chkAuthor->isChecked());
0306     cfg->setProperty("exif", exif->isChecked());
0307     cfg->setProperty("xmp", xmp->isChecked());
0308     cfg->setProperty("iptc", iptc->isChecked());
0309     cfg->setProperty("storeMetaData", chkMetadata->isChecked());
0310 
0311     QString enabledFilters;
0312     for (const auto *filter: m_filterRegistryModel.enabledFilters()) {
0313         enabledFilters += filter->id() + ',';
0314     }
0315     cfg->setProperty("filters", enabledFilters);
0316 
0317     return cfg;
0318 }