File indexing completed on 2025-04-27 03:58:07

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2007-02-03
0007  * Description : Loading parameters for multithreaded loading
0008  *
0009  * SPDX-FileCopyrightText: 2006-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0010  * SPDX-FileCopyrightText: 2012-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "loadingdescription.h"
0017 
0018 // Local includes
0019 
0020 #include "icctransform.h"
0021 #include "thumbnailinfo.h"
0022 #include "thumbnailsize.h"
0023 
0024 namespace Digikam
0025 {
0026 
0027 LoadingDescription::PreviewParameters::PreviewParameters()
0028     : type (NoPreview),
0029       size (0),
0030       flags(NoFlags)
0031 {
0032 }
0033 
0034 bool LoadingDescription::PreviewParameters::operator==(const PreviewParameters& other) const
0035 {
0036     return ((type             == other.type)            &&
0037             (size             == other.size)            &&
0038             (flags            == other.flags)           &&
0039             (previewSettings  == other.previewSettings) &&
0040             (extraParameter   == other.extraParameter)  &&
0041             (storageReference == other.storageReference));
0042 }
0043 
0044 bool LoadingDescription::PreviewParameters::onlyPregenerate() const
0045 {
0046     return (flags & OnlyPregenerate);
0047 }
0048 
0049 bool LoadingDescription::PreviewParameters::onlyFromStorage() const
0050 {
0051     return (flags & OnlyFromStorage);
0052 }
0053 
0054 bool LoadingDescription::PostProcessingParameters::operator==(const PostProcessingParameters& other) const
0055 {
0056     return (colorManagement == other.colorManagement);
0057 }
0058 
0059 bool LoadingDescription::PostProcessingParameters::needsProcessing() const
0060 {
0061     return (colorManagement != NoColorConversion);
0062 }
0063 
0064 void LoadingDescription::PostProcessingParameters::setTransform(const IccTransform& transform)
0065 {
0066     iccData = QVariant::fromValue<IccTransform>(transform);
0067 }
0068 
0069 bool LoadingDescription::PostProcessingParameters::hasTransform() const
0070 {
0071     return (!iccData.isNull() && iccData.canConvert<IccTransform>());
0072 }
0073 
0074 IccTransform LoadingDescription::PostProcessingParameters::transform() const
0075 {
0076     return iccData.value<IccTransform>();
0077 }
0078 
0079 void LoadingDescription::PostProcessingParameters::setProfile(const IccProfile& profile)
0080 {
0081     iccData = QVariant::fromValue<IccProfile>(profile);
0082 }
0083 
0084 bool LoadingDescription::PostProcessingParameters::hasProfile() const
0085 {
0086     return (!iccData.isNull() && iccData.canConvert<IccProfile>());
0087 }
0088 
0089 IccProfile LoadingDescription::PostProcessingParameters::profile() const
0090 {
0091     return iccData.value<IccProfile>();
0092 }
0093 
0094 // ----------------------------------------------------------------------------
0095 
0096 LoadingDescription::LoadingDescription()
0097     : filePath                  (QString()),
0098       rawDecodingSettings       (DRawDecoding()),
0099       rawDecodingHint           (RawDecodingDefaultSettings),
0100       previewParameters         (PreviewParameters()),
0101       postProcessingParameters  (PostProcessingParameters())
0102 {
0103 }
0104 
0105 LoadingDescription::LoadingDescription(const QString& filePath,
0106                                        ColorManagementSettings cm)
0107     : filePath              (filePath),
0108       rawDecodingSettings   (DRawDecoding()),
0109       rawDecodingHint       (RawDecodingDefaultSettings),
0110       previewParameters     (PreviewParameters())
0111 {
0112       postProcessingParameters.colorManagement = cm;
0113 }
0114 
0115 LoadingDescription::LoadingDescription(const QString& filePath,
0116                                        const DRawDecoding& settings,
0117                                        RawDecodingHint hint,
0118                                        ColorManagementSettings cm)
0119     : filePath              (filePath),
0120       rawDecodingSettings   (settings),
0121       rawDecodingHint       (hint),
0122       previewParameters     (PreviewParameters())
0123 {
0124       postProcessingParameters.colorManagement = cm;
0125 }
0126 
0127 LoadingDescription::LoadingDescription(const QString& filePath,
0128                                        const PreviewSettings& previewSettings,
0129                                        int size,
0130                                        ColorManagementSettings cm,
0131                                        LoadingDescription::PreviewParameters::PreviewType type)
0132     : filePath(filePath),
0133       rawDecodingSettings(DRawDecoding()),
0134       rawDecodingHint(RawDecodingDefaultSettings)
0135 {
0136     previewParameters.type                   = type;
0137     previewParameters.size                   = size;
0138     previewParameters.previewSettings        = previewSettings;
0139     postProcessingParameters.colorManagement = cm;
0140 }
0141 
0142 QString LoadingDescription::cacheKey() const
0143 {
0144     // Here we have the knowledge which LoadingDescriptions / RawFileDecodingSettings
0145     // must be cached separately.
0146 
0147     // Thumbnail loading. This one is easy.
0148 
0149     if      (previewParameters.type == PreviewParameters::Thumbnail)
0150     {
0151         QString fileRef = filePath.isEmpty() ? (QLatin1String("id:/") + previewParameters.storageReference.toString())
0152                                              : filePath;
0153 
0154         return (fileRef + QLatin1String("-thumbnail-") + QString::number(previewParameters.size));
0155     }
0156     else if (previewParameters.type == PreviewParameters::DetailThumbnail)
0157     {
0158         QString fileRef    = filePath.isEmpty() ? (QLatin1String("id:/") + previewParameters.storageReference.toString())
0159                                                 : filePath;
0160         QRect rect         =  previewParameters.extraParameter.toRect();
0161         QString rectString = QString::fromLatin1("%1,%2-%3x%4-")
0162                              .arg(rect.x())
0163                              .arg(rect.y())
0164                              .arg(rect.width())
0165                              .arg(rect.height());
0166 
0167         return (fileRef + QLatin1String("-thumbnail-") + rectString + QString::number(previewParameters.size));
0168     }
0169 
0170     // DImg loading
0171 
0172     if (previewParameters.type == PreviewParameters::NoPreview)
0173     {
0174         // Assumption: Full loading. For Raw images, we need to check all parameters here.
0175         // Non-raw images will always be loaded full-size.
0176         // NOTE: do not identify these by cache key only, check the settings!
0177 
0178         if      (rawDecodingHint == RawDecodingGlobalSettings)
0179         {
0180             return (filePath + QLatin1String("-globalraw"));
0181         }
0182         else if (rawDecodingHint == RawDecodingCustomSettings)
0183         {
0184             return (filePath + QLatin1String("-customraw"));
0185         }
0186     }
0187     else
0188     {
0189         // Assumption: Size-limited previews are always eight bit and do not care for raw settings.
0190 
0191         if (previewParameters.size)
0192         {
0193             return (filePath + QLatin1String("-previewImage-") + QString::number(previewParameters.size));
0194         }
0195         else
0196         {
0197             return (filePath + QLatin1String("-previewImage"));
0198         }
0199     }
0200 
0201     QString suffix;
0202 
0203     // Assumption: Time-optimized loading is used for previews and non-previews
0204 
0205     if (rawDecodingHint == RawDecodingTimeOptimized)
0206     {
0207         // Assumption: With time-optimized, we can have 8 or 16bit and halfSize or demosaiced.
0208 
0209         suffix += QLatin1String("-timeoptimized");
0210 
0211         if (!rawDecodingSettings.rawPrm.sixteenBitsImage)
0212         {
0213             suffix += QLatin1String("-8");
0214         }
0215 
0216         if (rawDecodingSettings.rawPrm.halfSizeColorImage)
0217         {
0218             suffix += QLatin1String("-halfSize");
0219         }
0220     }
0221 
0222     return (filePath + suffix);
0223 }
0224 
0225 QStringList LoadingDescription::lookupCacheKeys() const
0226 {
0227     // Build a hierarchy which cache entries may be used for this LoadingDescription.
0228 
0229     // Thumbnail loading. No other cache key included!
0230 
0231     if ((previewParameters.type == PreviewParameters::Thumbnail) ||
0232         (previewParameters.type == PreviewParameters::DetailThumbnail))
0233     {
0234         return QStringList() << cacheKey();
0235     }
0236 
0237     // DImg loading.
0238     // Typically, the first is the best. An actual loading operation may use a
0239     // lower-quality loading and will effectively only add the last entry of the
0240     // list to the cache, although it can accept the first if already available.
0241     // Hierarchy:
0242     //  Raw with GlobalSettings and CustomSettings
0243     //  Raw with optimized loading, 8 or 16bit
0244     //      full size
0245     //      halfSize
0246     //  "Normal" image (default raw parameters)
0247     //  Preview image
0248     //      full size
0249     //      reduced size
0250 
0251     QStringList cacheKeys;
0252 
0253     if (previewParameters.type != PreviewParameters::NoPreview)
0254     {
0255         if (previewParameters.size)
0256         {
0257             cacheKeys << filePath + QLatin1String("-previewImage-") + QString::number(previewParameters.size);
0258         }
0259 
0260         // full size preview
0261 
0262         cacheKeys << filePath + QLatin1String("-previewImage");
0263     }
0264 
0265     if (rawDecodingHint == RawDecodingDefaultSettings)
0266     {
0267         cacheKeys << filePath;
0268     }
0269 
0270     if (rawDecodingHint == RawDecodingTimeOptimized)
0271     {
0272         if (rawDecodingSettings.rawPrm.sixteenBitsImage)
0273         {
0274             cacheKeys << filePath + QLatin1String("-timeoptimized");
0275 
0276             if (rawDecodingSettings.rawPrm.halfSizeColorImage)
0277             {
0278                 cacheKeys << filePath + QLatin1String("-timeoptimized-halfSize");
0279             }
0280         }
0281         else
0282         {
0283             cacheKeys << filePath + QLatin1String("-timeoptimized-8");
0284 
0285             if (rawDecodingSettings.rawPrm.halfSizeColorImage)
0286             {
0287                 cacheKeys << filePath + QLatin1String("-timeoptimized-8-halfSize");
0288             }
0289         }
0290     }
0291 
0292     if      (rawDecodingHint == RawDecodingGlobalSettings)
0293     {
0294         cacheKeys << filePath + QLatin1String("-globalraw");
0295     }
0296     else if (rawDecodingHint == RawDecodingCustomSettings)
0297     {
0298         cacheKeys << filePath + QLatin1String("-customraw");
0299     }
0300 
0301     return cacheKeys;
0302 }
0303 
0304 bool LoadingDescription::needCheckRawDecoding() const
0305 {
0306     return ((rawDecodingHint == RawDecodingGlobalSettings) ||
0307             (rawDecodingHint == RawDecodingCustomSettings));
0308 }
0309 
0310 bool LoadingDescription::isReducedVersion() const
0311 {
0312     // return true if this loads anything but the full version
0313 
0314     return (rawDecodingSettings.rawPrm.halfSizeColorImage ||
0315             (previewParameters.type != PreviewParameters::NoPreview));
0316 }
0317 
0318 bool LoadingDescription::operator==(const LoadingDescription& other) const
0319 {
0320     return ((filePath                 == other.filePath)                   &&
0321             (rawDecodingSettings      == other.rawDecodingSettings)        &&
0322             (previewParameters        == other.previewParameters)          &&
0323             (postProcessingParameters == other.postProcessingParameters));
0324 }
0325 
0326 bool LoadingDescription::operator!=(const LoadingDescription& other) const
0327 {
0328     return (!operator==(other));
0329 }
0330 
0331 bool LoadingDescription::equalsIgnoreReducedVersion(const LoadingDescription& other) const
0332 {
0333     return (filePath == other.filePath);
0334 }
0335 
0336 bool LoadingDescription::equalsOrBetterThan(const LoadingDescription& other) const
0337 {
0338     // This method is similar to operator==. But it returns true as well if this
0339     // loads a "better" version than <other>.
0340     // Preview parameters must have the same size, or other has no size restriction.
0341     // Comparing raw decoding settings is complicated. We allow to be loaded with optimizeTimeLoading().
0342 
0343     DRawDecoding fast = rawDecodingSettings;
0344     fast.optimizeTimeLoading();
0345 
0346     return (
0347             (filePath == other.filePath) &&
0348             (
0349                 (rawDecodingSettings == other.rawDecodingSettings) ||
0350                 (fast                == other.rawDecodingSettings)
0351             ) &&
0352             (
0353                 (previewParameters.size == other.previewParameters.size) ||
0354                 other.previewParameters.size
0355             )
0356            );
0357 }
0358 
0359 bool LoadingDescription::isThumbnail() const
0360 {
0361     return ((previewParameters.type == PreviewParameters::Thumbnail) ||
0362             (previewParameters.type == PreviewParameters::DetailThumbnail));
0363 }
0364 
0365 bool LoadingDescription::isPreviewImage() const
0366 {
0367     return (previewParameters.type == PreviewParameters::PreviewImage);
0368 }
0369 
0370 ThumbnailIdentifier LoadingDescription::thumbnailIdentifier() const
0371 {
0372     ThumbnailIdentifier id;
0373 
0374     if (!isThumbnail())
0375     {
0376         return id;
0377     }
0378 
0379     id.filePath = filePath;
0380     id.id       = previewParameters.storageReference.toLongLong();
0381 
0382     return id;
0383 }
0384 
0385 QStringList LoadingDescription::possibleCacheKeys(const QString& filePath)
0386 {
0387     QStringList keys;
0388     keys << filePath ;
0389     keys << filePath + QLatin1String("-timeoptimized-8-halfSize");
0390     keys << filePath + QLatin1String("-timeoptimized-8");
0391     keys << filePath + QLatin1String("-timeoptimized-halfSize");
0392     keys << filePath + QLatin1String("-timeoptimized");
0393     keys << filePath + QLatin1String("-customraw");
0394     keys << filePath + QLatin1String("-globalraw");
0395 
0396     for (int i = 1 ; i <= ThumbnailSize::HD ; ++i)
0397     {
0398         keys << filePath + QLatin1String("-previewImage-") + QString::number(i);
0399     }
0400 
0401     return keys;
0402 }
0403 
0404 QStringList LoadingDescription::possibleThumbnailCacheKeys(const QString& filePath)
0405 {
0406     // FIXME: With details, there is an endless number of possible cache keys. Need different approach.
0407 
0408     QStringList keys;
0409 
0410     // there are (ThumbnailSize::HD) possible keys...
0411 
0412     QString path = filePath + QLatin1String("-thumbnail-");
0413 
0414     for (int i = 1 ; i <= ThumbnailSize::HD ; ++i)
0415     {
0416         keys << path + QString::number(i);
0417     }
0418 
0419     return keys;
0420 }
0421 
0422 } // namespace Digikam