File indexing completed on 2024-04-28 04:20:14
0001 0002 /* 0003 Copyright (c) 2003-2007 Clarence Dang <dang@kde.org> 0004 All rights reserved. 0005 0006 Redistribution and use in source and binary forms, with or without 0007 modification, are permitted provided that the following conditions 0008 are met: 0009 0010 1. Redistributions of source code must retain the above copyright 0011 notice, this list of conditions and the following disclaimer. 0012 2. Redistributions in binary form must reproduce the above copyright 0013 notice, this list of conditions and the following disclaimer in the 0014 documentation and/or other materials provided with the distribution. 0015 0016 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 0017 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0018 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 0019 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 0020 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 0021 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0022 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0023 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0024 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0025 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0026 */ 0027 0028 #define DEBUG_KP_DOCUMENT_SAVE_OPTIONS 0 0029 0030 0031 #include "kpDocumentSaveOptions.h" 0032 0033 #include "kpDefs.h" 0034 #include "pixmapfx/kpPixmapFX.h" 0035 0036 #include <KConfigGroup> 0037 #include "kpLogCategories.h" 0038 #include <KSharedConfig> 0039 0040 #include <QImage> 0041 #include <QString> 0042 0043 //--------------------------------------------------------------------- 0044 0045 class kpDocumentSaveOptionsPrivate 0046 { 0047 public: 0048 QString m_mimeType; 0049 int m_colorDepth{}; 0050 bool m_dither{}; 0051 int m_quality{}; 0052 }; 0053 0054 //--------------------------------------------------------------------- 0055 0056 kpDocumentSaveOptions::kpDocumentSaveOptions () 0057 : d (new kpDocumentSaveOptionsPrivate ()) 0058 { 0059 d->m_mimeType = invalidMimeType (); 0060 d->m_colorDepth = invalidColorDepth (); 0061 d->m_dither = initialDither (); 0062 d->m_quality = invalidQuality (); 0063 } 0064 0065 //--------------------------------------------------------------------- 0066 0067 kpDocumentSaveOptions::kpDocumentSaveOptions (const kpDocumentSaveOptions &rhs) 0068 : d (new kpDocumentSaveOptionsPrivate ()) 0069 { 0070 d->m_mimeType = rhs.mimeType (); 0071 d->m_colorDepth = rhs.colorDepth (); 0072 d->m_dither = rhs.dither (); 0073 d->m_quality = rhs.quality (); 0074 } 0075 0076 //--------------------------------------------------------------------- 0077 0078 kpDocumentSaveOptions::kpDocumentSaveOptions (const QString &mimeType, int colorDepth, bool dither, int quality) 0079 : d (new kpDocumentSaveOptionsPrivate ()) 0080 { 0081 d->m_mimeType = mimeType; 0082 d->m_colorDepth = colorDepth; 0083 d->m_dither = dither; 0084 d->m_quality = quality; 0085 } 0086 0087 //--------------------------------------------------------------------- 0088 0089 kpDocumentSaveOptions::~kpDocumentSaveOptions () 0090 { 0091 delete d; 0092 } 0093 0094 //--------------------------------------------------------------------- 0095 0096 0097 // public 0098 bool kpDocumentSaveOptions::operator== (const kpDocumentSaveOptions &rhs) const 0099 { 0100 return (mimeType () == rhs.mimeType () && 0101 colorDepth () == rhs.colorDepth () && 0102 dither () == rhs.dither () && 0103 quality () == rhs.quality ()); 0104 } 0105 0106 //--------------------------------------------------------------------- 0107 0108 // public 0109 bool kpDocumentSaveOptions::operator!= (const kpDocumentSaveOptions &rhs) const 0110 { 0111 return !(*this == rhs); 0112 } 0113 0114 //--------------------------------------------------------------------- 0115 0116 0117 // public 0118 kpDocumentSaveOptions &kpDocumentSaveOptions::operator= (const kpDocumentSaveOptions &rhs) 0119 { 0120 setMimeType (rhs.mimeType ()); 0121 setColorDepth (rhs.colorDepth ()); 0122 setDither (rhs.dither ()); 0123 setQuality (rhs.quality ()); 0124 0125 return *this; 0126 } 0127 0128 //--------------------------------------------------------------------- 0129 0130 0131 // public 0132 void kpDocumentSaveOptions::printDebug (const QString &prefix) const 0133 { 0134 const QString usedPrefix = !prefix.isEmpty () ? 0135 prefix + QLatin1String (": ") : 0136 QString(); 0137 0138 qCDebug(kpLogDocument) << usedPrefix 0139 << "mimeType=" << mimeType () 0140 << " colorDepth=" << colorDepth () 0141 << " dither=" << dither () 0142 << " quality=" << quality (); 0143 } 0144 0145 //--------------------------------------------------------------------- 0146 0147 0148 // public 0149 QString kpDocumentSaveOptions::mimeType () const 0150 { 0151 return d->m_mimeType; 0152 } 0153 0154 //--------------------------------------------------------------------- 0155 0156 // public 0157 void kpDocumentSaveOptions::setMimeType (const QString &mimeType) 0158 { 0159 Q_ASSERT(mimeType.isEmpty () || mimeType.contains (QLatin1Char('/'))); 0160 d->m_mimeType = mimeType; 0161 } 0162 0163 //--------------------------------------------------------------------- 0164 0165 0166 // public static 0167 QString kpDocumentSaveOptions::invalidMimeType () 0168 { 0169 return {}; 0170 } 0171 0172 //--------------------------------------------------------------------- 0173 0174 // public static 0175 bool kpDocumentSaveOptions::mimeTypeIsInvalid (const QString &mimeType) 0176 { 0177 return (mimeType == invalidMimeType ()); 0178 } 0179 0180 //--------------------------------------------------------------------- 0181 0182 // public 0183 bool kpDocumentSaveOptions::mimeTypeIsInvalid () const 0184 { 0185 return mimeTypeIsInvalid (mimeType ()); 0186 } 0187 0188 //--------------------------------------------------------------------- 0189 0190 0191 // public 0192 int kpDocumentSaveOptions::colorDepth () const 0193 { 0194 return d->m_colorDepth; 0195 } 0196 0197 // public 0198 void kpDocumentSaveOptions::setColorDepth (int depth) 0199 { 0200 d->m_colorDepth = depth; 0201 } 0202 0203 0204 // public static 0205 int kpDocumentSaveOptions::invalidColorDepth () 0206 { 0207 return -1; 0208 } 0209 0210 // public static 0211 bool kpDocumentSaveOptions::colorDepthIsInvalid (int colorDepth) 0212 { 0213 return (colorDepth != 1 && colorDepth != 8 && colorDepth != 32); 0214 } 0215 0216 // public 0217 bool kpDocumentSaveOptions::colorDepthIsInvalid () const 0218 { 0219 return colorDepthIsInvalid (colorDepth ()); 0220 } 0221 0222 0223 // public 0224 bool kpDocumentSaveOptions::dither () const 0225 { 0226 return d->m_dither; 0227 } 0228 0229 // public 0230 void kpDocumentSaveOptions::setDither (bool dither) 0231 { 0232 d->m_dither = dither; 0233 } 0234 0235 0236 // public static 0237 int kpDocumentSaveOptions::initialDither () 0238 { 0239 return false; // to avoid accidental double dithering 0240 } 0241 0242 0243 // public 0244 int kpDocumentSaveOptions::quality () const 0245 { 0246 return d->m_quality; 0247 } 0248 0249 // public 0250 void kpDocumentSaveOptions::setQuality (int quality) 0251 { 0252 d->m_quality = quality; 0253 } 0254 0255 0256 // public static 0257 int kpDocumentSaveOptions::invalidQuality () 0258 { 0259 return -2; 0260 } 0261 0262 // public static 0263 bool kpDocumentSaveOptions::qualityIsInvalid (int quality) 0264 { 0265 return (quality < -1 || quality > 100); 0266 } 0267 0268 // public 0269 bool kpDocumentSaveOptions::qualityIsInvalid () const 0270 { 0271 return qualityIsInvalid (quality ()); 0272 } 0273 0274 0275 // public static 0276 QString kpDocumentSaveOptions::defaultMimeType (const KConfigGroup &config) 0277 { 0278 return config.readEntry (kpSettingForcedMimeType, 0279 QStringLiteral ("image/png")); 0280 } 0281 0282 // public static 0283 void kpDocumentSaveOptions::saveDefaultMimeType (KConfigGroup &config, 0284 const QString &mimeType) 0285 { 0286 config.writeEntry (kpSettingForcedMimeType, mimeType); 0287 } 0288 0289 0290 // public static 0291 int kpDocumentSaveOptions::defaultColorDepth (const KConfigGroup &config) 0292 { 0293 int colorDepth = 0294 config.readEntry (kpSettingForcedColorDepth, -1); 0295 0296 if (colorDepthIsInvalid (colorDepth)) 0297 { 0298 // (not screen depth, in case of transparency) 0299 colorDepth = 32; 0300 } 0301 0302 return colorDepth; 0303 } 0304 0305 //--------------------------------------------------------------------- 0306 0307 // public static 0308 void kpDocumentSaveOptions::saveDefaultColorDepth (KConfigGroup &config, int colorDepth) 0309 { 0310 config.writeEntry (kpSettingForcedColorDepth, colorDepth); 0311 } 0312 0313 //--------------------------------------------------------------------- 0314 0315 0316 // public static 0317 int kpDocumentSaveOptions::defaultDither (const KConfigGroup &config) 0318 { 0319 return config.readEntry (kpSettingForcedDither, initialDither ()); 0320 } 0321 0322 //--------------------------------------------------------------------- 0323 0324 // public static 0325 void kpDocumentSaveOptions::saveDefaultDither (KConfigGroup &config, bool dither) 0326 { 0327 config.writeEntry (kpSettingForcedDither, dither); 0328 } 0329 0330 //--------------------------------------------------------------------- 0331 0332 0333 // public static 0334 int kpDocumentSaveOptions::defaultQuality (const KConfigGroup &config) 0335 { 0336 int val = config.readEntry (kpSettingForcedQuality, -1); 0337 0338 return qualityIsInvalid (val) ? -1 : val; 0339 } 0340 0341 //--------------------------------------------------------------------- 0342 0343 // public static 0344 void kpDocumentSaveOptions::saveDefaultQuality (KConfigGroup &config, int quality) 0345 { 0346 config.writeEntry (kpSettingForcedQuality, quality); 0347 } 0348 0349 //--------------------------------------------------------------------- 0350 0351 0352 // public static 0353 kpDocumentSaveOptions kpDocumentSaveOptions::defaultDocumentSaveOptions (const KConfigGroup &config) 0354 { 0355 kpDocumentSaveOptions saveOptions; 0356 saveOptions.setMimeType (defaultMimeType (config)); 0357 saveOptions.setColorDepth (defaultColorDepth (config)); 0358 saveOptions.setDither (defaultDither (config)); 0359 saveOptions.setQuality (defaultQuality (config)); 0360 0361 #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS 0362 saveOptions.printDebug ("kpDocumentSaveOptions::defaultDocumentSaveOptions()"); 0363 #endif 0364 0365 return saveOptions; 0366 } 0367 0368 //--------------------------------------------------------------------- 0369 0370 // public static 0371 bool kpDocumentSaveOptions::saveDefaultDifferences (KConfigGroup &config, 0372 const kpDocumentSaveOptions &oldDocInfo, 0373 const kpDocumentSaveOptions &newDocInfo) 0374 { 0375 bool savedSomething = false; 0376 0377 #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS 0378 qCDebug(kpLogDocument) << "kpDocumentSaveOptions::saveDefaultDifferences()"; 0379 oldDocInfo.printDebug ("\told"); 0380 newDocInfo.printDebug ("\tnew"); 0381 #endif 0382 0383 if (newDocInfo.mimeType () != oldDocInfo.mimeType ()) 0384 { 0385 saveDefaultMimeType (config, newDocInfo.mimeType ()); 0386 savedSomething = true; 0387 } 0388 0389 if (newDocInfo.colorDepth () != oldDocInfo.colorDepth ()) 0390 { 0391 saveDefaultColorDepth (config, newDocInfo.colorDepth ()); 0392 savedSomething = true; 0393 } 0394 0395 if (newDocInfo.dither () != oldDocInfo.dither ()) 0396 { 0397 saveDefaultDither (config, newDocInfo.dither ()); 0398 savedSomething = true; 0399 } 0400 0401 if (newDocInfo.quality () != oldDocInfo.quality ()) 0402 { 0403 saveDefaultQuality (config, newDocInfo.quality ()); 0404 savedSomething = true; 0405 } 0406 0407 return savedSomething; 0408 } 0409 0410 //--------------------------------------------------------------------- 0411 // Currently, Depth and Quality settings are mutually exclusive with 0412 // Depth overriding Quality. I've currently favoured Quality with the 0413 // below mimetypes (i.e. all lossy mimetypes are only given Quality settings, 0414 // no Depth settings). 0415 // 0416 // To test whether depth is configurable, write an image in the new 0417 // mimetype with all depths and read each one back. See what 0418 // kpDocument thinks the depth is when it gets QImage to read it. 0419 0420 0421 // public static 0422 int kpDocumentSaveOptions::mimeTypeMaximumColorDepth(const QString &mimeType) 0423 { 0424 // SYNC: update mime info here 0425 0426 if ( mimeType == QStringLiteral("image/x-eps") ) 0427 return 32; // Grayscale actually (unenforced since depth not set to configurable) 0428 0429 if ( mimeType == QStringLiteral("image/x-portable-bitmap") ) 0430 return 1; 0431 0432 if ( mimeType == QStringLiteral("image/x-portable-graymap") ) 0433 return 8; // Grayscale actually (unenforced since depth not set to configurable) 0434 0435 if ( mimeType == QStringLiteral("image/x-xbitmap") ) 0436 return 1; 0437 0438 return 32; 0439 } 0440 0441 //--------------------------------------------------------------------- 0442 0443 // public 0444 int kpDocumentSaveOptions::mimeTypeMaximumColorDepth () const 0445 { 0446 return mimeTypeMaximumColorDepth (mimeType ()); 0447 } 0448 0449 //--------------------------------------------------------------------- 0450 0451 // public static 0452 bool kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth (const QString &mimeType) 0453 { 0454 QStringList defaultMimeTypes; 0455 0456 // SYNC: update mime info here 0457 defaultMimeTypes << QStringLiteral ("image/png"); 0458 defaultMimeTypes << QStringLiteral ("image/bmp"); 0459 defaultMimeTypes << QStringLiteral ("image/x-pcx"); 0460 0461 // TODO: Only 1, 24 not 8; Qt only sees 32 but "file" cmd realizes 0462 // it's either 1 or 24. 0463 defaultMimeTypes << QStringLiteral ("image/x-rgb"); 0464 0465 // TODO: Only 8 and 24 - no 1. 0466 defaultMimeTypes << QStringLiteral ("image/x-xpixmap"); 0467 0468 return defaultMimeTypes.contains(mimeType); 0469 } 0470 0471 //--------------------------------------------------------------------- 0472 0473 // public 0474 bool kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth () const 0475 { 0476 return mimeTypeHasConfigurableColorDepth (mimeType ()); 0477 } 0478 0479 //--------------------------------------------------------------------- 0480 0481 // public static 0482 bool kpDocumentSaveOptions::mimeTypeHasConfigurableQuality (const QString &mimeType) 0483 { 0484 QStringList defaultMimeTypes; 0485 0486 // SYNC: update mime info here 0487 defaultMimeTypes << QStringLiteral ("image/jp2"); 0488 defaultMimeTypes << QStringLiteral ("image/jpeg"); 0489 defaultMimeTypes << QStringLiteral ("image/webp"); 0490 defaultMimeTypes << QStringLiteral ("image/avif"); 0491 defaultMimeTypes << QStringLiteral ("image/heif"); 0492 defaultMimeTypes << QStringLiteral ("image/heic"); 0493 0494 return defaultMimeTypes.contains(mimeType); 0495 } 0496 0497 //--------------------------------------------------------------------- 0498 0499 // public 0500 bool kpDocumentSaveOptions::mimeTypeHasConfigurableQuality () const 0501 { 0502 return mimeTypeHasConfigurableQuality (mimeType ()); 0503 } 0504 0505 //--------------------------------------------------------------------- 0506 0507 // public 0508 int kpDocumentSaveOptions::isLossyForSaving (const QImage &image) const 0509 { 0510 int ret = 0; 0511 0512 if (mimeTypeMaximumColorDepth () < image.depth ()) 0513 { 0514 ret |= MimeTypeMaximumColorDepthLow; 0515 } 0516 0517 if (mimeTypeHasConfigurableColorDepth () && 0518 !colorDepthIsInvalid () /*REFACTOR: guarantee it is valid*/ && 0519 ((colorDepth () < image.depth ()) || 0520 (colorDepth () < 32 && image.hasAlphaChannel()))) 0521 { 0522 ret |= ColorDepthLow; 0523 } 0524 0525 if (mimeTypeHasConfigurableQuality () && 0526 !qualityIsInvalid ()) 0527 { 0528 ret |= Quality; 0529 } 0530 0531 return ret; 0532 } 0533 0534 //---------------------------------------------------------------------