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"