File indexing completed on 2024-05-12 16:01:49

0001 /*
0002     This file is part of the KDE libraries
0003 
0004     SPDX-FileCopyrightText: 2001 Werner Trobin <trobin@kde.org>
0005     SPDX-FileCopyrightText: 2002 Werner Trobin <trobin@kde.org>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #include "KisImportExportFilter.h"
0011 
0012 #include <QFile>
0013 #include <QFileInfo>
0014 #include <kis_debug.h>
0015 #include <QStack>
0016 #include "KisImportExportManager.h"
0017 #include <KoColorSpaceRegistry.h>
0018 #include <KoColorModelStandardIds.h>
0019 #include <KisExportCheckBase.h>
0020 #include <KisExportCheckRegistry.h>
0021 #include "KoUpdater.h"
0022 #include <klocalizedstring.h>
0023 #include "kis_config.h"
0024 #include <KoStore.h>
0025 #include <KisDocument.h>
0026 
0027 const QString KisImportExportFilter::ImageContainsTransparencyTag = "ImageContainsTransparency";
0028 const QString KisImportExportFilter::ColorModelIDTag = "ColorModelID";
0029 const QString KisImportExportFilter::ColorDepthIDTag = "ColorDepthID";
0030 const QString KisImportExportFilter::sRGBTag = "sRGB";
0031 const QString KisImportExportFilter::CICPPrimariesTag = "CICPCompatiblePrimaries";
0032 const QString KisImportExportFilter::CICPTransferCharacteristicsTag = "CICPCompatibleTransferFunction";
0033 const QString KisImportExportFilter::HDRTag = "HDRSupported";
0034 
0035 class Q_DECL_HIDDEN KisImportExportFilter::Private
0036 {
0037 public:
0038     QPointer<KoUpdater> updater;
0039     QByteArray mime;
0040     QString filename;
0041     QString realFilename;
0042     bool batchmode;
0043 
0044     QMap<QString, KisExportCheckBase*> capabilities;
0045 
0046     Private()
0047         : updater(0), mime("")
0048         , batchmode(false)
0049     {}
0050 
0051     ~Private()
0052     {
0053         qDeleteAll(capabilities);
0054     }
0055 
0056 };
0057 
0058 
0059 KisImportExportFilter::KisImportExportFilter(QObject *parent)
0060     : QObject(parent)
0061     , d(new Private)
0062 {
0063 }
0064 
0065 KisImportExportFilter::~KisImportExportFilter()
0066 {
0067     if (d->updater) {
0068         d->updater->setProgress(100);
0069     }
0070     delete d;
0071 }
0072 
0073 QString KisImportExportFilter::filename() const
0074 {
0075     return d->filename;
0076 }
0077 
0078 QString KisImportExportFilter::realFilename() const
0079 {
0080     return d->realFilename;
0081 }
0082 
0083 bool KisImportExportFilter::batchMode() const
0084 {
0085     return d->batchmode;
0086 }
0087 
0088 
0089 void KisImportExportFilter::setBatchMode(bool batchmode)
0090 {
0091     d->batchmode = batchmode;
0092 }
0093 
0094 void KisImportExportFilter::setFilename(const QString &filename)
0095 {
0096     d->filename = filename;
0097 }
0098 
0099 void KisImportExportFilter::setRealFilename(const QString &filename)
0100 {
0101     d->realFilename = filename;
0102 }
0103 
0104 
0105 void KisImportExportFilter::setMimeType(const QString &mime)
0106 {
0107     d->mime = mime.toLatin1();
0108 }
0109 
0110 QByteArray KisImportExportFilter::mimeType() const
0111 {
0112     return d->mime;
0113 }
0114 
0115 KisPropertiesConfigurationSP KisImportExportFilter::defaultConfiguration(const QByteArray &from, const QByteArray &to) const
0116 {
0117     Q_UNUSED(from);
0118     Q_UNUSED(to);
0119     return 0;
0120 }
0121 
0122 KisPropertiesConfigurationSP KisImportExportFilter::lastSavedConfiguration(const QByteArray &from, const QByteArray &to) const
0123 {
0124     KisPropertiesConfigurationSP cfg = defaultConfiguration(from, to);
0125     const QString filterConfig = KisConfig(true).exportConfigurationXML(to);
0126     if (cfg && !filterConfig.isEmpty()) {
0127         cfg->fromXML(filterConfig, false);
0128     }
0129     return cfg;
0130 }
0131 
0132 KisConfigWidget *KisImportExportFilter::createConfigurationWidget(QWidget *, const QByteArray &from, const QByteArray &to) const
0133 {
0134     Q_UNUSED(from);
0135     Q_UNUSED(to);
0136     return 0;
0137 }
0138 
0139 QMap<QString, KisExportCheckBase *> KisImportExportFilter::exportChecks()
0140 {
0141     qDeleteAll(d->capabilities);
0142     initializeCapabilities();
0143     return d->capabilities;
0144 }
0145 
0146 QString KisImportExportFilter::verify(const QString &fileName) const
0147 {
0148     QFileInfo fi(fileName);
0149 
0150     if (!fi.exists()) {
0151         return i18n("%1 does not exist after writing. Try saving again under a different name, in another location.", fileName);
0152     }
0153 
0154     if (!fi.isReadable()) {
0155         return i18n("%1 is not readable", fileName);
0156     }
0157 
0158     if (fi.size() < 10)  {
0159         return i18n("%1 is smaller than 10 bytes, it must be corrupt. Try saving again under a different name, in another location.", fileName);
0160     }
0161 
0162     QFile f(fileName);
0163     f.open(QFile::ReadOnly);
0164     QByteArray ba = f.read(std::min(f.size(), (qint64)1000));
0165     bool found = false;
0166     for(int i = 0; i < ba.size(); ++i) {
0167         if (ba.at(i) > 0) {
0168             found = true;
0169             break;
0170         }
0171     }
0172 
0173     if (!found) {
0174         return i18n("%1 has only zero bytes in the first 1000 bytes, it's probably corrupt. Try saving again under a different name, in another location.", fileName);
0175     }
0176 
0177     return QString();
0178 }
0179 
0180 void KisImportExportFilter::setUpdater(QPointer<KoUpdater> updater)
0181 {
0182     d->updater = updater;
0183 }
0184 
0185 QPointer<KoUpdater> KisImportExportFilter::updater()
0186 {
0187     return d->updater;
0188 }
0189 
0190 void KisImportExportFilter::setProgress(int value)
0191 {
0192     if (d->updater) {
0193         d->updater->setValue(value);
0194     }
0195 }
0196 
0197 void KisImportExportFilter::initializeCapabilities()
0198 {
0199     // XXX: Initialize everything to fully supported?
0200 }
0201 
0202 void KisImportExportFilter::addCapability(KisExportCheckBase *capability)
0203 {
0204     d->capabilities[capability->id()] = capability;
0205 }
0206 
0207 
0208 
0209 void KisImportExportFilter::addSupportedColorModels(QList<QPair<KoID, KoID> > supportedColorModels, const QString &name, KisExportCheckBase::Level level)
0210 {
0211     Q_ASSERT(level != KisExportCheckBase::SUPPORTED);
0212     QString layerMessage;
0213     QString imageMessage;
0214     QList<KoID> allColorModels = KoColorSpaceRegistry::instance()->colorModelsList(KoColorSpaceRegistry::AllColorSpaces);
0215     Q_FOREACH(const KoID &colorModelID, allColorModels) {
0216         QList<KoID> allColorDepths = KoColorSpaceRegistry::instance()->colorDepthList(colorModelID.id(), KoColorSpaceRegistry::AllColorSpaces);
0217         Q_FOREACH(const KoID &colorDepthID, allColorDepths) {
0218 
0219             KisExportCheckFactory *colorModelCheckFactory =
0220                     KisExportCheckRegistry::instance()->get("ColorModelCheck/" + colorModelID.id() + "/" + colorDepthID.id());
0221             KisExportCheckFactory *colorModelPerLayerCheckFactory =
0222                     KisExportCheckRegistry::instance()->get("ColorModelPerLayerCheck/" + colorModelID.id() + "/" + colorDepthID.id());
0223 
0224             if(!colorModelCheckFactory || !colorModelPerLayerCheckFactory) {
0225                 qWarning() << "No factory for" << colorModelID << colorDepthID;
0226                 continue;
0227             }
0228 
0229             if (supportedColorModels.contains(QPair<KoID, KoID>(colorModelID, colorDepthID))) {
0230                 addCapability(colorModelCheckFactory->create(KisExportCheckBase::SUPPORTED));
0231                 addCapability(colorModelPerLayerCheckFactory->create(KisExportCheckBase::SUPPORTED));
0232             }
0233             else {
0234 
0235 
0236                 if (level == KisExportCheckBase::PARTIALLY) {
0237                     imageMessage = i18nc("image conversion warning",
0238                                          "%1 cannot save images with color model <b>%2</b> and depth <b>%3</b>. The image will be converted."
0239                                          ,name, colorModelID.name(), colorDepthID.name());
0240 
0241                     layerMessage =
0242                             i18nc("image conversion warning",
0243                                   "%1 cannot save layers with color model <b>%2</b> and depth <b>%3</b>. The layers will be converted or skipped."
0244                                   ,name, colorModelID.name(), colorDepthID.name());
0245                 }
0246                 else {
0247                     imageMessage = i18nc("image conversion warning",
0248                                          "%1 cannot save images with color model <b>%2</b> and depth <b>%3</b>. The image will not be saved."
0249                                          ,name, colorModelID.name(), colorDepthID.name());
0250 
0251                     layerMessage =
0252                             i18nc("image conversion warning",
0253                                   "%1 cannot save layers with color model <b>%2</b> and depth <b>%3</b>. The layers will be skipped."
0254                                   , name, colorModelID.name(), colorDepthID.name());
0255                  }
0256 
0257 
0258 
0259                 addCapability(colorModelCheckFactory->create(level, imageMessage));
0260                 addCapability(colorModelPerLayerCheckFactory->create(level, layerMessage));
0261             }
0262         }
0263     }
0264 }
0265 
0266 QString KisImportExportFilter::verifyZiPBasedFiles(const QString &fileName, const QStringList &filesToCheck) const
0267 {
0268     QScopedPointer<KoStore> store(KoStore::createStore(fileName, KoStore::Read, KIS_MIME_TYPE, KoStore::Zip));
0269 
0270     if (!store || store->bad()) {
0271         return i18n("Could not open the saved file %1. Please try to save again in a different location.", fileName);
0272     }
0273 
0274     Q_FOREACH(const QString &file, filesToCheck) {
0275         if (!store->hasFile(file)) {
0276             return i18n("File %1 is missing in %2 and is broken. Please try to save again in a different location.", file, fileName);
0277         }
0278     }
0279 
0280     return QString();
0281 
0282 }