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 //---------------------------------------------------------------------