1 /*
2 This file is part of darktable,
3 Copyright (C) 2012-2020 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
19 #ifdef HAVE_GRAPHICSMAGICK
20 #include "imageio_gm.h"
21 #include "common/colorspaces.h"
22 #include "common/darktable.h"
23 #include "common/exif.h"
24 #include "control/conf.h"
25 #include "develop/develop.h"
26 #include "imageio.h"
27
28 #include <assert.h>
29 #include <inttypes.h>
30 #include <magick/api.h>
31 #include <memory.h>
32 #include <stdio.h>
33 #include <strings.h>
34
35
36 // we only support images with certain filename extensions via GraphicsMagick;
37 // RAWs are excluded as GraphicsMagick would render them with third party
38 // libraries in reduced quality - slow and only 8-bit
_supported_image(const gchar * filename)39 static gboolean _supported_image(const gchar *filename)
40 {
41 const char *extensions_whitelist[] = { "tif", "tiff", "gif", "jpc", "jp2", "bmp", "dcm", "jng",
42 "miff", "mng", "pbm", "pnm", "ppm", "pgm", NULL };
43 gboolean supported = FALSE;
44 char *ext = g_strrstr(filename, ".");
45 if(!ext) return FALSE;
46 ext++;
47 for(const char **i = extensions_whitelist; *i != NULL; i++)
48 if(!g_ascii_strncasecmp(ext, *i, strlen(*i)))
49 {
50 supported = TRUE;
51 break;
52 }
53 return supported;
54 }
55
56
dt_imageio_open_gm(dt_image_t * img,const char * filename,dt_mipmap_buffer_t * mbuf)57 dt_imageio_retval_t dt_imageio_open_gm(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
58 {
59 int err = DT_IMAGEIO_FILE_CORRUPTED;
60 ExceptionInfo exception;
61 Image *image = NULL;
62 ImageInfo *image_info = NULL;
63 uint32_t width, height;
64
65 if(!_supported_image(filename)) return DT_IMAGEIO_FILE_CORRUPTED;
66
67 if(!img->exif_inited) (void)dt_exif_read(img, filename);
68
69 GetExceptionInfo(&exception);
70 image_info = CloneImageInfo((ImageInfo *)NULL);
71
72 g_strlcpy(image_info->filename, filename, sizeof(image_info->filename));
73
74 image = ReadImage(image_info, &exception);
75 if(exception.severity != UndefinedException) CatchException(&exception);
76 if(!image)
77 {
78 fprintf(stderr, "[GraphicsMagick_open] image `%s' not found\n", img->filename);
79 err = DT_IMAGEIO_FILE_NOT_FOUND;
80 goto error;
81 }
82
83 dt_print(DT_DEBUG_IMAGEIO, "[GraphicsMagick_open] image `%s' loading\n", img->filename);
84
85 if(IsCMYKColorspace(image->colorspace))
86 {
87 fprintf(stderr, "[GraphicsMagick_open] error: CMYK images are not supported.\n");
88 err = DT_IMAGEIO_FILE_CORRUPTED;
89 goto error;
90 }
91
92 width = image->columns;
93 height = image->rows;
94
95 img->width = width;
96 img->height = height;
97
98 img->buf_dsc.channels = 4;
99 img->buf_dsc.datatype = TYPE_FLOAT;
100
101 float *mipbuf = (float *)dt_mipmap_cache_alloc(mbuf, img);
102 if(!mipbuf)
103 {
104 fprintf(stderr, "[GraphicsMagick_open] could not alloc full buffer for image `%s'\n", img->filename);
105 err = DT_IMAGEIO_CACHE_FULL;
106 goto error;
107 }
108
109 for(uint32_t row = 0; row < height; row++)
110 {
111 float *bufprt = mipbuf + (size_t)4 * row * img->width;
112 int ret = DispatchImage(image, 0, row, width, 1, "RGBP", FloatPixel, bufprt, &exception);
113 if(exception.severity != UndefinedException) CatchException(&exception);
114 if(ret != MagickPass)
115 {
116 fprintf(stderr, "[GraphicsMagick_open] error reading image `%s'\n", img->filename);
117 err = DT_IMAGEIO_FILE_CORRUPTED;
118 goto error;
119 }
120 }
121
122 if(image) DestroyImage(image);
123 if(image_info) DestroyImageInfo(image_info);
124 DestroyExceptionInfo(&exception);
125
126 img->buf_dsc.filters = 0u;
127 img->flags &= ~DT_IMAGE_RAW;
128 img->flags &= ~DT_IMAGE_HDR;
129 img->flags &= ~DT_IMAGE_S_RAW;
130 img->flags |= DT_IMAGE_LDR;
131
132 return DT_IMAGEIO_OK;
133
134 error:
135 if(image) DestroyImage(image);
136 if(image_info) DestroyImageInfo(image_info);
137 DestroyExceptionInfo(&exception);
138 return err;
139 }
140 #endif
141
142 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
143 // vim: shiftwidth=2 expandtab tabstop=2 cindent
144 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
145