File indexing completed on 2024-04-28 15:50:40

0001 /*
0002     SPDX-FileCopyrightText: 2006-2015 Gilles Caulier <caulier dot gilles at gmail dot com>
0003     SPDX-FileCopyrightText: 2006-2013 Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0004     SPDX-FileCopyrightText: 2007-2008 Guillaume Castagnino <casta at xwing dot info>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "kdcraw.h"
0010 #include "kdcraw_p.h"
0011 
0012 // Qt includes
0013 
0014 #include <QFile>
0015 #include <QFileInfo>
0016 #include <QStringList>
0017 
0018 // LibRaw includes
0019 
0020 #include <libraw_version.h>
0021 
0022 #ifdef LIBRAW_HAS_CONFIG
0023 #include <libraw_config.h>
0024 #endif
0025 
0026 // Local includes
0027 
0028 #include "libkdcraw_debug.h"
0029 #include "libkdcraw_version.h"
0030 #include "rawfiles.h"
0031 
0032 namespace KDcrawIface
0033 {
0034 
0035 KDcraw::KDcraw()
0036     : d(new KDcrawPrivate(this))
0037 {
0038     m_cancel = false;
0039 }
0040 
0041 KDcraw::~KDcraw()
0042 {
0043     cancel();
0044 }
0045 
0046 QString KDcraw::version()
0047 {
0048     return QString::fromLatin1(KDCRAW_VERSION_STRING);
0049 }
0050 
0051 void KDcraw::cancel()
0052 {
0053     m_cancel = true;
0054 }
0055 
0056 bool KDcraw::loadRawPreview(QImage& image, const QString& path)
0057 {
0058     // In first, try to extract the embedded JPEG preview. Very fast.
0059     bool ret = loadEmbeddedPreview(image, path);
0060 
0061     if (ret)
0062         return true;
0063 
0064     // In second, decode and half size of RAW picture. More slow.
0065     return (loadHalfPreview(image, path));
0066 }
0067 
0068 bool KDcraw::loadEmbeddedPreview(QImage& image, const QString& path)
0069 {
0070     QByteArray imgData;
0071 
0072     if ( loadEmbeddedPreview(imgData, path) )
0073     {
0074         qCDebug(LIBKDCRAW_LOG) << "Preview data size:" << imgData.size();
0075 
0076         if (image.loadFromData( imgData ))
0077         {
0078             qCDebug(LIBKDCRAW_LOG) << "Using embedded RAW preview extraction";
0079             return true;
0080         }
0081     }
0082 
0083     qCDebug(LIBKDCRAW_LOG) << "Failed to load embedded RAW preview";
0084     return false;
0085 }
0086 
0087 bool KDcraw::loadEmbeddedPreview(QByteArray& imgData, const QString& path)
0088 {
0089     QFileInfo fileInfo(path);
0090     QString   rawFilesExt = QString::fromUtf8(rawFiles());
0091     QString   ext         = fileInfo.suffix().toUpper();
0092 
0093     if (!fileInfo.exists() || ext.isEmpty() || !rawFilesExt.toUpper().contains(ext))
0094         return false;
0095 
0096     LibRaw raw;
0097 
0098     int ret = raw.open_file((const char*)(QFile::encodeName(path)).constData());
0099 
0100     if (ret != LIBRAW_SUCCESS)
0101     {
0102         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run open_file: " << libraw_strerror(ret);
0103         raw.recycle();
0104         return false;
0105     }
0106 
0107     return (KDcrawPrivate::loadEmbeddedPreview(imgData, raw));
0108 }
0109 
0110 bool KDcraw::loadEmbeddedPreview(QByteArray& imgData, const QBuffer& buffer)
0111 {
0112     QString rawFilesExt = QString::fromUtf8(rawFiles());
0113     LibRaw  raw;
0114 
0115     QByteArray inData = buffer.data();
0116     int ret           = raw.open_buffer((void*) inData.data(), (size_t) inData.size());
0117 
0118     if (ret != LIBRAW_SUCCESS)
0119     {
0120         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run open_buffer: " << libraw_strerror(ret);
0121         raw.recycle();
0122         return false;
0123     }
0124 
0125     return (KDcrawPrivate::loadEmbeddedPreview(imgData, raw));
0126 }
0127 
0128 bool KDcraw::loadHalfPreview(QImage& image, const QString& path)
0129 {
0130     QFileInfo fileInfo(path);
0131     QString   rawFilesExt = QString::fromUtf8(rawFiles());
0132     QString   ext = fileInfo.suffix().toUpper();
0133 
0134     if (!fileInfo.exists() || ext.isEmpty() || !rawFilesExt.toUpper().contains(ext))
0135         return false;
0136 
0137     qCDebug(LIBKDCRAW_LOG) << "Try to use reduced RAW picture extraction";
0138 
0139     LibRaw raw;
0140     raw.imgdata.params.use_auto_wb   = 1;         // Use automatic white balance.
0141     raw.imgdata.params.use_camera_wb = 1;         // Use camera white balance, if possible.
0142     raw.imgdata.params.half_size     = 1;         // Half-size color image (3x faster than -q).
0143 
0144     int ret = raw.open_file((const char*)(QFile::encodeName(path)).constData());
0145 
0146     if (ret != LIBRAW_SUCCESS)
0147     {
0148         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run open_file: " << libraw_strerror(ret);
0149         raw.recycle();
0150         return false;
0151     }
0152 
0153 
0154     if(!KDcrawPrivate::loadHalfPreview(image, raw))
0155     {
0156         qCDebug(LIBKDCRAW_LOG) << "Failed to get half preview from LibRaw!";
0157         return false;
0158     }
0159 
0160     qCDebug(LIBKDCRAW_LOG) << "Using reduced RAW picture extraction";
0161 
0162     return true;
0163 }
0164 
0165 bool KDcraw::loadHalfPreview(QByteArray& imgData, const QString& path)
0166 {
0167     QFileInfo fileInfo(path);
0168     QString   rawFilesExt = QString::fromUtf8(rawFiles());
0169     QString   ext = fileInfo.suffix().toUpper();
0170 
0171     if (!fileInfo.exists() || ext.isEmpty() || !rawFilesExt.toUpper().contains(ext))
0172         return false;
0173 
0174     qCDebug(LIBKDCRAW_LOG) << "Try to use reduced RAW picture extraction";
0175 
0176     LibRaw raw;
0177     int ret = raw.open_file((const char*)(QFile::encodeName(path)).constData());
0178 
0179     if (ret != LIBRAW_SUCCESS)
0180     {
0181         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_process: " << libraw_strerror(ret);
0182         raw.recycle();
0183         return false;
0184     }
0185 
0186     QImage image;
0187 
0188     if (!KDcrawPrivate::loadHalfPreview(image, raw))
0189     {
0190         qCDebug(LIBKDCRAW_LOG) << "KDcraw: failed to get half preview: " << libraw_strerror(ret);
0191         return false;
0192     }
0193 
0194     QBuffer buffer(&imgData);
0195     buffer.open(QIODevice::WriteOnly);
0196     image.save(&buffer, "JPEG"); 
0197 
0198     return true;
0199 }
0200 
0201 bool KDcraw::loadHalfPreview(QByteArray& imgData, const QBuffer& inBuffer)
0202 {
0203     QString rawFilesExt = QString::fromUtf8(rawFiles());
0204     LibRaw  raw;
0205 
0206     QByteArray inData = inBuffer.data();
0207     int ret           = raw.open_buffer((void*) inData.data(), (size_t) inData.size());
0208 
0209     if (ret != LIBRAW_SUCCESS)
0210     {
0211         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_make_mem_image: " << libraw_strerror(ret);
0212         raw.recycle();
0213         return false;
0214     }
0215 
0216     QImage image;
0217 
0218     if (!KDcrawPrivate::loadHalfPreview(image, raw))
0219     {
0220         qCDebug(LIBKDCRAW_LOG) << "KDcraw: failed to get half preview: " << libraw_strerror(ret);
0221         return false;
0222     }
0223 
0224     QBuffer buffer(&imgData);
0225     buffer.open(QIODevice::WriteOnly);
0226     image.save(&buffer, "JPG"); 
0227 
0228     return true;
0229 }
0230 
0231 bool KDcraw::loadFullImage(QImage& image, const QString& path, const RawDecodingSettings& settings)
0232 {
0233     QFileInfo fileInfo(path);
0234     QString   rawFilesExt = QString::fromUtf8(rawFiles());
0235     QString   ext         = fileInfo.suffix().toUpper();
0236 
0237     if (!fileInfo.exists() || ext.isEmpty() || !rawFilesExt.toUpper().contains(ext))
0238         return false;
0239 
0240     qCDebug(LIBKDCRAW_LOG) << "Try to load full RAW picture...";
0241 
0242     RawDecodingSettings prm = settings;
0243     prm.sixteenBitsImage    = false;
0244     QByteArray imgData;
0245     int width, height, rgbmax;
0246 
0247     KDcraw decoder;
0248     bool ret = decoder.decodeRAWImage(path, prm, imgData, width, height, rgbmax);
0249 
0250     if (!ret)
0251     {
0252         qCDebug(LIBKDCRAW_LOG) << "Failed to load full RAW picture";
0253         return false;
0254     }
0255 
0256     uchar* sptr  = (uchar*)imgData.data();
0257     uchar tmp8[2];
0258 
0259     // Set RGB color components.
0260     for (int i = 0 ; i < width * height ; ++i)
0261     {
0262         // Swap Red and Blue
0263         tmp8[0] = sptr[2];
0264         tmp8[1] = sptr[0];
0265         sptr[0] = tmp8[0];
0266         sptr[2] = tmp8[1];
0267 
0268         sptr += 3;
0269     }
0270 
0271     image      = QImage(width, height, QImage::Format_ARGB32);
0272     uint* dptr = reinterpret_cast<uint*>(image.bits());
0273     sptr       = (uchar*)imgData.data();
0274 
0275     for (int i = 0 ; i < width * height ; ++i)
0276     {
0277         *dptr++ = qRgba(sptr[2], sptr[1], sptr[0], 0xFF);
0278         sptr += 3;
0279     }
0280 
0281     qCDebug(LIBKDCRAW_LOG) << "Load full RAW picture done";
0282 
0283     return true;
0284 }
0285 
0286 bool KDcraw::rawFileIdentify(DcrawInfoContainer& identify, const QString& path)
0287 {
0288     QFileInfo fileInfo(path);
0289     QString rawFilesExt  = QString::fromUtf8(rawFiles());
0290     QString ext          = fileInfo.suffix().toUpper();
0291     identify.isDecodable = false;
0292 
0293     if (!fileInfo.exists() || ext.isEmpty() || !rawFilesExt.toUpper().contains(ext))
0294         return false;
0295 
0296     LibRaw raw;
0297 
0298     int ret = raw.open_file((const char*)(QFile::encodeName(path)).constData());
0299 
0300     if (ret != LIBRAW_SUCCESS)
0301     {
0302         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run open_file: " << libraw_strerror(ret);
0303         raw.recycle();
0304         return false;
0305     }
0306 
0307     ret = raw.adjust_sizes_info_only();
0308 
0309     if (ret != LIBRAW_SUCCESS)
0310     {
0311         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run adjust_sizes_info_only: " << libraw_strerror(ret);
0312         raw.recycle();
0313         return false;
0314     }
0315 
0316     KDcrawPrivate::fillIndentifyInfo(&raw, identify);
0317     raw.recycle();
0318     return true;
0319 }
0320 
0321 // ----------------------------------------------------------------------------------
0322 
0323 bool KDcraw::extractRAWData(const QString& filePath, QByteArray& rawData, DcrawInfoContainer& identify, unsigned int shotSelect)
0324 {
0325     QFileInfo fileInfo(filePath);
0326     QString rawFilesExt  = QString::fromUtf8(rawFiles());
0327     QString ext          = fileInfo.suffix().toUpper();
0328     identify.isDecodable = false;
0329 
0330     if (!fileInfo.exists() || ext.isEmpty() || !rawFilesExt.toUpper().contains(ext))
0331         return false;
0332 
0333     if (m_cancel)
0334         return false;
0335 
0336     d->setProgress(0.1);
0337 
0338     LibRaw raw;
0339     // Set progress call back function.
0340     raw.set_progress_handler(callbackForLibRaw, d.get());
0341 
0342     int ret = raw.open_file((const char*)(QFile::encodeName(filePath)).constData());
0343 
0344     if (ret != LIBRAW_SUCCESS)
0345     {
0346         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run open_file: " << libraw_strerror(ret);
0347         raw.recycle();
0348         return false;
0349     }
0350 
0351     if (m_cancel)
0352     {
0353         raw.recycle();
0354         return false;
0355     }
0356 
0357     d->setProgress(0.3);
0358 
0359     raw.imgdata.params.output_bps  = 16;
0360 #if LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 21)
0361     raw.imgdata.rawparams.shot_select = shotSelect;
0362 #else
0363     raw.imgdata.params.shot_select = shotSelect;
0364 #endif
0365     ret                            = raw.unpack();
0366 
0367     if (ret != LIBRAW_SUCCESS)
0368     {
0369         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run unpack: " << libraw_strerror(ret);
0370         raw.recycle();
0371         return false;
0372     }
0373 
0374     if (m_cancel)
0375     {
0376         raw.recycle();
0377         return false;
0378     }
0379 
0380     d->setProgress(0.4);
0381 
0382     ret = raw.raw2image();
0383 
0384     if (ret != LIBRAW_SUCCESS)
0385     {
0386         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run raw2image: " << libraw_strerror(ret);
0387         raw.recycle();
0388         return false;
0389     }
0390 
0391     if (m_cancel)
0392     {
0393         raw.recycle();
0394         return false;
0395     }
0396 
0397     d->setProgress(0.6);
0398 
0399     KDcrawPrivate::fillIndentifyInfo(&raw, identify);
0400 
0401     if (m_cancel)
0402     {
0403         raw.recycle();
0404         return false;
0405     }
0406 
0407     d->setProgress(0.8);
0408 
0409     rawData = QByteArray();
0410 
0411     if (raw.imgdata.idata.filters == 0)
0412     {
0413         rawData.resize((int)(raw.imgdata.sizes.iwidth * raw.imgdata.sizes.iheight  * raw.imgdata.idata.colors * sizeof(unsigned short)));
0414 
0415         unsigned short* output = reinterpret_cast<unsigned short*>(rawData.data());
0416 
0417         for (unsigned int row = 0; row < raw.imgdata.sizes.iheight; row++)
0418         {
0419             for (unsigned int col = 0; col < raw.imgdata.sizes.iwidth; col++)
0420             {
0421                 for (int color = 0; color < raw.imgdata.idata.colors; color++)
0422                 {
0423                     *output = raw.imgdata.image[raw.imgdata.sizes.iwidth*row + col][color];
0424                     output++;
0425                 }
0426             }
0427         }
0428     }
0429     else
0430     {
0431         rawData.resize((int)(raw.imgdata.sizes.iwidth * raw.imgdata.sizes.iheight * sizeof(unsigned short)));
0432 
0433         unsigned short* output = reinterpret_cast<unsigned short*>(rawData.data());
0434 
0435         for (uint row = 0; row < raw.imgdata.sizes.iheight; row++)
0436         {
0437             for (uint col = 0; col < raw.imgdata.sizes.iwidth; col++)
0438             {
0439                 *output = raw.imgdata.image[raw.imgdata.sizes.iwidth*row + col][raw.COLOR(row, col)];
0440                 output++;
0441             }
0442         }
0443     }
0444 
0445     raw.recycle();
0446     d->setProgress(1.0);
0447 
0448     return true;
0449 }
0450 
0451 bool KDcraw::decodeHalfRAWImage(const QString& filePath, const RawDecodingSettings& rawDecodingSettings,
0452                                 QByteArray& imageData, int& width, int& height, int& rgbmax)
0453 {
0454     m_rawDecodingSettings                    = rawDecodingSettings;
0455     m_rawDecodingSettings.halfSizeColorImage = true;
0456     return (d->loadFromLibraw(filePath, imageData, width, height, rgbmax));
0457 }
0458 
0459 bool KDcraw::decodeRAWImage(const QString& filePath, const RawDecodingSettings& rawDecodingSettings,
0460                             QByteArray& imageData, int& width, int& height, int& rgbmax)
0461 {
0462     m_rawDecodingSettings = rawDecodingSettings;
0463     return (d->loadFromLibraw(filePath, imageData, width, height, rgbmax));
0464 }
0465 
0466 bool KDcraw::checkToCancelWaitingData()
0467 {
0468     return m_cancel;
0469 }
0470 
0471 void KDcraw::setWaitingDataProgress(double)
0472 {
0473 }
0474 
0475 const char* KDcraw::rawFiles()
0476 {
0477     return raw_file_extentions;
0478 }
0479 
0480 QStringList KDcraw::rawFilesList()
0481 {
0482     QString string = QString::fromLatin1(rawFiles());
0483     return string.remove(QLatin1String("*.")).split(QLatin1Char(' '));
0484 }
0485 
0486 int KDcraw::rawFilesVersion()
0487 {
0488     return raw_file_extensions_version;
0489 }
0490 
0491 QStringList KDcraw::supportedCamera()
0492 {
0493     QStringList camera;
0494     const char** const list = LibRaw::cameraList();
0495 
0496     for (int i = 0; i < LibRaw::cameraCount(); i++)
0497         camera.append(QString::fromUtf8(list[i]));
0498 
0499     return camera;
0500 }
0501 
0502 QString KDcraw::librawVersion()
0503 {
0504     return QString::fromLatin1(LIBRAW_VERSION_STR).remove(QLatin1String("-Release"));
0505 }
0506 
0507 int KDcraw::librawUseGomp()
0508 {
0509 #ifdef LIBRAW_HAS_CONFIG
0510 #   ifdef LIBRAW_USE_OPENMP
0511     return true;
0512 #   else
0513     return false;
0514 #   endif
0515 #else
0516     return -1;
0517 #endif
0518 }
0519 
0520 int KDcraw::librawUseRawSpeed()
0521 {
0522 #ifdef LIBRAW_HAS_CONFIG
0523 #   ifdef LIBRAW_USE_RAWSPEED
0524     return true;
0525 #   else
0526     return false;
0527 #   endif
0528 #else
0529     return -1;
0530 #endif
0531 }
0532 
0533 int KDcraw::librawUseGPL2DemosaicPack()
0534 {
0535 #ifdef LIBRAW_HAS_CONFIG
0536 #   ifdef LIBRAW_USE_DEMOSAIC_PACK_GPL2
0537     return true;
0538 #   else
0539     return false;
0540 #   endif
0541 #else
0542     return -1;
0543 #endif
0544 }
0545 
0546 int KDcraw::librawUseGPL3DemosaicPack()
0547 {
0548 #ifdef LIBRAW_HAS_CONFIG
0549 #   ifdef LIBRAW_USE_DEMOSAIC_PACK_GPL3
0550     return true;
0551 #   else
0552     return false;
0553 #   endif
0554 #else
0555     return -1;
0556 #endif
0557 }
0558 
0559 }  // namespace KDcrawIface
0560 
0561 #include "moc_kdcraw.cpp"