Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
imageio.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2014 johannes hanika.
4 Copyright (C) 2010 Anton Blanchard.
5 Copyright (C) 2010-2012 Henrik Andersson.
6 Copyright (C) 2010 Kaminsky Andrey.
7 Copyright (C) 2010-2020 Tobias Ellinghaus.
8 Copyright (C) 2011 Bruce Guenter.
9 Copyright (C) 2011 Omari Stephens.
10 Copyright (C) 2011 Sergey Pavlov.
11 Copyright (C) 2011-2014, 2019 Ulrich Pegelow.
12 Copyright (C) 2012-2015 Jérémy Rosen.
13 Copyright (C) 2012-2014 Pascal de Bruijn.
14 Copyright (C) 2012-2015, 2018-2021 Pascal Obry.
15 Copyright (C) 2012 Richard Wonka.
16 Copyright (C) 2013 Simon Spannagel.
17 Copyright (C) 2014-2015 Pedro Côrte-Real.
18 Copyright (C) 2014-2018 Roman Lebedev.
19 Copyright (C) 2015 Edouard Gomez.
20 Copyright (C) 2016 Chris Hodapp.
21 Copyright (C) 2016, 2020 Matthieu Volat.
22 Copyright (C) 2017 Žilvinas Žaltiena.
23 Copyright (C) 2018-2019 Edgardo Hoszowski.
24 Copyright (C) 2018 Sören Witt.
25 Copyright (C) 2019, 2022 Aldric Renaudin.
26 Copyright (C) 2019 Andreas Schneider.
27 Copyright (C) 2019-2022 Hanno Schwalm.
28 Copyright (C) 2019-2021 Heiko Bauke.
29 Copyright (C) 2019 Philippe Weyland.
30 Copyright (C) 2020 a.
31 Copyright (C) 2020, 2022-2026 Aurélien PIERRE.
32 Copyright (C) 2020-2021 Hubert Kowalski.
33 Copyright (C) 2020 Miloš Komarčević.
34 Copyright (C) 2021 Daniel Vogelbacher.
35 Copyright (C) 2021 luzpaz.
36 Copyright (C) 2021 Ralf Brown.
37 Copyright (C) 2022 Martin Bařinka.
38 Copyright (C) 2022 parafin.
39 Copyright (C) 2022 Philipp Lutz.
40 Copyright (C) 2023-2024 Alynx Zhou.
41 Copyright (C) 2023 Ricky Moon.
42
43 darktable is free software: you can redistribute it and/or modify
44 it under the terms of the GNU General Public License as published by
45 the Free Software Foundation, either version 3 of the License, or
46 (at your option) any later version.
47
48 darktable is distributed in the hope that it will be useful,
49 but WITHOUT ANY WARRANTY; without even the implied warranty of
50 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
51 GNU General Public License for more details.
52
53 You should have received a copy of the GNU General Public License
54 along with darktable. If not, see <http://www.gnu.org/licenses/>.
55*/
56#include "common/image.h"
57#ifdef HAVE_CONFIG_H
58#include "config.h"
59#endif
60#include "common/colorlabels.h"
61#include "common/colorspaces.h"
62#include "common/darktable.h"
63#include "common/debug.h"
64#include "common/exif.h"
65#include "common/image_cache.h"
66#include "common/history.h"
67#include "common/imageio.h"
69#ifdef HAVE_OPENEXR
70#include "common/imageio_exr.h"
71#endif
72#ifdef HAVE_OPENJPEG
73#include "common/imageio_j2k.h"
74#endif
75#include "common/imageio_gm.h"
76#include "common/imageio_im.h"
78#include "common/imageio_jpeg.h"
79#include "common/imageio_pfm.h"
80#include "common/imageio_png.h"
81#include "common/imageio_pnm.h"
84#include "common/imageio_rgbe.h"
85#include "common/imageio_tiff.h"
86#ifdef HAVE_LIBAVIF
87#include "common/imageio_avif.h"
88#endif
89#ifdef HAVE_LIBHEIF
90#include "common/imageio_heif.h"
91#endif
92#ifdef HAVE_WEBP
93#include "common/imageio_webp.h"
94#endif
96#include "common/mipmap_cache.h"
97#include "common/styles.h"
98#include "control/conf.h"
99#include "control/control.h"
100#include "develop/blend.h"
101#include "develop/develop.h"
102#include "develop/imageop.h"
103
104#if defined(HAVE_GRAPHICSMAGICK)
105#include <magick/api.h>
106#include <magick/blob.h>
107#elif defined(HAVE_IMAGEMAGICK)
108#include <MagickWand/MagickWand.h>
109#endif
110
111#include <assert.h>
112#include <glib/gstdio.h>
113#include <inttypes.h>
114#include <math.h>
115#include <stdio.h>
116#include <stdlib.h>
117#include <string.h>
118#include <strings.h>
119
120// These lists drive *type inference from the file extension only* (dt_imageio_get_type_from_extension).
121// They are deliberately conservative: the extension is only allowed to commit a dynamic-range flag
122// when the container's sample format is fixed. A raw extension always means sensor data; an
123// integer-only container is always LDR; a float-only container is always HDR.
124//
125// Containers that can hold EITHER integer or float / high-bit-depth data — TIFF, AVIF, HEIF/HEIC,
126// and `dng` — are NOT listed here on purpose: their dynamic range cannot be known before decoding,
127// so they stay UNKNOWN until dt_image_buffer_resolve_flags() classifies them from the decoded
128// buffer datatype (TYPE_FLOAT -> HDR, integer non-raw -> LDR). Decoder *routing* for those formats
129// lives in the separate raster_formats[] / hdr_formats[] lists below, which is a different concern.
130static const gchar *_supported_raw[]
131 = { "3fr", "ari", "arw", "bay", "cr2", "cr3", "crw", "dc2", "dcr", "erf", "fff",
132 "ia", "iiq", "k25", "kc2", "kdc", "mdc", "mef", "mos", "mrw", "nef", "nrw",
133 "orf", "pef", "raf", "raw", "rw2", "rwl", "sr2", "srf", "srw", "sti", "x3f", NULL };
134// integer-only raster containers — unambiguously low dynamic range:
135static const gchar *_supported_ldr[]
136 = { "bmp", "bmq", "cap", "cine", "cs1", "dcm", "gif", "gpr", "j2c", "j2k", "jng", "jp2", "jpc",
137 "jpeg", "jpg", "miff", "mng", "ori", "pbm", "pgm", "png", "pnm", "ppm", "pxn", "qtk", "rdc",
138 "webp", NULL };
139// float-only raster containers — unambiguously high dynamic range:
140static const gchar *_supported_hdr[] = { "exr", "hdr", "pfm", NULL };
141
157#if defined(HAVE_GRAPHICSMAGICK)
158static const char *_preview_format_from_mime_type(const char *mime_type)
159{
160 if(IS_NULL_PTR(mime_type) || mime_type[0] == '\0') return NULL;
161
162 if(!strcmp(mime_type, "image/jpeg")) return "JPEG";
163 if(!strcmp(mime_type, "image/png")) return "PNG";
164 if(!strcmp(mime_type, "image/tiff")) return "TIFF";
165 if(!strcmp(mime_type, "image/x-tiff")) return "TIFF";
166 if(!strcmp(mime_type, "image/gif")) return "GIF";
167 if(!strcmp(mime_type, "image/bmp")) return "BMP";
168 if(!strcmp(mime_type, "image/x-portable-pixmap")) return "PPM";
169 if(!strcmp(mime_type, "image/x-portable-graymap")) return "PGM";
170 if(!strcmp(mime_type, "image/x-portable-bitmap")) return "PBM";
171 if(!strcmp(mime_type, "image/x-portable-anymap")) return "PNM";
172 if(!strcmp(mime_type, "image/webp")) return "WEBP";
173 return NULL;
174}
175#endif
176
177// Best-effort image-type hint from the file extension. Returns DT_IMAGE_RAW / DT_IMAGE_LDR /
178// DT_IMAGE_HDR for the unambiguous extensions, or 0 ("unknown") for containers whose dynamic range
179// only the decoder can settle (TIFF, AVIF, HEIF/HEIC, DNG). Callers must treat 0 as "decode it";
180// dt_image_buffer_resolve_flags() sets the authoritative LDR/HDR/MOSAIC flags once decoded.
182{
183 const char *ext = g_str_has_prefix(extension, ".") ? extension + 1 : extension;
184 for(const char **i = _supported_raw; !IS_NULL_PTR(*i); i++)
185 {
186 if(!g_ascii_strncasecmp(ext, *i, strlen(*i)))
187 {
188 return DT_IMAGE_RAW;
189 }
190 }
191 for(const char **i = _supported_hdr; !IS_NULL_PTR(*i); i++)
192 {
193 if(!g_ascii_strncasecmp(ext, *i, strlen(*i)))
194 {
195 return DT_IMAGE_HDR;
196 }
197 }
198 for(const char **i = _supported_ldr; !IS_NULL_PTR(*i); i++)
199 {
200 if(!g_ascii_strncasecmp(ext, *i, strlen(*i)))
201 {
202 return DT_IMAGE_LDR;
203 }
204 }
205 // default to 0
206 return 0;
207}
208
209int dt_imageio_large_thumbnail(const char *filename, uint8_t **buffer, int32_t *th_width, int32_t *th_height,
211{
212 int res = 1;
213
214 uint8_t *buf = NULL;
215 char *mime_type = NULL;
216 size_t bufsize;
217
218 if(dt_exif_get_thumbnail(filename, &buf, &bufsize, &mime_type, th_width, th_height, MAX(width, height)))
219 goto error;
220
221 if(strcmp(mime_type, "image/jpeg") == 0)
222 {
223 // Decompress the JPG into our own memory format
225 if(dt_imageio_jpeg_decompress_header(buf, bufsize, &jpg)) goto error;
226 *buffer = (uint8_t *)dt_pixelpipe_cache_alloc_align_cache(
227 sizeof(uint8_t) * 4 * jpg.width * jpg.height,
228 0);
229 if(!*buffer) goto error;
230
231 *th_width = jpg.width;
232 *th_height = jpg.height;
233 // TODO: check if the embedded thumbs have a color space set! currently we assume that it's always sRGB
235 if(dt_imageio_jpeg_decompress(&jpg, *buffer))
236 {
238 *buffer = NULL;
239 goto error;
240 }
241
242 res = 0;
243 }
244 else
245 {
246#if defined(HAVE_GRAPHICSMAGICK)
247 const char *const preview_format = _preview_format_from_mime_type(mime_type);
248 ExceptionInfo exception;
249 Image *image = NULL;
250 ImageInfo *image_info = NULL;
251
252 GetExceptionInfo(&exception);
253 image_info = CloneImageInfo((ImageInfo *)NULL);
254 if(!IS_NULL_PTR(preview_format))
255 g_strlcpy(image_info->magick, preview_format, sizeof(image_info->magick));
256
257 // GraphicsMagick calls assert() -> abort() on some malformed embedded
258 // previews instead of reporting through `exception`. Recover instead of
259 // crashing the whole app; on recovery, `image`/`image_info`/`exception`
260 // are NOT touched again (see imageio_magick_abort_guard.h) - we leak
261 // them and bail out directly, only freeing the buffer Ansel itself
262 // allocated if the per-row decode loop got partway through it.
263 DT_MAGICK_ABORT_GUARD("dt_imageio_large_thumbnail GM", filename, {
264 if(*buffer)
265 {
267 *buffer = NULL;
268 }
269 goto error;
270 });
271
272 image = BlobToImage(image_info, buf, bufsize, &exception);
273
274 if(exception.severity != UndefinedException) CatchException(&exception);
275
276 if(IS_NULL_PTR(image))
277 {
278 fprintf(stderr, "[dt_imageio_large_thumbnail GM] thumbnail not found?\n");
279 goto error_gm;
280 }
281
282 *th_width = image->columns;
283 *th_height = image->rows;
284 *color_space = DT_COLORSPACE_SRGB; // FIXME: this assumes that embedded thumbnails are always srgb
285
286 *buffer = (uint8_t *)dt_pixelpipe_cache_alloc_align_cache(
287 sizeof(uint8_t) * 4 * image->columns * image->rows,
288 0);
289 if(!*buffer) goto error_gm;
290
291 for(uint32_t row = 0; row < image->rows; row++)
292 {
293 uint8_t *bufprt = *buffer + (size_t)4 * row * image->columns;
294 int gm_ret = DispatchImage(image, 0, row, image->columns, 1, "RGBP", CharPixel, bufprt, &exception);
295
296 if(exception.severity != UndefinedException) CatchException(&exception);
297
298 if(gm_ret != MagickPass)
299 {
300 fprintf(stderr, "[dt_imageio_large_thumbnail GM] error_gm reading thumbnail\n");
302 *buffer = NULL;
303 goto error_gm;
304 }
305 }
306
307 // fprintf(stderr, "[dt_imageio_large_thumbnail GM] successfully decoded thumbnail\n");
308 res = 0;
309
310 error_gm:
311 DT_MAGICK_ABORT_GUARD_DISARM();
312 if(image) DestroyImage(image);
313 if(image_info) DestroyImageInfo(image_info);
314 DestroyExceptionInfo(&exception);
315 if(res) goto error;
316#elif defined(HAVE_IMAGEMAGICK)
317 MagickWand *image = NULL;
318 MagickBooleanType mret;
319
320 image = NewMagickWand();
321
322 // ImageMagick calls assert() -> abort() on some malformed embedded
323 // previews instead of reporting through its normal error status.
324 // Recover instead of crashing the whole app; on recovery, `image` is
325 // NOT touched again (see imageio_magick_abort_guard.h) - we leak the
326 // wand and bail out directly, only freeing the buffer Ansel itself
327 // allocated if it was set before the abort.
328 DT_MAGICK_ABORT_GUARD("dt_imageio_large_thumbnail IM", filename, {
329 if(*buffer)
330 {
331 dt_free(*buffer);
332 *buffer = NULL;
333 }
334 goto error;
335 });
336
337 mret = MagickReadImageBlob(image, buf, bufsize);
338 if(mret != MagickTrue)
339 {
340 fprintf(stderr, "[dt_imageio_large_thumbnail IM] thumbnail not found?\n");
341 goto error_im;
342 }
343
344 *th_width = MagickGetImageWidth(image);
345 *th_height = MagickGetImageHeight(image);
346 switch (MagickGetImageColorspace(image)) {
347 case sRGBColorspace:
349 break;
350 default:
351 fprintf(stderr,
352 "[dt_imageio_large_thumbnail IM] could not map colorspace, using sRGB");
354 break;
355 }
356
357 *buffer = malloc(sizeof(uint8_t) * (*th_width) * (*th_height) * 4);
358 if(IS_NULL_PTR(*buffer)) goto error_im;
359
360 mret = MagickExportImagePixels(image, 0, 0, *th_width, *th_height, "RGBP", CharPixel, *buffer);
361 if(mret != MagickTrue) {
362 dt_free(*buffer);
363 fprintf(stderr,
364 "[dt_imageio_large_thumbnail IM] error while reading thumbnail\n");
365 goto error_im;
366 }
367
368 res = 0;
369
370error_im:
371 DT_MAGICK_ABORT_GUARD_DISARM();
372 DestroyMagickWand(image);
373 if(res != 0) goto error;
374#else
375 fprintf(stderr,
376 "[dt_imageio_large_thumbnail] error: The thumbnail image is not in "
377 "JPEG format, and DT was built without neither GraphicsMagick or "
378 "ImageMagick. Please rebuild DT with GraphicsMagick or ImageMagick "
379 "support enabled.\n");
380#endif
381 }
382
383 if(res)
384 {
385 fprintf(
386 stderr,
387 "[dt_imageio_large_thumbnail] error: Not a supported thumbnail image format or broken thumbnail: %s\n",
388 mime_type);
389 goto error;
390 }
391
392error:
393 dt_free(mime_type);
394 dt_free(buf);
395 return res;
396}
397
398gboolean dt_imageio_has_mono_preview(const char *filename)
399{
401 uint8_t *tmp = NULL;
402 int32_t thumb_width = 0, thumb_height = 0;
403 gboolean mono = FALSE;
404
405 if(dt_imageio_large_thumbnail(filename, &tmp, &thumb_width, &thumb_height, &color_space, -1, -1))
406 goto cleanup;
407 if((thumb_width < 32) || (thumb_height < 32) || (IS_NULL_PTR(tmp)))
408 goto cleanup;
409
410 mono = TRUE;
411 for(int y = 0; y < thumb_height; y++)
412 {
413 uint8_t *in = (uint8_t *)tmp + (size_t)4 * y * thumb_width;
414 for(int x = 0; x < thumb_width; x++, in += 4)
415 {
416 if((in[0] != in[1]) || (in[0] != in[2]) || (in[1] != in[2]))
417 {
418 mono = FALSE;
419 goto cleanup;
420 }
421 }
422 }
423
424 cleanup:
425
426 dt_print(DT_DEBUG_IMAGEIO,"[dt_imageio_has_mono_preview] testing `%s', yes/no %i, %ix%i\n", filename, mono, thumb_width, thumb_height);
428 return mono;
429}
430
432void dt_imageio_flip_buffers(char *out, const char *in, const size_t bpp, const int wd, const int ht,
433 const int fwd, const int fht, const int stride,
434 const dt_image_orientation_t orientation)
435{
436 if(!orientation)
437 {
439 for(int j = 0; j < ht; j++) memcpy(out + (size_t)j * bpp * wd, in + (size_t)j * stride, bpp * wd);
440 return;
441 }
442 int ii = 0, jj = 0;
443 int si = bpp, sj = wd * bpp;
444 if(orientation & ORIENTATION_SWAP_XY)
445 {
446 sj = bpp;
447 si = ht * bpp;
448 }
449 if(orientation & ORIENTATION_FLIP_Y)
450 {
451 jj = (int)fht - jj - 1;
452 sj = -sj;
453 }
454 if(orientation & ORIENTATION_FLIP_X)
455 {
456 ii = (int)fwd - ii - 1;
457 si = -si;
458 }
460 for(int j = 0; j < ht; j++)
461 {
462 char *out2 = out + (size_t)labs(sj) * jj + (size_t)labs(si) * ii + (size_t)sj * j;
463 const char *in2 = in + (size_t)stride * j;
464 for(int i = 0; i < wd; i++)
465 {
466 memcpy(out2, in2, bpp);
467 in2 += bpp;
468 out2 += si;
469 }
470 }
471}
472
473void dt_imageio_flip_buffers_ui8_to_float(float *out, const uint8_t *in, const float black, const float white,
474 const int ch, const int wd, const int ht, const int fwd,
475 const int fht, const int stride,
476 const dt_image_orientation_t orientation)
477{
478 const float scale = 1.0f / (white - black);
479 if(!orientation)
480 {
482 for(int j = 0; j < ht; j++)
483 for(int i = 0; i < wd; i++)
484 for(int k = 0; k < ch; k++)
485 out[4 * ((size_t)j * wd + i) + k] = (in[(size_t)j * stride + (size_t)ch * i + k] - black) * scale;
486 return;
487 }
488 int ii = 0, jj = 0;
489 int si = 4, sj = wd * 4;
490 if(orientation & ORIENTATION_SWAP_XY)
491 {
492 sj = 4;
493 si = ht * 4;
494 }
495 if(orientation & ORIENTATION_FLIP_Y)
496 {
497 jj = (int)fht - jj - 1;
498 sj = -sj;
499 }
500 if(orientation & ORIENTATION_FLIP_X)
501 {
502 ii = (int)fwd - ii - 1;
503 si = -si;
504 }
506 for(int j = 0; j < ht; j++)
507 {
508 float *out2 = out + (size_t)labs(sj) * jj + (size_t)labs(si) * ii + sj * j;
509 const uint8_t *in2 = in + (size_t)stride * j;
510 for(int i = 0; i < wd; i++)
511 {
512 for(int k = 0; k < ch; k++) out2[k] = (in2[k] - black) * scale;
513 in2 += ch;
514 out2 += si;
515 }
516 }
517}
518
520{
521 // if buf is NULL, don't proceed
522 if(IS_NULL_PTR(buf))
523 return DT_IMAGEIO_OK;
524
526
527#ifdef HAVE_OPENEXR
528 ret = dt_imageio_open_exr(img, filename, buf);
529 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
530 return ret;
531#endif
532
533 ret = dt_imageio_open_rgbe(img, filename, buf);
534 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
535 return ret;
536
537 ret = dt_imageio_open_pfm(img, filename, buf);
538 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
539 return ret;
540
541#ifdef HAVE_LIBAVIF
542 ret = dt_imageio_open_avif(img, filename, buf);
543 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
544 return ret;
545#endif
546
547#ifdef HAVE_LIBHEIF
548 ret = dt_imageio_open_heif(img, filename, buf);
549 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
550 return ret;
551#endif
552
553 ret = dt_imageio_open_exotic(img, filename, buf);
554 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
555 return ret;
556
558}
559
560static const char *raster_formats[] = {
561 ".jpg", ".jpeg", ".png", ".tiff", ".tif", ".pgm", ".pbm", ".ppm",
562
563#ifdef HAVE_OPENJPEG
564 ".jp2", ".j2k",
565#endif
566
567#ifdef HAVE_WEBP
568 ".webp",
569#endif
570
571 NULL,
572};
573
574gboolean dt_imageio_is_raster(const char *filename)
575{
576 const char *c = filename + strlen(filename);
577 while(c > filename && *c != '.') c--;
578 if(*c != '.') return FALSE;
579
580 int i = 0;
581 while(raster_formats[i])
582 {
583 if(!strcasecmp(c, raster_formats[i])) return TRUE;
584 i++;
585 }
586
587 return FALSE;
588}
589
590// We include DNG here since it's handled by raw libs
591static const char *raw_formats[] = {
592 ".3fr", ".ari", ".arw", ".bay", ".bmq", ".cap", ".cine", ".cr2", ".crw", ".cs1", ".dc2",
593 ".dcr", ".dng", ".gpr", ".erf", ".fff", ".ia", ".iiq", ".k25", ".kc2", ".kdc", ".mdc",
594 ".mef", ".mos", ".mrw", ".nef", ".nrw", ".orf", ".ori", ".pef", ".pxn", ".qtk", ".raf",
595 ".raw", ".rdc", ".rw2", ".rwl", ".sr2", ".srf", ".srw", ".x3f",
596
597#ifdef HAVE_LIBRAW
598 ".cr3",
599#endif
600
601 NULL
602};
603
604
605gboolean dt_imageio_is_raw(const char *filename)
606{
607 const char *c = filename + strlen(filename);
608 while(c > filename && *c != '.') c--;
609 if(*c != '.') return FALSE;
610
611 int i = 0;
612 while(raw_formats[i])
613 {
614 if(!strcasecmp(c, raw_formats[i])) return TRUE;
615 i++;
616 }
617
618 return FALSE;
619}
620
621static const char *hdr_formats[] = {
622 ".pfm", ".hdr",
623
624#ifdef HAVE_OPENEXR
625 ".exr",
626#endif
627
628#ifdef HAVE_LIBAVIF
629 ".avif",
630#endif
631
632#ifdef HAVE_LIBHEIF
633 ".heif", ".heic", ".hif",
634#endif
635
636 NULL
637};
638
639
640int dt_imageio_is_hdr(const char *filename)
641{
642 const char *c = filename + strlen(filename);
643 while(c > filename && *c != '.') c--;
644 if(*c != '.') return FALSE;
645
646 int i = 0;
647 while(hdr_formats[i])
648 {
649 if(!strcasecmp(c, hdr_formats[i])) return TRUE;
650 i++;
651 }
652
653 return FALSE;
654}
655
656static gboolean _is_in_list(char *elem, char *list)
657{
658 // Search if elem is contained in the coma-separated list string
659 gboolean success = FALSE;
660 if(elem && list)
661 {
662 while(!IS_NULL_PTR(list) && !success)
663 {
664 success = !g_ascii_strncasecmp(list, elem, strlen(elem));
665 list = strtok(NULL, ",");
666 }
667 }
668
669 return success;
670}
671
672gboolean dt_imageio_is_handled_by_libraw(dt_image_t *img, const char *filename)
673{
674 // Allow users to define some extensions, makers and models that should be handled by Libraw
675 gboolean is_handled = FALSE;
676
677 char *ext = g_strrstr(filename, ".") + 1; // move the pointer after the extension dot
678 char *extensions = dt_conf_get_string("libraw/extensions");
679 char *makers = dt_conf_get_string("libraw/makers");
680 char *models = dt_conf_get_string("libraw/models");
681
682 is_handled |= _is_in_list(ext, strtok(extensions, ","));
683 is_handled |= _is_in_list(img->exif_maker, strtok(makers, ","));
684 is_handled |= _is_in_list(img->exif_model, strtok(models, ","));
685
686 dt_free(extensions);
687 dt_free(makers);
688 dt_free(models);
689
690 const char *iolib = (is_handled) ? "Libraw" : "Rawspeed";
691 dt_print(DT_DEBUG_IMAGEIO, "[image I/O] image `%s` from camera `%s` of maker `%s` loaded with %s\n", filename,
692 img->exif_model, img->exif_maker, iolib);
693
694 return is_handled;
695}
696
697// transparent read method to load ldr image to dt_raw_image_t with exif and so on.
699{
700 // if buf is NULL, don't proceed
701 if(IS_NULL_PTR(buf))
702 return DT_IMAGEIO_OK;
703
705
706 ret = dt_imageio_open_jpeg(img, filename, buf);
707 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
708 return ret;
709
710 ret = dt_imageio_open_tiff(img, filename, buf);
711 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
712 return ret;
713
714#ifdef HAVE_WEBP
715 ret = dt_imageio_open_webp(img, filename, buf);
716 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
717 return ret;
718#endif
719
720 ret = dt_imageio_open_png(img, filename, buf);
721 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
722 return ret;
723
724#ifdef HAVE_OPENJPEG
725 ret = dt_imageio_open_j2k(img, filename, buf);
726 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
727 return ret;
728#endif
729
730 ret = dt_imageio_open_pnm(img, filename, buf);
731 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
732 return ret;
733
734 ret = dt_imageio_open_exotic(img, filename, buf);
735 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
736 return ret;
737
739}
740
742{
743 // if buf is NULL, don't proceed
744 if(IS_NULL_PTR(buf))
745 return DT_IMAGEIO_OK;
746
748
749 /* check if user wants to force processing through Libraw */
750 const gboolean force_libraw = dt_imageio_is_handled_by_libraw(img, filename);
751
752 /* use rawspeed to load the raw */
753 if(!force_libraw)
754 {
755 ret = dt_imageio_open_rawspeed(img, filename, buf);
756 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
757 return ret;
758 }
759
760#ifdef HAVE_LIBRAW
761 /* fallback that tries to open file via LibRAW to support Canon CR3 */
762 ret = dt_imageio_open_libraw(img, filename, buf);
763 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
764 return ret;
765#endif
766
767 /* try Rawspeed again in case Libraw was forced but failed */
768 if(force_libraw)
769 {
770 ret = dt_imageio_open_rawspeed(img, filename, buf);
771 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
772 return ret;
773 }
774
775 /* fallback that tries to open file via GraphicsMagick */
776 ret = dt_imageio_open_exotic(img, filename, buf);
777 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
778 return ret;
779
781}
782
783void dt_imageio_to_fractional(float in, uint32_t *num, uint32_t *den)
784{
785 if(!(in >= 0))
786 {
787 *num = *den = 0;
788 return;
789 }
790 *den = 1;
791 *num = (int)(in * *den + .5f);
792 while(fabsf(*num / (float)*den - in) > 0.001f)
793 {
794 *den *= 10;
795 *num = (int)(in * *den + .5f);
796 }
797}
798
799int dt_imageio_export(const int32_t imgid, const char *filename, dt_imageio_module_format_t *format,
800 dt_imageio_module_data_t *format_params, const gboolean high_quality,
801 const gboolean copy_metadata, const gboolean export_masks,
802 dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename,
804 dt_imageio_module_data_t *storage_params, int num, int total, dt_export_metadata_t *metadata)
805{
806 if(strcmp(format->mime(format_params), "x-copy") == 0)
807 /* This is a just a copy, skip process and just export */
808 return format->write_image(format_params, filename, NULL, icc_type, icc_filename, NULL, 0, imgid, num, total, NULL,
809 export_masks);
810 else
811 {
812 const gboolean is_scaling =
813 dt_conf_is_equal("plugins/lighttable/export/resizing", "scaling");
814
815 return dt_imageio_export_with_flags(imgid, filename, format, format_params, FALSE, FALSE, TRUE, is_scaling,
816 FALSE, NULL, copy_metadata, export_masks, icc_type, icc_filename, icc_intent,
817 storage, storage_params, num, total, metadata, NULL);
818 }
819}
820
821gboolean _apply_style_before_export(dt_develop_t *dev, dt_imageio_module_data_t *format_params, const int32_t imgid)
822{
823 GList *style_items = dt_styles_get_item_list(format_params->style, TRUE, -1);
824 if(IS_NULL_PTR(style_items))
825 {
826 dt_control_log(_("cannot find the style '%s' to apply during export."), format_params->style);
827 return TRUE;
828 }
829
830 dt_ioppr_check_iop_order(dev, imgid, "dt_imageio_export_with_flags");
832 dt_ioppr_update_for_style_items(dev, style_items, TRUE);
833
834 for(GList *st_items = style_items; st_items; st_items = g_list_next(st_items))
835 {
836 dt_style_item_t *st_item = (dt_style_item_t *)st_items->data;
837 dt_styles_apply_style_item(dev, st_item);
838 }
839
840 g_list_free_full(style_items, dt_style_item_free);
841 style_items = NULL;
842
843 return FALSE;
844}
845
846void _print_export_debug(dt_dev_pixelpipe_t *pipe, dt_imageio_module_data_t *format_params, const gboolean use_style)
847{
849 {
850 fprintf(stderr,"[dt_imageio_export_with_flags] ");
851 if(use_style)
852 {
853 fprintf(stderr,"appending style `%s'\n", format_params->style);
854 }
855 else fprintf(stderr,"\n");
856 int cnt = 0;
857 for(GList *nodes = pipe->nodes; nodes; nodes = g_list_next(nodes))
858 {
860 if(piece->enabled)
861 {
862 cnt++;
863 fprintf(stderr," %s", piece->module->op);
864 }
865 }
866 fprintf(stderr," (%i)\n", cnt);
867 }
868}
869
870
871void _filter_pipeline(const char *filter, dt_dev_pixelpipe_t *pipe)
872{
873 // Warning: can only filter prior to or past to a certain module, but not both !!!
874 if(filter)
875 {
876 if(!strncmp(filter, "pre:", 4)) dt_dev_pixelpipe_disable_after(pipe, filter + 4);
877 if(!strncmp(filter, "post:", 5)) dt_dev_pixelpipe_disable_before(pipe, filter + 5);
878 }
879}
880
881
883 const dt_imageio_module_data_t *format_params, const gboolean is_scaling, double *scale,
884 int width, int height, int *processed_width, int *processed_height)
885{
886 const double image_ratio = (double)pipe->processed_width / (double)pipe->processed_height;
887
888 if(is_scaling)
889 {
890 double _num, _denum;
892 const double scale_factor = _num / _denum;
893 *scale = fmin(scale_factor, 1.);
894 *processed_height = (int)roundf(pipe->processed_height * (*scale));
895 *processed_width = (int)roundf(pipe->processed_width * (*scale));
896 return 0;
897 }
898
899 // if width and height are both 0, we use the full resolution of the image
900 if(width == 0 && height == 0)
901 {
902 // original resolution
903 *processed_width = pipe->processed_width;
904 *processed_height = pipe->processed_height;
905 *scale = 1.;
906 return 0;
907 }
908
909 if(width > 0 && height > 0)
910 {
911 // fixed width and height : fit within a bounding box
912 *processed_width = MIN(pipe->processed_width, width);
913 *processed_height = MIN(pipe->processed_height, height);
914 double scale_x = (double)*processed_width / (double)pipe->processed_width;
915 double scale_y = (double)*processed_height / (double)pipe->processed_height;
916 *scale = fmin(scale_x, scale_y);
917
918 // Note : we handle each case separately to avoid rounding errors
919 if(image_ratio > 1.0)
920 {
921 // landscape image, width is the limiting factor
922 *processed_width = MIN((int)roundf(pipe->processed_width * (*scale)), pipe->processed_width);
923 *processed_height = MIN((int)roundf(*processed_width / image_ratio), pipe->processed_height);
924 }
925 else if(image_ratio < 1.0)
926 {
927 // portrait image, height is the limiting factor
928 *processed_height = MIN((int)roundf(pipe->processed_height * (*scale)), pipe->processed_height);
929 *processed_width = MIN((int)roundf(*processed_height * image_ratio), pipe->processed_width);
930 }
931 else
932 {
933 // square image, both width and height are the limiting factors
934 *processed_width = MIN((int)roundf(pipe->processed_width * (*scale)), pipe->processed_width);
935 *processed_height = MIN((int)roundf(pipe->processed_height * (*scale)), pipe->processed_height);
936 }
937 return 0;
938 }
939
940 if(width > 0)
941 {
942 // fluid height, fixed width
943 *processed_width = MIN(pipe->processed_width, width);
944 *processed_height = (int)roundf(*processed_width / image_ratio);
945 }
946 else if(height > 0)
947 {
948 // fluid width, fixed height
949 *processed_height = MIN(pipe->processed_height, height);
950 *processed_width = (int)roundf(*processed_height * image_ratio);
951 }
952
953 double scale_x = (double)*processed_width / (double)pipe->processed_width;
954 double scale_y = (double)*processed_height / (double)pipe->processed_height;
955 *scale = fmin(scale_x, scale_y);
956
957 return 0;
958}
959
960
961void _clamp_float_to_uint8(const float *const inbuf, uint8_t *const outbuf, const size_t processed_width,
962 const size_t processed_height)
963{
965 for(size_t k = 0; k < processed_width * processed_height; k++)
967 outbuf[4 * k + c] = (uint8_t)CLAMPF(roundf(inbuf[4 * k + c] * 255.f), 0.f, 255.f);
968}
969
970
971void _swap_byteorder_float_to_uint8(const float *const restrict inbuf, uint8_t *const outbuf,
972 const size_t processed_width, const size_t processed_height)
973{
975 for(size_t k = 0; k < processed_width * processed_height; k++)
976 {
977 outbuf[4 * k + 0] = (uint8_t)CLAMPF(roundf(inbuf[4 * k + 2] * 255.f), 0.f, 255.f);
978 outbuf[4 * k + 1] = (uint8_t)CLAMPF(roundf(inbuf[4 * k + 1] * 255.f), 0.f, 255.f);
979 outbuf[4 * k + 2] = (uint8_t)CLAMPF(roundf(inbuf[4 * k + 0] * 255.f), 0.f, 255.f);
980 outbuf[4 * k + 3] = (uint8_t)CLAMPF(roundf(inbuf[4 * k + 3] * 255.f), 0.f, 255.f);
981 }
982}
983
984
985void _export_final_buffer_to_uint16(const float *const restrict inbuf, uint16_t *const outbuf,
986 const size_t processed_width, const size_t processed_height)
987{
989 for(size_t k = 0; k < processed_width * processed_height; k++)
991 outbuf[4 * k + c] = (uint16_t)CLAMP(roundf(inbuf[4 * k + c] * 65535.f), 0.f, 65535.f);
992}
993
994// internal function: to avoid exif blob reading + 8-bit byteorder flag + high-quality override
995int dt_imageio_export_with_flags(const int32_t imgid, const char *filename,
997 const gboolean ignore_exif, const gboolean display_byteorder,
998 const gboolean high_quality, gboolean is_scaling, const gboolean thumbnail_export,
999 const char *filter, const gboolean copy_metadata, const gboolean export_masks,
1000 dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename,
1002 dt_imageio_module_data_t *storage_params, int num, int total,
1003 dt_export_metadata_t *metadata, dt_atomic_int *shutdown)
1004{
1005 dt_times_t start;
1006 dt_get_times(&start);
1007
1010 void *outbuf = NULL;
1011
1012 // Get the history, aka sequence of editing changes
1013 dt_develop_t dev;
1014 dt_dev_init(&dev, 0);
1015 dt_dev_load_image(&dev, imgid);
1017
1018 // Apply styles on top of current history
1019 const gboolean use_style = !thumbnail_export && format_params->style[0] != '\0';
1020 // If a style is to be applied during export, add the iop params into the history
1021 if(use_style && _apply_style_before_export(&dev, format_params, imgid))
1022 goto error;
1023
1024 int width = MAX(format_params->max_width, 0);
1025 int height = MAX(format_params->max_height, 0);
1026 double scale = 1.;
1027
1028 // Get a pipeline, aka sequence of nodes
1029 int res = 0;
1030 dt_dev_pixelpipe_t pipe;
1031 if(thumbnail_export)
1032 res = dt_dev_pixelpipe_init_thumbnail(&pipe, &dev);
1033 else
1034 res = dt_dev_pixelpipe_init_export(&pipe, &dev, format->levels(format_params), export_masks);
1035
1036 if(!res) goto error;
1037
1038 pipe.shutdown_ext = shutdown;
1039
1041
1042 // Sync history with pipeline nodes
1043 // Update the ICC type if DT_COLORSPACE_NONE is passed
1044 dt_colorspaces_get_output_profile(imgid, &icc_type, icc_filename);
1045 dt_dev_pixelpipe_set_icc(&pipe, icc_type, icc_filename, icc_intent);
1046
1047 // Find out what input size we want
1049
1050 // Take a local copy of the input buffer so we can release the mipmap cache lock immediately
1051 dt_mipmap_cache_get(cache, &buf, imgid, size, DT_MIPMAP_BLOCKING, 'r');
1052
1053 if(IS_NULL_PTR(buf.buf) || buf.width == 0 || buf.height == 0)
1054 {
1056 goto error;
1057 }
1058
1059 const size_t buf_width = buf.width;
1060 const size_t buf_height = buf.height;
1062
1063 // Update size with actual input and resync nodes
1064 dt_dev_pixelpipe_set_input(&pipe, imgid, buf_width, buf_height, buf.iscale, size);
1066
1067 // Write debug info to stdout
1068 _print_export_debug(&pipe, format_params, use_style);
1069
1070 // Remove modules past or prior a certain one.
1071 // Useful for partial exports, for technical purposes (HDR merge)
1072 _filter_pipeline(filter, &pipe);
1073
1074 // This export path drives the pipe directly instead of through dt_dev_pixelpipe_change(), so
1075 // establish the buffer-format contract (and disable incompatible nodes) explicitly, after the
1076 // optional filtering changed the node set and before ROI planning / global hashing.
1078
1079 // Get theoritical final size of image, taking distortions and croppings AND borders into account,
1080 // considering full-size original input. Meaning we can enlarge or reduce the original image,
1081 // even taking full-res input.
1082 // Needs to be done after optional filtering, in case we filter out distortion modules
1084 &pipe.processed_height);
1085
1086 dt_show_times(&start, "[export] creating pixelpipe");
1087
1088 // Compute the actual final sizes that fit within the bounding box width*height
1089 // while preserving original image ratio
1090 int processed_width = 0;
1091 int processed_height = 0;
1092 _get_export_size(&dev, &pipe, format_params, is_scaling, &scale, width, height,
1093 &processed_width, &processed_height);
1094
1096 "[dt_imageio_export] (direct) image input %ix%i, turned to output %ix%i, will be exported to fit %ix%i "
1097 "--> final size is %ix%i\n",
1098 pipe.iwidth, pipe.iheight, pipe.processed_width, pipe.processed_height, width, height, processed_width,
1099 processed_height);
1100
1101
1102 const int bpp = format->bpp(format_params);
1103
1104 dt_iop_roi_t roi = (dt_iop_roi_t){ 0, 0, processed_width, processed_height, scale };
1105
1106 dt_get_times(&start);
1107 int err = dt_dev_pixelpipe_process(&pipe, roi);
1108 dt_show_times(&start, thumbnail_export ? "[dev_process_thumbnail] pixel pipeline processing thread"
1109 : "[dev_process_export] pixel pipeline processing thread");
1110
1111 if(dt_dev_backbuf_get_hash(&pipe.backbuf) == -1 || err)
1112 {
1113 dt_print(DT_DEBUG_IMAGEIO, "[dt_imageio_export_with_flags] no valid output buffer\n");
1114 goto error;
1115 }
1116
1117 struct dt_pixel_cache_entry_t *cache_entry;
1118 void *data = NULL;
1119 /* Atomically look up the final pipeline output and increment its refcount under the cache
1120 * mutex. peek() + separate ref_count_entry() has a TOCTOU window: peek releases its
1121 * tryrdlock immediately and returns with no ownership, so a concurrent eviction thread
1122 * could see refcount==1 (backbuf keepalive only) and decrement it to 0 between peek()
1123 * returning and our ref_count_entry() call — leaving us with a dangling data pointer that
1124 * the OpenMP conversion threads then read → SIGSEGV. ref_entry_by_hash() closes that
1125 * window by holding cache->lock across both the lookup and the increment. */
1128 &data, &cache_entry)
1129 || !data)
1130 {
1131 if(cache_entry)
1133 goto error;
1134 }
1135
1136 /* Hold a read lock for the duration of the conversion so no writer can replace the buffer
1137 * while the OpenMP threads are reading it. */
1139
1140 // Down-conversion to low-precision formats:
1141 const size_t pixels = pipe.backbuf.width * pipe.backbuf.height * 4;
1142 if(bpp == 8)
1143 {
1145 sizeof(uint8_t) * pixels,
1146 0);
1147 if(outbuf && display_byteorder)
1149 else if(outbuf)
1151
1152 /* Thumbnail export stores the in-memory RGBA buffer straight into the mipmap cache.
1153 * The thumbnail pipeline does not maintain a meaningful alpha contract across all
1154 * modules, so random zero/garbage alpha values would make valid RGB thumbnails render
1155 * black in consumers that composite the mipmap buffer. Keep thumbnail alpha opaque at
1156 * the export boundary and leave RGB untouched. */
1157 if(outbuf && thumbnail_export)
1158 {
1159 uint8_t *thumbnail_buf = (uint8_t *)outbuf;
1161 for(size_t k = 0; k < pixels / 4; k++) thumbnail_buf[4 * k + 3] = UINT8_MAX;
1162 }
1163 }
1164 else if(bpp == 16)
1165 {
1167 sizeof(uint16_t) * pixels,
1168 0);
1169 if(outbuf)
1171
1172 if(outbuf && thumbnail_export)
1173 {
1174 uint16_t *thumbnail_buf = (uint16_t *)outbuf;
1176 for(size_t k = 0; k < pixels / 4; k++) thumbnail_buf[4 * k + 3] = UINT16_MAX;
1177 }
1178 }
1179 else // output float, no further harm done to the pixels :)
1180 {
1182 sizeof(float_t) * pixels,
1183 0);
1184 if(outbuf)
1185 memcpy(outbuf, data, sizeof(float_t) * pixels);
1186
1187 if(outbuf && thumbnail_export)
1188 {
1189 float *thumbnail_buf = (float *)outbuf;
1191 for(size_t k = 0; k < pixels / 4; k++) thumbnail_buf[4 * k + 3] = 1.0f;
1192 }
1193 }
1194
1195 // Decrease ref count on the cache entry and release the read lock
1198
1199 if(IS_NULL_PTR(outbuf)) goto error;
1200
1201 format_params->width = pipe.backbuf.width;
1202 format_params->height = pipe.backbuf.height;
1203
1204 // Exif data should be 65536 bytes max, but if original size is close to that,
1205 // adding new tags could make it go over that... so let it be and see what
1206 // happens when we write the image
1207 int length = 0;
1208 uint8_t *exif_profile = NULL;
1209
1210 if(!ignore_exif)
1211 {
1212 gboolean from_cache = TRUE;
1213 char pathname[PATH_MAX] = { 0 };
1214 dt_image_full_path(imgid, pathname, sizeof(pathname), &from_cache, __FUNCTION__);
1215 // find output color profile for this image:
1216 int sRGB = (icc_type == DT_COLORSPACE_SRGB);
1217 // last param is dng mode, it's false here
1218 length = dt_exif_read_blob(&exif_profile, pathname, imgid, sRGB, pipe.backbuf.width, pipe.backbuf.height, 0);
1219 }
1220
1221 // Finally: write image buffer to target container
1222 res = format->write_image(format_params, filename, outbuf, icc_type, icc_filename, exif_profile, length, imgid,
1223 num, total, &pipe, export_masks);
1224
1225 dt_free(exif_profile);
1226 if(res) goto error;
1227
1229 dt_dev_cleanup(&dev);
1230
1231 /* now write xmp into that container, if possible */
1232 if(copy_metadata && (format->flags(format_params) & FORMAT_FLAGS_SUPPORT_XMP))
1233 dt_exif_xmp_attach_export(imgid, filename, metadata);
1234
1235 if(!thumbnail_export && strcmp(format->mime(format_params), "memory")
1236 && !(format->flags(format_params) & FORMAT_FLAGS_NO_TMPFILE))
1237 {
1239 format_params, storage, storage_params);
1240 }
1241
1243 return 0; // success
1244
1245error:
1248 dt_dev_cleanup(&dev);
1249 return 1;
1250}
1251
1252
1253// fallback read method in case file could not be opened yet.
1254// use GraphicsMagick (if supported) to read exotic LDRs
1256 dt_mipmap_buffer_t *buf)
1257{
1258 // if buf is NULL, don't proceed
1259 if(IS_NULL_PTR(buf))
1260 return DT_IMAGEIO_OK;
1261
1263
1264#if defined(HAVE_GRAPHICSMAGICK)
1265 ret = dt_imageio_open_gm(img, filename, buf);
1266#elif defined(HAVE_IMAGEMAGICK)
1267 ret = dt_imageio_open_im(img, filename, buf);
1268#else
1270#endif
1271
1272 return ret;
1273}
1274
1275// =================================================
1276// combined reading
1277// =================================================
1278
1279dt_imageio_retval_t dt_imageio_open(dt_image_t *img, // non-const * means you hold a write lock!
1280 const char *filename, // full path
1281 dt_mipmap_buffer_t *buf)
1282{
1283 /* first of all, check if file exists, don't bother to test loading if not exists */
1284 if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
1285 return !DT_IMAGEIO_OK;
1286
1288 img->loader = LOADER_UNKNOWN;
1289
1290 // Start with extensions that are supposed to work.
1291 // If they don't, they are corrupted.
1292
1293 if(dt_imageio_is_raster(filename))
1294 {
1295 ret = dt_imageio_open_raster(img, filename, buf);
1296 if(ret != DT_IMAGEIO_OK)
1297 {
1298 fprintf(stderr, "[imageio] The file %s is corrupted. Abort.\n", filename);
1299 dt_control_log(_("The file `%s` is corrupted."), filename);
1300 return ret;
1301 }
1302 }
1303
1304 if(dt_imageio_is_raw(filename))
1305 {
1306 ret = dt_imageio_open_raw(img, filename, buf);
1307 if(ret != DT_IMAGEIO_OK)
1308 {
1309 fprintf(stderr, "[imageio] The file %s is corrupted. Abort.\n", filename);
1310 dt_control_log(_("The file `%s` is corrupted."), filename);
1311 return ret;
1312 }
1313 }
1314
1315 if(dt_imageio_is_hdr(filename))
1316 {
1317 ret = dt_imageio_open_hdr(img, filename, buf);
1318 if(ret != DT_IMAGEIO_OK)
1319 {
1320 fprintf(stderr, "[imageio] The file %s is corrupted. Abort.\n", filename);
1321 dt_control_log(_("The file `%s` is corrupted."), filename);
1322 return ret;
1323 }
1324 }
1325
1326 // fallback: bruteforce everything hoping for a miracle
1327 // Most likely, it's a format we never heard of.
1328 if(ret != DT_IMAGEIO_OK && ret != DT_IMAGEIO_CACHE_FULL)
1329 ret = dt_imageio_open_raster(img, filename, buf);
1330
1331 if(ret != DT_IMAGEIO_OK && ret != DT_IMAGEIO_CACHE_FULL)
1332 ret = dt_imageio_open_raw(img, filename, buf);
1333
1334 if(ret != DT_IMAGEIO_OK && ret != DT_IMAGEIO_CACHE_FULL)
1335 ret = dt_imageio_open_hdr(img, filename, buf);
1336
1337 // Final check and abort
1338 if(ret != DT_IMAGEIO_OK)
1339 {
1340 fprintf(stderr, "[imageio] The file %s is supported by none of our decoders.\n", filename);
1341 dt_control_log(_("The file `%s` is supported by none of our decoders."), filename);
1342 return ret;
1343 }
1344
1345 img->p_width = img->width - img->crop_x - img->crop_width;
1346 img->p_height = img->height - img->crop_y - img->crop_height;
1347
1348 // The codec has now populated img->dsc: finalize the buffer-derived type flags
1349 // (DT_IMAGE_MOSAIC + DT_IMAGE_BUFFER_RESOLVED). This is the single point where the
1350 // decoded descriptor is mapped to the persisted classification.
1352
1353 return ret;
1354}
1355
1356gboolean dt_imageio_lookup_makermodel(const char *maker, const char *model,
1357 char *mk, int mk_len, char *md, int md_len,
1358 char *al, int al_len)
1359{
1360 // At this stage, we can't tell which loader is used to open the image.
1361 gboolean found = dt_rawspeed_lookup_makermodel(maker, model,
1362 mk, mk_len,
1363 md, md_len,
1364 al, al_len);
1365 if(found == FALSE)
1366 {
1367 // Special handling for CR3 raw files via libraw
1369 mk, mk_len,
1370 md, md_len,
1371 al, al_len);
1372 }
1373 return found;
1374}
1375
1376// clang-format off
1377// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1378// vim: shiftwidth=2 expandtab tabstop=2 cindent
1379// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1380// 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
atomic_int dt_atomic_int
Definition atomic.h:66
const char * extension(dt_imageio_module_data_t *data)
Definition avif.c:645
void cleanup(dt_imageio_module_format_t *self)
Definition avif.c:164
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
const dt_colorspaces_color_profile_t * dt_colorspaces_get_output_profile(const int32_t imgid, dt_colorspaces_color_profile_type_t *over_type, const char *over_filename)
dt_iop_color_intent_t
Definition colorspaces.h:63
dt_colorspaces_color_profile_type_t
Definition colorspaces.h:81
@ DT_COLORSPACE_SRGB
Definition colorspaces.h:84
static dt_aligned_pixel_t sRGB
const dt_colormatrix_t dt_aligned_pixel_t out
static const int row
void dt_image_buffer_resolve_flags(dt_image_t *img)
void dt_image_full_path(const int32_t imgid, char *pathname, size_t pathname_len, gboolean *from_cache, const char *calling_func)
Get the full path of an image out of the database.
gchar * dt_conf_get_string(const char *name)
gboolean dt_conf_is_equal(const char *name, const char *value)
void dt_control_log(const char *msg,...)
Definition control.c:777
void dt_show_times(const dt_times_t *start, const char *prefix)
Definition darktable.c:1638
darktable_t darktable
Definition darktable.c:183
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
@ DT_DEBUG_IMAGEIO
Definition darktable.h:755
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
Definition darktable.h:445
#define dt_free(ptr)
Definition darktable.h:478
static void dt_get_times(dt_times_t *t)
Definition darktable.h:983
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:475
#define __DT_CLONE_TARGETS__
Definition darktable.h:379
#define for_four_channels(_var,...)
Definition darktable.h:686
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:270
#define PATH_MAX
Definition darktable.h:1189
#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:293
void dt_dev_pop_history_items(dt_develop_t *dev)
Thread-safe wrapper around dt_dev_pop_history_items_ext(), then update GUI.
void dt_dev_pixelpipe_propagate_formats(dt_dev_pixelpipe_t *pipe)
void dt_dev_pixelpipe_get_roi_out(dt_dev_pixelpipe_t *pipe, const int width_in, const int height_in, int *width, int *height)
void dt_dev_cleanup(dt_develop_t *dev)
Definition develop.c:225
dt_dev_image_storage_t dt_dev_load_image(dt_develop_t *dev, const int32_t imgid)
Definition develop.c:940
void dt_dev_init(dt_develop_t *dev, int32_t gui_attached)
Definition develop.c:128
int dt_exif_xmp_attach_export(const int32_t imgid, const char *filename, void *metadata)
Definition exif.cc:4249
int dt_exif_get_thumbnail(const char *path, uint8_t **buffer, size_t *size, char **mime_type, int *width, int *height, int min_width)
Definition exif.cc:1701
int dt_exif_read_blob(uint8_t **buf, const char *path, const int32_t imgid, const int sRGB, const int out_width, const int out_height, const int dng_mode)
Definition exif.cc:1894
dt_image_orientation_t
Definition image.h:203
@ ORIENTATION_SWAP_XY
Definition image.h:208
@ ORIENTATION_FLIP_Y
Definition image.h:206
@ ORIENTATION_FLIP_X
Definition image.h:207
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_flags_t
Definition image.h:91
@ DT_IMAGE_RAW
Definition image.h:111
@ DT_IMAGE_HDR
Definition image.h:113
@ DT_IMAGE_LDR
Definition image.h:109
@ LOADER_UNKNOWN
Definition image.h:222
int bpp
int 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, gboolean is_scaling, 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, dt_atomic_int *shutdown)
Definition imageio.c:995
void _clamp_float_to_uint8(const float *const inbuf, uint8_t *const outbuf, const size_t processed_width, const size_t processed_height)
Definition imageio.c:961
void 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)
Definition imageio.c:473
int dt_imageio_is_hdr(const char *filename)
Definition imageio.c:640
static const gchar * _supported_raw[]
Definition imageio.c:131
static const char * raster_formats[]
Definition imageio.c:560
static const char * raw_formats[]
Definition imageio.c:591
gboolean dt_imageio_lookup_makermodel(const char *maker, const char *model, char *mk, int mk_len, char *md, int md_len, char *al, int al_len)
Definition imageio.c:1356
dt_imageio_retval_t dt_imageio_open(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
Definition imageio.c:1279
int 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 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)
Definition imageio.c:799
void _swap_byteorder_float_to_uint8(const float *const restrict inbuf, uint8_t *const outbuf, const size_t processed_width, const size_t processed_height)
Definition imageio.c:971
dt_imageio_retval_t dt_imageio_open_raster(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
Definition imageio.c:698
void _filter_pipeline(const char *filter, dt_dev_pixelpipe_t *pipe)
Definition imageio.c:871
static const gchar * _supported_ldr[]
Definition imageio.c:136
static const char * hdr_formats[]
Definition imageio.c:621
gboolean dt_imageio_is_raster(const char *filename)
Definition imageio.c:574
gboolean dt_imageio_has_mono_preview(const char *filename)
Definition imageio.c:398
void dt_imageio_to_fractional(float in, uint32_t *num, uint32_t *den)
Definition imageio.c:783
gboolean dt_imageio_is_handled_by_libraw(dt_image_t *img, const char *filename)
Definition imageio.c:672
gboolean _get_export_size(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, const dt_imageio_module_data_t *format_params, const gboolean is_scaling, double *scale, int width, int height, int *processed_width, int *processed_height)
Definition imageio.c:882
gboolean _apply_style_before_export(dt_develop_t *dev, dt_imageio_module_data_t *format_params, const int32_t imgid)
Definition imageio.c:821
dt_imageio_retval_t dt_imageio_open_hdr(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
Definition imageio.c:519
dt_imageio_retval_t dt_imageio_open_raw(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
Definition imageio.c:741
static gboolean _is_in_list(char *elem, char *list)
Definition imageio.c:656
gboolean dt_imageio_is_raw(const char *filename)
Definition imageio.c:605
dt_imageio_retval_t dt_imageio_open_exotic(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
Definition imageio.c:1255
dt_image_flags_t dt_imageio_get_type_from_extension(const char *extension)
Map Exiv2 preview MIME types to decoder format identifiers.
Definition imageio.c:181
int dt_imageio_large_thumbnail(const char *filename, uint8_t **buffer, int32_t *th_width, int32_t *th_height, dt_colorspaces_color_profile_type_t *color_space, const int width, const int height)
Load the thumbnail embedded into a RAW file having at least the size MAX(width, height) x MAX(width,...
Definition imageio.c:209
static const gchar * _supported_hdr[]
Definition imageio.c:140
void _print_export_debug(dt_dev_pixelpipe_t *pipe, dt_imageio_module_data_t *format_params, const gboolean use_style)
Definition imageio.c:846
__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:432
void _export_final_buffer_to_uint16(const float *const restrict inbuf, uint16_t *const outbuf, const size_t processed_width, const size_t processed_height)
Definition imageio.c:985
dt_imageio_retval_t dt_imageio_open_avif(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
dt_imageio_retval_t dt_imageio_open_exr(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
dt_imageio_retval_t dt_imageio_open_gm(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
Definition imageio_gm.h:33
dt_imageio_retval_t dt_imageio_open_heif(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
dt_imageio_retval_t dt_imageio_open_im(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
Definition imageio_im.h:34
dt_imageio_retval_t dt_imageio_open_j2k(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
int dt_imageio_jpeg_decompress_header(const void *in, size_t length, dt_imageio_jpeg_t *jpg)
dt_imageio_retval_t dt_imageio_open_jpeg(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
int dt_imageio_jpeg_decompress(dt_imageio_jpeg_t *jpg, uint8_t *out)
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)
gchar * dt_imageio_resizing_factor_get_and_parsing(double *num, double *denum)
@ FORMAT_FLAGS_SUPPORT_XMP
@ FORMAT_FLAGS_NO_TMPFILE
dt_imageio_retval_t dt_imageio_open_pfm(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
Definition imageio_pfm.c:44
dt_imageio_retval_t dt_imageio_open_png(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
dt_imageio_retval_t dt_imageio_open_pnm(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
gboolean dt_rawspeed_lookup_makermodel(const char *maker, const char *model, char *mk, int mk_len, char *md, int md_len, char *al, int al_len)
dt_imageio_retval_t dt_imageio_open_rawspeed(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
dt_imageio_retval_t dt_imageio_open_rgbe(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
dt_imageio_retval_t dt_imageio_open_tiff(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
dt_imageio_retval_t dt_imageio_open_webp(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
const char * maker
const char * model
void dt_ioppr_resync_modules_order(dt_develop_t *dev)
Update dev->iop module order values from dev->iop_order_list.
Definition iop_order.c:1271
void dt_ioppr_update_for_style_items(dt_develop_t *dev, GList *st_items, gboolean append)
Update dev->iop_order_list with modules referenced by style items.
Definition iop_order.c:1753
int dt_ioppr_check_iop_order(dt_develop_t *dev, const int32_t imgid, const char *msg)
Debug helper to validate the current order for a develop context.
Definition iop_order.c:2383
static const float x
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#define CLAMPF(a, mn, mx)
Definition math.h:89
size_t size
Definition mipmap_cache.c:3
dt_colorspaces_color_profile_type_t color_space
Definition mipmap_cache.c:5
#define dt_mipmap_cache_get(A, B, C, D, E, F)
@ DT_MIPMAP_BLOCKING
#define dt_mipmap_cache_release(A, B)
dt_mipmap_size_t
@ DT_MIPMAP_FULL
void dt_dev_pixelpipe_cache_ref_count_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Increase/Decrease the reference count on the cache line as to prevent LRU item removal....
gboolean dt_dev_pixelpipe_cache_ref_entry_by_hash(dt_dev_pixelpipe_cache_t *cache, const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry)
Resolve and retain an existing cache entry by hash.
void dt_dev_pixelpipe_cache_rdlock_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
void dt_dev_pixelpipe_set_input(dt_dev_pixelpipe_t *pipe, int32_t imgid, int width, int height, float iscale, dt_mipmap_size_t size)
void dt_dev_pixelpipe_disable_before(dt_dev_pixelpipe_t *pipe, const char *op)
void dt_dev_pixelpipe_disable_after(dt_dev_pixelpipe_t *pipe, const char *op)
void dt_dev_pixelpipe_set_icc(dt_dev_pixelpipe_t *pipe, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent)
void dt_dev_pixelpipe_create_nodes(dt_dev_pixelpipe_t *pipe)
int dt_dev_pixelpipe_init_thumbnail(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
int dt_dev_pixelpipe_init_export(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, int levels, gboolean store_masks)
void dt_dev_pixelpipe_cleanup(dt_dev_pixelpipe_t *pipe)
int dt_dev_pixelpipe_process(dt_dev_pixelpipe_t *pipe, dt_iop_roi_t roi)
#define dt_dev_pixelpipe_synch_all(pipe)
static uint64_t dt_dev_backbuf_get_hash(const dt_backbuf_t *backbuf)
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:366
@ DT_SIGNAL_IMAGE_EXPORT_TMPFILE
This signal is raised after an image has been exported to a file, but before it is sent to facebook/p...
Definition signal.h:261
GList * dt_styles_get_item_list(const char *name, gboolean params, int32_t imgid)
void dt_styles_apply_style_item(dt_develop_t *dev, dt_style_item_t *style_item)
void dt_style_item_free(gpointer data)
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
Definition darktable.h:818
struct dt_mipmap_cache_t * mipmap_cache
Definition darktable.h:804
struct dt_control_signal_t * signals
Definition darktable.h:802
int32_t unmuted
Definition darktable.h:788
struct dt_iop_module_t *void * data
dt_backbuf_t backbuf
dt_atomic_int * shutdown_ext
int32_t height
Definition image.h:315
dt_image_loader_t loader
Definition image.h:335
int32_t crop_height
Definition image.h:316
int32_t width
Definition image.h:315
char exif_maker[64]
Definition image.h:292
int32_t crop_y
Definition image.h:316
int32_t crop_x
Definition image.h:316
int32_t p_height
Definition image.h:315
int32_t p_width
Definition image.h:315
char exif_model[64]
Definition image.h:293
int32_t crop_width
Definition image.h:316
Region of interest passed through the pixelpipe.
Definition imageop.h:72
void * data
dt_dev_pixelpipe_cache_t * cache
typedef double((*spd)(unsigned long int wavelength, double TempK))
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29