Coverage Report

Created: 2026-05-31 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libkdcraw/src/kdcraw_p.cpp
Line
Count
Source
1
/*
2
    SPDX-FileCopyrightText: 2008-2015 Gilles Caulier <caulier dot gilles at gmail dot com>
3
4
    SPDX-License-Identifier: GPL-2.0-or-later
5
*/
6
7
#include "kdcraw.h"
8
#include "kdcraw_p.h"
9
10
// Qt includes
11
12
#include <QString>
13
#include <QFile>
14
15
// Local includes
16
17
#include "libkdcraw_debug.h"
18
19
namespace KDcrawIface
20
{
21
22
int callbackForLibRaw(void* data, enum LibRaw_progress p, int iteration, int expected)
23
0
{
24
0
    if (data)
25
0
    {
26
0
        KDcrawPrivate* const d = static_cast<KDcrawPrivate*>(data);
27
28
0
        if (d)
29
0
        {
30
0
            return d->progressCallback(p, iteration, expected);
31
0
        }
32
0
    }
33
34
0
    return 0;
35
0
}
36
37
// --------------------------------------------------------------------------------------------------
38
39
KDcrawPrivate::KDcrawPrivate(KDcraw* const p)
40
0
    : m_parent(p)
41
0
{
42
0
    m_progress = 0.0;
43
0
}
44
45
0
KDcrawPrivate::~KDcrawPrivate() = default;
46
47
void KDcrawPrivate::createPPMHeader(QByteArray& imgData, libraw_processed_image_t* const img)
48
0
{
49
0
    QString header = QString::fromUtf8("P%1\n%2 %3\n%4\n").arg(img->colors == 3 ? QLatin1String("6") : QLatin1String("5"))
50
0
                                                          .arg(img->width)
51
0
                                                          .arg(img->height)
52
0
                                                          .arg((1 << img->bits)-1);
53
0
    imgData.append(header.toLatin1());
54
0
    imgData.append(QByteArray((const char*)img->data, (int)img->data_size));
55
0
}
56
57
int KDcrawPrivate::progressCallback(enum LibRaw_progress p, int iteration, int expected)
58
0
{
59
0
    qCDebug(LIBKDCRAW_LOG) << "LibRaw progress: " << libraw_strprogress(p) << " pass "
60
0
                           << iteration << " of " << expected;
61
62
    // post a little change in progress indicator to show raw processor activity.
63
0
    setProgress(progressValue()+0.01);
64
65
    // Clean processing termination by user...
66
0
    if (m_parent->checkToCancelWaitingData())
67
0
    {
68
0
        qCDebug(LIBKDCRAW_LOG) << "LibRaw process termination invoked...";
69
0
        m_parent->m_cancel = true;
70
0
        m_progress         = 0.0;
71
0
        return 1;
72
0
    }
73
74
    // Return 0 to continue processing...
75
0
    return 0;
76
0
}
77
78
void KDcrawPrivate::setProgress(double value)
79
0
{
80
0
    m_progress = value;
81
0
    m_parent->setWaitingDataProgress(m_progress);
82
0
}
83
84
double KDcrawPrivate::progressValue() const
85
0
{
86
0
    return m_progress;
87
0
}
88
89
void KDcrawPrivate::fillIndentifyInfo(LibRaw* const raw, DcrawInfoContainer& identify)
90
0
{
91
0
    identify.dateTime.setMSecsSinceEpoch(raw->imgdata.other.timestamp * 1000);
92
0
    identify.make             = QString::fromUtf8(raw->imgdata.idata.make);
93
0
    identify.model            = QString::fromUtf8(raw->imgdata.idata.model);
94
0
    identify.owner            = QString::fromUtf8(raw->imgdata.other.artist);
95
0
    identify.DNGVersion       = QString::number(raw->imgdata.idata.dng_version);
96
0
    identify.sensitivity      = raw->imgdata.other.iso_speed;
97
0
    identify.exposureTime     = raw->imgdata.other.shutter;
98
0
    identify.aperture         = raw->imgdata.other.aperture;
99
0
    identify.focalLength      = raw->imgdata.other.focal_len;
100
0
    identify.imageSize        = QSize(raw->imgdata.sizes.width, raw->imgdata.sizes.height);
101
0
    identify.fullSize         = QSize(raw->imgdata.sizes.raw_width, raw->imgdata.sizes.raw_height);
102
0
    identify.outputSize       = QSize(raw->imgdata.sizes.iwidth, raw->imgdata.sizes.iheight);
103
0
    identify.thumbSize        = QSize(raw->imgdata.thumbnail.twidth, raw->imgdata.thumbnail.theight);
104
0
    identify.topMargin        = raw->imgdata.sizes.top_margin;
105
0
    identify.leftMargin       = raw->imgdata.sizes.left_margin;
106
0
    identify.hasIccProfile    = raw->imgdata.color.profile ? true : false;
107
0
    identify.isDecodable      = true;
108
0
    identify.pixelAspectRatio = raw->imgdata.sizes.pixel_aspect;
109
0
    identify.rawColors        = raw->imgdata.idata.colors;
110
0
    identify.rawImages        = raw->imgdata.idata.raw_count;
111
0
    identify.blackPoint       = raw->imgdata.color.black;
112
113
0
    for (int ch = 0; ch < 4; ch++)
114
0
    {
115
0
        identify.blackPointCh[ch] = raw->imgdata.color.cblack[ch];
116
0
    }
117
118
0
    identify.whitePoint       = raw->imgdata.color.maximum;
119
0
    identify.orientation      = (DcrawInfoContainer::ImageOrientation)raw->imgdata.sizes.flip;
120
121
0
    memcpy(&identify.cameraColorMatrix1, &raw->imgdata.color.cmatrix, sizeof(raw->imgdata.color.cmatrix));
122
0
    memcpy(&identify.cameraColorMatrix2, &raw->imgdata.color.rgb_cam, sizeof(raw->imgdata.color.rgb_cam));
123
0
    memcpy(&identify.cameraXYZMatrix,    &raw->imgdata.color.cam_xyz, sizeof(raw->imgdata.color.cam_xyz));
124
125
0
    if (raw->imgdata.idata.filters)
126
0
    {
127
0
        if (!raw->imgdata.idata.cdesc[3])
128
0
        {
129
0
            raw->imgdata.idata.cdesc[3] = 'G';
130
0
        }
131
132
0
        for (int i=0; i < 16; i++)
133
0
        {
134
0
            identify.filterPattern.append(QChar::fromLatin1(raw->imgdata.idata.cdesc[raw->COLOR(i >> 1, i & 1)]));
135
0
        }
136
137
0
        identify.colorKeys = QString::fromLatin1(raw->imgdata.idata.cdesc);
138
0
    }
139
140
0
    for(int c = 0 ; c < raw->imgdata.idata.colors ; c++)
141
0
    {
142
0
        identify.daylightMult[c] = raw->imgdata.color.pre_mul[c];
143
0
    }
144
145
0
    if (raw->imgdata.color.cam_mul[0] > 0)
146
0
    {
147
0
        for(int c = 0 ; c < 4 ; c++)
148
0
        {
149
0
            identify.cameraMult[c] = raw->imgdata.color.cam_mul[c];
150
0
        }
151
0
    }
152
0
}
153
154
bool KDcrawPrivate::loadFromLibraw(const QString& filePath, QByteArray& imageData,
155
                                     int& width, int& height, int& rgbmax)
156
0
{
157
0
    m_parent->m_cancel = false;
158
159
0
    LibRaw raw;
160
    // Set progress call back function.
161
0
    raw.set_progress_handler(callbackForLibRaw, this);
162
163
0
    QByteArray deadpixelPath = QFile::encodeName(m_parent->m_rawDecodingSettings.deadPixelMap);
164
0
    QByteArray cameraProfile = QFile::encodeName(m_parent->m_rawDecodingSettings.inputProfile);
165
0
    QByteArray outputProfile = QFile::encodeName(m_parent->m_rawDecodingSettings.outputProfile);
166
167
0
    if (!m_parent->m_rawDecodingSettings.autoBrightness)
168
0
    {
169
        // Use a fixed white level, ignoring the image histogram.
170
0
        raw.imgdata.params.no_auto_bright = 1;
171
0
    }
172
173
0
    if (m_parent->m_rawDecodingSettings.sixteenBitsImage)
174
0
    {
175
        // (-4) 16bit ppm output
176
0
        raw.imgdata.params.output_bps = 16;
177
0
    }
178
179
0
    if (m_parent->m_rawDecodingSettings.halfSizeColorImage)
180
0
    {
181
        // (-h) Half-size color image (3x faster than -q).
182
0
        raw.imgdata.params.half_size = 1;
183
0
    }
184
185
0
    if (m_parent->m_rawDecodingSettings.RGBInterpolate4Colors)
186
0
    {
187
        // (-f) Interpolate RGB as four colors.
188
0
        raw.imgdata.params.four_color_rgb = 1;
189
0
    }
190
191
0
    if (m_parent->m_rawDecodingSettings.DontStretchPixels)
192
0
    {
193
        // (-j) Do not stretch the image to its correct aspect ratio.
194
0
        raw.imgdata.params.use_fuji_rotate = 1;
195
0
    }
196
197
    // (-H) Unclip highlight color.
198
0
    raw.imgdata.params.highlight = m_parent->m_rawDecodingSettings.unclipColors;
199
200
0
    if (m_parent->m_rawDecodingSettings.brightness != 1.0)
201
0
    {
202
        // (-b) Set Brightness value.
203
0
        raw.imgdata.params.bright = m_parent->m_rawDecodingSettings.brightness;
204
0
    }
205
206
0
    if (m_parent->m_rawDecodingSettings.enableBlackPoint)
207
0
    {
208
        // (-k) Set Black Point value.
209
0
        raw.imgdata.params.user_black = m_parent->m_rawDecodingSettings.blackPoint;
210
0
    }
211
212
0
    if (m_parent->m_rawDecodingSettings.enableWhitePoint)
213
0
    {
214
        // (-S) Set White Point value (saturation).
215
0
        raw.imgdata.params.user_sat = m_parent->m_rawDecodingSettings.whitePoint;
216
0
    }
217
218
0
    if (m_parent->m_rawDecodingSettings.medianFilterPasses > 0)
219
0
    {
220
        // (-m) After interpolation, clean up color artifacts by repeatedly applying a 3x3 median filter to the R-G and B-G channels.
221
0
        raw.imgdata.params.med_passes = m_parent->m_rawDecodingSettings.medianFilterPasses;
222
0
    }
223
224
0
    if (!m_parent->m_rawDecodingSettings.deadPixelMap.isEmpty())
225
0
    {
226
        // (-P) Read the dead pixel list from this file.
227
0
        raw.imgdata.params.bad_pixels = deadpixelPath.data();
228
0
    }
229
230
0
    switch (m_parent->m_rawDecodingSettings.whiteBalance)
231
0
    {
232
0
        case RawDecodingSettings::NONE:
233
0
        {
234
0
            break;
235
0
        }
236
0
        case RawDecodingSettings::CAMERA:
237
0
        {
238
            // (-w) Use camera white balance, if possible.
239
0
            raw.imgdata.params.use_camera_wb = 1;
240
0
            break;
241
0
        }
242
0
        case RawDecodingSettings::AUTO:
243
0
        {
244
            // (-a) Use automatic white balance.
245
0
            raw.imgdata.params.use_auto_wb = 1;
246
0
            break;
247
0
        }
248
0
        case RawDecodingSettings::CUSTOM:
249
0
        {
250
            /* Convert between Temperature and RGB.
251
             */
252
0
            double T;
253
0
            double RGB[3];
254
0
            double xD, yD, X, Y, Z;
255
0
            DcrawInfoContainer identify;
256
0
            T = m_parent->m_rawDecodingSettings.customWhiteBalance;
257
258
            /* Here starts the code picked and adapted from ufraw (0.12.1)
259
               to convert Temperature + green multiplier to RGB multipliers
260
            */
261
            /* Convert between Temperature and RGB.
262
             * Base on information from http://www.brucelindbloom.com/
263
             * The fit for D-illuminant between 4000K and 12000K are from CIE
264
             * The generalization to 2000K < T < 4000K and the blackbody fits
265
             * are my own and should be taken with a grain of salt.
266
             */
267
0
            const double XYZ_to_RGB[3][3] = {
268
0
                                                { 3.24071,  -0.969258,  0.0556352 },
269
0
                                                {-1.53726,  1.87599,    -0.203996 },
270
0
                                                {-0.498571, 0.0415557,  1.05707   }
271
0
                                            };
272
273
            // Fit for CIE Daylight illuminant
274
0
            if (T <= 4000)
275
0
            {
276
0
                xD = 0.27475e9/(T*T*T) - 0.98598e6/(T*T) + 1.17444e3/T + 0.145986;
277
0
            }
278
0
            else if (T <= 7000)
279
0
            {
280
0
                xD = -4.6070e9/(T*T*T) + 2.9678e6/(T*T) + 0.09911e3/T + 0.244063;
281
0
            }
282
0
            else
283
0
            {
284
0
                xD = -2.0064e9/(T*T*T) + 1.9018e6/(T*T) + 0.24748e3/T + 0.237040;
285
0
            }
286
287
0
            yD     = -3*xD*xD + 2.87*xD - 0.275;
288
0
            X      = xD/yD;
289
0
            Y      = 1;
290
0
            Z      = (1-xD-yD)/yD;
291
0
            RGB[0] = X*XYZ_to_RGB[0][0] + Y*XYZ_to_RGB[1][0] + Z*XYZ_to_RGB[2][0];
292
0
            RGB[1] = X*XYZ_to_RGB[0][1] + Y*XYZ_to_RGB[1][1] + Z*XYZ_to_RGB[2][1];
293
0
            RGB[2] = X*XYZ_to_RGB[0][2] + Y*XYZ_to_RGB[1][2] + Z*XYZ_to_RGB[2][2];
294
            /* End of the code picked to ufraw
295
            */
296
297
0
            RGB[1] = RGB[1] / m_parent->m_rawDecodingSettings.customWhiteBalanceGreen;
298
299
            /* By default, decraw override his default D65 WB
300
               We need to keep it as a basis : if not, colors with some
301
               DSLR will have a high dominant of color that will lead to
302
               a completely wrong WB
303
            */
304
0
            if (KDcraw::rawFileIdentify(identify, filePath))
305
0
            {
306
0
                RGB[0] = identify.daylightMult[0] / RGB[0];
307
0
                RGB[1] = identify.daylightMult[1] / RGB[1];
308
0
                RGB[2] = identify.daylightMult[2] / RGB[2];
309
0
            }
310
0
            else
311
0
            {
312
0
                RGB[0] = 1.0 / RGB[0];
313
0
                RGB[1] = 1.0 / RGB[1];
314
0
                RGB[2] = 1.0 / RGB[2];
315
0
                qCDebug(LIBKDCRAW_LOG) << "Warning: cannot get daylight multipliers";
316
0
            }
317
318
            // (-r) set Raw Color Balance Multipliers.
319
0
            raw.imgdata.params.user_mul[0] = RGB[0];
320
0
            raw.imgdata.params.user_mul[1] = RGB[1];
321
0
            raw.imgdata.params.user_mul[2] = RGB[2];
322
0
            raw.imgdata.params.user_mul[3] = RGB[1];
323
0
            break;
324
0
        }
325
0
        case RawDecodingSettings::AERA:
326
0
        {
327
            // (-A) Calculate the white balance by averaging a rectangular area from image.
328
0
            raw.imgdata.params.greybox[0] = m_parent->m_rawDecodingSettings.whiteBalanceArea.left();
329
0
            raw.imgdata.params.greybox[1] = m_parent->m_rawDecodingSettings.whiteBalanceArea.top();
330
0
            raw.imgdata.params.greybox[2] = m_parent->m_rawDecodingSettings.whiteBalanceArea.width();
331
0
            raw.imgdata.params.greybox[3] = m_parent->m_rawDecodingSettings.whiteBalanceArea.height();
332
0
            break;
333
0
        }
334
0
    }
335
336
    // (-q) Use an interpolation method.
337
0
    raw.imgdata.params.user_qual = m_parent->m_rawDecodingSettings.RAWQuality;
338
339
0
    switch (m_parent->m_rawDecodingSettings.NRType)
340
0
    {
341
0
        case RawDecodingSettings::WAVELETSNR:
342
0
        {
343
            // (-n) Use wavelets to erase noise while preserving real detail.
344
0
            raw.imgdata.params.threshold    = m_parent->m_rawDecodingSettings.NRThreshold;
345
0
            break;
346
0
        }
347
0
        case RawDecodingSettings::FBDDNR:
348
0
        {
349
            // (100 - 1000) => (1 - 10) conversion
350
0
            raw.imgdata.params.fbdd_noiserd = lround(m_parent->m_rawDecodingSettings.NRThreshold / 100.0);
351
0
            break;
352
0
        }
353
#if !LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 19)
354
        case RawDecodingSettings::LINENR:
355
        {
356
            // (100 - 1000) => (0.001 - 0.02) conversion.
357
            raw.imgdata.params.linenoise    = m_parent->m_rawDecodingSettings.NRThreshold * 2.11E-5 + 0.00111111;
358
            raw.imgdata.params.cfaline      = true;
359
            break;
360
        }
361
362
        case RawDecodingSettings::IMPULSENR:
363
        {
364
            // (100 - 1000) => (0.005 - 0.05) conversion.
365
            raw.imgdata.params.lclean       = m_parent->m_rawDecodingSettings.NRThreshold     * 5E-5;
366
            raw.imgdata.params.cclean       = m_parent->m_rawDecodingSettings.NRChroThreshold * 5E-5;
367
            raw.imgdata.params.cfa_clean    = true;
368
            break;
369
        }
370
#endif
371
0
        default:   // No Noise Reduction
372
0
        {
373
0
            raw.imgdata.params.threshold    = 0;
374
0
            raw.imgdata.params.fbdd_noiserd = 0;
375
#if !LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 19)
376
            raw.imgdata.params.linenoise    = 0;
377
            raw.imgdata.params.cfaline      = false;
378
            raw.imgdata.params.lclean       = 0;
379
            raw.imgdata.params.cclean       = 0;
380
            raw.imgdata.params.cfa_clean    = false;
381
#endif
382
0
            break;
383
0
        }
384
0
    }
385
386
#if !LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 19)
387
    // Chromatic aberration correction.
388
    raw.imgdata.params.ca_correc  = m_parent->m_rawDecodingSettings.enableCACorrection;
389
    raw.imgdata.params.cared      = m_parent->m_rawDecodingSettings.caMultiplier[0];
390
    raw.imgdata.params.cablue     = m_parent->m_rawDecodingSettings.caMultiplier[1];
391
#endif
392
393
    // Exposure Correction before interpolation.
394
0
    raw.imgdata.params.exp_correc = m_parent->m_rawDecodingSettings.expoCorrection;
395
0
    raw.imgdata.params.exp_shift  = m_parent->m_rawDecodingSettings.expoCorrectionShift;
396
0
    raw.imgdata.params.exp_preser = m_parent->m_rawDecodingSettings.expoCorrectionHighlight;
397
398
0
    switch (m_parent->m_rawDecodingSettings.inputColorSpace)
399
0
    {
400
0
        case RawDecodingSettings::EMBEDDED:
401
0
        {
402
            // (-p embed) Use input profile from RAW file to define the camera's raw colorspace.
403
0
            raw.imgdata.params.camera_profile = (char*)"embed";
404
0
            break;
405
0
        }
406
0
        case RawDecodingSettings::CUSTOMINPUTCS:
407
0
        {
408
0
            if (!m_parent->m_rawDecodingSettings.inputProfile.isEmpty())
409
0
            {
410
                // (-p) Use input profile file to define the camera's raw colorspace.
411
0
                raw.imgdata.params.camera_profile = cameraProfile.data();
412
0
            }
413
0
            break;
414
0
        }
415
0
        default:
416
0
        {
417
            // No input profile
418
0
            break;
419
0
        }
420
0
    }
421
422
0
    switch (m_parent->m_rawDecodingSettings.outputColorSpace)
423
0
    {
424
0
        case RawDecodingSettings::CUSTOMOUTPUTCS:
425
0
        {
426
0
            if (!m_parent->m_rawDecodingSettings.outputProfile.isEmpty())
427
0
            {
428
                // (-o) Use ICC profile file to define the output colorspace.
429
0
                raw.imgdata.params.output_profile = outputProfile.data();
430
0
            }
431
0
            break;
432
0
        }
433
0
        default:
434
0
        {
435
            // (-o) Define the output colorspace.
436
0
            raw.imgdata.params.output_color = m_parent->m_rawDecodingSettings.outputColorSpace;
437
0
            break;
438
0
        }
439
0
    }
440
441
    //-- Extended demosaicing settings ----------------------------------------------------------
442
443
0
    raw.imgdata.params.dcb_iterations = m_parent->m_rawDecodingSettings.dcbIterations;
444
0
    raw.imgdata.params.dcb_enhance_fl = m_parent->m_rawDecodingSettings.dcbEnhanceFl;
445
#if !LIBRAW_COMPILE_CHECK_VERSION_NOTLESS(0, 19)
446
    raw.imgdata.params.eeci_refine    = m_parent->m_rawDecodingSettings.eeciRefine;
447
    raw.imgdata.params.es_med_passes  = m_parent->m_rawDecodingSettings.esMedPasses;
448
#endif
449
450
    //-------------------------------------------------------------------------------------------
451
452
0
    setProgress(0.1);
453
454
0
    qCDebug(LIBKDCRAW_LOG) << filePath;
455
0
    qCDebug(LIBKDCRAW_LOG) << m_parent->m_rawDecodingSettings;
456
457
0
    int ret = raw.open_file((const char*)(QFile::encodeName(filePath)).constData());
458
459
0
    if (ret != LIBRAW_SUCCESS)
460
0
    {
461
0
        qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run open_file: " << libraw_strerror(ret);
462
0
        raw.recycle();
463
0
        return false;
464
0
    }
465
466
0
    if (m_parent->m_cancel)
467
0
    {
468
0
        raw.recycle();
469
0
        return false;
470
0
    }
471
472
0
    setProgress(0.2);
473
474
0
    ret = raw.unpack();
475
476
0
    if (ret != LIBRAW_SUCCESS)
477
0
    {
478
0
        qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run unpack: " << libraw_strerror(ret);
479
0
        raw.recycle();
480
0
        return false;
481
0
    }
482
483
0
    if (m_parent->m_cancel)
484
0
    {
485
0
        raw.recycle();
486
0
        return false;
487
0
    }
488
489
0
    setProgress(0.25);
490
491
0
    if (m_parent->m_rawDecodingSettings.fixColorsHighlights)
492
0
    {
493
0
        qCDebug(LIBKDCRAW_LOG) << "Applying LibRaw highlights adjustments";
494
        // 1.0 is fallback to default value
495
0
        raw.imgdata.params.adjust_maximum_thr = 1.0;
496
0
    }
497
0
    else
498
0
    {
499
0
        qCDebug(LIBKDCRAW_LOG) << "Disabling LibRaw highlights adjustments";
500
        // 0.0 disables this feature
501
0
        raw.imgdata.params.adjust_maximum_thr = 0.0;
502
0
    }
503
504
0
    ret = raw.dcraw_process();
505
506
0
    if (ret != LIBRAW_SUCCESS)
507
0
    {
508
0
        qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_process: " << libraw_strerror(ret);
509
0
        raw.recycle();
510
0
        return false;
511
0
    }
512
513
0
    if (m_parent->m_cancel)
514
0
    {
515
0
        raw.recycle();
516
0
        return false;
517
0
    }
518
519
0
    setProgress(0.3);
520
521
0
    libraw_processed_image_t* img = raw.dcraw_make_mem_image(&ret);
522
523
0
    if(!img)
524
0
    {
525
0
        qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_make_mem_image: " << libraw_strerror(ret);
526
0
        raw.recycle();
527
0
        return false;
528
0
    }
529
530
0
    if (m_parent->m_cancel)
531
0
    {
532
        // Clear memory allocation. Introduced with LibRaw 0.11.0
533
0
        raw.dcraw_clear_mem(img);
534
0
        raw.recycle();
535
0
        return false;
536
0
    }
537
538
0
    setProgress(0.35);
539
540
0
    width  = img->width;
541
0
    height = img->height;
542
0
    rgbmax = (1 << img->bits)-1;
543
544
0
    if (img->colors == 3)
545
0
    {
546
0
        imageData = QByteArray((const char*)img->data, (int)img->data_size);
547
0
    }
548
0
    else
549
0
    {
550
        // img->colors == 1 (Grayscale) : convert to RGB
551
0
        imageData = QByteArray();
552
553
0
        for (int i = 0 ; i < (int)img->data_size ; ++i)
554
0
        {
555
0
            for (int j = 0 ; j < 3 ; ++j)
556
0
            {
557
0
                imageData.append(img->data[i]);
558
0
            }
559
0
        }
560
0
    }
561
562
    // Clear memory allocation. Introduced with LibRaw 0.11.0
563
0
    raw.dcraw_clear_mem(img);
564
0
    raw.recycle();
565
566
0
    if (m_parent->m_cancel)
567
0
    {
568
0
        return false;
569
0
    }
570
571
0
    setProgress(0.4);
572
573
0
    qCDebug(LIBKDCRAW_LOG) << "LibRaw: data info: width=" << width
574
0
             << " height=" << height
575
0
             << " rgbmax=" << rgbmax;
576
577
0
    return true;
578
0
}
579
580
bool KDcrawPrivate::loadEmbeddedPreview(QByteArray& imgData, LibRaw& raw)
581
0
{
582
0
    int ret = raw.unpack_thumb();
583
584
0
    if (ret != LIBRAW_SUCCESS)
585
0
    {
586
0
        raw.recycle();
587
0
        qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run unpack_thumb: " << libraw_strerror(ret);
588
0
        raw.recycle();
589
0
        return false;
590
0
    }
591
592
0
    libraw_processed_image_t* const thumb = raw.dcraw_make_mem_thumb(&ret);
593
594
0
    if(!thumb)
595
0
    {
596
0
        qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_make_mem_thumb: " << libraw_strerror(ret);
597
0
        raw.recycle();
598
0
        return false;
599
0
    }
600
601
0
    if(thumb->type == LIBRAW_IMAGE_BITMAP)
602
0
    {
603
0
        createPPMHeader(imgData, thumb);
604
0
    }
605
0
    else
606
0
    {
607
0
        imgData = QByteArray((const char*)thumb->data, (int)thumb->data_size);
608
0
    }
609
610
    // Clear memory allocation. Introduced with LibRaw 0.11.0
611
0
    raw.dcraw_clear_mem(thumb);
612
0
    raw.recycle();
613
614
0
    if ( imgData.isEmpty() )
615
0
    {
616
0
        qCDebug(LIBKDCRAW_LOG) << "Failed to load JPEG thumb from LibRaw!";
617
0
        return false;
618
0
    }
619
620
0
    return true;
621
0
}
622
623
bool KDcrawPrivate::loadHalfPreview(QImage& image, LibRaw& raw)
624
0
{
625
0
    raw.imgdata.params.use_auto_wb   = 1;         // Use automatic white balance.
626
0
    raw.imgdata.params.use_camera_wb = 1;         // Use camera white balance, if possible.
627
0
    raw.imgdata.params.half_size     = 1;         // Half-size color image (3x faster than -q).
628
0
    QByteArray imgData;
629
630
0
    int ret = raw.unpack();
631
632
0
    if (ret != LIBRAW_SUCCESS)
633
0
    {
634
0
        qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run unpack: " << libraw_strerror(ret);
635
0
        raw.recycle();
636
0
        return false;
637
0
    }
638
639
0
    ret = raw.dcraw_process();
640
641
0
    if (ret != LIBRAW_SUCCESS)
642
0
    {
643
0
        qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_process: " << libraw_strerror(ret);
644
0
        raw.recycle();
645
0
        return false;
646
0
    }
647
648
0
    libraw_processed_image_t* halfImg = raw.dcraw_make_mem_image(&ret);
649
650
0
    if(!halfImg)
651
0
    {
652
0
        qCDebug(LIBKDCRAW_LOG) << "LibRaw: failed to run dcraw_make_mem_image: " << libraw_strerror(ret);
653
0
        raw.recycle();
654
0
        return false;
655
0
    }
656
657
0
    KDcrawPrivate::createPPMHeader(imgData, halfImg);
658
    // Clear memory allocation. Introduced with LibRaw 0.11.0
659
0
    raw.dcraw_clear_mem(halfImg);
660
0
    raw.recycle();
661
662
0
    if ( imgData.isEmpty() )
663
0
    {
664
0
        qCDebug(LIBKDCRAW_LOG) << "Failed to load half preview from LibRaw!";
665
0
        return false;
666
0
    }
667
668
0
    if (!image.loadFromData(imgData))
669
0
    {
670
0
        qCDebug(LIBKDCRAW_LOG) << "Failed to load PPM data from LibRaw!";
671
0
        return false;
672
0
    }
673
674
0
    return true;
675
0
}
676
677
}  // namespace KDcrawIface