File indexing completed on 2025-01-26 04:10:56

0001 /*
0002  *  SPDX-FileCopyrightText: 2005 Cyrille Berger <cberger@cberger.net>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_jpeg_export.h"
0008 
0009 #include <QCheckBox>
0010 #include <QSlider>
0011 #include <QColor>
0012 #include <QString>
0013 #include <QStringList>
0014 #include <QApplication>
0015 #include <QFileInfo>
0016 #include <QScopedPointer>
0017 
0018 #include <kpluginfactory.h>
0019 
0020 #include <KoColorSpace.h>
0021 #include <KoColorProfile.h>
0022 #include <KoColorSpaceConstants.h>
0023 #include <KoColorSpaceRegistry.h>
0024 
0025 #include <KisImportExportManager.h>
0026 #include <kis_slider_spin_box.h>
0027 #include <KisDocument.h>
0028 #include <KoDocumentInfo.h>
0029 #include <kis_image.h>
0030 #include <kis_group_layer.h>
0031 #include <kis_paint_layer.h>
0032 #include <kis_paint_device.h>
0033 #include <kis_properties_configuration.h>
0034 #include <kis_config.h>
0035 #include <kis_meta_data_store.h>
0036 #include <kis_meta_data_entry.h>
0037 #include <kis_meta_data_value.h>
0038 #include <kis_meta_data_schema.h>
0039 #include <kis_meta_data_schema_registry.h>
0040 #include <kis_meta_data_filter_registry_model.h>
0041 #include <kis_exif_info_visitor.h>
0042 #include <generator/kis_generator_layer.h>
0043 #include <KisExportCheckRegistry.h>
0044 #include <KisSpinBoxI18nHelper.h>
0045 #include "kis_jpeg_converter.h"
0046 
0047 class KisExternalLayer;
0048 
0049 K_PLUGIN_FACTORY_WITH_JSON(KisJPEGExportFactory, "krita_jpeg_export.json", registerPlugin<KisJPEGExport>();)
0050 
0051 KisJPEGExport::KisJPEGExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent)
0052 {
0053 }
0054 
0055 KisJPEGExport::~KisJPEGExport()
0056 {
0057 }
0058 
0059 KisImportExportErrorCode KisJPEGExport::convert(KisDocument *document, QIODevice *io,  KisPropertiesConfigurationSP configuration)
0060 {
0061     KisImageSP image = document->savingImage();
0062     Q_CHECK_PTR(image);
0063 
0064     // An extra option to pass to the config widget to set the state correctly, this isn't saved
0065     const KoColorSpace* cs = image->projection()->colorSpace();
0066     bool sRGB = cs->profile()->name().contains(QLatin1String("srgb"), Qt::CaseInsensitive);
0067     configuration->setProperty("is_sRGB", sRGB);
0068 
0069     KisJPEGOptions options;
0070     options.progressive = configuration->getBool("progressive", false);
0071     options.quality = configuration->getInt("quality", 80);
0072     options.forceSRGB = configuration->getBool("forceSRGB", false);
0073     options.saveProfile = configuration->getBool("saveProfile", true);
0074     options.optimize = configuration->getBool("optimize", true);
0075     options.smooth = configuration->getInt("smoothing", 0);
0076     options.baseLineJPEG = configuration->getBool("baseline", true);
0077     options.subsampling = configuration->getInt("subsampling", 0);
0078     options.exif = configuration->getBool("exif", true);
0079     options.iptc = configuration->getBool("iptc", true);
0080     options.xmp = configuration->getBool("xmp", true);
0081     KoColor c(KoColorSpaceRegistry::instance()->rgb8());
0082     c.fromQColor(Qt::white);
0083     options.transparencyFillColor = configuration->getColor("transparencyFillcolor", c).toQColor();
0084     KisMetaData::FilterRegistryModel m;
0085     m.setEnabledFilters(configuration->getString("filters").split(","));
0086     options.filters = m.enabledFilters();
0087     options.storeAuthor = configuration->getBool("storeAuthor", false);
0088     options.storeDocumentMetaData = configuration->getBool("storeMetaData", false);
0089 
0090     KisPaintDeviceSP pd = new KisPaintDevice(*image->projection());
0091 
0092     KisJPEGConverter kpc(document, batchMode());
0093     KisPaintLayerSP l = new KisPaintLayer(image, "projection", OPACITY_OPAQUE_U8, pd);
0094 
0095     KisExifInfoVisitor exivInfoVisitor;
0096     exivInfoVisitor.visit(image->rootLayer().data());
0097 
0098     QScopedPointer<KisMetaData::Store> metaDataStore;
0099     if (exivInfoVisitor.metaDataCount() == 1) {
0100         metaDataStore.reset(new KisMetaData::Store(*exivInfoVisitor.exifInfo()));
0101     }
0102     else {
0103         metaDataStore.reset(new KisMetaData::Store());
0104     }
0105 
0106     //add extra meta-data here
0107     const KisMetaData::Schema* dcSchema = KisMetaData::SchemaRegistry::instance()->schemaFromUri(KisMetaData::Schema::DublinCoreSchemaUri);
0108     Q_ASSERT(dcSchema);
0109     if (options.storeDocumentMetaData) {
0110         QString title = document->documentInfo()->aboutInfo("title");
0111         if (!title.isEmpty()) {
0112             if (metaDataStore->containsEntry("title")) {
0113                 metaDataStore->removeEntry("title");
0114             }
0115             metaDataStore->addEntry(KisMetaData::Entry(dcSchema, "title", KisMetaData::Value(QVariant(title))));
0116         }
0117         QString description = document->documentInfo()->aboutInfo("subject");
0118         if (description.isEmpty()) {
0119             description = document->documentInfo()->aboutInfo("abstract");
0120         }
0121         if (!description.isEmpty()) {
0122             QString keywords = document->documentInfo()->aboutInfo("keyword");
0123             if (!keywords.isEmpty()) {
0124                 description = description + " keywords: " + keywords;
0125             }
0126             if (metaDataStore->containsEntry("description")) {
0127                 metaDataStore->removeEntry("description");
0128             }
0129             metaDataStore->addEntry(KisMetaData::Entry(dcSchema, "description", KisMetaData::Value(QVariant(description))));
0130         }
0131         QString license = document->documentInfo()->aboutInfo("license");
0132         if (!license.isEmpty()) {
0133             if (metaDataStore->containsEntry("rights")) {
0134                 metaDataStore->removeEntry("rights");
0135             }
0136             metaDataStore->addEntry(KisMetaData::Entry(dcSchema, "rights", KisMetaData::Value(QVariant(license))));
0137         }
0138         QString date = document->documentInfo()->aboutInfo("date");
0139         if (!date.isEmpty() && !metaDataStore->containsEntry("rights")) {
0140             metaDataStore->addEntry(KisMetaData::Entry(dcSchema, "date", KisMetaData::Value(QVariant(date))));
0141         }
0142     }
0143     if (options.storeAuthor) {
0144         QString author = document->documentInfo()->authorInfo("creator");
0145         if (!author.isEmpty()) {
0146             if (!document->documentInfo()->authorContactInfo().isEmpty()) {
0147                 QString contact = document->documentInfo()->authorContactInfo().at(0);
0148                 if (!contact.isEmpty()) {
0149                     author = author+"("+contact+")";
0150                 }
0151             }
0152             if (metaDataStore->containsEntry("creator")) {
0153                 metaDataStore->removeEntry("creator");
0154             }
0155             metaDataStore->addEntry(KisMetaData::Entry(dcSchema, "creator", KisMetaData::Value(QVariant(author))));
0156         }
0157     }
0158 
0159     KisImportExportErrorCode res = kpc.buildFile(io, l, options, metaDataStore.data());
0160     return res;
0161 }
0162 
0163 KisPropertiesConfigurationSP KisJPEGExport::defaultConfiguration(const QByteArray &/*from*/, const QByteArray &/*to*/) const
0164 {
0165     KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
0166     cfg->setProperty("progressive", false);
0167     cfg->setProperty("quality", 80);
0168     cfg->setProperty("forceSRGB", false);
0169     cfg->setProperty("saveProfile", true);
0170     cfg->setProperty("optimize", true);
0171     cfg->setProperty("smoothing", 0);
0172     cfg->setProperty("baseline", true);
0173     cfg->setProperty("subsampling", 0);
0174     cfg->setProperty("exif", true);
0175     cfg->setProperty("iptc", true);
0176     cfg->setProperty("xmp", true);
0177     cfg->setProperty("storeAuthor", false);
0178     cfg->setProperty("storeMetaData", false);
0179 
0180     KoColor fill_color(KoColorSpaceRegistry::instance()->rgb8());
0181     fill_color = KoColor();
0182     fill_color.fromQColor(Qt::white);
0183     QVariant v;
0184     v.setValue(fill_color);
0185 
0186     cfg->setProperty("transparencyFillcolor", v);
0187     cfg->setProperty("filters", "");
0188 
0189     return cfg;
0190 }
0191 
0192 KisConfigWidget *KisJPEGExport::createConfigurationWidget(QWidget *parent, const QByteArray &/*from*/, const QByteArray &/*to*/) const
0193 {
0194     return new KisWdgOptionsJPEG(parent);
0195 }
0196 
0197 void KisJPEGExport::initializeCapabilities()
0198 {
0199     addCapability(KisExportCheckRegistry::instance()->get("sRGBProfileCheck")->create(KisExportCheckBase::SUPPORTED));
0200     addCapability(KisExportCheckRegistry::instance()->get("ExifCheck")->create(KisExportCheckBase::SUPPORTED));
0201 
0202     QList<QPair<KoID, KoID> > supportedColorModels;
0203     supportedColorModels << QPair<KoID, KoID>()
0204             << QPair<KoID, KoID>(RGBAColorModelID, Integer8BitsColorDepthID)
0205             << QPair<KoID, KoID>(GrayAColorModelID, Integer8BitsColorDepthID)
0206             << QPair<KoID, KoID>(CMYKAColorModelID, Integer8BitsColorDepthID);
0207     addSupportedColorModels(supportedColorModels, "JPEG");
0208 }
0209 
0210 
0211 KisWdgOptionsJPEG::KisWdgOptionsJPEG(QWidget *parent)
0212     : KisConfigWidget(parent)
0213 {
0214     setupUi(this);
0215 
0216     metaDataFilters->setModel(&m_filterRegistryModel);
0217     qualityLevel->setRange(0, 100, 0);
0218     KisSpinBoxI18nHelper::setText(qualityLevel, i18nc("{n} is the number value, % is the percent sign", "{n}%"));
0219     smoothLevel->setRange(0, 100, 0);
0220     KisSpinBoxI18nHelper::setText(smoothLevel, i18nc("{n} is the number value, % is the percent sign", "{n}%"));
0221 }
0222 
0223 
0224 void KisWdgOptionsJPEG::setConfiguration(const KisPropertiesConfigurationSP cfg)
0225 {
0226     progressive->setChecked(cfg->getBool("progressive", false));
0227     qualityLevel->setValue(cfg->getInt("quality", 80));
0228     optimize->setChecked(cfg->getBool("optimize", true));
0229     smoothLevel->setValue(cfg->getInt("smoothing", 0));
0230     baseLineJPEG->setChecked(cfg->getBool("baseline", true));
0231     subsampling->setCurrentIndex(cfg->getInt("subsampling", 0));
0232     exif->setChecked(cfg->getBool("exif", true));
0233     iptc->setChecked(cfg->getBool("iptc", true));
0234     xmp->setChecked(cfg->getBool("xmp", true));
0235     chkForceSRGB->setVisible(cfg->getBool("is_sRGB"));
0236     chkForceSRGB->setChecked(cfg->getBool("forceSRGB", false));
0237     chkSaveProfile->setChecked(cfg->getBool("saveProfile", true));
0238     KoColor background(KoColorSpaceRegistry::instance()->rgb8());
0239     background.fromQColor(Qt::white);
0240     bnTransparencyFillColor->setDefaultColor(background);
0241     bnTransparencyFillColor->setColor(cfg->getColor("transparencyFillcolor", background));
0242     chkAuthor->setChecked(cfg->getBool("storeAuthor", false));
0243     chkMetaData->setChecked(cfg->getBool("storeMetaData", false));
0244 
0245     m_filterRegistryModel.setEnabledFilters(cfg->getString("filters").split(','));
0246 
0247 }
0248 
0249 KisPropertiesConfigurationSP KisWdgOptionsJPEG::configuration() const
0250 {
0251     KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
0252 
0253     QVariant transparencyFillcolor;
0254     transparencyFillcolor.setValue(bnTransparencyFillColor->color());
0255 
0256     cfg->setProperty("progressive", progressive->isChecked());
0257     cfg->setProperty("quality", (int)qualityLevel->value());
0258     cfg->setProperty("forceSRGB", chkForceSRGB->isChecked());
0259     cfg->setProperty("saveProfile", chkSaveProfile->isChecked());
0260     cfg->setProperty("optimize", optimize->isChecked());
0261     cfg->setProperty("smoothing", (int)smoothLevel->value());
0262     cfg->setProperty("baseline", baseLineJPEG->isChecked());
0263     cfg->setProperty("subsampling", subsampling->currentIndex());
0264     cfg->setProperty("exif", exif->isChecked());
0265     cfg->setProperty("iptc", iptc->isChecked());
0266     cfg->setProperty("xmp", xmp->isChecked());
0267     cfg->setProperty("transparencyFillcolor", transparencyFillcolor);
0268     cfg->setProperty("storeAuthor", chkAuthor->isChecked());
0269     cfg->setProperty("storeMetaData", chkMetaData->isChecked());
0270 
0271     QString enabledFilters;
0272     Q_FOREACH (const KisMetaData::Filter* filter, m_filterRegistryModel.enabledFilters()) {
0273         enabledFilters = enabledFilters + filter->id() + ',';
0274     }
0275     cfg->setProperty("filters", enabledFilters);
0276 
0277     return cfg;
0278 }
0279 #include <kis_jpeg_export.moc>