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

0001 /*
0002     SPDX-FileCopyrightText: 2008-2015 Gilles Caulier <caulier dot gilles at gmail dot com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "kdcraw.h"
0008 #include "kdcraw_p.h"
0009 
0010 // Qt includes
0011 
0012 #include <QString>
0013 #include <QFile>
0014 
0015 // Local includes
0016 
0017 #include "libkdcraw_debug.h"
0018 
0019 namespace KDcrawIface
0020 {
0021 
0022 int callbackForLibRaw(void* data, enum LibRaw_progress p, int iteration, int expected)
0023 {
0024     if (data)
0025     {
0026         KDcrawPrivate* const d = static_cast<KDcrawPrivate*>(data);
0027 
0028         if (d)
0029         {
0030             return d->progressCallback(p, iteration, expected);
0031         }
0032     }
0033 
0034     return 0;
0035 }
0036 
0037 // --------------------------------------------------------------------------------------------------
0038 
0039 KDcrawPrivate::KDcrawPrivate(KDcraw* const p)
0040     : m_parent(p)
0041 {
0042     m_progress = 0.0;
0043 }
0044 
0045 KDcrawPrivate::~KDcrawPrivate() = default;
0046 
0047 void KDcrawPrivate::createPPMHeader(QByteArray& imgData, libraw_processed_image_t* const img)
0048 {
0049     QString header = QString::fromUtf8("P%1\n%2 %3\n%4\n").arg(img->colors == 3 ? QLatin1String("6") : QLatin1String("5"))
0050                                                           .arg(img->width)
0051                                                           .arg(img->height)
0052                                                           .arg((1 << img->bits)-1);
0053     imgData.append(header.toLatin1());
0054     imgData.append(QByteArray((const char*)img->data, (int)img->data_size));
0055 }
0056 
0057 int KDcrawPrivate::progressCallback(enum LibRaw_progress p, int iteration, int expected)
0058 {
0059     qCDebug(LIBKDCRAW_LOG) << "LibRaw progress: " << libraw_strprogress(p) << " pass "
0060                            << iteration << " of " << expected;
0061 
0062     // post a little change in progress indicator to show raw processor activity.
0063     setProgress(progressValue()+0.01);
0064 
0065     // Clean processing termination by user...
0066     if (m_parent->checkToCancelWaitingData())
0067     {
0068         qCDebug(LIBKDCRAW_LOG) << "LibRaw process termination invoked...";
0069         m_parent->m_cancel = true;
0070         m_progress         = 0.0;
0071         return 1;
0072     }
0073 
0074     // Return 0 to continue processing...
0075     return 0;
0076 }
0077 
0078 void KDcrawPrivate::setProgress(double value)
0079 {
0080     m_progress = value;
0081     m_parent->setWaitingDataProgress(m_progress);
0082 }
0083 
0084 double KDcrawPrivate::progressValue() const
0085 {
0086     return m_progress;
0087 }
0088 
0089 void KDcrawPrivate::fillIndentifyInfo(LibRaw* const raw, DcrawInfoContainer& identify)
0090 {
0091     identify.dateTime.setMSecsSinceEpoch(raw->imgdata.other.timestamp * 1000);
0092     identify.make             = QString::fromUtf8(raw->imgdata.idata.make);
0093     identify.model            = QString::fromUtf8(raw->imgdata.idata.model);
0094     identify.owner            = QString::fromUtf8(raw->imgdata.other.artist);
0095     identify.DNGVersion       = QString::number(raw->imgdata.idata.dng_version);
0096     identify.sensitivity      = raw->imgdata.other.iso_speed;
0097     identify.exposureTime     = raw->imgdata.other.shutter;
0098     identify.aperture         = raw->imgdata.other.aperture;
0099     identify.focalLength      = raw->imgdata.other.focal_len;
0100     identify.imageSize        = QSize(raw->imgdata.sizes.width, raw->imgdata.sizes.height);
0101     identify.fullSize         = QSize(raw->imgdata.sizes.raw_width, raw->imgdata.sizes.raw_height);
0102     identify.outputSize       = QSize(raw->imgdata.sizes.iwidth, raw->imgdata.sizes.iheight);
0103     identify.thumbSize        = QSize(raw->imgdata.thumbnail.twidth, raw->imgdata.thumbnail.theight);
0104     identify.topMargin        = raw->imgdata.sizes.top_margin;
0105     identify.leftMargin       = raw->imgdata.sizes.left_margin;
0106     identify.hasIccProfile    = raw->imgdata.color.profile ? true : false;
0107     identify.isDecodable      = true;
0108     identify.pixelAspectRatio = raw->imgdata.sizes.pixel_aspect;
0109     identify.rawColors        = raw->imgdata.idata.colors;
0110     identify.rawImages        = raw->imgdata.idata.raw_count;
0111     identify.blackPoint       = raw->imgdata.color.black;
0112 
0113     for (int ch = 0; ch < 4; ch++)
0114     {
0115         identify.blackPointCh[ch] = raw->imgdata.color.cblack[ch];
0116     }
0117 
0118     identify.whitePoint       = raw->imgdata.color.maximum;
0119     identify.orientation      = (DcrawInfoContainer::ImageOrientation)raw->imgdata.sizes.flip;
0120 
0121     memcpy(&identify.cameraColorMatrix1, &raw->imgdata.color.cmatrix, sizeof(raw->imgdata.color.cmatrix));
0122     memcpy(&identify.cameraColorMatrix2, &raw->imgdata.color.rgb_cam, sizeof(raw->imgdata.color.rgb_cam));
0123     memcpy(&identify.cameraXYZMatrix,    &raw->imgdata.color.cam_xyz, sizeof(raw->imgdata.color.cam_xyz));
0124 
0125     if (raw->imgdata.idata.filters)
0126     {
0127         if (!raw->imgdata.idata.cdesc[3])
0128         {
0129             raw->imgdata.idata.cdesc[3] = 'G';
0130         }
0131 
0132         for (int i=0; i < 16; i++)
0133         {
0134             identify.filterPattern.append(QChar::fromLatin1(raw->imgdata.idata.cdesc[raw->COLOR(i >> 1, i & 1)]));
0135         }
0136 
0137         identify.colorKeys = QString::fromLatin1(raw->imgdata.idata.cdesc);
0138     }
0139 
0140     for(int c = 0 ; c < raw->imgdata.idata.colors ; c++)
0141     {
0142         identify.daylightMult[c] = raw->imgdata.color.pre_mul[c];
0143     }
0144 
0145     if (raw->imgdata.color.cam_mul[0] > 0)
0146     {
0147         for(int c = 0 ; c < 4 ; c++)
0148         {
0149             identify.cameraMult[c] = raw->imgdata.color.cam_mul[c];
0150         }
0151     }
0152 }
0153 
0154 bool KDcrawPrivate::loadFromLibraw(const QString& filePath, QByteArray& imageData,
0155                                      int& width, int& height, int& rgbmax)
0156 {
0157     m_parent->m_cancel = false;
0158 
0159     LibRaw raw;
0160     // Set progress call back function.
0161     raw.set_progress_handler(callbackForLibRaw, this);
0162 
0163     QByteArray deadpixelPath = QFile::encodeName(m_parent->m_rawDecodingSettings.deadPixelMap);
0164     QByteArray cameraProfile = QFile::encodeName(m_parent->m_rawDecodingSettings.inputProfile);
0165     QByteArray outputProfile = QFile::encodeName(m_parent->m_rawDecodingSettings.outputProfile);
0166 
0167     if (!m_parent->m_rawDecodingSettings.autoBrightness)
0168     {
0169         // Use a fixed white level, ignoring the image histogram.
0170         raw.imgdata.params.no_auto_bright = 1;
0171     }
0172 
0173     if (m_parent->m_rawDecodingSettings.sixteenBitsImage)
0174     {
0175         // (-4) 16bit ppm output
0176         raw.imgdata.params.output_bps = 16;
0177     }
0178 
0179     if (m_parent->m_rawDecodingSettings.halfSizeColorImage)
0180     {
0181         // (-h) Half-size color image (3x faster than -q).
0182         raw.imgdata.params.half_size = 1;
0183     }
0184 
0185     if (m_parent->m_rawDecodingSettings.RGBInterpolate4Colors)
0186     {
0187         // (-f) Interpolate RGB as four colors.
0188         raw.imgdata.params.four_color_rgb = 1;
0189     }
0190 
0191     if (m_parent->m_rawDecodingSettings.DontStretchPixels)
0192     {
0193         // (-j) Do not stretch the image to its correct aspect ratio.
0194         raw.imgdata.params.use_fuji_rotate = 1;
0195     }
0196 
0197     // (-H) Unclip highlight color.
0198     raw.imgdata.params.highlight = m_parent->m_rawDecodingSettings.unclipColors;
0199 
0200     if (m_parent->m_rawDecodingSettings.brightness != 1.0)
0201     {
0202         // (-b) Set Brightness value.
0203         raw.imgdata.params.bright = m_parent->m_rawDecodingSettings.brightness;
0204     }
0205 
0206     if (m_parent->m_rawDecodingSettings.enableBlackPoint)
0207     {
0208         // (-k) Set Black Point value.
0209         raw.imgdata.params.user_black = m_parent->m_rawDecodingSettings.blackPoint;
0210     }
0211 
0212     if (m_parent->m_rawDecodingSettings.enableWhitePoint)
0213     {
0214         // (-S) Set White Point value (saturation).
0215         raw.imgdata.params.user_sat = m_parent->m_rawDecodingSettings.whitePoint;
0216     }
0217 
0218     if (m_parent->m_rawDecodingSettings.medianFilterPasses > 0)
0219     {
0220         // (-m) After interpolation, clean up color artifacts by repeatedly applying a 3x3 median filter to the R-G and B-G channels.
0221         raw.imgdata.params.med_passes = m_parent->m_rawDecodingSettings.medianFilterPasses;
0222     }
0223 
0224     if (!m_parent->m_rawDecodingSettings.deadPixelMap.isEmpty())
0225     {
0226         // (-P) Read the dead pixel list from this file.
0227         raw.imgdata.params.bad_pixels = deadpixelPath.data();
0228     }
0229 
0230     switch (m_parent->m_rawDecodingSettings.whiteBalance)
0231     {
0232         case RawDecodingSettings::NONE:
0233         {
0234             break;
0235         }
0236         case RawDecodingSettings::CAMERA:
0237         {
0238             // (-w) Use camera white balance, if possible.
0239             raw.imgdata.params.use_camera_wb = 1;
0240             break;
0241         }
0242         case RawDecodingSettings::AUTO:
0243         {
0244             // (-a) Use automatic white balance.
0245             raw.imgdata.params.use_auto_wb = 1;
0246             break;
0247         }
0248         case RawDecodingSettings::CUSTOM:
0249         {
0250             /* Convert between Temperature and RGB.
0251              */
0252             double T;
0253             double RGB[3];
0254             double xD, yD, X, Y, Z;
0255             DcrawInfoContainer identify;
0256             T = m_parent->m_rawDecodingSettings.customWhiteBalance;
0257 
0258             /* Here starts the code picked and adapted from ufraw (0.12.1)
0259                to convert Temperature + green multiplier to RGB multipliers
0260             */
0261             /* Convert between Temperature and RGB.
0262              * Base on information from http://www.brucelindbloom.com/
0263              * The fit for D-illuminant between 4000K and 12000K are from CIE
0264              * The generalization to 2000K < T < 4000K and the blackbody fits
0265              * are my own and should be taken with a grain of salt.
0266              */
0267             const double XYZ_to_RGB[3][3] = {
0268                                                 { 3.24071,  -0.969258,  0.0556352 },
0269                                                 {-1.53726,  1.87599,    -0.203996 },
0270                                                 {-0.498571, 0.0415557,  1.05707   }
0271                                             };
0272 
0273             // Fit for CIE Daylight illuminant
0274             if (T <= 4000)
0275             {
0276                 xD = 0.27475e9/(T*T*T) - 0.98598e6/(T*T) + 1.17444e3/T + 0.145986;
0277             }
0278             else if (T <= 7000)
0279             {
0280                 xD = -4.6070e9/(T*T*T) + 2.9678e6/(T*T) + 0.09911e3/T + 0.244063;
0281             }
0282             else
0283             {
0284                 xD = -2.0064e9/(T*T*T) + 1.9018e6/(T*T) + 0.24748e3/T + 0.237040;
0285             }
0286 
0287             yD     = -3*xD*xD + 2.87*xD - 0.275;
0288             X      = xD/yD;
0289             Y      = 1;
0290             Z      = (1-xD-yD)/yD;
0291             RGB[0] = X*XYZ_to_RGB[0][0] + Y*XYZ_to_RGB[1][0] + Z*XYZ_to_RGB[2][0];
0292             RGB[1] = X*XYZ_to_RGB[0][1] + Y*XYZ_to_RGB[1][1] + Z*XYZ_to_RGB[2][1];
0293             RGB[2] = X*XYZ_to_RGB[0][2] + Y*XYZ_to_RGB[1][2] + Z*XYZ_to_RGB[2][2];
0294             /* End of the code picked to ufraw
0295             */
0296 
0297             RGB[1] = RGB[1] / m_parent->m_rawDecodingSettings.customWhiteBalanceGreen;
0298 
0299             /* By default, decraw override his default D65 WB
0300                We need to keep it as a basis : if not, colors with some
0301                DSLR will have a high dominant of color that will lead to
0302                a completely wrong WB
0303             */
0304             if (KDcraw::rawFileIdentify(identify, filePath))
0305             {
0306                 RGB[0] = identify.daylightMult[0] / RGB[0];
0307                 RGB[1] = identify.daylightMult[1] / RGB[1];
0308                 RGB[2] = identify.daylightMult[2] / RGB[2];
0309             }
0310             else
0311             {
0312                 RGB[0] = 1.0 / RGB[0];
0313                 RGB[1] = 1.0 / RGB[1];
0314                 RGB[2] = 1.0 / RGB[2];
0315                 qCDebug(LIBKDCRAW_LOG) << "Warning: cannot get daylight multipliers";
0316             }
0317 
0318             // (-r) set Raw Color Balance Multipliers.
0319             raw.imgdata.params.user_mul[0] = RGB[0];
0320             raw.imgdata.params.user_mul[1] = RGB[1];
0321             raw.imgdata.params.user_mul[2] = RGB[2];
0322             raw.imgdata.params.user_mul[3] = RGB[1];
0323             break;
0324         }
0325         case RawDecodingSettings::AERA:
0326         {
0327             // (-A) Calculate the white balance by averaging a rectangular area from image.
0328             raw.imgdata.params.greybox[0] = m_parent->m_rawDecodingSettings.whiteBalanceArea.left();
0329             raw.imgdata.params.greybox[1] = m_parent->m_rawDecodingSettings.whiteBalanceArea.top();
0330             raw.imgdata.params.greybox[2] = m_parent->m_rawDecodingSettings.whiteBalanceArea.width();
0331             raw.imgdata.params.greybox[3] = m_parent->m_rawDecodingSettings.whiteBalanceArea.height();
0332             break;
0333         }
0334     }
0335 
0336     // (-q) Use an interpolation method.
0337     raw.imgdata.params.user_qual = m_parent->m_rawDecodingSettings.RAWQuality;
0338 
0339     switch (m_parent->m_rawDecodingSettings.NRType)
0340     {
0341         case RawDecodingSettings::WAVELETSNR:
0342         {
0343             // (-n) Use wavelets to erase noise while preserving real detail.
0344             raw.imgdata.params.threshold    = m_parent->m_rawDecodingSettings.NRThreshold;
0345             break;
0346         }
0347         case RawDecodingSettings::FBDDNR:
0348         {
0349             // (100 - 1000) => (1 - 10) conversion
0350             raw.imgdata.params.fbdd_noiserd = lround(m_parent->m_rawDecodingSettings.NRThreshold / 100.0);
0351             break;
0352         }
0353 #if !LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 19)
0354         case RawDecodingSettings::LINENR:
0355         {
0356             // (100 - 1000) => (0.001 - 0.02) conversion.
0357             raw.imgdata.params.linenoise    = m_parent->m_rawDecodingSettings.NRThreshold * 2.11E-5 + 0.00111111;
0358             raw.imgdata.params.cfaline      = true;
0359             break;
0360         }
0361 
0362         case RawDecodingSettings::IMPULSENR:
0363         {
0364             // (100 - 1000) => (0.005 - 0.05) conversion.
0365             raw.imgdata.params.lclean       = m_parent->m_rawDecodingSettings.NRThreshold     * 5E-5;
0366             raw.imgdata.params.cclean       = m_parent->m_rawDecodingSettings.NRChroThreshold * 5E-5;
0367             raw.imgdata.params.cfa_clean    = true;
0368             break;
0369         }
0370 #endif
0371         default:   // No Noise Reduction
0372         {
0373             raw.imgdata.params.threshold    = 0;
0374             raw.imgdata.params.fbdd_noiserd = 0;
0375 #if !LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 19)
0376             raw.imgdata.params.linenoise    = 0;
0377             raw.imgdata.params.cfaline      = false;
0378             raw.imgdata.params.lclean       = 0;
0379             raw.imgdata.params.cclean       = 0;
0380             raw.imgdata.params.cfa_clean    = false;
0381 #endif
0382             break;
0383         }
0384     }
0385 
0386 #if !LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 19)
0387     // Chromatic aberration correction.
0388     raw.imgdata.params.ca_correc  = m_parent->m_rawDecodingSettings.enableCACorrection;
0389     raw.imgdata.params.cared      = m_parent->m_rawDecodingSettings.caMultiplier[0];
0390     raw.imgdata.params.cablue     = m_parent->m_rawDecodingSettings.caMultiplier[1];
0391 #endif
0392 
0393     // Exposure Correction before interpolation.
0394     raw.imgdata.params.exp_correc = m_parent->m_rawDecodingSettings.expoCorrection;
0395     raw.imgdata.params.exp_shift  = m_parent->m_rawDecodingSettings.expoCorrectionShift;
0396     raw.imgdata.params.exp_preser = m_parent->m_rawDecodingSettings.expoCorrectionHighlight;
0397 
0398     switch (m_parent->m_rawDecodingSettings.inputColorSpace)
0399     {
0400         case RawDecodingSettings::EMBEDDED:
0401         {
0402             // (-p embed) Use input profile from RAW file to define the camera's raw colorspace.
0403             raw.imgdata.params.camera_profile = (char*)"embed";
0404             break;
0405         }
0406         case RawDecodingSettings::CUSTOMINPUTCS:
0407         {
0408             if (!m_parent->m_rawDecodingSettings.inputProfile.isEmpty())
0409             {
0410                 // (-p) Use input profile file to define the camera's raw colorspace.
0411                 raw.imgdata.params.camera_profile = cameraProfile.data();
0412             }
0413             break;
0414         }
0415         default:
0416         {
0417             // No input profile
0418             break;
0419         }
0420     }
0421 
0422     switch (m_parent->m_rawDecodingSettings.outputColorSpace)
0423     {
0424         case RawDecodingSettings::CUSTOMOUTPUTCS:
0425         {
0426             if (!m_parent->m_rawDecodingSettings.outputProfile.isEmpty())
0427             {
0428                 // (-o) Use ICC profile file to define the output colorspace.
0429                 raw.imgdata.params.output_profile = outputProfile.data();
0430             }
0431             break;
0432         }
0433         default:
0434         {
0435             // (-o) Define the output colorspace.
0436             raw.imgdata.params.output_color = m_parent->m_rawDecodingSettings.outputColorSpace;
0437             break;
0438         }
0439     }
0440 
0441     //-- Extended demosaicing settings ----------------------------------------------------------
0442 
0443     raw.imgdata.params.dcb_iterations = m_parent->m_rawDecodingSettings.dcbIterations;
0444     raw.imgdata.params.dcb_enhance_fl = m_parent->m_rawDecodingSettings.dcbEnhanceFl;
0445 #if !LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 19)
0446     raw.imgdata.params.eeci_refine    = m_parent->m_rawDecodingSettings.eeciRefine;
0447     raw.imgdata.params.es_med_passes  = m_parent->m_rawDecodingSettings.esMedPasses;
0448 #endif
0449 
0450     //-------------------------------------------------------------------------------------------
0451 
0452     setProgress(0.1);
0453 
0454     qCDebug(LIBKDCRAW_LOG) << filePath;
0455     qCDebug(LIBKDCRAW_LOG) << m_parent->m_rawDecodingSettings;
0456 
0457     int ret = raw.open_file((const char*)(QFile::encodeName(filePath)).constData());
0458 
0459     if (ret != LIBRAW_SUCCESS)
0460     {
0461         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run open_file: " << libraw_strerror(ret);
0462         raw.recycle();
0463         return false;
0464     }
0465 
0466     if (m_parent->m_cancel)
0467     {
0468         raw.recycle();
0469         return false;
0470     }
0471 
0472     setProgress(0.2);
0473 
0474     ret = raw.unpack();
0475 
0476     if (ret != LIBRAW_SUCCESS)
0477     {
0478         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run unpack: " << libraw_strerror(ret);
0479         raw.recycle();
0480         return false;
0481     }
0482 
0483     if (m_parent->m_cancel)
0484     {
0485         raw.recycle();
0486         return false;
0487     }
0488 
0489     setProgress(0.25);
0490 
0491     if (m_parent->m_rawDecodingSettings.fixColorsHighlights)
0492     {
0493         qCDebug(LIBKDCRAW_LOG) << "Applying LibRaw highlights adjustments";
0494         // 1.0 is fallback to default value
0495         raw.imgdata.params.adjust_maximum_thr = 1.0;
0496     }
0497     else
0498     {
0499         qCDebug(LIBKDCRAW_LOG) << "Disabling LibRaw highlights adjustments";
0500         // 0.0 disables this feature
0501         raw.imgdata.params.adjust_maximum_thr = 0.0;
0502     }
0503 
0504     ret = raw.dcraw_process();
0505 
0506     if (ret != LIBRAW_SUCCESS)
0507     {
0508         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_process: " << libraw_strerror(ret);
0509         raw.recycle();
0510         return false;
0511     }
0512 
0513     if (m_parent->m_cancel)
0514     {
0515         raw.recycle();
0516         return false;
0517     }
0518 
0519     setProgress(0.3);
0520 
0521     libraw_processed_image_t* img = raw.dcraw_make_mem_image(&ret);
0522 
0523     if(!img)
0524     {
0525         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_make_mem_image: " << libraw_strerror(ret);
0526         raw.recycle();
0527         return false;
0528     }
0529 
0530     if (m_parent->m_cancel)
0531     {
0532         // Clear memory allocation. Introduced with LibRaw 0.11.0
0533         raw.dcraw_clear_mem(img);
0534         raw.recycle();
0535         return false;
0536     }
0537 
0538     setProgress(0.35);
0539 
0540     width  = img->width;
0541     height = img->height;
0542     rgbmax = (1 << img->bits)-1;
0543 
0544     if (img->colors == 3)
0545     {
0546         imageData = QByteArray((const char*)img->data, (int)img->data_size);
0547     }
0548     else
0549     {
0550         // img->colors == 1 (Grayscale) : convert to RGB
0551         imageData = QByteArray();
0552 
0553         for (int i = 0 ; i < (int)img->data_size ; ++i)
0554         {
0555             for (int j = 0 ; j < 3 ; ++j)
0556             {
0557                 imageData.append(img->data[i]);
0558             }
0559         }
0560     }
0561 
0562     // Clear memory allocation. Introduced with LibRaw 0.11.0
0563     raw.dcraw_clear_mem(img);
0564     raw.recycle();
0565 
0566     if (m_parent->m_cancel)
0567     {
0568         return false;
0569     }
0570 
0571     setProgress(0.4);
0572 
0573     qCDebug(LIBKDCRAW_LOG) << "LibRaw: data info: width=" << width
0574              << " height=" << height
0575              << " rgbmax=" << rgbmax;
0576 
0577     return true;
0578 }
0579 
0580 bool KDcrawPrivate::loadEmbeddedPreview(QByteArray& imgData, LibRaw& raw)
0581 {
0582     int ret = raw.unpack_thumb();
0583 
0584     if (ret != LIBRAW_SUCCESS)
0585     {
0586         raw.recycle();
0587         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run unpack_thumb: " << libraw_strerror(ret);
0588         raw.recycle();
0589         return false;
0590     }
0591 
0592     libraw_processed_image_t* const thumb = raw.dcraw_make_mem_thumb(&ret);
0593 
0594     if(!thumb)
0595     {
0596         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_make_mem_thumb: " << libraw_strerror(ret);
0597         raw.recycle();
0598         return false;
0599     }
0600 
0601     if(thumb->type == LIBRAW_IMAGE_BITMAP)
0602     {
0603         createPPMHeader(imgData, thumb);
0604     }
0605     else
0606     {
0607         imgData = QByteArray((const char*)thumb->data, (int)thumb->data_size);
0608     }
0609 
0610     // Clear memory allocation. Introduced with LibRaw 0.11.0
0611     raw.dcraw_clear_mem(thumb);
0612     raw.recycle();
0613 
0614     if ( imgData.isEmpty() )
0615     {
0616         qCDebug(LIBKDCRAW_LOG) << "Failed to load JPEG thumb from LibRaw!";
0617         return false;
0618     }
0619 
0620     return true;
0621 }
0622 
0623 bool KDcrawPrivate::loadHalfPreview(QImage& image, LibRaw& raw)
0624 {
0625     raw.imgdata.params.use_auto_wb   = 1;         // Use automatic white balance.
0626     raw.imgdata.params.use_camera_wb = 1;         // Use camera white balance, if possible.
0627     raw.imgdata.params.half_size     = 1;         // Half-size color image (3x faster than -q).
0628     QByteArray imgData;
0629 
0630     int ret = raw.unpack();
0631 
0632     if (ret != LIBRAW_SUCCESS)
0633     {
0634         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run unpack: " << libraw_strerror(ret);
0635         raw.recycle();
0636         return false;
0637     }
0638 
0639     ret = raw.dcraw_process();
0640 
0641     if (ret != LIBRAW_SUCCESS)
0642     {
0643         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_process: " << libraw_strerror(ret);
0644         raw.recycle();
0645         return false;
0646     }
0647 
0648     libraw_processed_image_t* halfImg = raw.dcraw_make_mem_image(&ret);
0649 
0650     if(!halfImg)
0651     {
0652         qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_make_mem_image: " << libraw_strerror(ret);
0653         raw.recycle();
0654         return false;
0655     }
0656 
0657     KDcrawPrivate::createPPMHeader(imgData, halfImg);
0658     // Clear memory allocation. Introduced with LibRaw 0.11.0
0659     raw.dcraw_clear_mem(halfImg);
0660     raw.recycle();
0661 
0662     if ( imgData.isEmpty() )
0663     {
0664         qCDebug(LIBKDCRAW_LOG) << "Failed to load half preview from LibRaw!";
0665         return false;
0666     }
0667 
0668     if (!image.loadFromData(imgData))
0669     {
0670         qCDebug(LIBKDCRAW_LOG) << "Failed to load PPM data from LibRaw!";
0671         return false;
0672     }
0673 
0674     return true;
0675 }
0676 
0677 }  // namespace KDcrawIface