/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 |