Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
imageio_libraw.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2021 Daniel Vogelbacher.
4 Copyright (C) 2021-2022 Miloš Komarčević.
5 Copyright (C) 2021-2022 Pascal Obry.
6 Copyright (C) 2022 Martin Bařinka.
7 Copyright (C) 2022 Philipp Lutz.
8 Copyright (C) 2023 Aurélien PIERRE.
9
10 darktable is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 darktable is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with darktable. If not, see <http://www.gnu.org/licenses/>.
22*/
23
24#ifdef HAVE_LIBRAW
25#include "common/darktable.h"
26#include "imageio.h"
27#include "imageio_gm.h"
28#include "develop/develop.h"
29#include "common/exif.h"
30#include "common/colorspaces.h"
31#include "control/conf.h"
32
33#include <memory.h>
34#include <stdio.h>
35#include <inttypes.h>
36#include <strings.h>
37#include <assert.h>
38
39#include <libraw/libraw.h>
40
41
42typedef struct model_map
43{
44 const gchar *exif_make;
45 const gchar *exif_model;
46 const gchar *clean_make;
47 const gchar *clean_model;
48 const gchar *clean_alias;
49
50} model_map_t;
51
52
53const model_map_t modelMap[] = {
54 {
55 .exif_make = "Canon",
56 .exif_model = "Canon EOS R",
57 .clean_make = "Canon",
58 .clean_model = "EOS R",
59 .clean_alias = "EOS R"
60 },
61 {
62 .exif_make = "Canon",
63 .exif_model = "Canon EOS RP",
64 .clean_make = "Canon",
65 .clean_model = "EOS RP",
66 .clean_alias = "EOS RP"
67 },
68 {
69 .exif_make = "Canon",
70 .exif_model = "Canon EOS R5",
71 .clean_make = "Canon",
72 .clean_model = "EOS R5",
73 .clean_alias = "EOS R5"
74 },
75 {
76 .exif_make = "Canon",
77 .exif_model = "Canon EOS R6",
78 .clean_make = "Canon",
79 .clean_model = "EOS R6",
80 .clean_alias = "EOS R6"
81 },
82 {
83 .exif_make = "Canon",
84 .exif_model = "Canon EOS R3",
85 .clean_make = "Canon",
86 .clean_model = "EOS R3",
87 .clean_alias = "EOS R3"
88 },
89 {
90 .exif_make = "Canon",
91 .exif_model = "Canon EOS R7",
92 .clean_make = "Canon",
93 .clean_model = "EOS R7",
94 .clean_alias = "EOS R7"
95 },
96 {
97 .exif_make = "Canon",
98 .exif_model = "Canon EOS R10",
99 .clean_make = "Canon",
100 .clean_model = "EOS R10",
101 .clean_alias = "EOS R10"
102 },
103 {
104 .exif_make = "Canon",
105 .exif_model = "Canon EOS M50",
106 .clean_make = "Canon",
107 .clean_model = "EOS M50",
108 .clean_alias = "EOS M50"
109 },
110 {
111 .exif_make = "Canon",
112 .exif_model = "Canon EOS KISS M",
113 .clean_make = "Canon",
114 .clean_model = "EOS M50",
115 .clean_alias = "EOS KISS M"
116 },
117 {
118 .exif_make = "Canon",
119 .exif_model = "Canon EOS M50m2",
120 .clean_make = "Canon",
121 .clean_model = "EOS M50 Mark II",
122 .clean_alias = "EOS M50 Mark II"
123 },
124 {
125 .exif_make = "Canon",
126 .exif_model = "Canon EOS KISS M2",
127 .clean_make = "Canon",
128 .clean_model = "EOS M50 Mark II",
129 .clean_alias = "EOS KISS M2"
130 },
131 {
132 .exif_make = "Canon",
133 .exif_model = "Canon EOS M6 Mark II",
134 .clean_make = "Canon",
135 .clean_model = "EOS M6 Mark II",
136 .clean_alias = "EOS M6 Mark II"
137 },
138 {
139 .exif_make = "Canon",
140 .exif_model = "Canon EOS M200",
141 .clean_make = "Canon",
142 .clean_model = "EOS M200",
143 .clean_alias = "EOS M200"
144 },
145 {
146 .exif_make = "Canon",
147 .exif_model = "Canon EOS 250D",
148 .clean_make = "Canon",
149 .clean_model = "EOS 250D",
150 .clean_alias = "EOS 250D"
151 },
152 {
153 .exif_make = "Canon",
154 .exif_model = "Canon EOS Kiss X10",
155 .clean_make = "Canon",
156 .clean_model = "EOS 250D",
157 .clean_alias = "EOS Kiss X10"
158 },
159 {
160 .exif_make = "Canon",
161 .exif_model = "Canon EOS Rebel SL3",
162 .clean_make = "Canon",
163 .clean_model = "EOS 250D",
164 .clean_alias = "EOS Rebel SL3"
165 },
166 {
167 .exif_make = "Canon",
168 .exif_model = "Canon EOS 200D II",
169 .clean_make = "Canon",
170 .clean_model = "EOS 250D",
171 .clean_alias = "EOS 200D Mark II"
172 },
173 {
174 .exif_make = "Canon",
175 .exif_model = "Canon EOS 850D",
176 .clean_make = "Canon",
177 .clean_model = "EOS 850D",
178 .clean_alias = "EOS 850D"
179 },
180 {
181 .exif_make = "Canon",
182 .exif_model = "Canon EOS Kiss X10i",
183 .clean_make = "Canon",
184 .clean_model = "EOS 850D",
185 .clean_alias = "EOS Kiss X10i"
186 },
187 {
188 .exif_make = "Canon",
189 .exif_model = "Canon EOS Rebel T8i",
190 .clean_make = "Canon",
191 .clean_model = "EOS 850D",
192 .clean_alias = "EOS Rebel T8i"
193 },
194 {
195 .exif_make = "Canon",
196 .exif_model = "Canon EOS 90D",
197 .clean_make = "Canon",
198 .clean_model = "EOS 90D",
199 .clean_alias = "EOS 90D"
200 },
201 {
202 .exif_make = "Canon",
203 .exif_model = "Canon EOS-1D X Mark III",
204 .clean_make = "Canon",
205 .clean_model = "EOS-1D X Mark III",
206 .clean_alias = "EOS-1D X Mark III"
207 },
208 {
209 .exif_make = "Canon",
210 .exif_model = "Canon PowerShot G7 X Mark III",
211 .clean_make = "Canon",
212 .clean_model = "PowerShot G7 X Mark III",
213 .clean_alias = "PowerShot G7 X Mark III"
214 },
215 {
216 .exif_make = "Canon",
217 .exif_model = "Canon PowerShot G5 X Mark II",
218 .clean_make = "Canon",
219 .clean_model = "PowerShot G5 X Mark II",
220 .clean_alias = "PowerShot G5 X Mark II"
221 }
222};
223
224gboolean dt_libraw_lookup_makermodel(const char *maker, const char *model,
225 char *mk, int mk_len, char *md, int md_len,
226 char *al, int al_len)
227{
228 for(int i = 0; i < sizeof(modelMap) / sizeof(modelMap[0]); ++i)
229 {
230 if(!g_strcmp0(maker, modelMap[i].exif_make) && !g_strcmp0(model, modelMap[i].exif_model))
231 {
232 //printf("input model: %s, exif model: %s\n", model, modelMap[i].exif_model);
233 g_strlcpy(mk, modelMap[i].clean_make, mk_len);
234 g_strlcpy(md, modelMap[i].clean_model, md_len);
235 g_strlcpy(al, modelMap[i].clean_alias, al_len);
236 return TRUE;
237 }
238 }
239 return FALSE;
240}
241
242
244{
246 int libraw_err = LIBRAW_SUCCESS;
247 if(!img->exif_inited) (void)dt_exif_read(img, filename);
248
249 libraw_data_t *raw = libraw_init(0);
251
252#if defined(_WIN32) && (defined(UNICODE) || defined(_UNICODE))
253 wchar_t *wfilename = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL);
254 libraw_err = libraw_open_wfile(raw, wfilename);
255 dt_free(wfilename);
256#else
257 libraw_err = libraw_open_file(raw, filename);
258#endif
259 if(libraw_err != LIBRAW_SUCCESS) goto error;
260
261 libraw_err = libraw_unpack(raw);
262 if(libraw_err != LIBRAW_SUCCESS) goto error;
263
264 // Bad method to detect if camera is fully supported by LibRaw,
265 // but seems to be the best available. LibRaw crx decoder can actually
266 // decode the raw data, but internal metadata like wb_coeffs, crops etc.
267 // are not populated into libraw structure, or image is not of CFA type.
268 if(raw->rawdata.color.cam_mul[0] == 0.0f || isnan(raw->rawdata.color.cam_mul[0]) || IS_NULL_PTR(raw->rawdata.raw_image))
269 {
270 fprintf(stderr, "[libraw_open] detected unsupported image `%s'\n", img->filename);
271 goto error;
272 }
273
274 // Copy white level (all linear_max[] equal single SpecularWhiteLevel for CR3, we can skip min or mean)
275 img->raw_white_point = raw->rawdata.color.linear_max[0] ? raw->rawdata.color.linear_max[0] :raw->rawdata.color.maximum;
276
277 // Copy black level
278 img->raw_black_level = raw->rawdata.color.black;
279 for(size_t c = 0; c < 4; ++c)
280 img->raw_black_level_separate[c] = raw->rawdata.color.black + raw->rawdata.color.cblack[c];
281
282 // AsShot WB coeffs
283 for(size_t c = 0; c < 4; ++c)
284 img->wb_coeffs[c] = raw->rawdata.color.cam_mul[c];
285
286 // Grab the adobe coeff
287 for(int k = 0; k < 4; k++)
288 for(int i = 0; i < 3; i++)
289 img->adobe_XYZ_to_CAM[k][i] = raw->rawdata.color.cam_xyz[k][i];
290
291 // Raw dimensions. This is the full sensor range.
292 img->width = raw->rawdata.sizes.raw_width;
293 img->height = raw->rawdata.sizes.raw_height;
294
295 // Apply crop parameters
296 libraw_raw_inset_crop_t *ric = &raw->rawdata.sizes.raw_inset_crops[0];
297 img->crop_x = ric->cleft;
298 img->crop_y = ric->ctop;
299 img->crop_width = raw->rawdata.sizes.raw_width - ric->cwidth - ric->cleft;
300 img->crop_height = raw->rawdata.sizes.raw_height - ric->cheight - ric->ctop;
301
302 // In general we should run through entire post-processing to get corrected filters.
303 // This incurs a significant performance penalty.
304 libraw_err = libraw_dcraw_process(raw);
305 if(libraw_err != LIBRAW_SUCCESS) goto error;
306 img->dsc.filters = raw->idata.filters;
307
308 // For CR3, we only have Bayer data and a single channel
309 img->dsc.channels = 1;
310 img->dsc.datatype = TYPE_UINT16;
311 img->dsc.bpp = sizeof(uint16_t);
312 img->dsc.cst = IOP_CS_RAW;
313
315 {
316 img->flags |= DT_IMAGE_4BAYER;
317 }
318 else
319 {
320 img->flags &= ~DT_IMAGE_4BAYER;
321 }
322
323 if(img->dsc.filters)
324 {
325 img->flags &= ~DT_IMAGE_LDR;
326 img->flags &= ~DT_IMAGE_HDR;
327 img->flags |= DT_IMAGE_RAW;
328 }
329 else
330 {
331 // ldr dng. it exists :(
332 img->flags &= ~DT_IMAGE_RAW;
333 img->flags &= ~DT_IMAGE_HDR;
334 img->flags |= DT_IMAGE_LDR;
335 }
336
337 img->loader = LOADER_LIBRAW;
338
339 if(IS_NULL_PTR(mbuf))
340 {
341 err = DT_IMAGEIO_OK;
342 goto error;
343 }
344
345 // Allocate and copy image from libraw buffer to dt
346 void *buf = dt_mipmap_cache_alloc(mbuf, img);
347 if(IS_NULL_PTR(buf))
348 {
349 fprintf(stderr, "[libraw_open] could not alloc full buffer for image `%s'\n", img->filename);
351 goto error;
352 }
353 // Use faster memcpy if buffer sizes are equal
354 const size_t bufSize_mipmap = (size_t)img->width * img->height * sizeof(uint16_t);
355 const size_t bufSize_libraw = (size_t)raw->rawdata.sizes.raw_pitch * raw->rawdata.sizes.raw_height;
356 if(bufSize_mipmap == bufSize_libraw)
357 {
358 memcpy(buf, raw->rawdata.raw_image, bufSize_mipmap);
359 }
360 else
361 {
362 dt_imageio_flip_buffers((char *)buf, (char *)raw->rawdata.raw_image, sizeof(uint16_t),
363 raw->rawdata.sizes.raw_width, raw->rawdata.sizes.raw_height,
364 raw->rawdata.sizes.raw_width, raw->rawdata.sizes.raw_height,
365 raw->rawdata.sizes.raw_pitch, ORIENTATION_NONE);
366 }
367
368 err = DT_IMAGEIO_OK;
369
370error:
371 if(libraw_err != LIBRAW_SUCCESS)
372 fprintf(stderr, "[libraw_open] `%s': %s\n", img->filename, libraw_strerror(libraw_err));
373 libraw_close(raw);
374 return err;
375}
376#endif
377
378// clang-format off
379// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
380// vim: shiftwidth=2 expandtab tabstop=2 cindent
381// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
382// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
@ IOP_CS_RAW
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
#define dt_free(ptr)
Definition darktable.h:456
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
int dt_exif_read(dt_image_t *img, const char *path)
Definition exif.cc:1753
@ TYPE_UINT16
Definition format.h:47
@ ORIENTATION_NONE
Definition image.h:205
dt_imageio_retval_t
Definition image.h:78
@ DT_IMAGEIO_OK
Definition image.h:79
@ DT_IMAGEIO_CACHE_FULL
Definition image.h:82
@ DT_IMAGEIO_FILE_CORRUPTED
Definition image.h:81
@ DT_IMAGE_RAW
Definition image.h:111
@ DT_IMAGE_4BAYER
Definition image.h:127
@ DT_IMAGE_LDR
Definition image.h:109
@ LOADER_LIBRAW
Definition image.h:236
__DT_CLONE_TARGETS__ void dt_imageio_flip_buffers(char *out, const char *in, const size_t bpp, const int wd, const int ht, const int fwd, const int fht, const int stride, const dt_image_orientation_t orientation)
Definition imageio.c:398
#define FILTERS_ARE_4BAYER(filters)
Definition imageio.h:55
dt_imageio_retval_t dt_imageio_open_libraw(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
gboolean dt_libraw_lookup_makermodel(const char *maker, const char *model, char *mk, int mk_len, char *md, int md_len, char *al, int al_len)
const char * maker
const char * model
float *const restrict const size_t k
void * dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img)
int32_t height
Definition image.h:315
uint16_t raw_black_level
Definition image.h:350
dt_image_loader_t loader
Definition image.h:335
uint32_t raw_white_point
Definition image.h:352
int32_t exif_inited
Definition image.h:283
int32_t crop_height
Definition image.h:316
int32_t flags
Definition image.h:319
int32_t width
Definition image.h:315
int32_t crop_y
Definition image.h:316
int32_t crop_x
Definition image.h:316
dt_iop_buffer_dsc_t dsc
Definition image.h:337
float adobe_XYZ_to_CAM[4][3]
Definition image.h:362
int32_t crop_width
Definition image.h:316
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:304
uint16_t raw_black_level_separate[4]
Definition image.h:351
dt_aligned_pixel_t wb_coeffs
Definition image.h:359
uint32_t filters
Definition format.h:60
unsigned int channels
Definition format.h:54
dt_iop_buffer_type_t datatype
Definition format.h:56