File indexing completed on 2024-05-19 04:29:13
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 KisImportUserFeedbackInterface *importUserFeedBackInterface {nullptr}; 0044 0045 QMap<QString, KisExportCheckBase*> capabilities; 0046 0047 Private() 0048 : updater(0), mime("") 0049 , batchmode(false) 0050 {} 0051 0052 ~Private() 0053 { 0054 qDeleteAll(capabilities); 0055 } 0056 0057 }; 0058 0059 0060 KisImportExportFilter::KisImportExportFilter(QObject *parent) 0061 : QObject(parent) 0062 , d(new Private) 0063 { 0064 } 0065 0066 KisImportExportFilter::~KisImportExportFilter() 0067 { 0068 if (d->updater) { 0069 d->updater->setProgress(100); 0070 } 0071 delete d; 0072 } 0073 0074 QString KisImportExportFilter::filename() const 0075 { 0076 return d->filename; 0077 } 0078 0079 QString KisImportExportFilter::realFilename() const 0080 { 0081 return d->realFilename; 0082 } 0083 0084 bool KisImportExportFilter::batchMode() const 0085 { 0086 return d->batchmode; 0087 } 0088 0089 KisImportUserFeedbackInterface *KisImportExportFilter::importUserFeedBackInterface() const 0090 { 0091 return d->importUserFeedBackInterface; 0092 } 0093 0094 void KisImportExportFilter::setBatchMode(bool batchmode) 0095 { 0096 d->batchmode = batchmode; 0097 } 0098 0099 void KisImportExportFilter::setImportUserFeedBackInterface(KisImportUserFeedbackInterface *interface) 0100 { 0101 d->importUserFeedBackInterface = interface; 0102 } 0103 0104 void KisImportExportFilter::setFilename(const QString &filename) 0105 { 0106 d->filename = filename; 0107 } 0108 0109 void KisImportExportFilter::setRealFilename(const QString &filename) 0110 { 0111 d->realFilename = filename; 0112 } 0113 0114 0115 void KisImportExportFilter::setMimeType(const QString &mime) 0116 { 0117 d->mime = mime.toLatin1(); 0118 } 0119 0120 QByteArray KisImportExportFilter::mimeType() const 0121 { 0122 return d->mime; 0123 } 0124 0125 KisPropertiesConfigurationSP KisImportExportFilter::defaultConfiguration(const QByteArray &from, const QByteArray &to) const 0126 { 0127 Q_UNUSED(from); 0128 Q_UNUSED(to); 0129 return 0; 0130 } 0131 0132 KisPropertiesConfigurationSP KisImportExportFilter::lastSavedConfiguration(const QByteArray &from, const QByteArray &to) const 0133 { 0134 KisPropertiesConfigurationSP cfg = defaultConfiguration(from, to); 0135 const QString filterConfig = KisConfig(true).exportConfigurationXML(to); 0136 if (cfg && !filterConfig.isEmpty()) { 0137 cfg->fromXML(filterConfig, false); 0138 } 0139 return cfg; 0140 } 0141 0142 KisConfigWidget *KisImportExportFilter::createConfigurationWidget(QWidget *, const QByteArray &from, const QByteArray &to) const 0143 { 0144 Q_UNUSED(from); 0145 Q_UNUSED(to); 0146 return 0; 0147 } 0148 0149 QMap<QString, KisExportCheckBase *> KisImportExportFilter::exportChecks() 0150 { 0151 qDeleteAll(d->capabilities); 0152 initializeCapabilities(); 0153 return d->capabilities; 0154 } 0155 0156 QString KisImportExportFilter::verify(const QString &fileName) const 0157 { 0158 QFileInfo fi(fileName); 0159 0160 if (!fi.exists()) { 0161 return i18n("%1 does not exist after writing. Try saving again under a different name, in another location.", fileName); 0162 } 0163 0164 if (!fi.isReadable()) { 0165 return i18n("%1 is not readable", fileName); 0166 } 0167 0168 if (fi.size() < 10) { 0169 return i18n("%1 is smaller than 10 bytes, it must be corrupt. Try saving again under a different name, in another location.", fileName); 0170 } 0171 0172 QFile f(fileName); 0173 f.open(QFile::ReadOnly); 0174 QByteArray ba = f.read(std::min(f.size(), (qint64)1000)); 0175 bool found = false; 0176 for(int i = 0; i < ba.size(); ++i) { 0177 if (ba.at(i) > 0) { 0178 found = true; 0179 break; 0180 } 0181 } 0182 0183 if (!found) { 0184 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); 0185 } 0186 0187 return QString(); 0188 } 0189 0190 void KisImportExportFilter::setUpdater(QPointer<KoUpdater> updater) 0191 { 0192 d->updater = updater; 0193 } 0194 0195 QPointer<KoUpdater> KisImportExportFilter::updater() 0196 { 0197 return d->updater; 0198 } 0199 0200 void KisImportExportFilter::setProgress(int value) 0201 { 0202 if (d->updater) { 0203 d->updater->setValue(value); 0204 } 0205 } 0206 0207 void KisImportExportFilter::initializeCapabilities() 0208 { 0209 // XXX: Initialize everything to fully supported? 0210 } 0211 0212 void KisImportExportFilter::addCapability(KisExportCheckBase *capability) 0213 { 0214 d->capabilities[capability->id()] = capability; 0215 } 0216 0217 0218 0219 void KisImportExportFilter::addSupportedColorModels(QList<QPair<KoID, KoID> > supportedColorModels, const QString &name, KisExportCheckBase::Level level) 0220 { 0221 Q_ASSERT(level != KisExportCheckBase::SUPPORTED); 0222 QString layerMessage; 0223 QString imageMessage; 0224 QList<KoID> allColorModels = KoColorSpaceRegistry::instance()->colorModelsList(KoColorSpaceRegistry::AllColorSpaces); 0225 Q_FOREACH(const KoID &colorModelID, allColorModels) { 0226 QList<KoID> allColorDepths = KoColorSpaceRegistry::instance()->colorDepthList(colorModelID.id(), KoColorSpaceRegistry::AllColorSpaces); 0227 Q_FOREACH(const KoID &colorDepthID, allColorDepths) { 0228 0229 KisExportCheckFactory *colorModelCheckFactory = 0230 KisExportCheckRegistry::instance()->get("ColorModelCheck/" + colorModelID.id() + "/" + colorDepthID.id()); 0231 KisExportCheckFactory *colorModelPerLayerCheckFactory = 0232 KisExportCheckRegistry::instance()->get("ColorModelPerLayerCheck/" + colorModelID.id() + "/" + colorDepthID.id()); 0233 0234 if(!colorModelCheckFactory || !colorModelPerLayerCheckFactory) { 0235 qWarning() << "No factory for" << colorModelID << colorDepthID; 0236 continue; 0237 } 0238 0239 if (supportedColorModels.contains(QPair<KoID, KoID>(colorModelID, colorDepthID))) { 0240 addCapability(colorModelCheckFactory->create(KisExportCheckBase::SUPPORTED)); 0241 addCapability(colorModelPerLayerCheckFactory->create(KisExportCheckBase::SUPPORTED)); 0242 } 0243 else { 0244 0245 0246 if (level == KisExportCheckBase::PARTIALLY) { 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 be converted." 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 converted or skipped." 0254 ,name, colorModelID.name(), colorDepthID.name()); 0255 } 0256 else { 0257 imageMessage = i18nc("image conversion warning", 0258 "%1 cannot save images with color model <b>%2</b> and depth <b>%3</b>. The image will not be saved." 0259 ,name, colorModelID.name(), colorDepthID.name()); 0260 0261 layerMessage = 0262 i18nc("image conversion warning", 0263 "%1 cannot save layers with color model <b>%2</b> and depth <b>%3</b>. The layers will be skipped." 0264 , name, colorModelID.name(), colorDepthID.name()); 0265 } 0266 0267 0268 0269 addCapability(colorModelCheckFactory->create(level, imageMessage)); 0270 addCapability(colorModelPerLayerCheckFactory->create(level, layerMessage)); 0271 } 0272 } 0273 } 0274 } 0275 0276 QString KisImportExportFilter::verifyZiPBasedFiles(const QString &fileName, const QStringList &filesToCheck) const 0277 { 0278 QScopedPointer<KoStore> store(KoStore::createStore(fileName, KoStore::Read, KIS_MIME_TYPE, KoStore::Zip)); 0279 0280 if (!store || store->bad()) { 0281 return i18n("Could not open the saved file %1. Please try to save again in a different location.", fileName); 0282 } 0283 0284 Q_FOREACH(const QString &file, filesToCheck) { 0285 if (!store->hasFile(file)) { 0286 return i18n("File %1 is missing in %2 and is broken. Please try to save again in a different location.", file, fileName); 0287 } 0288 } 0289 0290 return QString(); 0291 0292 }