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