Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
tiff.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010-2011, 2014 Henrik Andersson.
4 Copyright (C) 2010-2011 johannes hanika.
5 Copyright (C) 2011, 2013-2014 Pascal de Bruijn.
6 Copyright (C) 2011-2020 Tobias Ellinghaus.
7 Copyright (C) 2011 Togan Muftuoglu.
8 Copyright (C) 2012 James C. McPherson.
9 Copyright (C) 2012-2015, 2020-2021 Pascal Obry.
10 Copyright (C) 2012 Richard Wonka.
11 Copyright (C) 2012 Simon Spannagel.
12 Copyright (C) 2013 Jérémy Rosen.
13 Copyright (C) 2013 Thomas Pryds.
14 Copyright (C) 2013-2014 Ulrich Pegelow.
15 Copyright (C) 2014 Edouard Gomez.
16 Copyright (C) 2014, 2016 Roman Lebedev.
17 Copyright (C) 2017 luzpaz.
18 Copyright (C) 2018 Simon Raffeiner.
19 Copyright (C) 2019, 2022, 2025-2026 Aurélien PIERRE.
20 Copyright (C) 2019 Sam Smith.
21 Copyright (C) 2020 Diederik Ter Rahe.
22 Copyright (C) 2020 Hanno Schwalm.
23 Copyright (C) 2020-2021 Hubert Kowalski.
24 Copyright (C) 2020-2022 Miloš Komarčević.
25 Copyright (C) 2020-2021 Ralf Brown.
26 Copyright (C) 2022 Martin Bařinka.
27
28 darktable is free software: you can redistribute it and/or modify
29 it under the terms of the GNU General Public License as published by
30 the Free Software Foundation, either version 3 of the License, or
31 (at your option) any later version.
32
33 darktable is distributed in the hope that it will be useful,
34 but WITHOUT ANY WARRANTY; without even the implied warranty of
35 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 GNU General Public License for more details.
37
38 You should have received a copy of the GNU General Public License
39 along with darktable. If not, see <http://www.gnu.org/licenses/>.
40*/
41#include "bauhaus/bauhaus.h"
42#include "common/colorspaces.h"
43#include "common/darktable.h"
44#include "common/exif.h"
45#include "common/imageio.h"
47#include "common/math.h"
48#include "control/conf.h"
49#include "control/control.h"
52#include <inttypes.h>
53#include <memory.h>
54#include <stddef.h>
55#include <stdio.h>
56#include <stdlib.h>
57#include <tiffio.h>
58
59// it would be nice to save space by storing the masks as single channel float data,
60// but at least GIMP can't open TIFF files where not all layers have the same format.
61#define MASKS_USE_SAME_FORMAT
62
63DT_MODULE(3)
64
74
82
83
84int write_image(dt_imageio_module_data_t *d_tmp, const char *filename, const void *in_void,
85 dt_colorspaces_color_profile_type_t over_type, const char *over_filename,
86 void *exif, int exif_len, int32_t imgid, int num, int total, dt_dev_pixelpipe_t *pipe,
87 const gboolean export_masks)
88{
89 const dt_imageio_tiff_t *d = (dt_imageio_tiff_t *)d_tmp;
90
91 uint8_t *profile = NULL;
92 uint32_t profile_len = 0;
93
94 TIFF *tif = NULL;
95
96 void *rowdata = NULL;
97
98 gboolean free_mask = FALSE;
99 float *raster_mask = NULL;
100#ifdef _WIN32
101 wchar_t *wfilename = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL);
102#endif
103 int rc = 1; // default to error
104
105 if(imgid > 0)
106 {
107 cmsHPROFILE out_profile = dt_colorspaces_get_output_profile(imgid, &over_type, over_filename)->profile;
108 cmsSaveProfileToMem(out_profile, 0, &profile_len);
109 if(profile_len > 0)
110 {
111 profile = malloc(profile_len);
112 if(IS_NULL_PTR(profile))
113 {
114 rc = 1;
115 goto exit;
116 }
117 cmsSaveProfileToMem(out_profile, profile, &profile_len);
118 }
119 }
120
121 uint16_t n_pages = 1;
122 // only when masks are to be stored we check for extra pages!
123 if(export_masks && pipe)
124 {
125 for(GList *iter = pipe->nodes; iter; iter = g_list_next(iter))
126 {
127 const dt_dev_pixelpipe_iop_t *piece = (dt_dev_pixelpipe_iop_t *)iter->data;
128 if(piece->enabled)
129 n_pages += g_hash_table_size(piece->module->raster_mask.source.masks);
130 }
131 }
132
133 // Create little endian tiff image
134#ifdef _WIN32
135 tif = TIFFOpenW(wfilename, "wl");
136#else
137 tif = TIFFOpen(filename, "wl");
138#endif
139
140 if(IS_NULL_PTR(tif))
141 {
142 rc = 1;
143 goto exit;
144 }
145
146 if(n_pages > 1)
147 {
148 TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
149 TIFFSetField(tif, TIFFTAG_PAGENAME, _("image"));
150 TIFFSetField(tif, TIFFTAG_PAGENUMBER, 0, n_pages);
151 }
152 else
153 TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 0);
154
155 TIFFSetField(tif, TIFFTAG_DOCUMENTNAME, filename);
156
157 // http://partners.adobe.com/public/developer/en/tiff/TIFFphotoshop.pdf (dated 2002)
158 // "A proprietary ZIP/Flate compression code (0x80b2) has been used by some"
159 // "software vendors. This code should be considered obsolete. We recommend"
160 // "that TIFF implementations recognize and read the obsolete code but only"
161 // "write the official compression code (0x0008)."
162 // http://www.awaresystems.be/imaging/tiff/tifftags/compression.html
163 // http://www.awaresystems.be/imaging/tiff/tifftags/predictor.html
164 if(d->compress == 1)
165 {
166 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE);
167 TIFFSetField(tif, TIFFTAG_PREDICTOR, PREDICTOR_NONE);
168 TIFFSetField(tif, TIFFTAG_ZIPQUALITY, (uint16_t)d->compresslevel);
169 }
170 else if(d->compress == 2)
171 {
172 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE);
173 if(d->bpp == 32)
174 TIFFSetField(tif, TIFFTAG_PREDICTOR, PREDICTOR_FLOATINGPOINT);
175 else
176 TIFFSetField(tif, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL);
177 TIFFSetField(tif, TIFFTAG_ZIPQUALITY, (uint16_t)d->compresslevel);
178 }
179
180 if(!IS_NULL_PTR(profile))
181 {
182 TIFFSetField(tif, TIFFTAG_ICCPROFILE, (uint32_t)profile_len, profile);
183 }
184
185/* Howto check for a grayscale image?
186 We test every pixel for differences between the rgb channels using specific thresholds
187 for every precision. If there is such a pixel we keep it as an rgb image, otherwise
188 it's safe to assume a grayscale.
189 As there might be pipeline errors at the border we leave them alone.
190 After these checks layers can be used later on.
191*/
192 uint16_t layers = 3; // default are rgb images
193
194 int shortmode = 0;
195 if(dt_conf_key_exists("plugins/imageio/format/tiff/shortfile"))
196 shortmode = dt_conf_get_int("plugins/imageio/format/tiff/shortfile");
197
198 if((d->global.height > 4) && (d->global.width > 4) && shortmode)
199 {
200 layers = 1; // let's now assume a grayscale
201 if(d->bpp == 32)
202 {
203 for(int y = 1; y < d->global.height-1; y++)
204 {
205 float *in = (float *)in_void + (size_t)4 * y * d->global.width;
206 for(int x = 1; x < d->global.width-1; x++, in += 4)
207 {
208 if((fabsf(fmaxf(in[0], 0.001f) / fmaxf(in[1], 0.001f)) > 1.01f) ||
209 (fabsf(fmaxf(in[0], 0.001f) / fmaxf(in[2], 0.001f)) > 1.01f) ||
210 (fabsf(fmaxf(in[1], 0.001f) / fmaxf(in[2], 0.001f)) > 1.01f))
211 {
212 layers = 3;
213 goto checkdone;
214 }
215 }
216 }
217 }
218 else if(d->bpp == 16)
219 {
220 for(int y = 1; y < d->global.height-1; y++)
221 {
222 uint16_t *in = (uint16_t *)in_void + (size_t)4 * y * d->global.width;
223 for(int x = 1; x < d->global.width-1; x++, in += 4)
224 {
225 if((abs(in[0] - in[1]) > 100) ||
226 (abs(in[0] - in[2]) > 100) ||
227 (abs(in[1] - in[2]) > 100))
228 {
229 layers = 3;
230 goto checkdone;
231 }
232 }
233 }
234 }
235 else
236 {
237 for(int y = 1; y < d->global.height-1; y++)
238 {
239 uint8_t *in = (uint8_t *)in_void + (size_t)4 * y * d->global.width;
240 for(int x = 1; x < d->global.width-1; x++, in += 4)
241 {
242 if((abs(in[0] - in[1]) > 5) ||
243 (abs(in[0] - in[2]) > 5) ||
244 (abs(in[1] - in[2]) > 5))
245 {
246 layers = 3;
247 goto checkdone;
248 }
249 }
250 }
251 }
252
253 }
254 checkdone:
255 if(layers == 1)
256 dt_control_log(_("will export as a grayscale image"));
257
258 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, layers);
259 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (uint16_t)d->bpp);
260 TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, (d->bpp == 32) ? SAMPLEFORMAT_IEEEFP : SAMPLEFORMAT_UINT);
261 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32_t)d->global.width);
262 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32_t)d->global.height);
263 if(layers == 3)
264 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
265 else
266 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
267
268 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
269 TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
270 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, 0));
271
272 const int resolution = dt_conf_get_int("metadata/resolution");
273 TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)resolution);
274 TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)resolution);
275 TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
276
277 const size_t rowsize = (d->global.width * layers) * d->bpp / 8;
278 if((rowdata = malloc(rowsize)) == NULL)
279 {
280 rc = 1;
281 goto exit;
282 }
283
284 if(d->bpp == 32)
285 {
286 for(int y = 0; y < d->global.height; y++)
287 {
288 float *in = (float *)in_void + (size_t)4 * y * d->global.width;
289 float *out = (float *)rowdata;
290
291 for(int x = 0; x < d->global.width; x++, in += 4, out += layers)
292 {
293 memcpy(out, in, sizeof(float) * layers);
294 }
295
296 if(TIFFWriteScanline(tif, rowdata, y, 0) == -1)
297 {
298 rc = 1;
299 goto exit;
300 }
301 }
302 }
303 else if(d->bpp == 16)
304 {
305 for(int y = 0; y < d->global.height; y++)
306 {
307 uint16_t *in = (uint16_t *)in_void + (size_t)4 * y * d->global.width;
308 uint16_t *out = (uint16_t *)rowdata;
309
310 for(int x = 0; x < d->global.width; x++, in += 4, out += layers)
311 {
312 memcpy(out, in, sizeof(uint16_t) * layers);
313 }
314
315 if(TIFFWriteScanline(tif, rowdata, y, 0) == -1)
316 {
317 rc = 1;
318 goto exit;
319 }
320 }
321 }
322 else
323 {
324 for(int y = 0; y < d->global.height; y++)
325 {
326 uint8_t *in = (uint8_t *)in_void + (size_t)4 * y * d->global.width;
327 uint8_t *out = (uint8_t *)rowdata;
328
329 for(int x = 0; x < d->global.width; x++, in += 4, out += layers)
330 {
331 memcpy(out, in, sizeof(uint8_t) * layers);
332 }
333
334 if(TIFFWriteScanline(tif, rowdata, y, 0) == -1)
335 {
336 rc = 1;
337 goto exit;
338 }
339 }
340 }
341
342 rc = 0;
343
344 // close the file before adding exif data
345 if(tif)
346 {
347 TIFFClose(tif);
348 tif = NULL;
349 }
350 if(exif)
351 {
352 rc = dt_exif_write_blob(exif, exif_len, filename, d->compress > 0);
353 // Until we get symbolic error status codes, if rc is 1, return 0
354 rc = (rc == 1) ? 0 : 1;
355 }
356
357 // exiv2 doesn't support multi page tiffs. so we have to write in two steps. :-(
358
359 if(rc == 0 && n_pages > 1)
360 {
361#ifdef _WIN32
362 tif = TIFFOpenW(wfilename, "al");
363#else
364 tif = TIFFOpen(filename, "al");
365#endif
366
367 if(IS_NULL_PTR(tif))
368 {
369 rc = 1;
370 goto exit;
371 }
372
373 // add masks
374 float missing_raster_mask[8 * 8] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
375 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
376 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0,
377 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0,
378 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,
379 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
380 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
381 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
382 static const size_t missing_raster_mask_w = 8, missing_raster_mask_h = 8;
383 uint16_t page = 1;
384 for(GList *iter = pipe->nodes; iter; iter = g_list_next(iter))
385 {
387
388 GHashTableIter rm_iter;
389 gpointer key, value;
390
391 // The global cache remains authoritative even when the provider image was
392 // an exact hit and this pipeline node did not run locally.
393 g_hash_table_iter_init(&rm_iter, piece->module->raster_mask.source.masks);
394 while(g_hash_table_iter_next(&rm_iter, &key, &value))
395 {
396 if(free_mask) dt_pixelpipe_cache_free_align(raster_mask);
397 raster_mask = dt_dev_get_raster_mask(pipe, piece->module, GPOINTER_TO_INT(key), NULL, NULL);
398 free_mask = !IS_NULL_PTR(raster_mask);
399
400
401 size_t w = d->global.width, h = d->global.height;
402 if(IS_NULL_PTR(raster_mask))
403 {
404 // this should never happen
405 w = missing_raster_mask_w;
406 h = missing_raster_mask_h;
407 raster_mask = missing_raster_mask;
408 free_mask = FALSE;
409 }
410
411 TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
412 TIFFSetField(tif, TIFFTAG_PAGENUMBER, page, n_pages);
413
414 const char *pagename = g_hash_table_lookup(piece->module->raster_mask.source.masks, key);
415 if(pagename)
416 TIFFSetField(tif, TIFFTAG_PAGENAME, pagename);
417 else
418 TIFFSetField(tif, TIFFTAG_PAGENAME, piece->module->name());
419
420 if(d->compress == 1)
421 {
422 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE);
423 TIFFSetField(tif, TIFFTAG_PREDICTOR, PREDICTOR_NONE);
424 TIFFSetField(tif, TIFFTAG_ZIPQUALITY, (uint16_t)d->compresslevel);
425 }
426 else if(d->compress == 2)
427 {
428 TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE);
429 if(d->bpp == 32)
430 TIFFSetField(tif, TIFFTAG_PREDICTOR, PREDICTOR_FLOATINGPOINT);
431 else
432 TIFFSetField(tif, TIFFTAG_PREDICTOR, PREDICTOR_HORIZONTAL);
433 TIFFSetField(tif, TIFFTAG_ZIPQUALITY, (uint16_t)d->compresslevel);
434 }
435
436 TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)resolution);
437 TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)resolution);
438 TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
439
440 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32_t)w);
441 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32_t)h);
442 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
443 TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
444
445#ifdef MASKS_USE_SAME_FORMAT
446 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, layers);
447 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (uint16_t)d->bpp);
448 TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, (d->bpp == 32) ? SAMPLEFORMAT_IEEEFP : SAMPLEFORMAT_UINT);
449 if(layers == 3)
450 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
451 else
452 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
453 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, 0));
454
455 if(w != d->global.width)
456 {
457 dt_free(rowdata);
458 const size_t _rowsize = (w * layers) * d->bpp / 8;
459 rowdata = malloc(_rowsize);
460 }
461
462 if(d->bpp == 32)
463 {
464 for(int y = 0; y < h; y++)
465 {
466 const float *in = raster_mask + (size_t)y * w;
467 float *out = (float *)rowdata;
468
469 for(int x = 0; x < w; x++, out += layers)
470 {
471 for(int c = 0; c < layers; c++)
472 out[c] = in[x];
473 }
474
475 if(TIFFWriteScanline(tif, rowdata, y, 0) == -1)
476 {
477 rc = 1;
478 goto exit;
479 }
480 }
481 }
482 else if(d->bpp == 16)
483 {
484 for(int y = 0; y < h; y++)
485 {
486 const float *in = raster_mask + (size_t)y * w;
487 uint16_t *out = (uint16_t *)rowdata;
488
489 for(int x = 0; x < w; x++, out += layers)
490 {
491 for(int c = 0; c < layers; c++)
492 out[c] = CLIP(in[x]) * 65535.0f + 0.5f;
493 }
494
495 if(TIFFWriteScanline(tif, rowdata, y, 0) == -1)
496 {
497 rc = 1;
498 goto exit;
499 }
500 }
501 }
502 else
503 {
504 for(int y = 0; y < h; y++)
505 {
506 const float *in = raster_mask + (size_t)y * w;
507 uint8_t *out = (uint8_t *)rowdata;
508
509 for(int x = 0; x < w; x++, out += layers)
510 {
511 for(int c = 0; c < layers; c++)
512 out[c] = CLIP(in[x]) * 255.0f + 0.5f;
513 }
514
515 if(TIFFWriteScanline(tif, rowdata, y, 0) == -1)
516 {
517 rc = 1;
518 goto exit;
519 }
520 }
521 }
522#else // MASKS_USE_SAME_FORMAT
523 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
524 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 32);
525 TIFFSetField(tif, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
526 if(d->compress == 2) // override predictor set above assuming MASKS_USE_SAME_FORMAT
527 TIFFSetField(tif, TIFFTAG_PREDICTOR, PREDICTOR_FLOATINGPOINT);
528 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
529 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, 0));
530
531 for(int y = 0; y < h; y++)
532 {
533 const float *in = raster_mask + (size_t)y * w;
534 if(TIFFWriteScanline(tif, (void *)in, y, 0) == -1)
535 {
536 rc = 1;
537 goto exit;
538 }
539 }
540#endif // MASKS_USE_SAME_FORMAT
541
542 page++;
543
544 if(page < n_pages)
545 {
546 TIFFWriteDirectory(tif);
547 }
548 } // for all raster masks
549 } // for all pipe nodes
550
551 // success
552 rc = 0;
553 } // if more than 1 page, i.e., there are masks
554
555exit:
556 if(tif)
557 {
558 TIFFClose(tif);
559 tif = NULL;
560 }
561 dt_free(profile);
562 dt_free(rowdata);
563#ifdef _WIN32
564 dt_free(wfilename);
565#endif
566 if(free_mask)
568
569 return rc;
570}
571
572#if 0
573int dt_imageio_tiff_read_header(const char *filename, dt_imageio_tiff_t *tiff)
574{
575 tiff->handle = TIFFOpen(filename, "rl");
576 if( tiff->handle )
577 {
578 TIFFGetField(tiff->handle, TIFFTAG_IMAGEWIDTH, &tiff->width);
579 TIFFGetField(tiff->handle, TIFFTAG_IMAGELENGTH, &tiff->height);
580 }
581 return 1;
582}
583
584int dt_imageio_tiff_read(dt_imageio_tiff_t *tiff, uint8_t *out)
585{
586 TIFFClose(tiff->handle);
587 return 1;
588}
589#endif
590
592{
593 return sizeof(dt_imageio_tiff_t) - sizeof(TIFF *);
594}
595
596void *legacy_params(dt_imageio_module_format_t *self, const void *const old_params,
597 const size_t old_params_size, const int old_version, const int new_version,
598 size_t *new_size)
599{
600 if(old_version == 1 && new_version == 3)
601 {
602 typedef struct dt_imageio_tiff_v1_t
603 {
604 int max_width, max_height;
605 int width, height;
606 char style[128];
607 int bpp;
608 int compress;
609 TIFF *handle;
610 } dt_imageio_tiff_v1_t;
611
612 const dt_imageio_tiff_v1_t *o = (dt_imageio_tiff_v1_t *)old_params;
614
615 n->global.max_width = o->max_width;
616 n->global.max_height = o->max_height;
617 n->global.width = o->width;
618 n->global.height = o->height;
619 g_strlcpy(n->global.style, o->style, sizeof(o->style));
620 n->bpp = o->bpp;
621 n->compress = o->compress == 3 ? 2 : o->compress; // drop redundant float case
622 n->compresslevel = 6;
623 n->handle = o->handle;
624 *new_size = self->params_size(self);
625 return n;
626 }
627 else if(old_version == 2 && new_version == 3)
628 {
629 typedef struct dt_imageio_tiff_v2_t
630 {
631 int max_width, max_height;
632 int width, height;
633 char style[128];
634 gboolean style_append;
635 int bpp;
636 int compress;
637 TIFF *handle;
638 } dt_imageio_tiff_v2_t;
639
640 const dt_imageio_tiff_v2_t *o = (dt_imageio_tiff_v2_t *)old_params;
642
643 n->global.max_width = o->max_width;
644 n->global.max_height = o->max_height;
645 n->global.width = o->width;
646 n->global.height = o->height;
647 g_strlcpy(n->global.style, o->style, sizeof(o->style));
648 n->bpp = o->bpp;
649 n->compress = o->compress == 3 ? 2 : o->compress; // drop redundant float case
650 n->compresslevel = 6;
651 n->handle = o->handle;
652 *new_size = self->params_size(self);
653 return n;
654 }
655 return NULL;
656}
657
659{
661 d->bpp = dt_conf_get_int("plugins/imageio/format/tiff/bpp");
662 if(d->bpp != 16 && d->bpp != 32)
663 d->bpp = 8;
664
665 // Drop redundant float case from existing config
666 // TODO: Move to legacy eventually
667 d->compress = dt_conf_get_int("plugins/imageio/format/tiff/compress");
668 if(d->compress == 3)
669 {
670 d->compress = 2;
671 dt_conf_set_int("plugins/imageio/format/tiff/compress", d->compress);
672 }
673
674 // TIFF compression level might actually be zero, handle this
675 if(!dt_conf_key_exists("plugins/imageio/format/tiff/compresslevel"))
676 d->compresslevel = 6;
677 else
678 {
679 d->compresslevel = dt_conf_get_int("plugins/imageio/format/tiff/compresslevel");
680 if(d->compresslevel < 0 || d->compresslevel > 9) d->compresslevel = 6;
681 }
682
683 // TIFF shortfile
684 if(!dt_conf_key_exists("plugins/imageio/format/tiff/shortfile"))
685 d->shortfile = 0;
686 else
687 {
688 d->shortfile = dt_conf_get_int("plugins/imageio/format/tiff/shortfile");
689 }
690
691 return d;
692}
693
695{
696 dt_free(params);
697}
698
699int set_params(dt_imageio_module_format_t *self, const void *params, const int size)
700{
701 if(size != self->params_size(self)) return 1;
702 const dt_imageio_tiff_t *d = (dt_imageio_tiff_t *)params;
704
705 if(d->bpp == 16)
706 dt_bauhaus_combobox_set(g->bpp, 1);
707 else if(d->bpp == 32)
708 dt_bauhaus_combobox_set(g->bpp, 2);
709 else // (d->bpp == 8)
710 dt_bauhaus_combobox_set(g->bpp, 0);
711
712 dt_bauhaus_combobox_set(g->compress, d->compress);
713
714 dt_bauhaus_slider_set(g->compresslevel, d->compresslevel);
715
716 dt_bauhaus_combobox_set(g->shortfiles, d->shortfile);
717 return 0;
718}
719
721{
722 return ((dt_imageio_tiff_t *)p)->bpp;
723}
724
726{
727 int ret = IMAGEIO_RGB;
728
729 if(((dt_imageio_tiff_t *)p)->bpp == 8)
730 ret |= IMAGEIO_INT8;
731 else if(((dt_imageio_tiff_t *)p)->bpp == 16)
732 ret |= IMAGEIO_INT16;
733 else if(((dt_imageio_tiff_t *)p)->bpp == 32)
734 ret |= IMAGEIO_FLOAT;
735
736 return ret;
737}
738
740{
741 return "image/tiff";
742}
743
745{
746 return "tif";
747}
748
749const char *name()
750{
751 return _("TIFF (8/16/32-bit)");
752}
753
754static void bpp_combobox_changed(GtkWidget *widget, gpointer user_data)
755{
756 const int bpp = dt_bauhaus_combobox_get(widget);
757
758 if(bpp == 1)
759 dt_conf_set_int("plugins/imageio/format/tiff/bpp", 16);
760 else if(bpp == 2)
761 dt_conf_set_int("plugins/imageio/format/tiff/bpp", 32);
762 else // (bpp == 0)
763 dt_conf_set_int("plugins/imageio/format/tiff/bpp", 8);
764}
765
766static void shortfile_combobox_changed(GtkWidget *widget, gpointer user_data)
767{
768 const int mode = dt_bauhaus_combobox_get(widget);
769 dt_conf_set_int("plugins/imageio/format/tiff/shortfile", mode);
770}
771
772static void compress_combobox_changed(GtkWidget *widget, gpointer user_data)
773{
774 const int compress = dt_bauhaus_combobox_get(widget);
775 dt_conf_set_int("plugins/imageio/format/tiff/compress", compress);
776
777 if(compress == 0)
778 gtk_widget_set_sensitive(GTK_WIDGET(user_data), FALSE);
779 else
780 gtk_widget_set_sensitive(GTK_WIDGET(user_data), TRUE);
781
782}
783
784static void compress_level_changed(GtkWidget *slider, gpointer user_data)
785{
786 const int compresslevel = (int)dt_bauhaus_slider_get(slider);
787 dt_conf_set_int("plugins/imageio/format/tiff/compresslevel", compresslevel);
788}
789
791{
792}
793
797
799{
801 self->gui_data = (void *)gui;
802
803 const int bpp = dt_conf_get_int("plugins/imageio/format/tiff/bpp");
804
805 // Drop redundant float case from existing config
806 // TODO: Move to legacy eventually
807 int compress = dt_conf_get_int("plugins/imageio/format/tiff/compress");
808 if(compress == 3)
809 {
810 compress = 2;
811 dt_conf_set_int("plugins/imageio/format/tiff/compress", compress);
812 }
813
814 int shortmode = 0;
815 if(dt_conf_key_exists("plugins/imageio/format/tiff/shortfile"))
816 shortmode = dt_conf_get_int("plugins/imageio/format/tiff/shortfile");
817
818 // TIFF compression level might actually be zero!
819 int compresslevel = 6;
820 if(dt_conf_key_exists("plugins/imageio/format/tiff/compresslevel"))
821 compresslevel = dt_conf_get_int("plugins/imageio/format/tiff/compresslevel");
822
823 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
824
825 // Bit depth combo box
827 dt_bauhaus_widget_set_label(gui->bpp, N_("bit depth"));
828 dt_bauhaus_combobox_add(gui->bpp, _("8 bit"));
829 dt_bauhaus_combobox_add(gui->bpp, _("16 bit"));
830 dt_bauhaus_combobox_add(gui->bpp, _("32 bit (float)"));
831 if(bpp == 16)
833 else if(bpp == 32)
835 else // (bpp == 8)
837 gtk_box_pack_start(GTK_BOX(self->widget), gui->bpp, TRUE, TRUE, 0);
838 g_signal_connect(G_OBJECT(gui->bpp), "value-changed", G_CALLBACK(bpp_combobox_changed), NULL);
839
840 // Compression method combo box
842 dt_bauhaus_widget_set_label(gui->compress, N_("compression"));
843 dt_bauhaus_combobox_add(gui->compress, _("uncompressed"));
844 dt_bauhaus_combobox_add(gui->compress, _("deflate"));
845 dt_bauhaus_combobox_add(gui->compress, _("deflate with predictor"));
846 dt_bauhaus_combobox_set(gui->compress, compress);
847 gtk_box_pack_start(GTK_BOX(self->widget), gui->compress, TRUE, TRUE, 0);
848
849 // Compression level slider
851 dt_confgen_get_int("plugins/imageio/format/tiff/compresslevel", DT_MIN),
852 dt_confgen_get_int("plugins/imageio/format/tiff/compresslevel", DT_MAX),
853 1,
854 dt_confgen_get_int("plugins/imageio/format/tiff/compresslevel", DT_DEFAULT),
855 0);
856 dt_bauhaus_widget_set_label(gui->compresslevel, N_("compression level"));
857 dt_bauhaus_slider_set(gui->compresslevel, compresslevel);
858 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(gui->compresslevel), TRUE, TRUE, 0);
859 g_signal_connect(G_OBJECT(gui->compresslevel), "value-changed", G_CALLBACK(compress_level_changed), NULL);
860
861 g_signal_connect(G_OBJECT(gui->compress), "value-changed", G_CALLBACK(compress_combobox_changed), (gpointer)gui->compresslevel);
862
863 if(compress == 0)
864 gtk_widget_set_sensitive(gui->compresslevel, FALSE);
865
866 // shortfile option combo box
868 dt_bauhaus_widget_set_label(gui->shortfiles, N_("b&w image"));
869 dt_bauhaus_combobox_add(gui->shortfiles, _("write rgb colors"));
870 dt_bauhaus_combobox_add(gui->shortfiles, _("write grayscale"));
871 dt_bauhaus_combobox_set(gui->shortfiles, shortmode);
872 gtk_box_pack_start(GTK_BOX(self->widget), gui->shortfiles, TRUE, TRUE, 0);
873 g_signal_connect(G_OBJECT(gui->shortfiles), "value-changed", G_CALLBACK(shortfile_combobox_changed), NULL);
874}
875
877{
878 dt_free(self->gui_data);
879}
880
882{
884 dt_bauhaus_combobox_set(gui->bpp, 0); //8bpp
885 dt_bauhaus_slider_set(gui->compresslevel, dt_confgen_get_int("plugins/imageio/format/tiff/compresslevel", DT_DEFAULT));
886 dt_bauhaus_combobox_set(gui->shortfiles, dt_confgen_get_int("plugins/imageio/format/tiff/shortfile", DT_DEFAULT));
887}
888
893
894// clang-format off
895// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
896// vim: shiftwidth=2 expandtab tabstop=2 cindent
897// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
898// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
float dt_bauhaus_slider_get(GtkWidget *widget)
Definition bauhaus.c:3483
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2347
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3506
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2301
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1653
GtkWidget * dt_bauhaus_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
Definition bauhaus.c:1780
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1842
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:2016
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
const dt_colorspaces_color_profile_t * dt_colorspaces_get_output_profile(const int32_t imgid, dt_colorspaces_color_profile_type_t *over_type, const char *over_filename)
dt_colorspaces_color_profile_type_t
Definition colorspaces.h:81
const dt_colormatrix_t dt_aligned_pixel_t out
char * key
@ DT_DEFAULT
Definition conf.h:96
@ DT_MAX
Definition conf.h:98
@ DT_MIN
Definition conf.h:97
int dt_conf_key_exists(const char *key)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
int dt_confgen_get_int(const char *name, dt_confgen_value_kind_t kind)
void dt_control_log(const char *msg,...)
Definition control.c:761
darktable_t darktable
Definition darktable.c:181
#define DT_MODULE(MODVER)
Definition darktable.h:140
#define dt_free(ptr)
Definition darktable.h:456
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
int dt_exif_write_blob(uint8_t *blob, uint32_t size, const char *path, const int compressed)
Definition exif.cc:1816
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
#define DT_GUI_MODULE(x)
int bpp
@ IMAGEIO_INT16
Definition imageio.h:64
@ IMAGEIO_RGB
Definition imageio.h:70
@ IMAGEIO_INT8
Definition imageio.h:62
@ IMAGEIO_FLOAT
Definition imageio.h:66
@ FORMAT_FLAGS_SUPPORT_LAYERS
@ FORMAT_FLAGS_SUPPORT_XMP
static const float x
#define CLIP(x)
Definition math.h:81
size_t size
Definition mipmap_cache.c:3
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
float * dt_dev_get_raster_mask(dt_dev_pixelpipe_t *pipe, const struct dt_iop_module_t *raster_mask_source, const int raster_mask_id, const struct dt_iop_module_t *target_module, int *error)
Retrieve a provider mask from the global cache and transform it to a consumer.
struct _GtkWidget GtkWidget
Definition splash.h:29
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
struct dt_iop_module_t *void * data
GModule *GtkWidget * widget
GtkWidget * shortfiles
Definition tiff.c:80
GtkWidget * compresslevel
Definition tiff.c:79
GtkWidget * compress
Definition tiff.c:78
GtkWidget * bpp
Definition tiff.c:77
dt_imageio_module_data_t global
Definition tiff.c:67
int compresslevel
Definition tiff.c:70
TIFF * handle
Definition tiff.c:72
static void shortfile_combobox_changed(GtkWidget *widget, gpointer user_data)
Definition tiff.c:766
const char * mime(dt_imageio_module_data_t *data)
Definition tiff.c:739
int write_image(dt_imageio_module_data_t *d_tmp, const char *filename, const void *in_void, dt_colorspaces_color_profile_type_t over_type, const char *over_filename, void *exif, int exif_len, int32_t imgid, int num, int total, dt_dev_pixelpipe_t *pipe, const gboolean export_masks)
Definition tiff.c:84
size_t params_size(dt_imageio_module_format_t *self)
Definition tiff.c:591
void gui_reset(dt_imageio_module_format_t *self)
Definition tiff.c:881
void gui_init(dt_imageio_module_format_t *self)
Definition tiff.c:798
const char * extension(dt_imageio_module_data_t *data)
Definition tiff.c:744
static void compress_level_changed(GtkWidget *slider, gpointer user_data)
Definition tiff.c:784
int set_params(dt_imageio_module_format_t *self, const void *params, const int size)
Definition tiff.c:699
const char * name()
Definition tiff.c:749
void cleanup(dt_imageio_module_format_t *self)
Definition tiff.c:794
int levels(dt_imageio_module_data_t *p)
Definition tiff.c:725
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 tiff.c:596
void free_params(dt_imageio_module_format_t *self, dt_imageio_module_data_t *params)
Definition tiff.c:694
static void compress_combobox_changed(GtkWidget *widget, gpointer user_data)
Definition tiff.c:772
void init(dt_imageio_module_format_t *self)
Definition tiff.c:790
void * get_params(dt_imageio_module_format_t *self)
Definition tiff.c:658
void gui_cleanup(dt_imageio_module_format_t *self)
Definition tiff.c:876
static void bpp_combobox_changed(GtkWidget *widget, gpointer user_data)
Definition tiff.c:754