File indexing completed on 2025-01-19 03:51:03

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2005-11-01
0007  * Description : A digital camera RAW files loader for DImg
0008  *
0009  * SPDX-FileCopyrightText: 2005-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2005-2012 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "dimgrawloader.h"
0017 
0018 // C++ includes
0019 
0020 #include <cmath>
0021 
0022 // Qt includes
0023 
0024 #include <QByteArray>
0025 #include <QScopedPointer>
0026 
0027 // Local includes
0028 
0029 #include "digikam_debug.h"
0030 #include "dimgloaderobserver.h"
0031 #include "digikam_globals.h"
0032 
0033 namespace DigikamRAWDImgPlugin
0034 {
0035 
0036 DImgRAWLoader::DImgRAWLoader(DImg* const image, const DRawDecoding& rawDecodingSettings)
0037     : DImgLoader(image),
0038       m_observer(nullptr),
0039       m_filter(nullptr)
0040 {
0041     m_decoderSettings = rawDecodingSettings.rawPrm;
0042     m_filter          = new RawProcessingFilter(this);
0043     m_filter->setSettings(rawDecodingSettings);
0044 }
0045 
0046 DImgRAWLoader::~DImgRAWLoader()
0047 {
0048 }
0049 
0050 bool DImgRAWLoader::load(const QString& filePath, DImgLoaderObserver* const observer)
0051 {
0052     m_observer = observer;
0053 
0054     readMetadata(filePath);
0055 
0056     QScopedPointer<DRawInfo> dcrawIdentify(new DRawInfo);
0057 
0058     if (!DRawDecoder::rawFileIdentify(*dcrawIdentify, filePath))
0059     {
0060         return false;
0061     }
0062 
0063     if (m_loadFlags & LoadImageData)
0064     {
0065         int        width, height, rgbmax;
0066         QByteArray data;
0067 
0068         // NOTE: Here, we don't check a possible embedded work-space color profile using
0069         // the method checkExifWorkingColorSpace() like with JPEG, PNG, and TIFF loaders,
0070         // because RAW file are always in linear mode.
0071 
0072         if (m_decoderSettings.outputColorSpace == DRawDecoderSettings::CUSTOMOUTPUTCS)
0073         {
0074             if      (m_decoderSettings.outputProfile == IccProfile::sRGB().filePath())
0075             {
0076                 m_decoderSettings.outputColorSpace = DRawDecoderSettings::SRGB;
0077             }
0078             else if (m_decoderSettings.outputProfile == IccProfile::adobeRGB().filePath())
0079             {
0080                 m_decoderSettings.outputColorSpace = DRawDecoderSettings::ADOBERGB;
0081             }
0082             else if (m_decoderSettings.outputProfile == IccProfile::wideGamutRGB().filePath())
0083             {
0084                 m_decoderSettings.outputColorSpace = DRawDecoderSettings::WIDEGAMMUT;
0085             }
0086             else if (m_decoderSettings.outputProfile == IccProfile::proPhotoRGB().filePath())
0087             {
0088                 m_decoderSettings.outputColorSpace = DRawDecoderSettings::PROPHOTO;
0089             }
0090             else
0091             {
0092                 // Specifying a custom output is broken somewhere. We use the extremely
0093                 // wide gamut pro photo profile for 16bit (sRGB for 8bit) and convert afterwards.
0094 
0095                 m_filter->setOutputProfile(IccProfile(m_decoderSettings.outputProfile));
0096 
0097                 if (m_decoderSettings.sixteenBitsImage)
0098                 {
0099                     m_decoderSettings.outputColorSpace = DRawDecoderSettings::PROPHOTO;
0100                 }
0101                 else
0102                 {
0103                     m_decoderSettings.outputColorSpace = DRawDecoderSettings::SRGB;
0104                 }
0105             }
0106         }
0107 
0108         if (!DRawDecoder::decodeRAWImage(filePath, m_decoderSettings, data, width, height, rgbmax))
0109         {
0110             loadingFailed();
0111             return false;
0112         }
0113 
0114         if (!loadedFromRawData(data, width, height, rgbmax, observer))
0115         {
0116             loadingFailed();
0117             return false;
0118         }
0119     }
0120     else
0121     {
0122         imageWidth()  = dcrawIdentify->imageSize.width();
0123         imageHeight() = dcrawIdentify->imageSize.height();
0124     }
0125 
0126     imageSetAttribute(QLatin1String("format"),             QLatin1String("RAW"));
0127     imageSetAttribute(QLatin1String("originalColorModel"), DImg::COLORMODELRAW);
0128     imageSetAttribute(QLatin1String("originalBitDepth"),   16);
0129     imageSetAttribute(QLatin1String("originalSize"),       dcrawIdentify->imageSize);
0130 
0131     return true;
0132 }
0133 
0134 bool DImgRAWLoader::checkToCancelWaitingData()
0135 {
0136     return (m_observer ? !m_observer->continueQuery() : false);
0137 }
0138 
0139 void DImgRAWLoader::setWaitingDataProgress(double value)
0140 {
0141     if (m_observer)
0142     {
0143         m_observer->progressInfo((float)value);
0144     }
0145 }
0146 
0147 bool DImgRAWLoader::loadedFromRawData(const QByteArray& data,
0148                                       int width,
0149                                       int height,
0150                                       int rgbmax,
0151                                       DImgLoaderObserver* const observer)
0152 {
0153     int checkpoint = 0;
0154 
0155     if (m_decoderSettings.sixteenBitsImage)       // 16 bits image
0156     {
0157         uchar* const image = new_failureTolerant(width, height, 8);
0158 
0159         if (!image)
0160         {
0161             qCWarning(DIGIKAM_DIMG_LOG_RAW) << "Failed to allocate memory for loading raw file";
0162             return false;
0163         }
0164 
0165         unsigned short* dst = reinterpret_cast<unsigned short*>(image);
0166         uchar*          src = (uchar*)data.data();
0167         float fac           = 65535.0 / rgbmax;
0168         checkpoint          = 0;
0169 
0170         for (int h = 0 ; h < height ; ++h)
0171         {
0172             if (observer && h == checkpoint)
0173             {
0174                 checkpoint += granularity(observer, height, 1.0F);
0175 
0176                 if (!observer->continueQuery())
0177                 {
0178                     delete [] image;
0179                     return false;
0180                 }
0181 
0182                 observer->progressInfo(0.7F + 0.2F * (((float)h) / ((float)height)));
0183             }
0184 
0185             for (int w = 0 ; w < width ; ++w)
0186             {
0187                 if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)     // Intel
0188                 {
0189                     dst[0] = (unsigned short)((src[5] * 256 + src[4]) * fac);    // Blue
0190                     dst[1] = (unsigned short)((src[3] * 256 + src[2]) * fac);    // Green
0191                     dst[2] = (unsigned short)((src[1] * 256 + src[0]) * fac);    // Red
0192                 }
0193                 else
0194                 {
0195                     dst[0] = (unsigned short)((src[4] * 256 + src[5]) * fac);    // Blue
0196                     dst[1] = (unsigned short)((src[2] * 256 + src[3]) * fac);    // Green
0197                     dst[2] = (unsigned short)((src[0] * 256 + src[1]) * fac);    // Red
0198                 }
0199 
0200                 dst[3]  = 0xFFFF;
0201 
0202                 dst    += 4;
0203                 src    += 6;
0204             }
0205         }
0206 
0207         // ----------------------------------------------------------
0208 
0209         imageData() = (uchar*)image;
0210     }
0211     else        // 8 bits image
0212     {
0213         uchar* const image = new_failureTolerant(width, height, 4);
0214 
0215         if (!image)
0216         {
0217             qCWarning(DIGIKAM_DIMG_LOG_RAW) << "Failed to allocate memory for loading raw file";
0218             return false;
0219         }
0220 
0221         uchar* dst = image;
0222         uchar* src = (uchar*)data.data();
0223         checkpoint = 0;
0224 
0225         for (int h = 0 ; h < height ; ++h)
0226         {
0227 
0228             if (observer && h == checkpoint)
0229             {
0230                 checkpoint += granularity(observer, height, 1.0F);
0231 
0232                 if (!observer->continueQuery())
0233                 {
0234                     delete [] image;
0235                     return false;
0236                 }
0237 
0238                 observer->progressInfo(0.7F + 0.2F * (((float)h) / ((float)height)));
0239             }
0240 
0241             for (int w = 0 ; w < width ; ++w)
0242             {
0243                 // No need to adapt RGB components accordingly with rgbmax value because Raw engine
0244                 // always return rgbmax to 255 in 8 bits/color/pixels.
0245 
0246                 dst[0]  = src[2];    // Blue
0247                 dst[1]  = src[1];    // Green
0248                 dst[2]  = src[0];    // Red
0249                 dst[3]  = 0xFF;      // Alpha
0250 
0251                 dst    += 4;
0252                 src    += 3;
0253             }
0254         }
0255 
0256         // NOTE: if Color Management is not used here, output color space is in sRGB* color space.
0257         // Gamma and White balance are previously adjusted by Raw engine in 8 bits color depth.
0258 
0259         imageData() = image;
0260     }
0261 
0262     //----------------------------------------------------------
0263     // Assign the right color-space profile.
0264 
0265     switch (m_decoderSettings.outputColorSpace)
0266     {
0267         case DRawDecoderSettings::SRGB:
0268         {
0269             imageSetIccProfile(IccProfile::sRGB());
0270             break;
0271         }
0272 
0273         case DRawDecoderSettings::ADOBERGB:
0274         {
0275             imageSetIccProfile(IccProfile::adobeRGB());
0276             break;
0277         }
0278 
0279         case DRawDecoderSettings::WIDEGAMMUT:
0280         {
0281             imageSetIccProfile(IccProfile::wideGamutRGB());
0282             break;
0283         }
0284 
0285         case DRawDecoderSettings::PROPHOTO:
0286         {
0287             imageSetIccProfile(IccProfile::proPhotoRGB());
0288             break;
0289         }
0290 
0291         case DRawDecoderSettings::CUSTOMOUTPUTCS:
0292         {
0293             imageSetIccProfile(IccProfile(m_decoderSettings.outputProfile));
0294             break;
0295         }
0296 
0297         case DRawDecoderSettings::RAWCOLOR:
0298         {
0299             // No icc color-space profile to assign in RAW color mode.
0300 
0301             imageSetAttribute(QLatin1String("uncalibratedColor"), true);
0302             break;
0303         }
0304     }
0305 
0306     //----------------------------------------------------------
0307 
0308     FilterAction action = m_filter->filterAction();
0309     m_image->addFilterAction(action);
0310 
0311     imageWidth()        = width;
0312     imageHeight()       = height;
0313     imageSetAttribute(QLatin1String("rawDecodingSettings"),     QVariant::fromValue(m_filter->settings()));
0314     imageSetAttribute(QLatin1String("rawDecodingFilterAction"), QVariant::fromValue(action));
0315 
0316     // other attributes are set above
0317 
0318     return true;
0319 }
0320 
0321 void DImgRAWLoader::postProcess(DImgLoaderObserver* const observer)
0322 {
0323     if (m_filter->settings().postProcessingSettingsIsDirty())
0324     {
0325         m_filter->setObserver(observer, 90, 100);
0326         m_filter->setupFilter(*m_image);
0327         m_filter->startFilterDirectly();
0328     }
0329 }
0330 
0331 FilterAction DImgRAWLoader::filterAction() const
0332 {
0333     return m_filter->filterAction();
0334 }
0335 
0336 bool DImgRAWLoader::save(const QString&, DImgLoaderObserver* const)
0337 {
0338     // NOTE: RAW files are always Read only.
0339 
0340     return false;
0341 }
0342 
0343 bool DImgRAWLoader::hasAlpha() const
0344 {
0345     return false;
0346 }
0347 
0348 bool DImgRAWLoader::isReadOnly() const
0349 {
0350     return true;
0351 }
0352 
0353 bool DImgRAWLoader::sixteenBit() const
0354 {
0355     return m_decoderSettings.sixteenBitsImage;
0356 }
0357 
0358 } // namespace DigikamRAWDImgPlugin
0359 
0360 #include "moc_dimgrawloader.cpp"