Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
avif.c
Go to the documentation of this file.
1/*
2 * This file is part of darktable,
3 * Copyright (C) 2019-2021 Andreas Schneider.
4 * Copyright (C) 2020 Benoit Brummer.
5 * Copyright (C) 2020, 2022 Diederik Ter Rahe.
6 * Copyright (C) 2020-2021 Hubert Kowalski.
7 * Copyright (C) 2020-2022 Miloš Komarčević.
8 * Copyright (C) 2020-2021 Pascal Obry.
9 * Copyright (C) 2020 Tobias Ellinghaus.
10 * Copyright (C) 2021 luzpaz.
11 * Copyright (C) 2021 Ralf Brown.
12 * Copyright (C) 2022, 2025 Aurélien PIERRE.
13 * Copyright (C) 2022 Martin Bařinka.
14 * Copyright (C) 2023 Alynx Zhou.
15 * Copyright (C) 2025 Peter Kovář.
16 *
17 * darktable is free software: you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation, either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * darktable is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with darktable. If not, see <http://www.gnu.org/licenses/>.
29 */
30
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#include <inttypes.h>
36#include <stdio.h>
37#include <stdlib.h>
38
39#include "bauhaus/bauhaus.h"
40#include "common/colorspaces.h"
41#include "common/darktable.h"
42#include "common/exif.h"
43#include "common/imageio.h"
45#include "control/conf.h"
46#include "control/control.h"
48
49#include <avif/avif.h>
50
51#define AVIF_MIN_TILE_SIZE 512
52#define AVIF_MAX_TILE_SIZE 3072
53#define AVIF_DEFAULT_TILE_SIZE AVIF_MIN_TILE_SIZE * 2
54
55DT_MODULE(1)
56
62
68
74
84
93
94static const struct
95{
96 char *name;
97 uint32_t bit_depth;
98} avif_bit_depth[] = {
99 {
100 .name = N_("8 bit"),
101 .bit_depth = 8
102 },
103 {
104 .name = N_("10 bit"),
105 .bit_depth = 10
106 },
107 {
108 .name = N_("12 bit"),
109 .bit_depth = 12
110 },
111 {
112 .name = NULL,
113 }
115
117{
118 switch(comp)
119 {
121 return "lossless";
122 case AVIF_COMP_LOSSY:
123 return "lossy";
124 }
125
126 return "unknown";
127}
128
129/* Lookup table for tiling choices */
130static int floor_log2(int i)
131{
132 static const int floor_log2_table[] =
133 /* 0 1, 2, 3, 4, 5, 6, 7, 8, 9 */
134 { 0, 0, 2, 2, 4, 4, 4, 4, 8, 8,
135 8, 8, 8, 8, 8, 8, 16, 16, 16, 16,
136 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
137 16, 16, 32, 32, 32, 32, 32, 32, 32, 32,
138 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
139 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
140 32, 32, 32, 32 };
141 /* 0 1, 2, 3, 4, 5, 6, 7, 8, 9 */
142
143 if(i >= 64)
144 {
145 return 64;
146 }
147
148 return floor_log2_table[i];
149}
150
152{
153 const char *codecName = avifCodecName(AVIF_CODEC_CHOICE_AUTO,
154 AVIF_CODEC_FLAG_CAN_ENCODE);
155 if(IS_NULL_PTR(codecName))
156 {
158 "libavif doesn't offer encoding support!\n");
159 self->ready = FALSE;
160 return;
161 }
162}
163
167
169 const char *filename,
170 const void *in,
172 const char *over_filename,
173 void *exif,
174 int exif_len,
175 int32_t imgid,
176 int num,
177 int total,
178 struct dt_dev_pixelpipe_t *pipe,
179 const gboolean export_masks)
180{
182
183 avifPixelFormat format = AVIF_PIXEL_FORMAT_NONE;
184 avifImage *image = NULL;
185 avifRGBImage rgb = { .format = AVIF_RGB_FORMAT_RGB, };
186 avifEncoder *encoder = NULL;
187 uint8_t *icc_profile_data = NULL;
188 uint32_t icc_profile_len;
189 avifResult result;
190 int rc;
191
192 const size_t width = d->global.width;
193 const size_t height = d->global.height;
194 const size_t bit_depth = d->bit_depth > 0 ? d->bit_depth : 0;
195 enum avif_color_mode_e color_mode = d->color_mode;
196
197 switch(color_mode)
198 {
200 switch(d->compression_type)
201 {
203 format = AVIF_PIXEL_FORMAT_YUV444;
204 break;
205 case AVIF_COMP_LOSSY:
206 if(d->quality > 90)
207 {
208 format = AVIF_PIXEL_FORMAT_YUV444;
209 }
210 else if(d->quality > 80)
211 {
212 format = AVIF_PIXEL_FORMAT_YUV422;
213 }
214 else
215 {
216 format = AVIF_PIXEL_FORMAT_YUV420;
217 }
218 break;
219 }
220
221 break;
223 format = AVIF_PIXEL_FORMAT_YUV400;
224 break;
225 }
226
227 image = avifImageCreate(width, height, bit_depth, format);
228 if(IS_NULL_PTR(image))
229 {
231 "Failed to create AVIF image for writing [%s]\n",
232 filename);
233 rc = 1;
234 goto out;
235 }
236
238 "Exporting AVIF image [%s] "
239 "[width: %" G_GSIZE_FORMAT ", height: %" G_GSIZE_FORMAT ", bit depth: %" G_GSIZE_FORMAT ", comp: %s, quality: %u]\n",
240 filename,
241 width,
242 height,
243 bit_depth,
244 avif_get_compression_string(d->compression_type),
245 d->quality);
246
247 if(imgid > 0)
248 {
249 gboolean use_icc = FALSE;
250
251 /*
252 * Set these in advance so any upcoming RGB -> YUV use the proper
253 * coefficients.
254 */
255 switch(over_type)
256 {
258 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
259 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
260 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601;
261 break;
263 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
264 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_BT709;
265 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
266 break;
268 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
269 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_LINEAR;
270 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
271 break;
273 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
274 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_LINEAR;
275 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;
276 break;
278 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
279 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084;
280 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;
281 break;
283 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
284 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_HLG;
285 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;
286 break;
288 image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432;
289 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084;
290 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL;
291 break;
293 image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432;
294 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_HLG;
295 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL;
296 break;
298 image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432;
299 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
300 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL;
301 break;
302 default:
303 break;
304 }
305
306 // no change from default, unspecified CICP (2/2/2)
307 if(image->colorPrimaries == AVIF_COLOR_PRIMARIES_UNSPECIFIED)
308 {
309 use_icc = TRUE;
310 }
311
312 dt_print(DT_DEBUG_IMAGEIO, "[avif colorprofile profile: %s - %s]\n",
313 dt_colorspaces_get_name(over_type, filename),
314 use_icc ? "icc" : "nclx");
315
316 if(use_icc)
317 {
320 &over_type,
321 over_filename);
322 cmsHPROFILE out_profile = cp->profile;
323
324 cmsSaveProfileToMem(out_profile, 0, &icc_profile_len);
325 if(icc_profile_len > 0)
326 {
327 icc_profile_data = malloc(sizeof(uint8_t) * icc_profile_len);
328 if(IS_NULL_PTR(icc_profile_data))
329 {
330 rc = 1;
331 goto out;
332 }
333 cmsSaveProfileToMem(out_profile, icc_profile_data, &icc_profile_len);
334 (void)avifImageSetProfileICC(image, icc_profile_data, icc_profile_len);
335 }
336 }
337 }
338
339 /*
340 * Set the YUV range before conversion.
341 *
342 * Limited range (aka "studio range", "studio swing", etc) is simply when you
343 * cut off the ends of the actual range you have to avoid the actual minimum
344 * and maximum of the signal. For example, instead of having full range 8bpc
345 * ([0-255]) in each channel, you'd only use [16-235]. Anything 16 or below
346 * is treated as a 0.0 signal, and anything 235 or higher is treated as a 1.0
347 * signal.
348 *
349 * The *reason* this exists, is largely vestigial from the analog era.
350 *
351 * For picture we always want the full range.
352 */
353 image->yuvRange = AVIF_RANGE_FULL;
354
355 avifRGBImageSetDefaults(&rgb, image);
356 rgb.format = AVIF_RGB_FORMAT_RGB;
357
358 (void)avifRGBImageAllocatePixels(&rgb);
359
360 const float max_channel_f = (float)((1 << bit_depth) - 1);
361
362 const size_t rowbytes = rgb.rowBytes;
363
364 const float *const restrict in_data = (const float *)in;
365 uint8_t *const restrict out = (uint8_t *)rgb.pixels;
366
367 switch(bit_depth)
368 {
369 case 12:
370 case 10:
371 {
372 __OMP_PARALLEL_FOR_SIMD__(collapse(2))
373 for(size_t y = 0; y < height; y++)
374 {
375 for(size_t x = 0; x < width; x++)
376 {
377 const float *in_pixel = &in_data[(size_t)4 * ((y * width) + x)];
378 uint16_t *out_pixel = (uint16_t *)&out[(y * rowbytes) + (3 * sizeof(uint16_t) * x)];
379
380 out_pixel[0] = (uint16_t)roundf(CLAMP(in_pixel[0] * max_channel_f, 0, max_channel_f));
381 out_pixel[1] = (uint16_t)roundf(CLAMP(in_pixel[1] * max_channel_f, 0, max_channel_f));
382 out_pixel[2] = (uint16_t)roundf(CLAMP(in_pixel[2] * max_channel_f, 0, max_channel_f));
383 }
384 }
385 break;
386 }
387 case 8:
388 {
389 __OMP_PARALLEL_FOR_SIMD__(collapse(2))
390 for(size_t y = 0; y < height; y++)
391 {
392 for(size_t x = 0; x < width; x++)
393 {
394 const float *in_pixel = &in_data[(size_t)4 * ((y * width) + x)];
395 uint8_t *out_pixel = (uint8_t *)&out[(y * rowbytes) + (3 * sizeof(uint8_t) * x)];
396
397 out_pixel[0] = (uint8_t)roundf(CLAMP(in_pixel[0] * max_channel_f, 0, max_channel_f));
398 out_pixel[1] = (uint8_t)roundf(CLAMP(in_pixel[1] * max_channel_f, 0, max_channel_f));
399 out_pixel[2] = (uint8_t)roundf(CLAMP(in_pixel[2] * max_channel_f, 0, max_channel_f));
400 }
401 }
402 break;
403 }
404 default:
405 dt_control_log(_("invalid AVIF bit depth!"));
406 rc = 1;
407 goto out;
408 }
409
410 (void)avifImageRGBToYUV(image, &rgb);
411
412 if(exif && exif_len > 0)
413 (void)avifImageSetMetadataExif(image, exif, exif_len);
414
415 /* TODO: workaround; remove when exiv2 implements AVIF write support and update flags() */
416 char *xmp_string = dt_exif_xmp_read_string(imgid);
417 size_t xmp_len;
418 if(xmp_string && (xmp_len = strlen(xmp_string)) > 0)
419 {
420 (void)avifImageSetMetadataXMP(image, (const uint8_t *)xmp_string, xmp_len);
421 dt_free(xmp_string);
422 }
423
424 encoder = avifEncoderCreate();
425 if(IS_NULL_PTR(encoder))
426 {
428 "Failed to create AVIF encoder for image [%s]\n",
429 filename);
430 rc = 1;
431 goto out;
432 }
433
434 switch(d->compression_type)
435 {
437 /* It isn't recommend to use the extremities */
438 encoder->speed = AVIF_SPEED_SLOWEST + 1;
439
440 encoder->minQuantizer = AVIF_QUANTIZER_LOSSLESS;
441 encoder->maxQuantizer = AVIF_QUANTIZER_LOSSLESS;
442
443 break;
444 case AVIF_COMP_LOSSY:
445 encoder->speed = AVIF_SPEED_DEFAULT;
446
447 encoder->maxQuantizer = 100 - d->quality;
448 encoder->maxQuantizer = CLAMP(encoder->maxQuantizer, 0, 63);
449
450 encoder->minQuantizer = 64 - d->quality;
451 encoder->minQuantizer = CLAMP(encoder->minQuantizer, 0, 63);
452 break;
453 }
454
455 /*
456 * Tiling reduces the image quality but it has a negligible impact on
457 * still images.
458 *
459 * The minimum size for a tile is 512x512. We use a default tile size of
460 * 1024x1024.
461 */
462 switch(d->tiling)
463 {
464 case AVIF_TILING_ON:
465 {
466 size_t width_tile_size = AVIF_DEFAULT_TILE_SIZE;
467 size_t height_tile_size = AVIF_DEFAULT_TILE_SIZE;
468 size_t max_threads;
469
470 if(width >= 6144)
471 {
472 width_tile_size = AVIF_MIN_TILE_SIZE * 4;
473 }
474 else if (width >= 8192) {
475 width_tile_size = AVIF_MAX_TILE_SIZE;
476 }
477 if(height >= 6144)
478 {
479 height_tile_size = AVIF_MIN_TILE_SIZE * 4;
480 }
481 else if (height >= 8192) {
482 height_tile_size = AVIF_MAX_TILE_SIZE;
483 }
484
485 encoder->tileColsLog2 = floor_log2(width / width_tile_size) / 2;
486 encoder->tileRowsLog2 = floor_log2(height / height_tile_size) / 2;
487
488 /*
489 * This should be set to the final number of tiles, based on
490 * encoder->tileColsLog2 and encoder->tileRowsLog2.
491 */
492 max_threads = (1 << encoder->tileRowsLog2) * (1 << encoder->tileColsLog2);
493
494 encoder->maxThreads = MIN(max_threads, darktable.num_openmp_threads);
495 }
496 case AVIF_TILING_OFF:
497 break;
498 }
499
501 "[avif quality: %u => maxQuantizer: %u, minQuantizer: %u, "
502 "tileColsLog2: %u, tileRowsLog2: %u, threads: %u]\n",
503 d->quality,
504 encoder->maxQuantizer,
505 encoder->minQuantizer,
506 encoder->tileColsLog2,
507 encoder->tileRowsLog2,
508 encoder->maxThreads);
509
510 avifRWData output = AVIF_DATA_EMPTY;
511
512 result = avifEncoderWrite(encoder, image, &output);
513 if(result != AVIF_RESULT_OK)
514 {
516 "Failed to encode AVIF image [%s]: %s\n",
517 filename, avifResultToString(result));
518 rc = 1;
519 goto out;
520 }
521
522 if(output.size == 0 || IS_NULL_PTR(output.data))
523 {
525 "AVIF encoder returned empty data for [%s]\n",
526 filename);
527 rc = 1;
528 goto out;
529 }
530
531 /*
532 * Write image to disk
533 */
534 FILE *f = NULL;
535 size_t cnt = 0;
536
537 f = g_fopen(filename, "wb");
538 if(IS_NULL_PTR(f))
539 {
540 rc = 1;
541 goto out;
542 }
543
544 cnt = fwrite(output.data, 1, output.size, f);
545 fclose(f);
546 if(cnt != output.size)
547 {
548 g_unlink(filename);
549 rc = 1;
550 goto out;
551 }
552
553 rc = 0; /* success */
554out:
555 avifRGBImageFreePixels(&rgb);
556 avifImageDestroy(image);
557 avifEncoderDestroy(encoder);
558 avifRWDataFree(&output);
559 dt_free(icc_profile_data);
560
561 return rc;
562}
563
564
566{
567 return sizeof(dt_imageio_avif_t);
568}
569
571{
573
574 if(IS_NULL_PTR(d))
575 {
576 return NULL;
577 }
578
579 d->bit_depth = dt_conf_get_int("plugins/imageio/format/avif/bpp");
580 if(d->bit_depth != 10 && d->bit_depth != 12)
581 d->bit_depth = 8;
582
583 d->color_mode = dt_conf_get_int("plugins/imageio/format/avif/color_mode");
584 d->compression_type = dt_conf_get_int("plugins/imageio/format/avif/compression_type");
585
586 switch(d->compression_type)
587 {
589 d->quality = 100;
590 break;
591 case AVIF_COMP_LOSSY:
592 d->quality = dt_conf_get_int("plugins/imageio/format/avif/quality");
593 if(d->quality > 100)
594 {
595 d->quality = 100;
596 }
597 break;
598 }
599
600 d->tiling = !dt_conf_get_bool("plugins/imageio/format/avif/tiling");
601
602 return d;
603}
604
606 const void *params,
607 const int size)
608{
609 if(size != self->params_size(self))
610 return 1;
611 const dt_imageio_avif_t *d = (dt_imageio_avif_t *)params;
612
614 dt_bauhaus_combobox_set(g->bit_depth, d->bit_depth);
615 dt_bauhaus_combobox_set(g->color_mode, d->color_mode);
616 dt_bauhaus_combobox_set(g->tiling, d->tiling);
617 dt_bauhaus_combobox_set(g->compression_type, d->compression_type);
618 dt_bauhaus_slider_set(g->quality, d->quality);
619
620 return 0;
621}
622
625{
626 dt_free(params);
627}
628
629
631{
632 return 32; /* always request float */
633}
634
636{
638}
639
641{
642 return "image/avif";
643}
644
646{
647 return "avif";
648}
649
650const char *name()
651{
652 return _("AVIF (8/10/12-bit)");
653}
654
656{
657 /*
658 * As of exiv2 0.27.5 there is no write support for the AVIF format, so
659 * we do not return the XMP supported flag currently.
660 * Once exiv2 write support is there, the flag can be returned, and the
661 * direct XMP embedding workaround using avifImageSetMetadataXMP() above
662 * can be removed.
663 */
664 return 0; /* FORMAT_FLAGS_SUPPORT_XMP; */
665}
666
667static void bit_depth_changed(GtkWidget *widget, gpointer user_data)
668{
669 const uint32_t idx = dt_bauhaus_combobox_get(widget);
670
671 dt_conf_set_int("plugins/imageio/format/avif/bpp", avif_bit_depth[idx].bit_depth);
672}
673
674static void color_mode_changed(GtkWidget *widget, gpointer user_data)
675{
676 const enum avif_color_mode_e color_mode = dt_bauhaus_combobox_get(widget);
677
678 dt_conf_set_int("plugins/imageio/format/avif/color_mode", color_mode);
679}
680
681static void tiling_changed(GtkWidget *widget, gpointer user_data)
682{
683 const enum avif_tiling_e tiling = dt_bauhaus_combobox_get(widget);
684
685 dt_conf_set_bool("plugins/imageio/format/avif/tiling", !tiling);
686}
687
688static void compression_type_changed(GtkWidget *widget, gpointer user_data)
689{
690 const enum avif_compression_type_e compression_type = dt_bauhaus_combobox_get(widget);
691 dt_imageio_module_format_t *module = (dt_imageio_module_format_t *)user_data;
692 dt_imageio_avif_gui_t *gui = (dt_imageio_avif_gui_t *)module->gui_data;
693
694 dt_conf_set_int("plugins/imageio/format/avif/compression_type", compression_type);
695
696 switch(compression_type)
697 {
699 gtk_widget_set_sensitive(gui->quality, FALSE);
700 break;
701 case AVIF_COMP_LOSSY:
702 gtk_widget_set_sensitive(gui->quality, TRUE);
703 break;
704 }
705}
706
707static void quality_changed(GtkWidget *slider, gpointer user_data)
708{
709 const uint32_t quality = (int)dt_bauhaus_slider_get(slider);
710 dt_conf_set_int("plugins/imageio/format/avif/quality", quality);
711}
712
714{
717 const uint32_t bit_depth = dt_conf_get_int("plugins/imageio/format/avif/bit_depth");
718 const enum avif_color_mode_e color_mode = dt_conf_get_int("plugins/imageio/format/avif/color_mode");
719 const enum avif_tiling_e tiling = !dt_conf_get_bool("plugins/imageio/format/avif/tiling");
720 const enum avif_compression_type_e compression_type = dt_conf_get_int("plugins/imageio/format/avif/compression_type");
721 const uint32_t quality = dt_conf_get_int("plugins/imageio/format/avif/quality");
722
723 self->gui_data = (void *)gui;
724
725 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
726
727 /*
728 * Bit depth combo box
729 */
731
732 dt_bauhaus_widget_set_label(gui->bit_depth, N_("bit depth"));
733 size_t idx = 0;
734 for(size_t i = 0; !IS_NULL_PTR(avif_bit_depth[i].name); i++)
735 {
738 {
739 idx = i;
740 }
741 }
743
744 gtk_widget_set_tooltip_text(gui->bit_depth,
745 _("color information stored in an image, higher is better"));
746
747 gtk_box_pack_start(GTK_BOX(self->widget), gui->bit_depth, TRUE, TRUE, 0);
748
749 /*
750 * Color mode combo box
751 */
753 dt_bauhaus_widget_set_label(gui->color_mode, _("color mode"));
755 _("rgb colors"));
757 _("grayscale"));
758 dt_bauhaus_combobox_set(gui->color_mode, color_mode);
759
760 gtk_widget_set_tooltip_text(gui->color_mode,
761 _("saving as grayscale will reduce the size for black & white images"));
762
763 gtk_box_pack_start(GTK_BOX(self->widget),
764 gui->color_mode,
765 TRUE,
766 TRUE,
767 0);
768 /*
769 * Tiling combo box
770 */
772 dt_bauhaus_widget_set_label(gui->tiling, N_("tiling"));
774 _("on"));
776 _("off"));
778
779 gtk_widget_set_tooltip_text(gui->tiling,
780 _("tile an image into segments.\n"
781 "\n"
782 "makes encoding faster. the impact on quality reduction "
783 "is negligible, but increases the file size."));
784
785 gtk_box_pack_start(GTK_BOX(self->widget),
786 gui->tiling,
787 TRUE,
788 TRUE,
789 0);
790
791 /*
792 * Compression type combo box
793 */
795 dt_bauhaus_widget_set_label(gui->compression_type, N_("compression type"));
800 dt_bauhaus_combobox_set(gui->compression_type, compression_type);
801
802 gtk_widget_set_tooltip_text(gui->compression_type,
803 _("the compression for the image"));
804
805 gtk_box_pack_start(GTK_BOX(self->widget),
806 gui->compression_type,
807 TRUE,
808 TRUE,
809 0);
810
811 /*
812 * Quality combo box
813 */
815 dt_confgen_get_int("plugins/imageio/format/avif/quality", DT_MIN), /* min */
816 dt_confgen_get_int("plugins/imageio/format/avif/quality", DT_MAX), /* max */
817 1, /* step */
818 dt_confgen_get_int("plugins/imageio/format/avif/quality", DT_DEFAULT), /* default */
819 0); /* digits */
820 dt_bauhaus_widget_set_label(gui->quality, N_("quality"));
821 dt_bauhaus_slider_set_default(gui->quality, dt_confgen_get_int("plugins/imageio/format/avif/quality", DT_DEFAULT));
823
824 gtk_widget_set_tooltip_text(gui->quality,
825 _("the quality of an image, less quality means fewer details.\n"
826 "\n"
827 "the following applies only to lossy setting\n"
828 "\n"
829 "pixelformat based on quality:\n"
830 "\n"
831 " 91% - 100% -> YUV444\n"
832 " 81% - 90% -> YUV422\n"
833 " 5% - 80% -> YUV420\n"));
834
835 if(quality > 0 && quality <= 100)
836 {
837 dt_bauhaus_slider_set(gui->quality, quality);
838 }
839 gtk_box_pack_start(GTK_BOX(self->widget), gui->quality, TRUE, TRUE, 0);
840
841 switch(compression_type)
842 {
844 gtk_widget_set_sensitive(gui->quality, FALSE);
845 break;
846 case AVIF_COMP_LOSSY:
847 break;
848 }
849
850 g_signal_connect(G_OBJECT(gui->bit_depth),
851 "value-changed",
852 G_CALLBACK(bit_depth_changed),
853 NULL);
854 g_signal_connect(G_OBJECT(gui->color_mode),
855 "value-changed",
856 G_CALLBACK(color_mode_changed),
857 (gpointer)self);
858 g_signal_connect(G_OBJECT(gui->tiling),
859 "value-changed",
860 G_CALLBACK(tiling_changed),
861 (gpointer)self);
862 g_signal_connect(G_OBJECT(gui->compression_type),
863 "value-changed",
864 G_CALLBACK(compression_type_changed),
865 (gpointer)self);
866 g_signal_connect(G_OBJECT(gui->quality),
867 "value-changed",
868 G_CALLBACK(quality_changed),
869 NULL);
870}
871
873{
874 dt_free(self->gui_data);
875}
876
878{
880
881 const enum avif_color_mode_e color_mode = dt_confgen_get_int("plugins/imageio/format/avif/color_mode", DT_DEFAULT);
882 const enum avif_tiling_e tiling = !dt_confgen_get_bool("plugins/imageio/format/avif/tiling", DT_DEFAULT);
883 const enum avif_compression_type_e compression_type = dt_confgen_get_int("plugins/imageio/format/avif/compression_type", DT_DEFAULT);
884 const uint32_t quality = dt_confgen_get_int("plugins/imageio/format/avif/quality", DT_DEFAULT);
885
886 dt_bauhaus_combobox_set(gui->bit_depth, 0); //8bpp
887 dt_bauhaus_combobox_set(gui->color_mode, color_mode);
889 dt_bauhaus_combobox_set(gui->compression_type, compression_type);
890 dt_bauhaus_slider_set(gui->quality, quality);
891
892 compression_type_changed(GTK_WIDGET(gui->compression_type), self);
893 quality_changed(GTK_WIDGET(gui->quality), self);
894 bit_depth_changed(GTK_WIDGET(gui->bit_depth), self);
895}
896// clang-format off
897// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
898// vim: shiftwidth=2 expandtab tabstop=2 cindent
899// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
900// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
const char * mime(dt_imageio_module_data_t *data)
Definition avif.c:640
size_t params_size(dt_imageio_module_format_t *self)
Definition avif.c:565
#define AVIF_MIN_TILE_SIZE
Definition avif.c:51
static void bit_depth_changed(GtkWidget *widget, gpointer user_data)
Definition avif.c:667
void gui_reset(dt_imageio_module_format_t *self)
Definition avif.c:877
avif_compression_type_e
Definition avif.c:58
@ AVIF_COMP_LOSSY
Definition avif.c:60
@ AVIF_COMP_LOSSLESS
Definition avif.c:59
void gui_init(dt_imageio_module_format_t *self)
Definition avif.c:713
#define AVIF_DEFAULT_TILE_SIZE
Definition avif.c:53
const char * extension(dt_imageio_module_data_t *data)
Definition avif.c:645
uint32_t bit_depth
Definition avif.c:97
int set_params(dt_imageio_module_format_t *self, const void *params, const int size)
Definition avif.c:605
char * name
Definition avif.c:96
static int floor_log2(int i)
Definition avif.c:130
#define AVIF_MAX_TILE_SIZE
Definition avif.c:52
void cleanup(dt_imageio_module_format_t *self)
Definition avif.c:164
static const struct @52 avif_bit_depth[]
avif_color_mode_e
Definition avif.c:70
@ AVIF_COLOR_MODE_RGB
Definition avif.c:71
@ AVIF_COLOR_MODE_GRAYSCALE
Definition avif.c:72
void free_params(dt_imageio_module_format_t *self, dt_imageio_module_data_t *params)
Definition avif.c:623
int levels(struct dt_imageio_module_data_t *data)
Definition avif.c:635
void init(dt_imageio_module_format_t *self)
Definition avif.c:151
static void color_mode_changed(GtkWidget *widget, gpointer user_data)
Definition avif.c:674
void * get_params(dt_imageio_module_format_t *self)
Definition avif.c:570
static void tiling_changed(GtkWidget *widget, gpointer user_data)
Definition avif.c:681
int write_image(struct dt_imageio_module_data_t *data, const char *filename, const void *in, 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 avif.c:168
static void compression_type_changed(GtkWidget *widget, gpointer user_data)
Definition avif.c:688
avif_tiling_e
Definition avif.c:64
@ AVIF_TILING_ON
Definition avif.c:65
@ AVIF_TILING_OFF
Definition avif.c:66
void gui_cleanup(dt_imageio_module_format_t *self)
Definition avif.c:872
static const char * avif_get_compression_string(enum avif_compression_type_e comp)
Definition avif.c:116
static void quality_changed(GtkWidget *slider, gpointer user_data)
Definition avif.c:707
void dt_bauhaus_slider_set_default(GtkWidget *widget, float def)
Definition bauhaus.c:1640
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_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3598
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
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)
const char * dt_colorspaces_get_name(dt_colorspaces_color_profile_type_t type, const char *filename)
dt_colorspaces_color_profile_type_t
Definition colorspaces.h:81
@ DT_COLORSPACE_SRGB
Definition colorspaces.h:84
@ DT_COLORSPACE_REC709
@ DT_COLORSPACE_HLG_P3
@ DT_COLORSPACE_PQ_P3
@ DT_COLORSPACE_PQ_REC2020
@ DT_COLORSPACE_HLG_REC2020
@ DT_COLORSPACE_LIN_REC2020
Definition colorspaces.h:87
@ DT_COLORSPACE_DISPLAY_P3
@ DT_COLORSPACE_LIN_REC709
Definition colorspaces.h:86
static dt_aligned_pixel_t rgb
const dt_aligned_pixel_t f
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
@ DT_DEFAULT
Definition conf.h:96
@ DT_MAX
Definition conf.h:98
@ DT_MIN
Definition conf.h:97
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
void dt_conf_set_int(const char *name, int val)
gboolean dt_confgen_get_bool(const char *name, dt_confgen_value_kind_t kind)
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
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
@ DT_DEBUG_IMAGEIO
Definition darktable.h:733
#define DT_MODULE(MODVER)
Definition darktable.h:140
#define dt_free(ptr)
Definition darktable.h:456
#define __OMP_PARALLEL_FOR_SIMD__(...)
Definition darktable.h:259
#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
char * dt_exif_xmp_read_string(const int32_t imgid)
Definition exif.cc:4116
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
#define DT_GUI_MODULE(x)
int bpp
@ IMAGEIO_RGB
Definition imageio.h:70
@ IMAGEIO_FLOAT
Definition imageio.h:66
static const float x
size_t size
Definition mipmap_cache.c:3
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
struct _GtkWidget GtkWidget
Definition splash.h:29
int32_t num_openmp_threads
Definition darktable.h:758
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
GtkWidget * tiling
Definition avif.c:91
GtkWidget * compression_type
Definition avif.c:89
GtkWidget * quality
Definition avif.c:90
GtkWidget * color_mode
Definition avif.c:88
GtkWidget * bit_depth
Definition avif.c:87
uint32_t compression_type
Definition avif.c:80
uint32_t tiling
Definition avif.c:82
uint32_t quality
Definition avif.c:81
dt_imageio_module_data_t global
Definition avif.c:77
uint32_t bit_depth
Definition avif.c:78
uint32_t color_mode
Definition avif.c:79
GModule *GtkWidget * widget
#define MIN(a, b)
Definition thinplate.c:32