File indexing completed on 2025-01-19 03:54:49

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2005-06-14
0007  * Description : DImg image loader interface
0008  *
0009  * SPDX-FileCopyrightText: 2005      by Renchi Raju <renchi dot raju at gmail dot com>
0010  * SPDX-FileCopyrightText: 2005-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 "dimgloader.h"
0017 
0018 // C++ includes
0019 
0020 #include <new>
0021 #include <cstddef>
0022 
0023 // Qt includes
0024 
0025 #include <QScopedPointer>
0026 
0027 // KDE includes
0028 
0029 #include <kmemoryinfo.h>
0030 
0031 // Local includes
0032 
0033 #include "dimg_p.h"
0034 #include "dmetadata.h"
0035 #include "dimgloaderobserver.h"
0036 
0037 namespace Digikam
0038 {
0039 
0040 DImgLoader::DImgLoader(DImg* const image)
0041     : m_image    (image),
0042       m_loadFlags(LoadAll)
0043 {
0044 }
0045 
0046 DImgLoader::~DImgLoader()
0047 {
0048 }
0049 
0050 void DImgLoader::setLoadFlags(LoadFlags flags)
0051 {
0052     m_loadFlags = flags;
0053 }
0054 
0055 bool DImgLoader::hasLoadedData() const
0056 {
0057     return ((m_loadFlags & (LoadImageData | LoadPreview)) && m_image->m_priv->data);
0058 }
0059 
0060 int DImgLoader::granularity(DImgLoaderObserver* const observer, int total, float progressSlice)
0061 {
0062     // Splits expect total value into the chunks where checks shall occur
0063     // and combines this with a possible correction factor from observer.
0064     // Progress slice is the part of 100% concerned with the current granularity
0065     // (E.g. in a loop only the values from 10% to 90% are used, then progressSlice is 0.8)
0066     // Current default is 1/20, that is progress info every 5%
0067 
0068     int granularity = 0;
0069 
0070     if (observer)
0071     {
0072         granularity = (int)((total / (20 * progressSlice)) / observer->granularity());
0073     }
0074 
0075     return (granularity ? granularity : 1);
0076 }
0077 
0078 unsigned char*& DImgLoader::imageData()
0079 {
0080     return m_image->m_priv->data;
0081 }
0082 
0083 quint64 DImgLoader::imageNumBytes() const
0084 {
0085     return m_image->numBytes();
0086 }
0087 
0088 unsigned int& DImgLoader::imageWidth()
0089 {
0090     return m_image->m_priv->width;
0091 }
0092 
0093 unsigned int& DImgLoader::imageHeight()
0094 {
0095     return m_image->m_priv->height;
0096 }
0097 
0098 bool DImgLoader::imageHasAlpha() const
0099 {
0100     return m_image->hasAlpha();
0101 }
0102 
0103 bool DImgLoader::imageSixteenBit() const
0104 {
0105     return m_image->sixteenBit();
0106 }
0107 
0108 int DImgLoader::imageBitsDepth() const
0109 {
0110     return m_image->bitsDepth();
0111 }
0112 
0113 int DImgLoader::imageBytesDepth() const
0114 {
0115     return m_image->bytesDepth();
0116 }
0117 
0118 void DImgLoader::imageSetIccProfile(const IccProfile& profile)
0119 {
0120     m_image->setIccProfile(profile);
0121 }
0122 
0123 QVariant DImgLoader::imageGetAttribute(const QString& key) const
0124 {
0125     return m_image->attribute(key);
0126 }
0127 
0128 QString DImgLoader::imageGetEmbbededText(const QString& key) const
0129 {
0130     return m_image->embeddedText(key);
0131 }
0132 
0133 void DImgLoader::imageSetAttribute(const QString& key, const QVariant& value)
0134 {
0135     m_image->setAttribute(key, value);
0136 }
0137 
0138 QMap<QString, QString>& DImgLoader::imageEmbeddedText() const
0139 {
0140     return m_image->m_priv->embeddedText;
0141 }
0142 
0143 void DImgLoader::imageSetEmbbededText(const QString& key, const QString& text)
0144 {
0145     m_image->setEmbeddedText(key, text);
0146 }
0147 
0148 void DImgLoader::loadingFailed()
0149 {
0150     if (m_image->m_priv->data)
0151     {
0152         delete [] m_image->m_priv->data;
0153     }
0154 
0155     m_image->m_priv->data   = nullptr;
0156     m_image->m_priv->width  = 0;
0157     m_image->m_priv->height = 0;
0158 }
0159 
0160 qint64 DImgLoader::checkAllocation(qint64 fullSize)
0161 {
0162     if ((quint64)fullSize >= std::numeric_limits<size_t>::max())
0163     {
0164         qCWarning(DIGIKAM_DIMG_LOG) << "Cannot allocate buffer of size" << fullSize;
0165         return 0;
0166     }
0167 
0168     // Do extra check if allocating serious amounts of memory.
0169     // At the time of writing (2011), I consider 100 MB as "serious".
0170 
0171     if (fullSize > (qint64)(100 * 1024 * 1024))
0172     {
0173         KMemoryInfo memInfo;
0174 
0175         if (memInfo.isNull())
0176         {
0177             qCWarning(DIGIKAM_DIMG_LOG) << "Not a recognized platform to get memory information";
0178 
0179             return -1;
0180         }
0181 
0182         qint64 available = memInfo.availablePhysical();
0183 
0184         if (available == 0)
0185         {
0186             qCWarning(DIGIKAM_DIMG_LOG) << "Error to get physical memory information form a recognized platform";
0187 
0188             return 0;
0189         }
0190 
0191         if (fullSize > available)
0192         {
0193             qCWarning(DIGIKAM_DIMG_LOG) << "Not enough memory to allocate buffer of size " << fullSize;
0194             qCWarning(DIGIKAM_DIMG_LOG) << "Available memory size is "                     << available;
0195 
0196             return 0;
0197         }
0198     }
0199 
0200     return fullSize;
0201 }
0202 
0203 bool DImgLoader::readMetadata(const QString& filePath)
0204 {
0205     if (!((m_loadFlags & LoadMetadata) || (m_loadFlags & LoadUniqueHash) || (m_loadFlags & LoadImageHistory)))
0206     {
0207         return false;
0208     }
0209 
0210     QScopedPointer<DMetadata> metaDataFromFile(new DMetadata);
0211 
0212     if (!metaDataFromFile->load(filePath))
0213     {
0214         m_image->setMetadata(MetaEngineData());
0215         return false;
0216     }
0217 
0218     m_image->setMetadata(metaDataFromFile->data());
0219 
0220     if (m_loadFlags & LoadImageHistory)
0221     {
0222         DImageHistory history = DImageHistory::fromXml(metaDataFromFile->getItemHistory());
0223         HistoryImageId id     = m_image->createHistoryImageId(filePath, HistoryImageId::Current);
0224         history << id;
0225 
0226         m_image->setItemHistory(history);
0227         imageSetAttribute(QLatin1String("originalImageHistory"), QVariant::fromValue(history));
0228     }
0229 
0230     return true;
0231 }
0232 
0233 bool DImgLoader::saveMetadata(const QString& filePath)
0234 {
0235     QScopedPointer<DMetadata> metaDataToFile(new DMetadata(filePath));
0236     metaDataToFile->setData(m_image->getMetadata());
0237 
0238     QVariant writingMode = imageGetAttribute(QLatin1String("metadataWritingMode"));
0239 
0240     if      (writingMode.isValid())
0241     {
0242         metaDataToFile->setMetadataWritingMode(writingMode.toInt());
0243     }
0244     else if (metaDataToFile->metadataWritingMode() == (int)DMetadata::WRITE_TO_SIDECAR_ONLY)
0245     {
0246         metaDataToFile->setMetadataWritingMode((int)DMetadata::WRITE_TO_SIDECAR_AND_FILE);
0247     }
0248 
0249     return metaDataToFile->applyChanges(true);
0250 }
0251 
0252 bool DImgLoader::checkExifWorkingColorSpace() const
0253 {
0254     QScopedPointer<DMetadata> metaData(new DMetadata(m_image->getMetadata()));
0255     IccProfile profile = metaData->getIccProfile();
0256 
0257     if (!profile.isNull())
0258     {
0259         m_image->setIccProfile(profile);
0260         return true;
0261     }
0262 
0263     return false;
0264 }
0265 
0266 void DImgLoader::storeColorProfileInMetadata()
0267 {
0268     IccProfile profile = m_image->getIccProfile();
0269 
0270     if (profile.isNull())
0271     {
0272         return;
0273     }
0274 
0275     QScopedPointer<DMetadata> metaData(new DMetadata(m_image->getMetadata()));
0276     metaData->setIccProfile(profile);
0277     m_image->setMetadata(metaData->data());
0278 }
0279 
0280 void DImgLoader::purgeExifWorkingColorSpace()
0281 {
0282     QScopedPointer<DMetadata> meta(new DMetadata(m_image->getMetadata()));
0283     meta->removeExifColorSpace();
0284     m_image->setMetadata(meta->data());
0285 }
0286 
0287 unsigned char* DImgLoader::new_failureTolerant(size_t unsecureSize)
0288 {
0289     return new_failureTolerant<unsigned char>(unsecureSize);
0290 }
0291 
0292 unsigned char* DImgLoader::new_failureTolerant(quint64 w, quint64 h, uint typesPerPixel)
0293 {
0294     return new_failureTolerant<unsigned char>(w, h, typesPerPixel);
0295 }
0296 
0297 unsigned short* DImgLoader::new_short_failureTolerant(size_t unsecureSize)
0298 {
0299     return new_failureTolerant<unsigned short>(unsecureSize);
0300 }
0301 
0302 unsigned short* DImgLoader::new_short_failureTolerant(quint64 w, quint64 h, uint typesPerPixel)
0303 {
0304     return new_failureTolerant<unsigned short>(w, h, typesPerPixel);
0305 }
0306 
0307 int DImgLoader::convertCompressionForLibPng(int value)
0308 {
0309     // PNG compression slider settings : 1 - 9 ==> libpng settings : 100 - 1.
0310 
0311     return ((int)(((1.0 - 100.0) / 8.0) * (float)value + 100.0 - ((1.0 - 100.0) / 8.0)));
0312 }
0313 
0314 int DImgLoader::convertCompressionForLibJpeg(int value)
0315 {
0316     // JPEG quality slider settings : 1 - 100 ==> libjpeg settings : 25 - 100.
0317 
0318     return ((int)((75.0 / 100.0) * (float)value + 26.0 - (75.0 / 100.0)));
0319 }
0320 
0321 } // namespace Digikam