Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
exr.cc
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010-2012 johannes hanika.
4 Copyright (C) 2010, 2013 Pascal de Bruijn.
5 Copyright (C) 2011 Henrik Andersson.
6 Copyright (C) 2012-2014, 2020-2021 Pascal Obry.
7 Copyright (C) 2012 Richard Wonka.
8 Copyright (C) 2012-2020 Tobias Ellinghaus.
9 Copyright (C) 2013 Jean-Sébastien Pédron.
10 Copyright (C) 2013 Jérémy Rosen.
11 Copyright (C) 2013 Thomas Pryds.
12 Copyright (C) 2013 Ulrich Pegelow.
13 Copyright (C) 2014 Martijn van Beers.
14 Copyright (C) 2014-2015 parafin.
15 Copyright (C) 2014-2016 Roman Lebedev.
16 Copyright (C) 2016-2017 Peter Budai.
17 Copyright (C) 2018 Maks Naumov.
18 Copyright (C) 2019, 2022, 2025 Aurélien PIERRE.
19 Copyright (C) 2020 Diederik Ter Rahe.
20 Copyright (C) 2021 Hubert Kowalski.
21 Copyright (C) 2022 Martin Bařinka.
22 Copyright (C) 2022 Miloš Komarčević.
23 Copyright (C) 2025 Alynx Zhou.
24
25 darktable is free software: you can redistribute it and/or modify
26 it under the terms of the GNU General Public License as published by
27 the Free Software Foundation, either version 3 of the License, or
28 (at your option) any later version.
29
30 darktable is distributed in the hope that it will be useful,
31 but WITHOUT ANY WARRANTY; without even the implied warranty of
32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 GNU General Public License for more details.
34
35 You should have received a copy of the GNU General Public License
36 along with darktable. If not, see <http://www.gnu.org/licenses/>.
37 */
38
39// needs to be defined before any system header includes for control/conf.h to work in C++ code
40#define __STDC_FORMAT_MACROS
41
42#include "glib.h"
43
44#include "widgets/bauhaus.h"
46#include "system/macros.h"
47#include "system/openmp.h"
48#include "system/mem_alloc.h"
50#include "common/xmp_sidecar.h"
53#include "common/conf.h"
56
58
59#include <OpenEXR/ImfChannelList.h>
60#include <OpenEXR/ImfFrameBuffer.h>
61#include <OpenEXR/ImfStandardAttributes.h>
62#include <OpenEXR/ImfThreading.h>
63#include <OpenEXR/ImfOutputFile.h>
65
66#ifdef __cplusplus
67extern "C" {
68#endif
69
70DT_MODULE(5)
71
73{
74 NO_COMPRESSION = 0, // no compression
75 RLE_COMPRESSION = 1, // run length encoding
76 ZIPS_COMPRESSION = 2, // zlib compression, one scan line at a time
77 ZIP_COMPRESSION = 3, // zlib compression, in blocks of 16 scan lines
78 PIZ_COMPRESSION = 4, // piz-based wavelet compression
79 PXR24_COMPRESSION = 5, // lossy 24-bit float compression
80 B44_COMPRESSION = 6, // lossy 4-by-4 pixel block compression,
81 // fixed compression rate
82 B44A_COMPRESSION = 7, // lossy 4-by-4 pixel block compression,
83 // flat fields are compressed more
84 DWAA_COMPRESSION = 8, // lossy DCT based compression, in blocks
85 // of 32 scanlines
86 DWAB_COMPRESSION = 9, // lossy DCT based compression, in blocks
87 // of 256 scanlines
88 NUM_COMPRESSION_METHODS // number of different compression methods
89}; // copy of Imf::Compression
90
92{
93 EXR_PT_UINT = 0, // unsigned int (32 bit)
94 EXR_PT_HALF = 1, // half (16 bit floating point)
95 EXR_PT_FLOAT = 2, // float (32 bit floating point)
96 NUM_PIXELTYPES // number of different pixel types
97}; // copy of Imf::PixelType
98
105
111
113{
114 Imf::BlobAttribute::registerAttributeType();
115}
116
120
121int write_image(dt_imageio_module_data_t *tmp, const char *filename, const void *in_tmp,
122 dt_colorspaces_color_profile_type_t over_type, const char *over_filename,
123 void *exif, int exif_len, int32_t imgid, int num, int total, struct dt_dev_pixelpipe_t *pipe,
124 const gboolean export_masks)
125{
126 const dt_imageio_exr_t *exr = (dt_imageio_exr_t *)tmp;
127
128 Imf::setGlobalThreadCount(dt_get_num_openmp_threads());
129
130 Imf::Header header(exr->global.width, exr->global.height, 1, Imath::V2f(0, 0), 1, Imf::INCREASING_Y,
131 (Imf::Compression)exr->compression);
132
133 char comment[1024];
134 snprintf(comment, sizeof(comment), "Developed using %s", darktable_package_string);
135
136 header.insert("comment", Imf::StringAttribute(comment));
137
138 if(exif && exif_len > 0)
139 {
140 Imf::Blob exif_blob(exif_len, (uint8_t *)exif);
141 header.insert("exif", Imf::BlobAttribute(exif_blob));
142 }
143
144 char *xmp_string = dt_exif_xmp_read_string(imgid);
145 if(xmp_string && strlen(xmp_string) > 0)
146 {
147 header.insert("xmp", Imf::StringAttribute(xmp_string));
148 dt_free(xmp_string);
149 }
150
151 // try to add the chromaticities
152 if(imgid > 0)
153 {
154 cmsToneCurve *red_curve = NULL,
155 *green_curve = NULL,
156 *blue_curve = NULL;
157 cmsCIEXYZ *red_color = NULL,
158 *green_color = NULL,
159 *blue_color = NULL;
160 cmsHPROFILE out_profile = dt_colorspaces_get_output_profile(imgid, &over_type, over_filename)->profile;
161 float r[2], g[2], b[2], w[2];
162 float sum;
163 Imf::Chromaticities chromaticities;
164
165 if(!cmsIsMatrixShaper(out_profile)) goto icc_error;
166
167 red_curve = (cmsToneCurve *)cmsReadTag(out_profile, cmsSigRedTRCTag);
168 green_curve = (cmsToneCurve *)cmsReadTag(out_profile, cmsSigGreenTRCTag);
169 blue_curve = (cmsToneCurve *)cmsReadTag(out_profile, cmsSigBlueTRCTag);
170
171 red_color = (cmsCIEXYZ *)cmsReadTag(out_profile, cmsSigRedColorantTag);
172 green_color = (cmsCIEXYZ *)cmsReadTag(out_profile, cmsSigGreenColorantTag);
173 blue_color = (cmsCIEXYZ *)cmsReadTag(out_profile, cmsSigBlueColorantTag);
174
175 if(IS_NULL_PTR(red_curve) || IS_NULL_PTR(green_curve) || IS_NULL_PTR(blue_curve) || IS_NULL_PTR(red_color) || IS_NULL_PTR(green_color) || IS_NULL_PTR(blue_color))
176 goto icc_error;
177
178 if(!cmsIsToneCurveLinear(red_curve) || !cmsIsToneCurveLinear(green_curve) || !cmsIsToneCurveLinear(blue_curve))
179 goto icc_error;
180
181// printf("r: %f %f %f\n", red_color->X, red_color->Y, red_color->Z);
182// printf("g: %f %f %f\n", green_color->X, green_color->Y, green_color->Z);
183// printf("b: %f %f %f\n", blue_color->X, blue_color->Y, blue_color->Z);
184// printf("w: %f %f %f\n", white_point->X, white_point->Y, white_point->Z);
185
186 sum = red_color->X + red_color->Y + red_color->Z;
187 r[0] = red_color->X / sum;
188 r[1] = red_color->Y / sum;
189 sum = green_color->X + green_color->Y + green_color->Z;
190 g[0] = green_color->X / sum;
191 g[1] = green_color->Y / sum;
192 sum = blue_color->X + blue_color->Y + blue_color->Z;
193 b[0] = blue_color->X / sum;
194 b[1] = blue_color->Y / sum;
195
196 // hard code the white point to D50 as the primaries from the ICC should be adapted to that
197 // calculated from D50 illuminant XYZ values in ICC specs
198 w[0] = 0.345702915;
199 w[1] = 0.358538597;
200
201 chromaticities.red = Imath::V2f(r[0], r[1]);
202 chromaticities.green = Imath::V2f(g[0], g[1]);
203 chromaticities.blue = Imath::V2f(b[0], b[1]);
204 chromaticities.white = Imath::V2f(w[0], w[1]);
205
206 Imf::addChromaticities(header, chromaticities);
207 Imf::addWhiteLuminance(header, 1.0); // just assume 1 here
208
209 goto icc_end;
210
211icc_error:
212 dt_control_log("%s", _("the selected output profile doesn't work well with exr"));
213 fprintf(stderr, "[exr export] warning: exporting with anything but linear matrix profiles might lead to wrong results when opening the image\n");
214 }
215icc_end:
216
217 Imf::PixelType pixel_type = (Imf::PixelType)exr->pixel_type;
218
219 header.channels().insert("R", Imf::Channel(pixel_type, 1, 1, true));
220 header.channels().insert("G", Imf::Channel(pixel_type, 1, 1, true));
221 header.channels().insert("B", Imf::Channel(pixel_type, 1, 1, true));
222
223 Imf::OutputFile file(filename, header);
224
225 Imf::FrameBuffer data;
226 size_t stride;
227
228 if(pixel_type == Imf::PixelType::FLOAT)
229 {
230 stride = 4 * sizeof(float);
231 const float *in = (const float *)in_tmp;
232
233 data.insert("R", Imf::Slice(pixel_type, (char *)(in + 0), stride,
234 stride * exr->global.width));
235
236 data.insert("G", Imf::Slice(pixel_type, (char *)(in + 1), stride,
237 stride * exr->global.width));
238
239 data.insert("B", Imf::Slice(pixel_type, (char *)(in + 2), stride,
240 stride * exr->global.width));
241
242 file.setFrameBuffer(data);
243 file.writePixels(exr->global.height);
244 }
245 else
246 {
247 const size_t width = exr->global.width;
248 const size_t height = exr->global.height;
249 stride = 3 * sizeof(unsigned short);
250 unsigned short *out = (unsigned short *)malloc(stride * width * height);
251 if(IS_NULL_PTR(out))
252 return 1;
253
254#ifdef _OPENMP
255#pragma omp parallel for simd default(none) collapse(2) firstprivate(height, width, in_tmp, out)
256#endif
257 for(size_t y = 0; y < height; y++)
258 {
259 for(size_t x = 0; x < width; x++)
260 {
261 const float *in_pixel = (const float *)in_tmp + 4 * ((y * width) + x);
262 unsigned short *out_pixel = out + 3 * ((y * width) + x);
263
264 out_pixel[0] = half(in_pixel[0]).bits();
265 out_pixel[1] = half(in_pixel[1]).bits();
266 out_pixel[2] = half(in_pixel[2]).bits();
267 }
268 }
269
270 data.insert("R", Imf::Slice(pixel_type, (char *)(out + 0), stride,
271 stride * exr->global.width));
272
273 data.insert("G", Imf::Slice(pixel_type, (char *)(out + 1), stride,
274 stride * exr->global.width));
275
276 data.insert("B", Imf::Slice(pixel_type, (char *)(out + 2), stride,
277 stride * exr->global.width));
278
279 file.setFrameBuffer(data);
280 file.writePixels(exr->global.height);
281
282 dt_free(out);
283 }
284
285 return 0;
286}
287
289{
290 return sizeof(dt_imageio_exr_t);
291}
292
293void *legacy_params(dt_imageio_module_format_t *self, const void *const old_params,
294 const size_t old_params_size, const int old_version, const int new_version,
295 size_t *new_size)
296{
297 if(old_version == 1 && new_version == 5)
298 {
299 struct dt_imageio_exr_v1_t
300 {
301 int max_width, max_height;
302 int width, height;
303 char style[128];
304 };
305
306 const dt_imageio_exr_v1_t *o = (dt_imageio_exr_v1_t *)old_params;
308
309 n->global.max_width = o->max_width;
310 n->global.max_height = o->max_height;
311 n->global.width = o->width;
312 n->global.height = o->height;
313 g_strlcpy(n->global.style, o->style, sizeof(o->style));
314 n->compression = PIZ_COMPRESSION;
315 n->pixel_type = EXR_PT_FLOAT;
316 *new_size = self->params_size(self);
317 return n;
318 }
319 if(old_version == 2 && new_version == 5)
320 {
321 struct dt_imageio_exr_v2_t
322 {
323 int max_width, max_height;
324 int width, height;
325 char style[128];
328 };
329
330 const dt_imageio_exr_v2_t *o = (dt_imageio_exr_v2_t *)old_params;
332
333 // last param was dropped (pixel type)
334 n->global.max_width = o->max_width;
335 n->global.max_height = o->max_height;
336 n->global.width = o->width;
337 n->global.height = o->height;
338 g_strlcpy(n->global.style, o->style, sizeof(o->style));
339 n->compression = o->compression;
340 n->pixel_type = o->pixel_type >= EXR_PT_HALF ? o->pixel_type : EXR_PT_FLOAT;
341 *new_size = self->params_size(self);
342 return n;
343 }
344 if(old_version == 3 && new_version == 5)
345 {
346 struct dt_imageio_exr_v3_t
347 {
348 int max_width, max_height;
349 int width, height;
350 char style[128];
352 };
353
354 const dt_imageio_exr_v3_t *o = (dt_imageio_exr_v3_t *)old_params;
356
357 n->global.max_width = o->max_width;
358 n->global.max_height = o->max_height;
359 n->global.width = o->width;
360 n->global.height = o->height;
361 g_strlcpy(n->global.style, o->style, sizeof(o->style));
362 n->compression = o->compression;
363 n->pixel_type = EXR_PT_FLOAT;
364 *new_size = self->params_size(self);
365 return n;
366 }
367 if(old_version == 4 && new_version == 5)
368 {
369 struct dt_imageio_exr_v4_t
370 {
373 };
374
375 const dt_imageio_exr_v4_t *o = (dt_imageio_exr_v4_t *)old_params;
377
378 n->global.max_width = o->global.max_width;
379 n->global.max_height = o->global.max_height;
380 n->global.width = o->global.width;
381 n->global.height = o->global.height;
382 g_strlcpy(n->global.style, o->global.style, sizeof(o->global.style));
383 n->compression = o->compression;
384 n->pixel_type = EXR_PT_FLOAT;
385 *new_size = self->params_size(self);
386 return n;
387 }
388 return NULL;
389}
390
392{
393 dt_imageio_exr_t *d = (dt_imageio_exr_t *)calloc(1, sizeof(dt_imageio_exr_t));
394 d->compression = (dt_imageio_exr_compression_t)dt_conf_get_int("plugins/imageio/format/exr/compression");
395 const int bpp = dt_conf_get_int("plugins/imageio/format/exr/bpp");
396 d->pixel_type = (dt_imageio_exr_pixeltype_t)(bpp >> 4);
397 return d;
398}
399
401{
402 dt_free(params);
403}
404
405int set_params(dt_imageio_module_format_t *self, const void *params, const int size)
406{
407 if(size != (int)self->params_size(self)) return 1;
410 dt_bauhaus_combobox_set(g->bpp, d->pixel_type - EXR_PT_HALF);
411 dt_bauhaus_combobox_set(g->compression, d->compression);
412 return 0;
413}
414
416{
417 return 32; // always request float, any conversion is done internally
418}
419
424
426{
427 return "image/x-exr";
428}
429
431{
432 return "exr";
433}
434
435const char *name()
436{
437 return _("OpenEXR (16/32-bit float)");
438}
439
440static void bpp_combobox_changed(GtkWidget *widget, gpointer user_data)
441{
442 const int pixel_type = dt_bauhaus_combobox_get(widget) + EXR_PT_HALF;
443 dt_conf_set_int("plugins/imageio/format/exr/bpp", pixel_type << 4);
444}
445
446static void compression_combobox_changed(GtkWidget *widget, gpointer user_data)
447{
448 const int compression = dt_bauhaus_combobox_get(widget);
449 dt_conf_set_int("plugins/imageio/format/exr/compression", compression);
450}
451
453{
454 self->gui_data = malloc(sizeof(dt_imageio_exr_gui_t));
456
457 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
458
459 // Bit depth combo box
460 const int bpp_last = dt_conf_get_int("plugins/imageio/format/exr/bpp");
461
463 dt_bauhaus_widget_set_label(gui->bpp, N_("bit depth"));
464
465 dt_bauhaus_combobox_add(gui->bpp, _("16 bit"));
466 dt_bauhaus_combobox_add(gui->bpp, _("32 bit"));
467 dt_bauhaus_combobox_set(gui->bpp, (bpp_last >> 4) - EXR_PT_HALF);
468 gtk_box_pack_start(GTK_BOX(self->widget), gui->bpp, TRUE, TRUE, 0);
469 g_signal_connect(G_OBJECT(gui->bpp), "value-changed", G_CALLBACK(bpp_combobox_changed), NULL);
470
471 // Compression combo box
472 const int compression_last = dt_conf_get_int("plugins/imageio/format/exr/compression");
473
475 dt_bauhaus_widget_set_label(gui->compression, N_("compression"));
476
477 dt_bauhaus_combobox_add(gui->compression, _("uncompressed"));
478 dt_bauhaus_combobox_add(gui->compression, _("RLE"));
479 dt_bauhaus_combobox_add(gui->compression, _("ZIPS"));
480 dt_bauhaus_combobox_add(gui->compression, _("ZIP"));
481 dt_bauhaus_combobox_add(gui->compression, _("PIZ"));
482 dt_bauhaus_combobox_add(gui->compression, _("PXR24"));
483 dt_bauhaus_combobox_add(gui->compression, _("B44"));
484 dt_bauhaus_combobox_add(gui->compression, _("B44A"));
485 dt_bauhaus_combobox_add(gui->compression, _("DWAA"));
486 dt_bauhaus_combobox_add(gui->compression, _("DWAB"));
487 dt_bauhaus_combobox_set(gui->compression, compression_last);
488 gtk_box_pack_start(GTK_BOX(self->widget), gui->compression, TRUE, TRUE, 0);
489 g_signal_connect(G_OBJECT(gui->compression), "value-changed", G_CALLBACK(compression_combobox_changed), NULL);
490}
491
493{
494 dt_free(self->gui_data);
495}
496
498{
500 const int bpp = dt_confgen_get_int("plugins/imageio/format/exr/bpp", DT_DEFAULT);
502 dt_bauhaus_combobox_set(gui->compression, dt_confgen_get_int("plugins/imageio/format/exr/compression", DT_DEFAULT));
503}
504
505
506
507#ifdef __cplusplus
508}
509#endif
510// clang-format off
511// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
512// vim: shiftwidth=2 expandtab tabstop=2 cindent
513// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
514// clang-format on
#define TRUE
Definition ashift_lsd.c:162
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2136
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2090
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1504
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1698
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:1824
static const float x
The colour-profile module's API: which profiles exist, and how to apply one.
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
Definition colorspaces.h:98
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
int dt_confgen_get_int(const char *name, dt_confgen_value_kind_t kind)
@ DT_DEFAULT
Definition conf.h:135
const char darktable_package_string[]
void dt_control_log(const char *msg,...)
Definition control.c:824
int dt_get_num_openmp_threads(void)
Number of OpenMP threads the application decided to use.
Definition darktable.c:518
struct dt_bauhaus_t * dt_bauhaus_get_global(void)
Definition darktable.c:646
const char * mime(dt_imageio_module_data_t *data)
Definition exr.cc:425
size_t params_size(dt_imageio_module_format_t *self)
Definition exr.cc:288
void gui_reset(dt_imageio_module_format_t *self)
Definition exr.cc:497
void gui_init(dt_imageio_module_format_t *self)
Definition exr.cc:452
const char * extension(dt_imageio_module_data_t *data)
Definition exr.cc:430
int write_image(dt_imageio_module_data_t *tmp, const char *filename, const void *in_tmp, dt_colorspaces_color_profile_type_t over_type, const char *over_filename, void *exif, int exif_len, int32_t imgid, int num, int total, struct dt_dev_pixelpipe_t *pipe, const gboolean export_masks)
Definition exr.cc:121
dt_imageio_exr_compression_t
Definition exr.cc:73
@ DWAB_COMPRESSION
Definition exr.cc:86
@ PXR24_COMPRESSION
Definition exr.cc:79
@ DWAA_COMPRESSION
Definition exr.cc:84
@ RLE_COMPRESSION
Definition exr.cc:75
@ NUM_COMPRESSION_METHODS
Definition exr.cc:88
@ B44A_COMPRESSION
Definition exr.cc:82
@ NO_COMPRESSION
Definition exr.cc:74
@ B44_COMPRESSION
Definition exr.cc:80
@ ZIP_COMPRESSION
Definition exr.cc:77
@ PIZ_COMPRESSION
Definition exr.cc:78
@ ZIPS_COMPRESSION
Definition exr.cc:76
int set_params(dt_imageio_module_format_t *self, const void *params, const int size)
Definition exr.cc:405
const char * name()
Definition exr.cc:435
void cleanup(dt_imageio_module_format_t *self)
Definition exr.cc:117
int levels(dt_imageio_module_data_t *p)
Definition exr.cc:420
void * legacy_params(dt_imageio_module_format_t *self, const void *const old_params, const size_t old_params_size, const int old_version, const int new_version, size_t *new_size)
Definition exr.cc:293
dt_imageio_exr_pixeltype_t
Definition exr.cc:92
@ EXR_PT_UINT
Definition exr.cc:93
@ EXR_PT_FLOAT
Definition exr.cc:95
@ EXR_PT_HALF
Definition exr.cc:94
@ NUM_PIXELTYPES
Definition exr.cc:96
void free_params(dt_imageio_module_format_t *self, dt_imageio_module_data_t *params)
Definition exr.cc:400
static void compression_combobox_changed(GtkWidget *widget, gpointer user_data)
Definition exr.cc:446
void init(dt_imageio_module_format_t *self)
Definition exr.cc:112
void * get_params(dt_imageio_module_format_t *self)
Definition exr.cc:391
void gui_cleanup(dt_imageio_module_format_t *self)
Definition exr.cc:492
static void bpp_combobox_changed(GtkWidget *widget, gpointer user_data)
Definition exr.cc:440
#define DT_GUI_MODULE(x)
int bpp
@ IMAGEIO_RGB
@ IMAGEIO_FLOAT
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)
#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:96
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
size_t size
Definition mipmap_cache.c:3
#define DT_MODULE(MODVER)
Instantiate the version handshake every module must export. Use once, at file scope,...
Imf ::TypedAttribute< Imf ::Blob > BlobAttribute
dt_colorspaces_color_profile_type_t
const float r
cmsHPROFILE profile
the actual profile; NULL for the three category entries
GtkWidget * compression
Definition exr.cc:109
GtkWidget * bpp
Definition exr.cc:108
dt_imageio_exr_compression_t compression
Definition exr.cc:102
dt_imageio_module_data_t global
Definition exr.cc:101
dt_imageio_exr_pixeltype_t pixel_type
Definition exr.cc:103
GModule *GtkWidget * widget
Telling the user something happened.
#define DT_GUI_BOX_SPACING
char * dt_exif_xmp_read_string(const int32_t imgid)
The XMP document that carries an image's development: history stack, mask shapes, module order,...