1 /*
2 This file is part of darktable,
3 Copyright (C) 2009-2021 darktable developers.
4
5 darktable is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 darktable is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with darktable. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #ifdef HAVE_CONFIG_H
19 #include "config.h"
20 #endif
21 #include "common/colorlabels.h"
22 #include "common/colorspaces.h"
23 #include "common/darktable.h"
24 #include "common/debug.h"
25 #include "common/exif.h"
26 #include "common/image_cache.h"
27 #include "common/imageio.h"
28 #include "common/imageio_module.h"
29 #ifdef HAVE_OPENEXR
30 #include "common/imageio_exr.h"
31 #endif
32 #ifdef HAVE_OPENJPEG
33 #include "common/imageio_j2k.h"
34 #endif
35 #include "common/image_compression.h"
36 #include "common/imageio_gm.h"
37 #include "common/imageio_im.h"
38 #include "common/imageio_jpeg.h"
39 #include "common/imageio_pfm.h"
40 #include "common/imageio_png.h"
41 #include "common/imageio_pnm.h"
42 #include "common/imageio_rawspeed.h"
43 #include "common/imageio_rgbe.h"
44 #include "common/imageio_tiff.h"
45 #ifdef HAVE_LIBAVIF
46 #include "common/imageio_avif.h"
47 #endif
48 #include "common/mipmap_cache.h"
49 #include "common/styles.h"
50 #include "control/conf.h"
51 #include "control/control.h"
52 #include "develop/blend.h"
53 #include "develop/develop.h"
54 #include "develop/imageop.h"
55
56 #ifdef HAVE_GRAPHICSMAGICK
57 #include <magick/api.h>
58 #include <magick/blob.h>
59 #elif defined HAVE_IMAGEMAGICK
60 #include <MagickWand/MagickWand.h>
61 #endif
62
63 #include <assert.h>
64 #include <glib/gstdio.h>
65 #include <inttypes.h>
66 #include <math.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <strings.h>
71
72 #ifdef USE_LUA
73 #include "lua/image.h"
74 #endif
75
76 // load a full-res thumbnail:
dt_imageio_large_thumbnail(const char * filename,uint8_t ** buffer,int32_t * width,int32_t * height,dt_colorspaces_color_profile_type_t * color_space)77 int dt_imageio_large_thumbnail(const char *filename, uint8_t **buffer, int32_t *width, int32_t *height,
78 dt_colorspaces_color_profile_type_t *color_space)
79 {
80 int res = 1;
81
82 uint8_t *buf = NULL;
83 char *mime_type = NULL;
84 size_t bufsize;
85
86 // get the biggest thumb from exif
87 if(dt_exif_get_thumbnail(filename, &buf, &bufsize, &mime_type)) goto error;
88
89 if(strcmp(mime_type, "image/jpeg") == 0)
90 {
91 // Decompress the JPG into our own memory format
92 dt_imageio_jpeg_t jpg;
93 if(dt_imageio_jpeg_decompress_header(buf, bufsize, &jpg)) goto error;
94 *buffer = (uint8_t *)dt_alloc_align(64, sizeof(uint8_t) * 4 * jpg.width * jpg.height);
95 if(!*buffer) goto error;
96
97 *width = jpg.width;
98 *height = jpg.height;
99 // TODO: check if the embedded thumbs have a color space set! currently we assume that it's always sRGB
100 *color_space = DT_COLORSPACE_SRGB;
101 if(dt_imageio_jpeg_decompress(&jpg, *buffer))
102 {
103 dt_free_align(*buffer);
104 *buffer = NULL;
105 goto error;
106 }
107
108 res = 0;
109 }
110 else
111 {
112 #ifdef HAVE_GRAPHICSMAGICK
113 ExceptionInfo exception;
114 Image *image = NULL;
115 ImageInfo *image_info = NULL;
116
117 GetExceptionInfo(&exception);
118 image_info = CloneImageInfo((ImageInfo *)NULL);
119
120 image = BlobToImage(image_info, buf, bufsize, &exception);
121
122 if(exception.severity != UndefinedException) CatchException(&exception);
123
124 if(!image)
125 {
126 fprintf(stderr, "[dt_imageio_large_thumbnail GM] thumbnail not found?\n");
127 goto error_gm;
128 }
129
130 *width = image->columns;
131 *height = image->rows;
132 *color_space = DT_COLORSPACE_SRGB; // FIXME: this assumes that embedded thumbnails are always srgb
133
134 *buffer = (uint8_t *)dt_alloc_align(64, sizeof(uint8_t) * 4 * image->columns * image->rows);
135 if(!*buffer) goto error_gm;
136
137 for(uint32_t row = 0; row < image->rows; row++)
138 {
139 uint8_t *bufprt = *buffer + (size_t)4 * row * image->columns;
140 int gm_ret = DispatchImage(image, 0, row, image->columns, 1, "RGBP", CharPixel, bufprt, &exception);
141
142 if(exception.severity != UndefinedException) CatchException(&exception);
143
144 if(gm_ret != MagickPass)
145 {
146 fprintf(stderr, "[dt_imageio_large_thumbnail GM] error_gm reading thumbnail\n");
147 dt_free_align(*buffer);
148 *buffer = NULL;
149 goto error_gm;
150 }
151 }
152
153 // fprintf(stderr, "[dt_imageio_large_thumbnail GM] successfully decoded thumbnail\n");
154 res = 0;
155
156 error_gm:
157 if(image) DestroyImage(image);
158 if(image_info) DestroyImageInfo(image_info);
159 DestroyExceptionInfo(&exception);
160 if(res) goto error;
161 #elif defined HAVE_IMAGEMAGICK
162 MagickWand *image = NULL;
163 MagickBooleanType mret;
164
165 image = NewMagickWand();
166 mret = MagickReadImageBlob(image, buf, bufsize);
167 if (mret != MagickTrue)
168 {
169 fprintf(stderr, "[dt_imageio_large_thumbnail IM] thumbnail not found?\n");
170 goto error_im;
171 }
172
173 *width = MagickGetImageWidth(image);
174 *height = MagickGetImageHeight(image);
175 switch (MagickGetImageColorspace(image)) {
176 case sRGBColorspace:
177 *color_space = DT_COLORSPACE_SRGB;
178 break;
179 default:
180 fprintf(stderr,
181 "[dt_imageio_large_thumbnail IM] could not map colorspace, using sRGB");
182 *color_space = DT_COLORSPACE_SRGB;
183 break;
184 }
185
186 *buffer = malloc(sizeof(uint8_t) * (*width) * (*height) * 4);
187 if (*buffer == NULL) goto error_im;
188
189 mret = MagickExportImagePixels(image, 0, 0, *width, *height, "RGBP", CharPixel, *buffer);
190 if (mret != MagickTrue) {
191 free(*buffer);
192 *buffer = NULL;
193 fprintf(stderr,
194 "[dt_imageio_large_thumbnail IM] error while reading thumbnail\n");
195 goto error_im;
196 }
197
198 res = 0;
199
200 error_im:
201 DestroyMagickWand(image);
202 if (res != 0) goto error;
203 #else
204 fprintf(stderr,
205 "[dt_imageio_large_thumbnail] error: The thumbnail image is not in "
206 "JPEG format, and DT was built without neither GraphicsMagick or "
207 "ImageMagick. Please rebuild DT with GraphicsMagick or ImageMagick "
208 "support enabled.\n");
209 #endif
210 }
211
212 if(res)
213 {
214 fprintf(
215 stderr,
216 "[dt_imageio_large_thumbnail] error: Not a supported thumbnail image format or broken thumbnail: %s\n",
217 mime_type);
218 goto error;
219 }
220
221 error:
222 free(mime_type);
223 free(buf);
224 return res;
225 }
226
dt_imageio_has_mono_preview(const char * filename)227 gboolean dt_imageio_has_mono_preview(const char *filename)
228 {
229 dt_colorspaces_color_profile_type_t color_space;
230 uint8_t *tmp = NULL;
231 int32_t thumb_width = 0, thumb_height = 0;
232 gboolean mono = FALSE;
233
234 if(dt_imageio_large_thumbnail(filename, &tmp, &thumb_width, &thumb_height, &color_space))
235 goto cleanup;
236 if((thumb_width < 32) || (thumb_height < 32) || (tmp == NULL))
237 goto cleanup;
238
239 mono = TRUE;
240 for(int y = 0; y < thumb_height; y++)
241 {
242 uint8_t *in = (uint8_t *)tmp + (size_t)4 * y * thumb_width;
243 for(int x = 0; x < thumb_width; x++, in += 4)
244 {
245 if((in[0] != in[1]) || (in[0] != in[2]) || (in[1] != in[2]))
246 {
247 mono = FALSE;
248 goto cleanup;
249 }
250 }
251 }
252
253 cleanup:
254
255 dt_print(DT_DEBUG_IMAGEIO,"[dt_imageio_has_mono_preview] testing `%s', yes/no %i, %ix%i\n", filename, mono, thumb_width, thumb_height);
256 if(tmp) dt_free_align(tmp);
257 return mono;
258 }
259
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)260 void dt_imageio_flip_buffers(char *out, const char *in, const size_t bpp, const int wd, const int ht,
261 const int fwd, const int fht, const int stride,
262 const dt_image_orientation_t orientation)
263 {
264 if(!orientation)
265 {
266 #ifdef _OPENMP
267 #pragma omp parallel for default(none) \
268 dt_omp_firstprivate(ht, wd, bpp, stride) \
269 shared(in, out) \
270 schedule(static)
271 #endif
272 for(int j = 0; j < ht; j++) memcpy(out + (size_t)j * bpp * wd, in + (size_t)j * stride, bpp * wd);
273 return;
274 }
275 int ii = 0, jj = 0;
276 int si = bpp, sj = wd * bpp;
277 if(orientation & ORIENTATION_SWAP_XY)
278 {
279 sj = bpp;
280 si = ht * bpp;
281 }
282 if(orientation & ORIENTATION_FLIP_Y)
283 {
284 jj = (int)fht - jj - 1;
285 sj = -sj;
286 }
287 if(orientation & ORIENTATION_FLIP_X)
288 {
289 ii = (int)fwd - ii - 1;
290 si = -si;
291 }
292 #ifdef _OPENMP
293 #pragma omp parallel for default(none) \
294 dt_omp_firstprivate(wd, bpp, ht, stride) \
295 shared(in, out, jj, ii, sj, si) \
296 schedule(static)
297 #endif
298 for(int j = 0; j < ht; j++)
299 {
300 char *out2 = out + (size_t)labs(sj) * jj + (size_t)labs(si) * ii + (size_t)sj * j;
301 const char *in2 = in + (size_t)stride * j;
302 for(int i = 0; i < wd; i++)
303 {
304 memcpy(out2, in2, bpp);
305 in2 += bpp;
306 out2 += si;
307 }
308 }
309 }
310
dt_imageio_flip_buffers_ui8_to_float(float * out,const uint8_t * in,const float black,const float white,const int ch,const int wd,const int ht,const int fwd,const int fht,const int stride,const dt_image_orientation_t orientation)311 void dt_imageio_flip_buffers_ui8_to_float(float *out, const uint8_t *in, const float black, const float white,
312 const int ch, const int wd, const int ht, const int fwd,
313 const int fht, const int stride,
314 const dt_image_orientation_t orientation)
315 {
316 const float scale = 1.0f / (white - black);
317 if(!orientation)
318 {
319 #ifdef _OPENMP
320 #pragma omp parallel for default(none) \
321 dt_omp_firstprivate(wd, scale, black, ht, ch, stride) \
322 shared(in, out) \
323 schedule(static)
324 #endif
325 for(int j = 0; j < ht; j++)
326 for(int i = 0; i < wd; i++)
327 for(int k = 0; k < ch; k++)
328 out[4 * ((size_t)j * wd + i) + k] = (in[(size_t)j * stride + (size_t)ch * i + k] - black) * scale;
329 return;
330 }
331 int ii = 0, jj = 0;
332 int si = 4, sj = wd * 4;
333 if(orientation & ORIENTATION_SWAP_XY)
334 {
335 sj = 4;
336 si = ht * 4;
337 }
338 if(orientation & ORIENTATION_FLIP_Y)
339 {
340 jj = (int)fht - jj - 1;
341 sj = -sj;
342 }
343 if(orientation & ORIENTATION_FLIP_X)
344 {
345 ii = (int)fwd - ii - 1;
346 si = -si;
347 }
348 #ifdef _OPENMP
349 #pragma omp parallel for default(none) \
350 dt_omp_firstprivate(wd, ch, scale, black, stride, ht) \
351 shared(in, out, jj, ii, sj, si) \
352 schedule(static)
353 #endif
354 for(int j = 0; j < ht; j++)
355 {
356 float *out2 = out + (size_t)labs(sj) * jj + (size_t)labs(si) * ii + sj * j;
357 const uint8_t *in2 = in + (size_t)stride * j;
358 for(int i = 0; i < wd; i++)
359 {
360 for(int k = 0; k < ch; k++) out2[k] = (in2[k] - black) * scale;
361 in2 += ch;
362 out2 += si;
363 }
364 }
365 }
366
dt_imageio_write_pos(int i,int j,int wd,int ht,float fwd,float fht,dt_image_orientation_t orientation)367 size_t dt_imageio_write_pos(int i, int j, int wd, int ht, float fwd, float fht,
368 dt_image_orientation_t orientation)
369 {
370 int ii = i, jj = j, w = wd, fw = fwd, fh = fht;
371 if(orientation & ORIENTATION_SWAP_XY)
372 {
373 w = ht;
374 ii = j;
375 jj = i;
376 fw = fht;
377 fh = fwd;
378 }
379 if(orientation & ORIENTATION_FLIP_X) ii = (int)fw - ii - 1;
380 if(orientation & ORIENTATION_FLIP_Y) jj = (int)fh - jj - 1;
381 return (size_t)jj * w + ii;
382 }
383
dt_imageio_open_hdr(dt_image_t * img,const char * filename,dt_mipmap_buffer_t * buf)384 dt_imageio_retval_t dt_imageio_open_hdr(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
385 {
386 // if buf is NULL, don't proceed
387 if(!buf) return DT_IMAGEIO_OK;
388 // needed to alloc correct buffer size:
389 img->buf_dsc.channels = 4;
390 img->buf_dsc.datatype = TYPE_FLOAT;
391 img->buf_dsc.cst = iop_cs_rgb;
392 dt_imageio_retval_t ret;
393 dt_image_loader_t loader;
394 #ifdef HAVE_OPENEXR
395 loader = LOADER_EXR;
396 ret = dt_imageio_open_exr(img, filename, buf);
397 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL) goto return_label;
398 #endif
399 loader = LOADER_RGBE;
400 ret = dt_imageio_open_rgbe(img, filename, buf);
401 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL) goto return_label;
402 loader = LOADER_PFM;
403 ret = dt_imageio_open_pfm(img, filename, buf);
404 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL) goto return_label;
405
406 #ifdef HAVE_LIBAVIF
407 ret = dt_imageio_open_avif(img, filename, buf);
408 loader = LOADER_AVIF;
409 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL) goto return_label;
410 #endif
411 return_label:
412 if(ret == DT_IMAGEIO_OK)
413 {
414 img->buf_dsc.filters = 0u;
415 img->flags &= ~DT_IMAGE_LDR;
416 img->flags &= ~DT_IMAGE_RAW;
417 img->flags &= ~DT_IMAGE_S_RAW;
418 img->flags |= DT_IMAGE_HDR;
419 img->loader = loader;
420 }
421 return ret;
422 }
423
424 /* magic data: exclusion,offset,length, xx, yy, ...
425 just add magic bytes to match to this struct
426 to extend mathc on ldr formats.
427 */
428 static const uint8_t _imageio_ldr_magic[] = {
429 /* jpeg magics */
430 0x00, 0x00, 0x02, 0xff, 0xd8, // SOI marker
431
432 #ifdef HAVE_OPENJPEG
433 /* jpeg 2000, jp2 format */
434 0x00, 0x00, 0x0c, 0x0, 0x0, 0x0, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A,
435
436 /* jpeg 2000, j2k format */
437 0x00, 0x00, 0x05, 0xFF, 0x4F, 0xFF, 0x51, 0x00,
438 #endif
439
440 /* png image */
441 0x00, 0x01, 0x03, 0x50, 0x4E, 0x47, // ASCII 'PNG'
442
443
444 /* Canon CR2/CRW is like TIFF with additional magic numbers so must come
445 before tiff as an exclusion */
446
447 /* Most CR2 */
448 0x01, 0x00, 0x0a, 0x49, 0x49, 0x2a, 0x00, 0x10, 0x00, 0x00, 0x00, 0x43, 0x52,
449
450 /* CR3 (ISO Media) */
451 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 'f', 't', 'y', 'p', 'c', 'r', 'x', ' ', 0x00, 0x00, 0x00, 0x01, 'c', 'r', 'x', ' ', 'i', 's', 'o', 'm',
452
453 // Older Canon RAW format with TIF Extension (i.e. 1Ds and 1D)
454 0x01, 0x00, 0x0a, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x10, 0xba, 0xb0,
455
456 // Older Canon RAW format with TIF Extension (i.e. D2000)
457 0x01, 0x00, 0x0a, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x11, 0x34, 0x00, 0x04,
458
459 // Older Canon RAW format with TIF Extension (i.e. DCS1)
460 0x01, 0x00, 0x0a, 0x49, 0x49, 0x2a, 0x00, 0x00, 0x03, 0x00, 0x00, 0xff, 0x01,
461
462 // Older Kodak RAW format with TIF Extension (i.e. DCS520C)
463 0x01, 0x00, 0x0a, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x11, 0xa8, 0x00, 0x04,
464
465 // Older Kodak RAW format with TIF Extension (i.e. DCS560C)
466 0x01, 0x00, 0x0a, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x11, 0x76, 0x00, 0x04,
467
468 // Older Kodak RAW format with TIF Extension (i.e. DCS460D)
469 0x01, 0x00, 0x0a, 0x49, 0x49, 0x2a, 0x00, 0x00, 0x03, 0x00, 0x00, 0x7c, 0x01,
470
471 /* IIQ raw images, may be either .IIQ, or .TIF */
472 0x01, 0x08, 0x04, 0x49, 0x49, 0x49, 0x49,
473
474 /* tiff image, intel */
475 0x00, 0x00, 0x04, 0x4d, 0x4d, 0x00, 0x2a,
476
477 /* tiff image, motorola */
478 0x00, 0x00, 0x04, 0x49, 0x49, 0x2a, 0x00,
479
480 /* binary NetPNM images: pbm, pgm and pbm */
481 0x00, 0x00, 0x02, 0x50, 0x34,
482 0x00, 0x00, 0x02, 0x50, 0x35,
483 0x00, 0x00, 0x02, 0x50, 0x36
484 };
485
dt_imageio_is_ldr(const char * filename)486 gboolean dt_imageio_is_ldr(const char *filename)
487 {
488 FILE *fin = g_fopen(filename, "rb");
489 if(fin)
490 {
491 size_t offset = 0;
492 uint8_t block[32] = { 0 }; // keep this big enough for whatever magic size we want to compare to!
493 /* read block from file */
494 size_t s = fread(block, sizeof(block), 1, fin);
495 fclose(fin);
496
497 /* compare magic's */
498 while(s)
499 {
500 if(_imageio_ldr_magic[offset + 2] > sizeof(block)
501 || offset + 3 + _imageio_ldr_magic[offset + 2] > sizeof(_imageio_ldr_magic))
502 {
503 fprintf(stderr, "error: buffer in %s is too small!\n", __FUNCTION__);
504 return FALSE;
505 }
506 if(memcmp(_imageio_ldr_magic + offset + 3, block + _imageio_ldr_magic[offset + 1],
507 _imageio_ldr_magic[offset + 2]) == 0)
508 {
509 if(_imageio_ldr_magic[offset] == 0x01)
510 return FALSE;
511 else
512 return TRUE;
513 }
514 offset += 3 + (_imageio_ldr_magic + offset)[2];
515
516 /* check if finished */
517 if(offset >= sizeof(_imageio_ldr_magic)) break;
518 }
519 }
520 return FALSE;
521 }
522
dt_imageio_is_hdr(const char * filename)523 int dt_imageio_is_hdr(const char *filename)
524 {
525 const char *c = filename + strlen(filename);
526 while(c > filename && *c != '.') c--;
527 if(*c == '.')
528 if(!strcasecmp(c, ".pfm") || !strcasecmp(c, ".hdr")
529 #ifdef HAVE_OPENEXR
530 || !strcasecmp(c, ".exr")
531 #endif
532 #ifdef HAVE_LIBAVIF
533 || !strcasecmp(c, ".avif")
534 #endif
535 )
536 return 1;
537 return 0;
538 }
539
540 // transparent read method to load ldr image to dt_raw_image_t with exif and so on.
dt_imageio_open_ldr(dt_image_t * img,const char * filename,dt_mipmap_buffer_t * buf)541 dt_imageio_retval_t dt_imageio_open_ldr(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
542 {
543 // if buf is NULL, don't proceed
544 if(!buf) return DT_IMAGEIO_OK;
545 dt_imageio_retval_t ret;
546
547 ret = dt_imageio_open_jpeg(img, filename, buf);
548 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
549 {
550 img->buf_dsc.cst = iop_cs_rgb; // jpeg is always RGB
551 img->buf_dsc.filters = 0u;
552 img->flags &= ~DT_IMAGE_RAW;
553 img->flags &= ~DT_IMAGE_S_RAW;
554 img->flags &= ~DT_IMAGE_HDR;
555 img->flags |= DT_IMAGE_LDR;
556 img->loader = LOADER_JPEG;
557 return ret;
558 }
559
560 ret = dt_imageio_open_tiff(img, filename, buf);
561 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
562 {
563 // cst is set by dt_imageio_open_tiff()
564 img->buf_dsc.filters = 0u;
565 // TIFF can be HDR or LDR. corresponding flags are set in dt_imageio_open_tiff()
566 img->flags &= ~DT_IMAGE_RAW;
567 img->flags &= ~DT_IMAGE_S_RAW;
568 img->loader = LOADER_TIFF;
569 return ret;
570 }
571
572 ret = dt_imageio_open_png(img, filename, buf);
573 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
574 {
575 img->buf_dsc.cst = iop_cs_rgb; // png is always RGB
576 img->buf_dsc.filters = 0u;
577 img->flags &= ~DT_IMAGE_RAW;
578 img->flags &= ~DT_IMAGE_S_RAW;
579 img->flags &= ~DT_IMAGE_HDR;
580 img->flags |= DT_IMAGE_LDR;
581 img->loader = LOADER_PNG;
582 return ret;
583 }
584
585 #ifdef HAVE_OPENJPEG
586 ret = dt_imageio_open_j2k(img, filename, buf);
587 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
588 {
589 img->buf_dsc.cst = iop_cs_rgb; // j2k is always RGB
590 img->buf_dsc.filters = 0u;
591 img->flags &= ~DT_IMAGE_RAW;
592 img->flags &= ~DT_IMAGE_HDR;
593 img->flags &= ~DT_IMAGE_S_RAW;
594 img->flags |= DT_IMAGE_LDR;
595 img->loader = LOADER_J2K;
596 return ret;
597 }
598 #endif
599
600 ret = dt_imageio_open_pnm(img, filename, buf);
601 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
602 {
603 img->buf_dsc.cst = iop_cs_rgb; // pnm is always RGB
604 img->buf_dsc.filters = 0u;
605 img->flags &= ~DT_IMAGE_RAW;
606 img->flags &= ~DT_IMAGE_S_RAW;
607 img->flags &= ~DT_IMAGE_HDR;
608 img->flags |= DT_IMAGE_LDR;
609 img->loader = LOADER_PNM;
610 return ret;
611 }
612
613 return DT_IMAGEIO_FILE_CORRUPTED;
614 }
615
dt_imageio_to_fractional(float in,uint32_t * num,uint32_t * den)616 void dt_imageio_to_fractional(float in, uint32_t *num, uint32_t *den)
617 {
618 if(!(in >= 0))
619 {
620 *num = *den = 0;
621 return;
622 }
623 *den = 1;
624 *num = (int)(in * *den + .5f);
625 while(fabsf(*num / (float)*den - in) > 0.001f)
626 {
627 *den *= 10;
628 *num = (int)(in * *den + .5f);
629 }
630 }
631
dt_imageio_export(const int32_t imgid,const char * filename,dt_imageio_module_format_t * format,dt_imageio_module_data_t * format_params,const gboolean high_quality,const gboolean upscale,const gboolean copy_metadata,const gboolean export_masks,dt_colorspaces_color_profile_type_t icc_type,const gchar * icc_filename,dt_iop_color_intent_t icc_intent,dt_imageio_module_storage_t * storage,dt_imageio_module_data_t * storage_params,int num,int total,dt_export_metadata_t * metadata)632 int dt_imageio_export(const int32_t imgid, const char *filename, dt_imageio_module_format_t *format,
633 dt_imageio_module_data_t *format_params, const gboolean high_quality, const gboolean upscale,
634 const gboolean copy_metadata, const gboolean export_masks,
635 dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename,
636 dt_iop_color_intent_t icc_intent, dt_imageio_module_storage_t *storage,
637 dt_imageio_module_data_t *storage_params, int num, int total, dt_export_metadata_t *metadata)
638 {
639 if(strcmp(format->mime(format_params), "x-copy") == 0)
640 /* This is a just a copy, skip process and just export */
641 return format->write_image(format_params, filename, NULL, icc_type, icc_filename, NULL, 0, imgid, num, total, NULL,
642 export_masks);
643 else
644 return dt_imageio_export_with_flags(imgid, filename, format, format_params, FALSE, FALSE, high_quality, upscale,
645 FALSE, NULL, copy_metadata, export_masks, icc_type, icc_filename, icc_intent,
646 storage, storage_params, num, total, metadata);
647 }
648
649 // internal function: to avoid exif blob reading + 8-bit byteorder flag + high-quality override
dt_imageio_export_with_flags(const int32_t imgid,const char * filename,dt_imageio_module_format_t * format,dt_imageio_module_data_t * format_params,const gboolean ignore_exif,const gboolean display_byteorder,const gboolean high_quality,const gboolean upscale,const gboolean thumbnail_export,const char * filter,const gboolean copy_metadata,const gboolean export_masks,dt_colorspaces_color_profile_type_t icc_type,const gchar * icc_filename,dt_iop_color_intent_t icc_intent,dt_imageio_module_storage_t * storage,dt_imageio_module_data_t * storage_params,int num,int total,dt_export_metadata_t * metadata)650 int dt_imageio_export_with_flags(const int32_t imgid, const char *filename,
651 dt_imageio_module_format_t *format, dt_imageio_module_data_t *format_params,
652 const gboolean ignore_exif, const gboolean display_byteorder,
653 const gboolean high_quality, const gboolean upscale, const gboolean thumbnail_export,
654 const char *filter, const gboolean copy_metadata, const gboolean export_masks,
655 dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename,
656 dt_iop_color_intent_t icc_intent, dt_imageio_module_storage_t *storage,
657 dt_imageio_module_data_t *storage_params, int num, int total,
658 dt_export_metadata_t *metadata)
659 {
660 dt_develop_t dev;
661 dt_dev_init(&dev, 0);
662 dt_dev_load_image(&dev, imgid);
663
664 const gboolean buf_is_downscaled = (thumbnail_export && dt_conf_get_bool("ui/performance"));
665 dt_mipmap_buffer_t buf;
666 if(buf_is_downscaled)
667 dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, DT_MIPMAP_F, DT_MIPMAP_BLOCKING, 'r');
668 else
669 dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r');
670
671 const dt_image_t *img = &dev.image_storage;
672
673 if(!buf.buf || !buf.width || !buf.height)
674 {
675 fprintf(stderr, "[dt_imageio_export_with_flags] mipmap allocation for `%s' failed\n", filename);
676 dt_control_log(_("image `%s' is not available!"), img->filename);
677 goto error_early;
678 }
679
680 const int wd = img->width;
681 const int ht = img->height;
682
683
684 int res = 0;
685
686 dt_times_t start;
687 dt_get_times(&start);
688 dt_dev_pixelpipe_t pipe;
689 res = thumbnail_export ? dt_dev_pixelpipe_init_thumbnail(&pipe, wd, ht)
690 : dt_dev_pixelpipe_init_export(&pipe, wd, ht, format->levels(format_params), export_masks);
691 if(!res)
692 {
693 dt_control_log(
694 _("failed to allocate memory for %s, please lower the threads used for export or buy more memory."),
695 thumbnail_export ? C_("noun", "thumbnail export") : C_("noun", "export"));
696 goto error;
697 }
698
699 const gboolean use_style = !thumbnail_export && format_params->style[0] != '\0';
700 const gboolean appending = format_params->style_append != FALSE;
701 // If a style is to be applied during export, add the iop params into the history
702 if(use_style)
703 {
704 GList *style_items = dt_styles_get_item_list(format_params->style, TRUE, -1);
705 if(!style_items)
706 {
707 dt_control_log(_("cannot find the style '%s' to apply during export."), format_params->style);
708 goto error;
709 }
710
711 GList *modules_used = NULL;
712
713 dt_dev_pop_history_items_ext(&dev, appending ? dev.history_end : 0);
714 dt_ioppr_update_for_style_items(&dev, style_items, appending);
715
716 for(GList *st_items = style_items; st_items; st_items = g_list_next(st_items))
717 {
718 dt_style_item_t *st_item = (dt_style_item_t *)st_items->data;
719 dt_styles_apply_style_item(&dev, st_item, &modules_used, appending);
720 }
721
722 g_list_free(modules_used);
723 g_list_free_full(style_items, dt_style_item_free);
724 }
725
726 dt_ioppr_resync_modules_order(&dev);
727
728 dt_dev_pixelpipe_set_icc(&pipe, icc_type, icc_filename, icc_intent);
729 dt_dev_pixelpipe_set_input(&pipe, &dev, (float *)buf.buf, buf.width, buf.height, buf.iscale);
730 dt_dev_pixelpipe_create_nodes(&pipe, &dev);
731 dt_dev_pixelpipe_synch_all(&pipe, &dev);
732 if(darktable.unmuted & DT_DEBUG_IMAGEIO)
733 {
734 fprintf(stderr,"[dt_imageio_export_with_flags] ");
735 if(use_style)
736 {
737 if(appending) fprintf(stderr,"appending style `%s'\n", format_params->style);
738 else fprintf(stderr,"overwrite style `%s'\n", format_params->style);
739 }
740 else fprintf(stderr,"\n");
741 int cnt = 0;
742 for(GList *nodes = pipe.nodes; nodes; nodes = g_list_next(nodes))
743 {
744 dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)nodes->data;
745 if(piece->enabled)
746 {
747 cnt++;
748 fprintf(stderr," %s", piece->module->op);
749 }
750 }
751 fprintf(stderr," (%i)\n", cnt);
752 }
753
754 if(filter)
755 {
756 if(!strncmp(filter, "pre:", 4)) dt_dev_pixelpipe_disable_after(&pipe, filter + 4);
757 if(!strncmp(filter, "post:", 5)) dt_dev_pixelpipe_disable_before(&pipe, filter + 5);
758 }
759
760 dt_dev_pixelpipe_get_dimensions(&pipe, &dev, pipe.iwidth, pipe.iheight, &pipe.processed_width,
761 &pipe.processed_height);
762
763 dt_show_times(&start, "[export] creating pixelpipe");
764
765 // find output color profile for this image:
766 int sRGB = 1;
767 if(icc_type == DT_COLORSPACE_SRGB)
768 {
769 sRGB = 1;
770 }
771 else if(icc_type == DT_COLORSPACE_NONE)
772 {
773 dt_iop_module_t *colorout = NULL;
774 for(GList *modules = dev.iop; modules; modules = g_list_next(modules))
775 {
776 colorout = (dt_iop_module_t *)modules->data;
777 if(colorout->get_p && strcmp(colorout->op, "colorout") == 0)
778 {
779 const dt_colorspaces_color_profile_type_t *type = colorout->get_p(colorout->params, "type");
780 sRGB = (!type || *type == DT_COLORSPACE_SRGB);
781 break; // colorout can't have > 1 instance
782 }
783 }
784 }
785 else
786 {
787 sRGB = 0;
788 }
789
790 // get only once at the beginning, in case the user changes it on the way:
791 const gboolean high_quality_processing
792 = ((format_params->max_width == 0 || format_params->max_width >= pipe.processed_width)
793 && (format_params->max_height == 0 || format_params->max_height >= pipe.processed_height))
794 ? FALSE
795 : high_quality;
796
797 /* The pipeline might have out-of-bounds problems at the right and lower borders leading to
798 artefacts or mem access errors if ignored. (#3646)
799 It's very difficult to prepare the pipeline avoiding this **and** not introducing artefacts.
800 But we can test for that situation and if there is an out-of-bounds problem we
801 have basically two options:
802 a) reduce the output image size by one for width & height.
803 b) increase the scale while keeping the output size. In theory this marginally reduces quality.
804
805 These are the rules for export:
806 1. If we have the **full image** (defined by dt_image_t width, height and crops) we look for upscale.
807 If this is off use a), if on use b)
808 2. If we have defined format_params->max_width or/and height we use b)
809 3. Thumbnails are defined as in 2 so use b)
810 4. Cropped images are detected and use b)
811 5. Upscaled images use b)
812 6. Rotating by +-90° does not change the output size.
813 7. Never generate images larger than requested.
814 */
815
816 const gboolean iscropped =
817 ((pipe.processed_width < (wd - img->crop_x - img->crop_width)) ||
818 (pipe.processed_height < (ht - img->crop_y - img->crop_height)));
819
820 const gboolean exact_size = (
821 iscropped ||
822 upscale ||
823 (format_params->max_width != 0) ||
824 (format_params->max_height != 0) ||
825 thumbnail_export);
826
827 int width = format_params->max_width > 0 ? format_params->max_width : 0;
828 int height = format_params->max_height > 0 ? format_params->max_height : 0;
829
830 if(iscropped && !thumbnail_export && width == 0 && height == 0)
831 {
832 width = pipe.processed_width;
833 height = pipe.processed_height;
834 }
835
836 const double max_scale = ( upscale && ( width > 0 || height > 0 )) ? 100.0 : 1.0;
837
838 const double scalex = width > 0 ? fmin((double)width / (double)pipe.processed_width, max_scale) : max_scale;
839 const double scaley = height > 0 ? fmin((double)height / (double)pipe.processed_height, max_scale) : max_scale;
840 double scale = fmin(scalex, scaley);
841 double corrscale = 1.0f;
842
843 int processed_width = 0;
844 int processed_height = 0;
845
846 gboolean corrected = FALSE;
847 float origin[] = { 0.0f, 0.0f };
848
849 if(dt_dev_distort_backtransform_plus(&dev, &pipe, 0.f, DT_DEV_TRANSFORM_DIR_ALL, origin, 1))
850 {
851 if((width == 0) && exact_size)
852 width = pipe.processed_width;
853 if((height == 0) && exact_size)
854 height = pipe.processed_height;
855
856 scale = fmin(width > 0 ? fmin((double)width / (double)pipe.processed_width, max_scale) : max_scale,
857 height > 0 ? fmin((double)height / (double)pipe.processed_height, max_scale) : max_scale);
858
859 const gboolean is_scaling =
860 dt_conf_is_equal("plugins/lighttable/export/resizing", "scaling");
861
862 if (is_scaling)
863 {
864 // scaling
865 double scale_factor = 1;
866 double _num, _denum;
867 dt_imageio_resizing_factor_get_and_parsing(&_num, &_denum);
868
869 scale_factor = _num / _denum;
870
871 if (!thumbnail_export)
872 {
873 scale = fmin(scale_factor, max_scale);
874 }
875 }
876
877 processed_width = scale * pipe.processed_width + 0.8f;
878 processed_height = scale * pipe.processed_height + 0.8f;
879
880 if((ceil((double)processed_width / scale) + origin[0] > pipe.iwidth) ||
881 (ceil((double)processed_height / scale) + origin[1] > pipe.iheight))
882 {
883 corrected = TRUE;
884 /* Here the scale is too **small** so while reading data from the right or low borders we are out-of-bounds.
885 We can either just decrease output width & height or
886 have to find a scale that takes data from within the origin data, so we have to increase scale to a size
887 that fits both width & height.
888 */
889 if(exact_size)
890 {
891 corrscale = fmax( ((double)(pipe.processed_width + 1) / (double)(pipe.processed_width)),
892 ((double)(pipe.processed_height +1) / (double)(pipe.processed_height)) );
893 scale = scale * corrscale;
894 }
895 else
896 {
897 processed_width--;
898 processed_height--;
899 }
900 }
901
902 dt_print(DT_DEBUG_IMAGEIO,"[dt_imageio_export] imgid %d, pipe %ix%i, range %ix%i --> exact %i, upscale %i, corrected %i, scale %.7f, corr %.6f, size %ix%i\n",
903 imgid, pipe.processed_width, pipe.processed_height, format_params->max_width, format_params->max_height,
904 exact_size, upscale, corrected, scale, corrscale, processed_width, processed_height);
905 }
906 else
907 {
908 processed_width = floor(scale * pipe.processed_width);
909 processed_height = floor(scale * pipe.processed_height);
910 dt_print(DT_DEBUG_IMAGEIO,"[dt_imageio_export] (direct) imgid %d, pipe %ix%i, range %ix%i --> size %ix%i / %ix%i\n",
911 imgid, pipe.processed_width, pipe.processed_height, format_params->max_width, format_params->max_height,
912 processed_width, processed_height, width, height);
913 }
914
915 const int bpp = format->bpp(format_params);
916
917 dt_get_times(&start);
918 if(high_quality_processing)
919 {
920 /*
921 * if high quality processing was requested, downsampling will be done
922 * at the very end of the pipe (just before border and watermark)
923 */
924 dt_dev_pixelpipe_process_no_gamma(&pipe, &dev, 0, 0, processed_width, processed_height, scale);
925 }
926 else
927 {
928 // else, downsampling will be right after demosaic
929
930 // so we need to turn temporarily disable in-pipe late downsampling iop.
931
932 // find the finalscale module
933 dt_dev_pixelpipe_iop_t *finalscale = NULL;
934 {
935 for(const GList *nodes = g_list_last(pipe.nodes); nodes; nodes = g_list_previous(nodes))
936 {
937 dt_dev_pixelpipe_iop_t *node = (dt_dev_pixelpipe_iop_t *)(nodes->data);
938 if(!strcmp(node->module->op, "finalscale"))
939 {
940 finalscale = node;
941 break;
942 }
943 }
944 }
945
946 if(finalscale) finalscale->enabled = 0;
947
948 // do the processing (8-bit with special treatment, to make sure we can use openmp further down):
949 if(bpp == 8)
950 dt_dev_pixelpipe_process(&pipe, &dev, 0, 0, processed_width, processed_height, scale);
951 else
952 dt_dev_pixelpipe_process_no_gamma(&pipe, &dev, 0, 0, processed_width, processed_height, scale);
953
954 if(finalscale) finalscale->enabled = 1;
955 }
956 dt_show_times(&start, thumbnail_export ? "[dev_process_thumbnail] pixel pipeline processing"
957 : "[dev_process_export] pixel pipeline processing");
958
959 uint8_t *outbuf = pipe.backbuf;
960
961 // downconversion to low-precision formats:
962 if(bpp == 8)
963 {
964 if(display_byteorder)
965 {
966 if(high_quality_processing)
967 {
968 const float *const inbuf = (float *)outbuf;
969 for(size_t k = 0; k < (size_t)processed_width * processed_height; k++)
970 {
971 // convert in place, this is unfortunately very serial..
972 const uint8_t r = roundf(CLAMP(inbuf[4 * k + 2] * 0xff, 0, 0xff));
973 const uint8_t g = roundf(CLAMP(inbuf[4 * k + 1] * 0xff, 0, 0xff));
974 const uint8_t b = roundf(CLAMP(inbuf[4 * k + 0] * 0xff, 0, 0xff));
975 outbuf[4 * k + 0] = r;
976 outbuf[4 * k + 1] = g;
977 outbuf[4 * k + 2] = b;
978 }
979 }
980 // else processing output was 8-bit already, and no need to swap order
981 }
982 else // need to flip
983 {
984 // ldr output: char
985 if(high_quality_processing)
986 {
987 const float *const inbuf = (float *)outbuf;
988 for(size_t k = 0; k < (size_t)processed_width * processed_height; k++)
989 {
990 // convert in place, this is unfortunately very serial..
991 const uint8_t r = roundf(CLAMP(inbuf[4 * k + 0] * 0xff, 0, 0xff));
992 const uint8_t g = roundf(CLAMP(inbuf[4 * k + 1] * 0xff, 0, 0xff));
993 const uint8_t b = roundf(CLAMP(inbuf[4 * k + 2] * 0xff, 0, 0xff));
994 outbuf[4 * k + 0] = r;
995 outbuf[4 * k + 1] = g;
996 outbuf[4 * k + 2] = b;
997 }
998 }
999 else
1000 { // !display_byteorder, need to swap:
1001 uint8_t *const buf8 = pipe.backbuf;
1002 #ifdef _OPENMP
1003 #pragma omp parallel for default(none) \
1004 dt_omp_firstprivate(processed_width, processed_height, buf8) \
1005 schedule(static)
1006 #endif
1007 // just flip byte order
1008 for(size_t k = 0; k < (size_t)processed_width * processed_height; k++)
1009 {
1010 uint8_t tmp = buf8[4 * k + 0];
1011 buf8[4 * k + 0] = buf8[4 * k + 2];
1012 buf8[4 * k + 2] = tmp;
1013 }
1014 }
1015 }
1016 }
1017 else if(bpp == 16)
1018 {
1019 // uint16_t per color channel
1020 float *buff = (float *)outbuf;
1021 uint16_t *buf16 = (uint16_t *)outbuf;
1022 for(int y = 0; y < processed_height; y++)
1023 for(int x = 0; x < processed_width; x++)
1024 {
1025 // convert in place
1026 const size_t k = (size_t)processed_width * y + x;
1027 for(int i = 0; i < 3; i++) buf16[4 * k + i] = roundf(CLAMP(buff[4 * k + i] * 0xffff, 0, 0xffff));
1028 }
1029 }
1030 // else output float, no further harm done to the pixels :)
1031
1032 format_params->width = processed_width;
1033 format_params->height = processed_height;
1034
1035 if(!ignore_exif)
1036 {
1037 int length;
1038 uint8_t *exif_profile = NULL; // Exif data should be 65536 bytes max, but if original size is close to that,
1039 // adding new tags could make it go over that... so let it be and see what
1040 // happens when we write the image
1041 char pathname[PATH_MAX] = { 0 };
1042 gboolean from_cache = TRUE;
1043 dt_image_full_path(imgid, pathname, sizeof(pathname), &from_cache);
1044 // last param is dng mode, it's false here
1045 length = dt_exif_read_blob(&exif_profile, pathname, imgid, sRGB, processed_width, processed_height, 0);
1046
1047 res = format->write_image(format_params, filename, outbuf, icc_type, icc_filename, exif_profile, length, imgid,
1048 num, total, &pipe, export_masks);
1049
1050 free(exif_profile);
1051 }
1052 else
1053 {
1054 res = format->write_image(format_params, filename, outbuf, icc_type, icc_filename, NULL, 0, imgid, num, total,
1055 &pipe, export_masks);
1056 }
1057
1058 if(res)
1059 goto error;
1060
1061 dt_dev_pixelpipe_cleanup(&pipe);
1062 dt_dev_cleanup(&dev);
1063 dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
1064
1065 /* now write xmp into that container, if possible */
1066 if(copy_metadata && (format->flags(format_params) & FORMAT_FLAGS_SUPPORT_XMP))
1067 {
1068 dt_exif_xmp_attach_export(imgid, filename, metadata);
1069 // no need to cancel the export if this fail
1070 }
1071
1072 if(!thumbnail_export && strcmp(format->mime(format_params), "memory")
1073 && !(format->flags(format_params) & FORMAT_FLAGS_NO_TMPFILE))
1074 {
1075 #ifdef USE_LUA
1076 //Synchronous calling of lua intermediate-export-image events
1077 dt_lua_lock();
1078
1079 lua_State *L = darktable.lua_state.state;
1080
1081 luaA_push(L, dt_lua_image_t, &imgid);
1082
1083 lua_pushstring(L, filename);
1084
1085 luaA_push_type(L, format->parameter_lua_type, format_params);
1086
1087 if (storage)
1088 luaA_push_type(L, storage->parameter_lua_type, storage_params);
1089 else
1090 lua_pushnil(L);
1091
1092 dt_lua_event_trigger(L, "intermediate-export-image", 4);
1093
1094 dt_lua_unlock();
1095 #endif
1096
1097 DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_IMAGE_EXPORT_TMPFILE, imgid, filename, format,
1098 format_params, storage, storage_params);
1099 }
1100
1101 return 0; // success
1102
1103 error:
1104 dt_dev_pixelpipe_cleanup(&pipe);
1105 error_early:
1106 dt_dev_cleanup(&dev);
1107 dt_mipmap_cache_release(darktable.mipmap_cache, &buf);
1108 return 1;
1109 }
1110
1111
1112 // fallback read method in case file could not be opened yet.
1113 // use GraphicsMagick (if supported) to read exotic LDRs
dt_imageio_open_exotic(dt_image_t * img,const char * filename,dt_mipmap_buffer_t * buf)1114 dt_imageio_retval_t dt_imageio_open_exotic(dt_image_t *img, const char *filename,
1115 dt_mipmap_buffer_t *buf)
1116 {
1117 // if buf is NULL, don't proceed
1118 if(!buf) return DT_IMAGEIO_OK;
1119 #ifdef HAVE_GRAPHICSMAGICK
1120 dt_imageio_retval_t ret = dt_imageio_open_gm(img, filename, buf);
1121 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
1122 {
1123 img->buf_dsc.cst = iop_cs_rgb;
1124 img->buf_dsc.filters = 0u;
1125 img->flags &= ~DT_IMAGE_RAW;
1126 img->flags &= ~DT_IMAGE_S_RAW;
1127 img->flags &= ~DT_IMAGE_HDR;
1128 img->flags |= DT_IMAGE_LDR;
1129 img->loader = LOADER_GM;
1130 return ret;
1131 }
1132 #elif HAVE_IMAGEMAGICK
1133 dt_imageio_retval_t ret = dt_imageio_open_im(img, filename, buf);
1134 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
1135 {
1136 img->buf_dsc.filters = 0u;
1137 img->flags &= ~DT_IMAGE_RAW;
1138 img->flags &= ~DT_IMAGE_HDR;
1139 img->flags |= DT_IMAGE_LDR;
1140 img->loader = LOADER_IM;
1141 return ret;
1142 }
1143 #endif
1144
1145 return DT_IMAGEIO_FILE_CORRUPTED;
1146 }
1147
dt_imageio_update_monochrome_workflow_tag(int32_t id,int mask)1148 void dt_imageio_update_monochrome_workflow_tag(int32_t id, int mask)
1149 {
1150 if(mask & (DT_IMAGE_MONOCHROME | DT_IMAGE_MONOCHROME_PREVIEW | DT_IMAGE_MONOCHROME_BAYER))
1151 {
1152 guint tagid = 0;
1153 char tagname[64];
1154 snprintf(tagname, sizeof(tagname), "darktable|mode|monochrome");
1155 dt_tag_new(tagname, &tagid);
1156 dt_tag_attach(tagid, id, FALSE, FALSE);
1157 }
1158 else
1159 dt_tag_detach_by_string("darktable|mode|monochrome", id, FALSE, FALSE);
1160
1161 DT_DEBUG_CONTROL_SIGNAL_RAISE(darktable.signals, DT_SIGNAL_TAG_CHANGED);
1162 }
1163
dt_imageio_set_hdr_tag(dt_image_t * img)1164 void dt_imageio_set_hdr_tag(dt_image_t *img)
1165 {
1166 guint tagid = 0;
1167 char tagname[64];
1168 snprintf(tagname, sizeof(tagname), "darktable|mode|hdr");
1169 dt_tag_new(tagname, &tagid);
1170 dt_tag_attach(tagid, img->id, FALSE, FALSE);
1171 img->flags |= DT_IMAGE_HDR;
1172 img->flags &= ~DT_IMAGE_LDR;
1173 }
1174
1175 // =================================================
1176 // combined reading
1177 // =================================================
1178
dt_imageio_open(dt_image_t * img,const char * filename,dt_mipmap_buffer_t * buf)1179 dt_imageio_retval_t dt_imageio_open(dt_image_t *img, // non-const * means you hold a write lock!
1180 const char *filename, // full path
1181 dt_mipmap_buffer_t *buf)
1182 {
1183 /* first of all, check if file exists, don't bother to test loading if not exists */
1184 if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) return !DT_IMAGEIO_OK;
1185 const int32_t was_hdr = (img->flags & DT_IMAGE_HDR);
1186 const int32_t was_bw = dt_image_monochrome_flags(img);
1187
1188 dt_imageio_retval_t ret = DT_IMAGEIO_FILE_CORRUPTED;
1189 img->loader = LOADER_UNKNOWN;
1190
1191 /* check if file is ldr using magic's */
1192 if(dt_imageio_is_ldr(filename)) ret = dt_imageio_open_ldr(img, filename, buf);
1193
1194 /* silly check using file extensions: */
1195 if(ret != DT_IMAGEIO_OK && ret != DT_IMAGEIO_CACHE_FULL && dt_imageio_is_hdr(filename))
1196 ret = dt_imageio_open_hdr(img, filename, buf);
1197
1198 /* use rawspeed to load the raw */
1199 if(ret != DT_IMAGEIO_OK && ret != DT_IMAGEIO_CACHE_FULL)
1200 {
1201 ret = dt_imageio_open_rawspeed(img, filename, buf);
1202 if(ret == DT_IMAGEIO_OK)
1203 {
1204 img->buf_dsc.cst = iop_cs_RAW;
1205 img->loader = LOADER_RAWSPEED;
1206 }
1207 }
1208
1209 /* fallback that tries to open file via GraphicsMagick */
1210 if(ret != DT_IMAGEIO_OK && ret != DT_IMAGEIO_CACHE_FULL)
1211 ret = dt_imageio_open_exotic(img, filename, buf);
1212
1213 if((ret == DT_IMAGEIO_OK) && !was_hdr && (img->flags & DT_IMAGE_HDR))
1214 dt_imageio_set_hdr_tag(img);
1215
1216 if((ret == DT_IMAGEIO_OK) && (was_bw != dt_image_monochrome_flags(img)))
1217 dt_imageio_update_monochrome_workflow_tag(img->id, dt_image_monochrome_flags(img));
1218
1219 img->p_width = img->width - img->crop_x - img->crop_width;
1220 img->p_height = img->height - img->crop_y - img->crop_height;
1221
1222 return ret;
1223 }
1224
1225 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
1226 // vim: shiftwidth=2 expandtab tabstop=2 cindent
1227 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1228