Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
imageio_core.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*/
57#include "common/image.h"
58#ifdef HAVE_CONFIG_H
59#include "config.h"
60#endif
61#include "system/macros.h"
62#include "system/openmp.h"
64#include "system/mem_alloc.h"
65#include "system/simd.h"
66#include "common/logging.h"
67#include "common/times.h"
68#include "common/paths.h"
70#include "common/xmp_sidecar.h"
71#include "metadata/exif.h"
72#include "caches/image_cache.h"
73#include "history/history.h"
77#ifdef HAVE_OPENEXR
78#include "imageio/imageio_exr.h"
79#endif
80#ifdef HAVE_OPENJPEG
81#include "imageio/imageio_j2k.h"
82#endif
83#include "imageio/imageio_gm.h"
84#include "imageio/imageio_im.h"
87#include "imageio/imageio_pfm.h"
88#include "imageio/imageio_png.h"
89#include "imageio/imageio_pnm.h"
94#ifdef HAVE_LIBAVIF
96#endif
97#ifdef HAVE_LIBHEIF
99#endif
100#ifdef HAVE_WEBP
101#include "imageio/imageio_webp.h"
102#endif
104#include "caches/mipmap_cache.h"
105#include "common/styles.h"
106#include "common/conf.h"
107#include "control/user_message.h"
108#include "develop/develop.h"
109#include "develop/imageop.h"
110
111#if defined(HAVE_GRAPHICSMAGICK)
112#include <magick/api.h>
113#include <magick/blob.h>
114#elif defined(HAVE_IMAGEMAGICK)
115#include <MagickWand/MagickWand.h>
116#endif
117
118#include <assert.h>
119#include <glib/gstdio.h>
120#include <inttypes.h>
121#include <math.h>
122#include <stdio.h>
123#include <stdlib.h>
124#include <string.h>
125#include <strings.h>
127#include "control/signal.h"
128
144#if defined(HAVE_GRAPHICSMAGICK)
145static const char *_preview_format_from_mime_type(const char *mime_type)
146{
147 if(IS_NULL_PTR(mime_type) || mime_type[0] == '\0') return NULL;
148
149 if(!strcmp(mime_type, "image/jpeg")) return "JPEG";
150 if(!strcmp(mime_type, "image/png")) return "PNG";
151 if(!strcmp(mime_type, "image/tiff")) return "TIFF";
152 if(!strcmp(mime_type, "image/x-tiff")) return "TIFF";
153 if(!strcmp(mime_type, "image/gif")) return "GIF";
154 if(!strcmp(mime_type, "image/bmp")) return "BMP";
155 if(!strcmp(mime_type, "image/x-portable-pixmap")) return "PPM";
156 if(!strcmp(mime_type, "image/x-portable-graymap")) return "PGM";
157 if(!strcmp(mime_type, "image/x-portable-bitmap")) return "PBM";
158 if(!strcmp(mime_type, "image/x-portable-anymap")) return "PNM";
159 if(!strcmp(mime_type, "image/webp")) return "WEBP";
160 return NULL;
161}
162#endif
163
164// Best-effort image-type hint from the file extension. Returns DT_IMAGE_RAW / DT_IMAGE_LDR /
165// DT_IMAGE_HDR for the unambiguous extensions, or 0 ("unknown") for containers whose dynamic range
166// only the decoder can settle (TIFF, AVIF, HEIF/HEIC, DNG -- see dt_image_ext_is_ambiguous()).
167// Callers must treat 0 as "decode it"; dt_image_buffer_resolve_flags() sets the authoritative
168// LDR/HDR/MOSAIC flags once decoded.
169int dt_imageio_large_thumbnail(const char *filename, uint8_t **buffer, int32_t *th_width, int32_t *th_height,
171{
172 int res = 1;
173
174 uint8_t *buf = NULL;
175 char *mime_type = NULL;
176 size_t bufsize;
177
179 goto error;
180
181 if(strcmp(mime_type, "image/jpeg") == 0)
182 {
183 // Decompress the JPG into our own memory format
186 *buffer = (uint8_t *)dt_pixelpipe_cache_alloc_align_cache(
187 sizeof(uint8_t) * 4 * jpg.width * jpg.height,
188 0);
189 if(!*buffer) goto error;
190
191 *th_width = jpg.width;
192 *th_height = jpg.height;
193 // TODO: check if the embedded thumbs have a color space set! currently we assume that it's always sRGB
195 if(dt_imageio_jpeg_decompress(&jpg, *buffer))
196 {
198 *buffer = NULL;
199 goto error;
200 }
201
202 res = 0;
203 }
204 else
205 {
206#if defined(HAVE_GRAPHICSMAGICK)
208 ExceptionInfo exception;
209 Image *image = NULL;
210 ImageInfo *image_info = NULL;
211
212 GetExceptionInfo(&exception);
213 image_info = CloneImageInfo((ImageInfo *)NULL);
215 g_strlcpy(image_info->magick, preview_format, sizeof(image_info->magick));
216
217 // GraphicsMagick calls assert() -> abort() on some malformed embedded
218 // previews instead of reporting through `exception`. Recover instead of
219 // crashing the whole app; on recovery, `image`/`image_info`/`exception`
220 // are NOT touched again (see imageio_magick_abort_guard.h) - we leak
221 // them and bail out directly, only freeing the buffer Ansel itself
222 // allocated if the per-row decode loop got partway through it.
223 DT_MAGICK_ABORT_GUARD("dt_imageio_large_thumbnail GM", filename, {
224 if(*buffer)
225 {
227 *buffer = NULL;
228 }
229 goto error;
230 });
231
232 image = BlobToImage(image_info, buf, bufsize, &exception);
233
234 if(exception.severity != UndefinedException) CatchException(&exception);
235
236 if(IS_NULL_PTR(image))
237 {
238 fprintf(stderr, "[dt_imageio_large_thumbnail GM] thumbnail not found?\n");
239 goto error_gm;
240 }
241
242 *th_width = image->columns;
243 *th_height = image->rows;
244 *color_space = DT_COLORSPACE_SRGB; // FIXME: this assumes that embedded thumbnails are always srgb
245
246 *buffer = (uint8_t *)dt_pixelpipe_cache_alloc_align_cache(
247 sizeof(uint8_t) * 4 * image->columns * image->rows,
248 0);
249 if(!*buffer) goto error_gm;
250
251 for(uint32_t row = 0; row < image->rows; row++)
252 {
253 uint8_t *bufprt = *buffer + (size_t)4 * row * image->columns;
254 int gm_ret = DispatchImage(image, 0, row, image->columns, 1, "RGBP", CharPixel, bufprt, &exception);
255
256 if(exception.severity != UndefinedException) CatchException(&exception);
257
258 if(gm_ret != MagickPass)
259 {
260 fprintf(stderr, "[dt_imageio_large_thumbnail GM] error_gm reading thumbnail\n");
262 *buffer = NULL;
263 goto error_gm;
264 }
265 }
266
267 // fprintf(stderr, "[dt_imageio_large_thumbnail GM] successfully decoded thumbnail\n");
268 res = 0;
269
270 error_gm:
272 if(image) DestroyImage(image);
273 if(image_info) DestroyImageInfo(image_info);
274 DestroyExceptionInfo(&exception);
275 if(res) goto error;
276#elif defined(HAVE_IMAGEMAGICK)
277 MagickWand *image = NULL;
279
280 image = NewMagickWand();
281
282 // ImageMagick calls assert() -> abort() on some malformed embedded
283 // previews instead of reporting through its normal error status.
284 // Recover instead of crashing the whole app; on recovery, `image` is
285 // NOT touched again (see imageio_magick_abort_guard.h) - we leak the
286 // wand and bail out directly, only freeing the buffer Ansel itself
287 // allocated if it was set before the abort.
288 DT_MAGICK_ABORT_GUARD("dt_imageio_large_thumbnail IM", filename, {
289 if(*buffer)
290 {
291 dt_free(*buffer);
292 *buffer = NULL;
293 }
294 goto error;
295 });
296
297 mret = MagickReadImageBlob(image, buf, bufsize);
298 if(mret != MagickTrue)
299 {
300 fprintf(stderr, "[dt_imageio_large_thumbnail IM] thumbnail not found?\n");
301 goto error_im;
302 }
303
306 switch (MagickGetImageColorspace(image)) {
307 case sRGBColorspace:
309 break;
310 default:
312 "[dt_imageio_large_thumbnail IM] could not map colorspace, using sRGB");
314 break;
315 }
316
317 *buffer = malloc(sizeof(uint8_t) * (*th_width) * (*th_height) * 4);
318 if(IS_NULL_PTR(*buffer)) goto error_im;
319
320 mret = MagickExportImagePixels(image, 0, 0, *th_width, *th_height, "RGBP", CharPixel, *buffer);
321 if(mret != MagickTrue) {
322 dt_free(*buffer);
324 "[dt_imageio_large_thumbnail IM] error while reading thumbnail\n");
325 goto error_im;
326 }
327
328 res = 0;
329
332 DestroyMagickWand(image);
333 if(res != 0) goto error;
334#else
336 "[dt_imageio_large_thumbnail] error: The thumbnail image is not in "
337 "JPEG format, and DT was built without neither GraphicsMagick or "
338 "ImageMagick. Please rebuild DT with GraphicsMagick or ImageMagick "
339 "support enabled.\n");
340#endif
341 }
342
343 if(res)
344 {
345 fprintf(
346 stderr,
347 "[dt_imageio_large_thumbnail] error: Not a supported thumbnail image format or broken thumbnail: %s\n",
348 mime_type);
349 goto error;
350 }
351
352error:
354 dt_free(buf);
355 return res;
356}
357
358gboolean dt_imageio_crop_thumbnail(const dt_boundingbox_t box, uint8_t *const buffer,
359 int32_t *width, int32_t *height)
360{
361 if(IS_NULL_PTR(buffer) || IS_NULL_PTR(width) || IS_NULL_PTR(height)) return FALSE;
362
363 const int32_t in_width = *width;
364 const int32_t in_height = *height;
365 if(in_width < 1 || in_height < 1) return FALSE;
366
367 /* The box is normalized against the frame the camera renders its previews from, which is the
368 * same DefaultCropOrigin/DefaultCropSize rectangle the tag itself references -- so it maps
369 * onto the decoded preview directly, at whatever resolution that preview happens to be. */
370 const int32_t left = CLAMP((int32_t)roundf(box[1] * in_width), 0, in_width - 1);
371 const int32_t top = CLAMP((int32_t)roundf(box[0] * in_height), 0, in_height - 1);
372 const int32_t right = CLAMP((int32_t)roundf(box[3] * in_width), left + 1, in_width);
373 const int32_t bottom = CLAMP((int32_t)roundf(box[2] * in_height), top + 1, in_height);
374
375 const int32_t out_width = right - left;
376 const int32_t out_height = bottom - top;
377 if(out_width == in_width && out_height == in_height) return FALSE;
378
379 /* Compact in place, forward: destination row j starts at 4 * j * out_width, its source at
380 * 4 * ((j + top) * in_width + left). Since out_width <= in_width and top, left >= 0, the
381 * destination never runs ahead of the source, so no row is overwritten before it is read. */
382 for(int32_t j = 0; j < out_height; j++)
383 {
384 const uint8_t *const source = buffer + 4 * ((size_t)(j + top) * in_width + left);
385 uint8_t *const destination = buffer + 4 * (size_t)j * out_width;
386 memmove(destination, source, 4 * (size_t)out_width);
387 }
388
389 *width = out_width;
391 return TRUE;
392}
393
394gboolean dt_imageio_has_mono_preview(const char *filename)
395{
397 uint8_t *tmp = NULL;
398 int32_t thumb_width = 0, thumb_height = 0;
399 gboolean mono = FALSE;
400
401 if(dt_imageio_large_thumbnail(filename, &tmp, &thumb_width, &thumb_height, &color_space, -1, -1))
402 goto cleanup;
403 if((thumb_width < 32) || (thumb_height < 32) || (IS_NULL_PTR(tmp)))
404 goto cleanup;
405
406 mono = TRUE;
407 for(int y = 0; y < thumb_height; y++)
408 {
409 uint8_t *in = (uint8_t *)tmp + (size_t)4 * y * thumb_width;
410 for(int x = 0; x < thumb_width; x++, in += 4)
411 {
412 if((in[0] != in[1]) || (in[0] != in[2]) || (in[1] != in[2]))
413 {
414 mono = FALSE;
415 goto cleanup;
416 }
417 }
418 }
419
420 cleanup:
421
422 dt_print(DT_DEBUG_IMAGEIO,"[dt_imageio_has_mono_preview] testing `%s', yes/no %i, %ix%i\n", filename, mono, thumb_width, thumb_height);
424 return mono;
425}
426
428void dt_imageio_flip_buffers(char *out, const char *in, const size_t bpp, const int wd, const int ht,
429 const int fwd, const int fht, const int stride,
430 const dt_image_orientation_t orientation)
431{
432 if(!orientation)
433 {
435 for(int j = 0; j < ht; j++) memcpy(out + (size_t)j * bpp * wd, in + (size_t)j * stride, bpp * wd);
436 return;
437 }
438 int ii = 0, jj = 0;
439 int si = bpp, sj = wd * bpp;
440 if(orientation & ORIENTATION_SWAP_XY)
441 {
442 sj = bpp;
443 si = ht * bpp;
444 }
445 if(orientation & ORIENTATION_FLIP_Y)
446 {
447 jj = (int)fht - jj - 1;
448 sj = -sj;
449 }
450 if(orientation & ORIENTATION_FLIP_X)
451 {
452 ii = (int)fwd - ii - 1;
453 si = -si;
454 }
456 for(int j = 0; j < ht; j++)
457 {
458 char *out2 = out + (size_t)labs(sj) * jj + (size_t)labs(si) * ii + (size_t)sj * j;
459 const char *in2 = in + (size_t)stride * j;
460 for(int i = 0; i < wd; i++)
461 {
462 memcpy(out2, in2, bpp);
463 in2 += bpp;
464 out2 += si;
465 }
466 }
467}
468
469void dt_imageio_flip_buffers_ui8_to_float(float *out, const uint8_t *in, const float black, const float white,
470 const int ch, const int wd, const int ht, const int fwd,
471 const int fht, const int stride,
472 const dt_image_orientation_t orientation)
473{
474 const float scale = 1.0f / (white - black);
475 if(!orientation)
476 {
478 for(int j = 0; j < ht; j++)
479 for(int i = 0; i < wd; i++)
480 for(int k = 0; k < ch; k++)
481 out[4 * ((size_t)j * wd + i) + k] = (in[(size_t)j * stride + (size_t)ch * i + k] - black) * scale;
482 return;
483 }
484 int ii = 0, jj = 0;
485 int si = 4, sj = wd * 4;
486 if(orientation & ORIENTATION_SWAP_XY)
487 {
488 sj = 4;
489 si = ht * 4;
490 }
491 if(orientation & ORIENTATION_FLIP_Y)
492 {
493 jj = (int)fht - jj - 1;
494 sj = -sj;
495 }
496 if(orientation & ORIENTATION_FLIP_X)
497 {
498 ii = (int)fwd - ii - 1;
499 si = -si;
500 }
502 for(int j = 0; j < ht; j++)
503 {
504 float *out2 = out + (size_t)labs(sj) * jj + (size_t)labs(si) * ii + sj * j;
505 const uint8_t *in2 = in + (size_t)stride * j;
506 for(int i = 0; i < wd; i++)
507 {
508 for(int k = 0; k < ch; k++) out2[k] = (in2[k] - black) * scale;
509 in2 += ch;
510 out2 += si;
511 }
512 }
513}
514
516{
517 // if buf is NULL, don't proceed
518 if(IS_NULL_PTR(buf))
519 return DT_IMAGEIO_OK;
520
522
523#ifdef HAVE_OPENEXR
524 ret = dt_imageio_open_exr(img, filename, buf);
525 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
526 return ret;
527#endif
528
529 ret = dt_imageio_open_rgbe(img, filename, buf);
530 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
531 return ret;
532
533 ret = dt_imageio_open_pfm(img, filename, buf);
534 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
535 return ret;
536
537#ifdef HAVE_LIBAVIF
538 ret = dt_imageio_open_avif(img, filename, buf);
539 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
540 return ret;
541#endif
542
543#ifdef HAVE_LIBHEIF
544 ret = dt_imageio_open_heif(img, filename, buf);
545 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
546 return ret;
547#endif
548
549 ret = dt_imageio_open_exotic(img, filename, buf);
550 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
551 return ret;
552
554}
555
556// Decoder routing: dt_image_ext_is_ldr() drives dt_imageio_open_raster(), the generic/
557// exotic-capable chain -- kept distinct from is_hdr() (dt_imageio_open_hdr(), the dedicated
558// OpenEXR/Radiance/PFM/AVIF/HEIF chain). See the comment on dt_image_ext_is_raw/_ldr/_hdr in
559// common/image_extensions.h for why these must never be combined for routing purposes.
560gboolean dt_imageio_is_raster(const char *filename)
561{
562 const char *c = filename + strlen(filename);
563 while(c > filename && *c != '.') c--;
564 if(*c != '.') return FALSE;
565 return dt_image_ext_is_ldr(c + 1);
566}
567
568gboolean dt_imageio_is_raw(const char *filename)
569{
570 const char *c = filename + strlen(filename);
571 while(c > filename && *c != '.') c--;
572 if(*c != '.') return FALSE;
573 return dt_image_ext_is_raw(c + 1);
574}
575
576int dt_imageio_is_hdr(const char *filename)
577{
578 const char *c = filename + strlen(filename);
579 while(c > filename && *c != '.') c--;
580 if(*c != '.') return FALSE;
581 return dt_image_ext_is_hdr(c + 1);
582}
583
584static gboolean _is_in_list(char *elem, char *list)
585{
586 // Search if elem is contained in the coma-separated list string
587 gboolean success = FALSE;
588 if(elem && list)
589 {
590 while(!IS_NULL_PTR(list) && !success)
591 {
592 success = !g_ascii_strncasecmp(list, elem, strlen(elem));
593 list = strtok(NULL, ",");
594 }
595 }
596
597 return success;
598}
599
600gboolean dt_imageio_is_handled_by_libraw(dt_image_t *img, const char *filename)
601{
602 // Allow users to define some extensions, makers and models that should be handled by Libraw
603 gboolean is_handled = FALSE;
604
605 char *ext = g_strrstr(filename, ".") + 1; // move the pointer after the extension dot
606 char *extensions = dt_conf_get_string("libraw/extensions");
607 char *makers = dt_conf_get_string("libraw/makers");
608 char *models = dt_conf_get_string("libraw/models");
609
612 is_handled |= _is_in_list(img->exif_model, strtok(models, ","));
613
616 dt_free(models);
617
618 const char *iolib = (is_handled) ? "Libraw" : "Rawspeed";
619 dt_print(DT_DEBUG_IMAGEIO, "[image I/O] image `%s` from camera `%s` of maker `%s` loaded with %s\n", filename,
620 img->exif_model, img->exif_maker, iolib);
621
622 return is_handled;
623}
624
625// transparent read method to load ldr image to dt_raw_image_t with exif and so on.
627{
628 // if buf is NULL, don't proceed
629 if(IS_NULL_PTR(buf))
630 return DT_IMAGEIO_OK;
631
633
634 ret = dt_imageio_open_jpeg(img, filename, buf);
635 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
636 return ret;
637
638 ret = dt_imageio_open_tiff(img, filename, buf);
639 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
640 return ret;
641
642#ifdef HAVE_WEBP
643 ret = dt_imageio_open_webp(img, filename, buf);
644 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
645 return ret;
646#endif
647
648 ret = dt_imageio_open_png(img, filename, buf);
649 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
650 return ret;
651
652#ifdef HAVE_OPENJPEG
653 ret = dt_imageio_open_j2k(img, filename, buf);
654 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
655 return ret;
656#endif
657
658 ret = dt_imageio_open_pnm(img, filename, buf);
659 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
660 return ret;
661
662 ret = dt_imageio_open_exotic(img, filename, buf);
663 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
664 return ret;
665
667}
668
670{
671 // if buf is NULL, don't proceed
672 if(IS_NULL_PTR(buf))
673 return DT_IMAGEIO_OK;
674
676
677 /* check if user wants to force processing through Libraw */
678 const gboolean force_libraw = dt_imageio_is_handled_by_libraw(img, filename);
679
680 /* use rawspeed to load the raw */
681 if(!force_libraw)
682 {
683 ret = dt_imageio_open_rawspeed(img, filename, buf);
684 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
685 return ret;
686 }
687
688#ifdef HAVE_LIBRAW
689 /* fallback that tries to open file via LibRAW to support Canon CR3 */
690 ret = dt_imageio_open_libraw(img, filename, buf);
691 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
692 return ret;
693#endif
694
695 /* try Rawspeed again in case Libraw was forced but failed */
696 if(force_libraw)
697 {
698 ret = dt_imageio_open_rawspeed(img, filename, buf);
699 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
700 return ret;
701 }
702
703 /* fallback that tries to open file via GraphicsMagick */
704 ret = dt_imageio_open_exotic(img, filename, buf);
705 if(ret == DT_IMAGEIO_OK || ret == DT_IMAGEIO_CACHE_FULL)
706 return ret;
707
709}
710
711void dt_imageio_to_fractional(float in, uint32_t *num, uint32_t *den)
712{
713 if(!(in >= 0))
714 {
715 *num = *den = 0;
716 return;
717 }
718 *den = 1;
719 *num = (int)(in * *den + .5f);
720 while(fabsf(*num / (float)*den - in) > 0.001f)
721 {
722 *den *= 10;
723 *num = (int)(in * *den + .5f);
724 }
725}
726
727int dt_imageio_export(const int32_t imgid, const char *filename, dt_imageio_module_format_t *format,
729 const gboolean copy_metadata, const gboolean export_masks,
730 dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename,
732 dt_imageio_module_data_t *storage_params, int num, int total, dt_export_metadata_t *metadata)
733{
734 if(strcmp(format->mime(format_params), "x-copy") == 0)
735 /* This is a just a copy, skip process and just export */
736 return format->write_image(format_params, filename, NULL, icc_type, icc_filename, NULL, 0, imgid, num, total, NULL,
737 export_masks);
738 else
739 {
740 const gboolean is_scaling =
741 dt_conf_is_equal("plugins/lighttable/export/resizing", "scaling");
742
743 return dt_imageio_export_with_flags(imgid, filename, format, format_params, FALSE, FALSE, TRUE, is_scaling,
744 FALSE, NULL, copy_metadata, export_masks, icc_type, icc_filename, icc_intent,
745 storage, storage_params, num, total, metadata, NULL);
746 }
747}
748
750{
753 {
754 dt_control_log(_("cannot find the style '%s' to apply during export."), format_params->style);
755 return TRUE;
756 }
757
758 dt_ioppr_check_iop_order(dev, imgid, "dt_imageio_export_with_flags");
761
763 {
766 }
767
770
771 return FALSE;
772}
773
775{
777 {
778 fprintf(stderr,"[dt_imageio_export_with_flags] ");
779 if(use_style)
780 {
781 fprintf(stderr,"appending style `%s'\n", format_params->style);
782 }
783 else fprintf(stderr,"\n");
784 int cnt = 0;
785 for(GList *nodes = pipe->nodes; nodes; nodes = g_list_next(nodes))
786 {
788 if(piece->enabled)
789 {
790 cnt++;
791 fprintf(stderr," %s", piece->module->op);
792 }
793 }
794 fprintf(stderr," (%i)\n", cnt);
795 }
796}
797
798
799void _filter_pipeline(const char *filter, dt_dev_pixelpipe_t *pipe)
800{
801 // Warning: can only filter prior to or past to a certain module, but not both !!!
802 if(filter)
803 {
804 if(!strncmp(filter, "pre:", 4)) dt_dev_pixelpipe_disable_after(pipe, filter + 4);
805 if(!strncmp(filter, "post:", 5)) dt_dev_pixelpipe_disable_before(pipe, filter + 5);
806 }
807}
808
809
811 const dt_imageio_module_data_t *format_params, const gboolean is_scaling, double *scale,
812 int width, int height, int *processed_width, int *processed_height)
813{
814 const double image_ratio = (double)pipe->processed_width / (double)pipe->processed_height;
815
816 if(is_scaling)
817 {
818 double _num, _denum;
820 const double scale_factor = _num / _denum;
821 *scale = fmin(scale_factor, 1.);
822 *processed_height = (int)roundf(pipe->processed_height * (*scale));
823 *processed_width = (int)roundf(pipe->processed_width * (*scale));
824 return 0;
825 }
826
827 // if width and height are both 0, we use the full resolution of the image
828 if(width == 0 && height == 0)
829 {
830 // original resolution
831 *processed_width = pipe->processed_width;
832 *processed_height = pipe->processed_height;
833 *scale = 1.;
834 return 0;
835 }
836
837 if(width > 0 && height > 0)
838 {
839 // fixed width and height : fit within a bounding box
840 *processed_width = MIN(pipe->processed_width, width);
841 *processed_height = MIN(pipe->processed_height, height);
842 double scale_x = (double)*processed_width / (double)pipe->processed_width;
843 double scale_y = (double)*processed_height / (double)pipe->processed_height;
844 *scale = fmin(scale_x, scale_y);
845
846 // Note : we handle each case separately to avoid rounding errors
847 if(image_ratio > 1.0)
848 {
849 // landscape image, width is the limiting factor
850 *processed_width = MIN((int)roundf(pipe->processed_width * (*scale)), pipe->processed_width);
851 *processed_height = MIN((int)roundf(*processed_width / image_ratio), pipe->processed_height);
852 }
853 else if(image_ratio < 1.0)
854 {
855 // portrait image, height is the limiting factor
856 *processed_height = MIN((int)roundf(pipe->processed_height * (*scale)), pipe->processed_height);
857 *processed_width = MIN((int)roundf(*processed_height * image_ratio), pipe->processed_width);
858 }
859 else
860 {
861 // square image, both width and height are the limiting factors
862 *processed_width = MIN((int)roundf(pipe->processed_width * (*scale)), pipe->processed_width);
863 *processed_height = MIN((int)roundf(pipe->processed_height * (*scale)), pipe->processed_height);
864 }
865 return 0;
866 }
867
868 if(width > 0)
869 {
870 // fluid height, fixed width
871 *processed_width = MIN(pipe->processed_width, width);
872 *processed_height = (int)roundf(*processed_width / image_ratio);
873 }
874 else if(height > 0)
875 {
876 // fluid width, fixed height
877 *processed_height = MIN(pipe->processed_height, height);
878 *processed_width = (int)roundf(*processed_height * image_ratio);
879 }
880
881 double scale_x = (double)*processed_width / (double)pipe->processed_width;
882 double scale_y = (double)*processed_height / (double)pipe->processed_height;
883 *scale = fmin(scale_x, scale_y);
884
885 return 0;
886}
887
888
889void _clamp_float_to_uint8(const float *const inbuf, uint8_t *const outbuf, const size_t processed_width,
890 const size_t processed_height)
891{
893 for(size_t k = 0; k < processed_width * processed_height; k++)
895 outbuf[4 * k + c] = (uint8_t)CLAMPF(roundf(inbuf[4 * k + c] * 255.f), 0.f, 255.f);
896}
897
898
899void _swap_byteorder_float_to_uint8(const float *const restrict inbuf, uint8_t *const outbuf,
900 const size_t processed_width, const size_t processed_height)
901{
903 for(size_t k = 0; k < processed_width * processed_height; k++)
904 {
905 outbuf[4 * k + 0] = (uint8_t)CLAMPF(roundf(inbuf[4 * k + 2] * 255.f), 0.f, 255.f);
906 outbuf[4 * k + 1] = (uint8_t)CLAMPF(roundf(inbuf[4 * k + 1] * 255.f), 0.f, 255.f);
907 outbuf[4 * k + 2] = (uint8_t)CLAMPF(roundf(inbuf[4 * k + 0] * 255.f), 0.f, 255.f);
908 outbuf[4 * k + 3] = (uint8_t)CLAMPF(roundf(inbuf[4 * k + 3] * 255.f), 0.f, 255.f);
909 }
910}
911
912
913void _export_final_buffer_to_uint16(const float *const restrict inbuf, uint16_t *const outbuf,
914 const size_t processed_width, const size_t processed_height)
915{
917 for(size_t k = 0; k < processed_width * processed_height; k++)
919 outbuf[4 * k + c] = (uint16_t)CLAMP(roundf(inbuf[4 * k + c] * 65535.f), 0.f, 65535.f);
920}
921
922// internal function: to avoid exif blob reading + 8-bit byteorder flag + high-quality override
923int dt_imageio_export_with_flags(const int32_t imgid, const char *filename,
925 const gboolean ignore_exif, const gboolean display_byteorder,
926 const gboolean high_quality, gboolean is_scaling, const gboolean thumbnail_export,
927 const char *filter, const gboolean copy_metadata, const gboolean export_masks,
928 dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename,
930 dt_imageio_module_data_t *storage_params, int num, int total,
931 dt_export_metadata_t *metadata, dt_atomic_int *shutdown)
932{
933 dt_times_t start;
934 dt_get_times(&start);
935
937 void *outbuf = NULL;
938
939 // Get the history, aka sequence of editing changes
940 dt_develop_t dev;
941 dt_dev_init(&dev, 0);
942 dt_dev_load_image(&dev, imgid);
944
945 // Apply styles on top of current history
946 const gboolean use_style = !thumbnail_export && format_params->style[0] != '\0';
947 // If a style is to be applied during export, add the iop params into the history
949 goto error;
950
951 int width = MAX(format_params->max_width, 0);
952 int height = MAX(format_params->max_height, 0);
953 double scale = 1.;
954
955 // Get a pipeline, aka sequence of nodes
956 int res = 0;
960 else
961 res = dt_dev_pixelpipe_init_export(&pipe, &dev, format->levels(format_params), export_masks);
962
963 if(!res) goto error;
964
965 pipe.shutdown_ext = shutdown;
966
968
969 // Sync history with pipeline nodes
970 // Update the ICC type if DT_COLORSPACE_NONE is passed
971 dt_colorspaces_get_output_profile(imgid, &icc_type, icc_filename);
972 dt_dev_pixelpipe_set_icc(&pipe, icc_type, icc_filename, icc_intent);
973
974 // Find out what input size we want
976
977 // Take a local copy of the input buffer so we can release the mipmap cache lock immediately
978 dt_mipmap_cache_get(&buf, imgid, size, DT_MIPMAP_BLOCKING, 'r');
979
980 if(IS_NULL_PTR(buf.buf) || buf.width == 0 || buf.height == 0)
981 {
983 goto error;
984 }
985
986 const size_t buf_width = buf.width;
987 const size_t buf_height = buf.height;
989
990 // Update size with actual input and resync nodes
991 dt_dev_pixelpipe_set_input(&pipe, imgid, buf_width, buf_height, buf.iscale, size);
993
994 // Write debug info to stdout
996
997 // Remove modules past or prior a certain one.
998 // Useful for partial exports, for technical purposes (HDR merge)
999 _filter_pipeline(filter, &pipe);
1000
1001 // This export path drives the pipe directly instead of through dt_dev_pixelpipe_change(), so
1002 // establish the buffer-format contract (and disable incompatible nodes) explicitly, after the
1003 // optional filtering changed the node set and before ROI planning / global hashing.
1005
1006 // Get theoritical final size of image, taking distortions and croppings AND borders into account,
1007 // considering full-size original input. Meaning we can enlarge or reduce the original image,
1008 // even taking full-res input.
1009 // Needs to be done after optional filtering, in case we filter out distortion modules
1011 &pipe.processed_height);
1012
1013 dt_show_times(&start, "[export] creating pixelpipe");
1014
1015 // Compute the actual final sizes that fit within the bounding box width*height
1016 // while preserving original image ratio
1017 int processed_width = 0;
1018 int processed_height = 0;
1019 _get_export_size(&dev, &pipe, format_params, is_scaling, &scale, width, height,
1020 &processed_width, &processed_height);
1021
1023 "[dt_imageio_export] (direct) image input %ix%i, turned to output %ix%i, will be exported to fit %ix%i "
1024 "--> final size is %ix%i\n",
1025 pipe.iwidth, pipe.iheight, pipe.processed_width, pipe.processed_height, width, height, processed_width,
1026 processed_height);
1027
1028
1029 const int bpp = format->bpp(format_params);
1030
1031 dt_iop_roi_t roi = (dt_iop_roi_t){ 0, 0, processed_width, processed_height, scale };
1032
1033 dt_get_times(&start);
1034 int err = dt_dev_pixelpipe_process(&pipe, roi);
1035 dt_show_times(&start, thumbnail_export ? "[dev_process_thumbnail] pixel pipeline processing thread"
1036 : "[dev_process_export] pixel pipeline processing thread");
1037
1038 if(dt_dev_backbuf_get_hash(&pipe.backbuf) == -1 || err)
1039 {
1040 dt_print(DT_DEBUG_IMAGEIO, "[dt_imageio_export_with_flags] no valid output buffer\n");
1041 goto error;
1042 }
1043
1044 struct dt_pixel_cache_entry_t *cache_entry;
1045 void *data = NULL;
1046 /* Atomically look up the final pipeline output and increment its refcount under the cache
1047 * mutex. peek() + separate ref_count_entry() has a TOCTOU window: peek releases its
1048 * tryrdlock immediately and returns with no ownership, so a concurrent eviction thread
1049 * could see refcount==1 (backbuf keepalive only) and decrement it to 0 between peek()
1050 * returning and our ref_count_entry() call — leaving us with a dangling data pointer that
1051 * the OpenMP conversion threads then read → SIGSEGV. ref_entry_by_hash() closes that
1052 * window by holding cache->lock across both the lookup and the increment. */
1054 &data, &cache_entry)
1055 || !data)
1056 {
1057 if(cache_entry)
1059 goto error;
1060 }
1061
1062 /* Hold a read lock for the duration of the conversion so no writer can replace the buffer
1063 * while the OpenMP threads are reading it. */
1065
1066 // Down-conversion to low-precision formats:
1067 const size_t pixels = pipe.backbuf.width * pipe.backbuf.height * 4;
1068 if(bpp == 8)
1069 {
1071 sizeof(uint8_t) * pixels,
1072 0);
1075 else if(outbuf)
1077
1078 /* Thumbnail export stores the in-memory RGBA buffer straight into the mipmap cache.
1079 * The thumbnail pipeline does not maintain a meaningful alpha contract across all
1080 * modules, so random zero/garbage alpha values would make valid RGB thumbnails render
1081 * black in consumers that composite the mipmap buffer. Keep thumbnail alpha opaque at
1082 * the export boundary and leave RGB untouched. */
1084 {
1085 uint8_t *thumbnail_buf = (uint8_t *)outbuf;
1087 for(size_t k = 0; k < pixels / 4; k++) thumbnail_buf[4 * k + 3] = UINT8_MAX;
1088 }
1089 }
1090 else if(bpp == 16)
1091 {
1093 sizeof(uint16_t) * pixels,
1094 0);
1095 if(outbuf)
1097
1099 {
1100 uint16_t *thumbnail_buf = (uint16_t *)outbuf;
1102 for(size_t k = 0; k < pixels / 4; k++) thumbnail_buf[4 * k + 3] = UINT16_MAX;
1103 }
1104 }
1105 else // output float, no further harm done to the pixels :)
1106 {
1108 sizeof(float_t) * pixels,
1109 0);
1110 if(outbuf)
1111 memcpy(outbuf, data, sizeof(float_t) * pixels);
1112
1114 {
1115 float *thumbnail_buf = (float *)outbuf;
1117 for(size_t k = 0; k < pixels / 4; k++) thumbnail_buf[4 * k + 3] = 1.0f;
1118 }
1119 }
1120
1121 // Decrease ref count on the cache entry and release the read lock
1124
1125 if(IS_NULL_PTR(outbuf)) goto error;
1126
1127 format_params->width = pipe.backbuf.width;
1128 format_params->height = pipe.backbuf.height;
1129
1130 // Exif data should be 65536 bytes max, but if original size is close to that,
1131 // adding new tags could make it go over that... so let it be and see what
1132 // happens when we write the image
1133 int length = 0;
1134 uint8_t *exif_profile = NULL;
1135
1136 if(!ignore_exif)
1137 {
1138 gboolean from_cache = TRUE;
1139 char pathname[PATH_MAX] = { 0 };
1141 // find output color profile for this image:
1142 int sRGB = (icc_type == DT_COLORSPACE_SRGB);
1143 // last param is dng mode, it's false here
1144 length = dt_exif_read_blob(&exif_profile, pathname, imgid, sRGB, pipe.backbuf.width, pipe.backbuf.height, 0);
1145 }
1146
1147 // Finally: write image buffer to target container
1148 res = format->write_image(format_params, filename, outbuf, icc_type, icc_filename, exif_profile, length, imgid,
1149 num, total, &pipe, export_masks);
1150
1152 if(res) goto error;
1153
1155 dt_dev_cleanup(&dev);
1156
1157 /* now write xmp into that container, if possible */
1158 if(copy_metadata && (format->flags(format_params) & FORMAT_FLAGS_SUPPORT_XMP))
1159 dt_exif_xmp_attach_export(imgid, filename, metadata);
1160
1161 if(!thumbnail_export && strcmp(format->mime(format_params), "memory")
1162 && !(format->flags(format_params) & FORMAT_FLAGS_NO_TMPFILE))
1163 {
1165 format_params, storage, storage_params);
1166 }
1167
1169 return 0; // success
1170
1171error:
1174 dt_dev_cleanup(&dev);
1175 return 1;
1176}
1177
1178
1179// fallback read method in case file could not be opened yet.
1180// use GraphicsMagick (if supported) to read exotic LDRs
1182 dt_mipmap_buffer_t *buf)
1183{
1184 // if buf is NULL, don't proceed
1185 if(IS_NULL_PTR(buf))
1186 return DT_IMAGEIO_OK;
1187
1189
1190#if defined(HAVE_GRAPHICSMAGICK)
1191 ret = dt_imageio_open_gm(img, filename, buf);
1192#elif defined(HAVE_IMAGEMAGICK)
1193 ret = dt_imageio_open_im(img, filename, buf);
1194#else
1196#endif
1197
1198 return ret;
1199}
1200
1201// =================================================
1202// combined reading
1203// =================================================
1204
1205dt_imageio_retval_t dt_imageio_open(dt_image_t *img, // non-const * means you hold a write lock!
1206 const char *filename, // full path
1207 dt_mipmap_buffer_t *buf)
1208{
1209 /* first of all, check if file exists, don't bother to test loading if not exists */
1210 if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
1211 return !DT_IMAGEIO_OK;
1212
1214 img->loader = LOADER_UNKNOWN;
1215
1216 // Start with the decoder(s) the extension routes to (fast path). Unlike before, a failure here
1217 // no longer aborts: an extension can route to more than one category (see
1218 // dt_image_ext_is_ambiguous() -- e.g. a linear DNG that a raw decoder can't demosaic, or a
1219 // renamed/mislabeled file), so let it cascade into the bruteforce section below instead of
1220 // reporting "corrupted" on a file a later attempt would have opened fine.
1221 if(dt_imageio_is_raster(filename))
1222 ret = dt_imageio_open_raster(img, filename, buf);
1223
1224 if(ret != DT_IMAGEIO_OK && ret != DT_IMAGEIO_CACHE_FULL && dt_imageio_is_raw(filename))
1225 ret = dt_imageio_open_raw(img, filename, buf);
1226
1227 if(ret != DT_IMAGEIO_OK && ret != DT_IMAGEIO_CACHE_FULL && dt_imageio_is_hdr(filename))
1228 ret = dt_imageio_open_hdr(img, filename, buf);
1229
1230 // fallback: bruteforce everything hoping for a miracle
1231 // Most likely, it's a format we never heard of.
1232 if(ret != DT_IMAGEIO_OK && ret != DT_IMAGEIO_CACHE_FULL)
1233 ret = dt_imageio_open_raster(img, filename, buf);
1234
1235 if(ret != DT_IMAGEIO_OK && ret != DT_IMAGEIO_CACHE_FULL)
1236 ret = dt_imageio_open_raw(img, filename, buf);
1237
1238 if(ret != DT_IMAGEIO_OK && ret != DT_IMAGEIO_CACHE_FULL)
1239 ret = dt_imageio_open_hdr(img, filename, buf);
1240
1241 // Final check and abort
1242 if(ret != DT_IMAGEIO_OK)
1243 {
1244 fprintf(stderr, "[imageio] The file %s is supported by none of our decoders.\n", filename);
1245 dt_control_log(_("The file `%s` is supported by none of our decoders."), filename);
1246 return ret;
1247 }
1248
1249 img->p_width = img->width - img->crop_x - img->crop_width;
1250 img->p_height = img->height - img->crop_y - img->crop_height;
1251
1252 // The codec has now populated img->dsc: finalize the buffer-derived type flags
1253 // (DT_IMAGE_MOSAIC + DT_IMAGE_BUFFER_RESOLVED). This is the single point where the
1254 // decoded descriptor is mapped to the persisted classification.
1256
1257 return ret;
1258}
1259
1261 dt_mipmap_buffer_t *buf)
1262{
1263 if(IS_NULL_PTR(buf)) return DT_IMAGEIO_LOAD_FAILED;
1264
1265 memset(buf, 0, sizeof(*buf));
1266 buf->size = DT_MIPMAP_FULL;
1267
1268 /* The decoder allocates into the entry it is handed. Owning one here is what lets callers
1269 * decode a file without knowing that a cache entry exists -- see the header. */
1272
1273 const dt_imageio_retval_t ret = dt_imageio_open(img, filename, buf);
1275 return ret;
1276}
1277
1279{
1280 if(IS_NULL_PTR(buf) || IS_NULL_PTR(buf->cache_entry)) return;
1282 buf->cache_entry = NULL;
1283 buf->buf = NULL;
1284}
1285
1286gboolean dt_imageio_lookup_makermodel(const char *maker, const char *model,
1287 char *mk, int mk_len, char *md, int md_len,
1288 char *al, int al_len)
1289{
1290 // At this stage, we can't tell which loader is used to open the image.
1291 gboolean found = dt_rawspeed_lookup_makermodel(maker, model,
1292 mk, mk_len,
1293 md, md_len,
1294 al, al_len);
1295 if(found == FALSE)
1296 {
1297 // Special handling for CR3 raw files via libraw
1299 mk, mk_len,
1300 md, md_len,
1301 al, al_len);
1302 }
1303 return found;
1304}
1305
1306// clang-format off
1307// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1308// vim: shiftwidth=2 expandtab tabstop=2 cindent
1309// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1310// 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:67
void cleanup(dt_imageio_module_format_t *self)
Definition avif.c:170
static const float x
The colour-profile module's API: which profiles exist, and how to apply one.
static dt_aligned_pixel_t sRGB
const dt_colormatrix_t dt_aligned_pixel_t out
const float top
static const int row
gchar * dt_conf_get_string(const char *name)
gboolean dt_conf_is_equal(const char *name, const char *value)
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.
void dt_control_log(const char *msg,...)
Definition control.c:774
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:219
dt_dev_image_storage_t dt_dev_load_image(dt_develop_t *dev, const int32_t imgid)
Definition develop.c:976
void dt_dev_init(dt_develop_t *dev, int32_t gui_attached)
Definition develop.c:127
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:1703
What a photograph says about itself: the EXIF, IPTC and XMP tags a camera and a cataloguer write,...
float dt_boundingbox_t[4]
Definition image.h:82
dt_image_orientation_t
Definition image.h:215
@ ORIENTATION_SWAP_XY
Definition image.h:220
@ ORIENTATION_FLIP_Y
Definition image.h:218
@ ORIENTATION_FLIP_X
Definition image.h:219
dt_imageio_retval_t
Definition image.h:90
@ DT_IMAGEIO_LOAD_FAILED
Definition image.h:98
@ DT_IMAGEIO_OK
Definition image.h:91
@ DT_IMAGEIO_CACHE_FULL
Definition image.h:94
@ DT_IMAGEIO_FILE_CORRUPTED
Definition image.h:93
@ LOADER_UNKNOWN
Definition image.h:255
gboolean dt_image_ext_is_ldr(const char *ext)
gboolean dt_image_ext_is_raw(const char *ext)
gboolean dt_image_ext_is_hdr(const char *ext)
int bpp
dt_imageio_retval_t dt_imageio_open_avif(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
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)
void _clamp_float_to_uint8(const float *const inbuf, uint8_t *const outbuf, const size_t processed_width, const size_t processed_height)
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)
int dt_imageio_is_hdr(const char *filename)
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)
dt_imageio_retval_t dt_imageio_open(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
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)
void dt_imageio_close_standalone(dt_mipmap_buffer_t *buf)
Release a buffer from dt_imageio_open_standalone(). NULL-safe, and safe to call on a buffer whose ope...
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)
dt_imageio_retval_t dt_imageio_open_raster(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
void _filter_pipeline(const char *filter, dt_dev_pixelpipe_t *pipe)
dt_imageio_retval_t dt_imageio_open_standalone(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
Decode a file into a buffer the CALLER owns, with no cache involvement.
gboolean dt_imageio_is_raster(const char *filename)
gboolean dt_imageio_has_mono_preview(const char *filename)
void dt_imageio_to_fractional(float in, uint32_t *num, uint32_t *den)
gboolean dt_imageio_crop_thumbnail(const dt_boundingbox_t box, uint8_t *const buffer, int32_t *width, int32_t *height)
Crop an 8-bit RGBA preview buffer in place to a normalized bounding box.
gboolean dt_imageio_is_handled_by_libraw(dt_image_t *img, const char *filename)
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)
gboolean _apply_style_before_export(dt_develop_t *dev, dt_imageio_module_data_t *format_params, const int32_t imgid)
dt_imageio_retval_t dt_imageio_open_hdr(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
dt_imageio_retval_t dt_imageio_open_raw(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
static gboolean _is_in_list(char *elem, char *list)
gboolean dt_imageio_is_raw(const char *filename)
dt_imageio_retval_t dt_imageio_open_exotic(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *buf)
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)
Map Exiv2 preview MIME types to decoder format identifiers.
void _print_export_debug(dt_dev_pixelpipe_t *pipe, dt_imageio_module_data_t *format_params, const gboolean use_style)
__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)
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)
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:34
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:42
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)
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)
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:1249
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:1721
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:2351
@ DT_DEBUG_IMAGEIO
Definition logging.h:54
int32_t dt_get_debug_flags(void)
Definition darktable.c:2075
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#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 macros.h:65
#define CLAMPF(a, mn, mx)
Definition math.h:91
#define dt_free(ptr)
Definition mem_alloc.h:97
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
size_t size
Definition mipmap_cache.c:3
dt_colorspaces_color_profile_type_t color_space
Definition mipmap_cache.c:5
@ DT_MIPMAP_BLOCKING
dt_mipmap_size_t
@ DT_MIPMAP_FULL
#define dt_mipmap_cache_get(B, C, D, E, F)
#define dt_mipmap_cache_release(B)
#define __OMP_PARALLEL_FOR__(...)
Definition openmp.h:60
#define PATH_MAX
Definition paths.h:45
void dt_dev_pixelpipe_cache_ref_count_entry(gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Increase/Decrease the reference count on the cache line as to prevent LRU item removal....
void dt_dev_pixelpipe_cache_rdlock_entry(gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
gboolean dt_dev_pixelpipe_cache_ref_entry_by_hash(const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry)
Resolve and retain an existing cache entry by hash.
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
#define dt_pixelpipe_cache_free_align(mem)
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)
dt_iop_color_intent_t
ICC rendering intent, as stored in iop params and in conf.
dt_colorspaces_color_profile_type_t
@ DT_COLORSPACE_SRGB
sRGB – registered TWICE, and the two entries are not interchangeable.
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:382
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:648
@ 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:264
#define for_four_channels(_var,...)
Definition simd.h:89
void dt_cache_entry_free_detached(dt_cache_entry_t *entry)
Release an entry from dt_cache_entry_new_detached(), and its data. NULL-safe.
dt_cache_entry_t * dt_cache_entry_new_detached(void)
Allocate a cache entry that belongs to NO cache, for a one-shot decode.
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_iop_module_t *void * data
dt_backbuf_t backbuf
dt_atomic_int * shutdown_ext
int32_t height
Definition image.h:373
dt_image_loader_t loader
Definition image.h:393
int32_t crop_height
Definition image.h:374
int32_t width
Definition image.h:373
char exif_maker[64]
Definition image.h:350
int32_t crop_y
Definition image.h:374
int32_t crop_x
Definition image.h:374
int32_t p_height
Definition image.h:373
int32_t p_width
Definition image.h:373
char exif_model[64]
Definition image.h:351
int32_t crop_width
Definition image.h:374
Region of interest passed through the pixelpipe.
Definition format.h:49
dt_cache_entry_t * cache_entry
dt_mipmap_size_t size
void * data
#define __DT_CLONE_TARGETS__
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
void dt_show_times(const dt_times_t *start, const char *prefix)
Definition darktable.c:2128
static void dt_get_times(dt_times_t *t)
Definition times.h:50
Telling the user something happened.
int dt_exif_xmp_attach_export(const int32_t imgid, const char *filename, void *metadata)
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)
The XMP document that carries an image's development: history stack, mask shapes, module order,...