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 "widgets/bauhaus.h"
41#include "system/macros.h"
42#include "system/openmp.h"
43#include "system/mem_alloc.h"
44#include "common/logging.h"
46#include <glib/gstdio.h>
47#include "common/xmp_sidecar.h"
50#include "common/conf.h"
53
54#include <avif/avif.h>
56
57#define AVIF_MIN_TILE_SIZE 512
58#define AVIF_MAX_TILE_SIZE 3072
59#define AVIF_DEFAULT_TILE_SIZE AVIF_MIN_TILE_SIZE * 2
60
61DT_MODULE(1)
62
68
74
80
90
99
100static const struct
101{
102 char *name;
103 uint32_t bit_depth;
104} avif_bit_depth[] = {
105 {
106 .name = N_("8 bit"),
107 .bit_depth = 8
108 },
109 {
110 .name = N_("10 bit"),
111 .bit_depth = 10
112 },
113 {
114 .name = N_("12 bit"),
115 .bit_depth = 12
116 },
117 {
118 .name = NULL,
119 }
121
123{
124 switch(comp)
125 {
127 return "lossless";
128 case AVIF_COMP_LOSSY:
129 return "lossy";
130 }
131
132 return "unknown";
133}
134
135/* Lookup table for tiling choices */
136static int floor_log2(int i)
137{
138 static const int floor_log2_table[] =
139 /* 0 1, 2, 3, 4, 5, 6, 7, 8, 9 */
140 { 0, 0, 2, 2, 4, 4, 4, 4, 8, 8,
141 8, 8, 8, 8, 8, 8, 16, 16, 16, 16,
142 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
143 16, 16, 32, 32, 32, 32, 32, 32, 32, 32,
144 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
145 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
146 32, 32, 32, 32 };
147 /* 0 1, 2, 3, 4, 5, 6, 7, 8, 9 */
148
149 if(i >= 64)
150 {
151 return 64;
152 }
153
154 return floor_log2_table[i];
155}
156
158{
159 const char *codecName = avifCodecName(AVIF_CODEC_CHOICE_AUTO,
160 AVIF_CODEC_FLAG_CAN_ENCODE);
161 if(IS_NULL_PTR(codecName))
162 {
164 "libavif doesn't offer encoding support!\n");
165 self->ready = FALSE;
166 return;
167 }
168}
169
173
175 const char *filename,
176 const void *in,
178 const char *over_filename,
179 void *exif,
180 int exif_len,
181 int32_t imgid,
182 int num,
183 int total,
184 struct dt_dev_pixelpipe_t *pipe,
185 const gboolean export_masks)
186{
188
189 avifPixelFormat format = AVIF_PIXEL_FORMAT_NONE;
190 avifImage *image = NULL;
191 avifRGBImage rgb = { .format = AVIF_RGB_FORMAT_RGB, };
192 avifEncoder *encoder = NULL;
193 uint8_t *icc_profile_data = NULL;
194 uint32_t icc_profile_len;
195 avifResult result;
196 int rc;
197
198 const size_t width = d->global.width;
199 const size_t height = d->global.height;
200 const size_t bit_depth = d->bit_depth > 0 ? d->bit_depth : 0;
201 enum avif_color_mode_e color_mode = d->color_mode;
202
203 switch(color_mode)
204 {
206 switch(d->compression_type)
207 {
209 format = AVIF_PIXEL_FORMAT_YUV444;
210 break;
211 case AVIF_COMP_LOSSY:
212 if(d->quality > 90)
213 {
214 format = AVIF_PIXEL_FORMAT_YUV444;
215 }
216 else if(d->quality > 80)
217 {
218 format = AVIF_PIXEL_FORMAT_YUV422;
219 }
220 else
221 {
222 format = AVIF_PIXEL_FORMAT_YUV420;
223 }
224 break;
225 }
226
227 break;
229 format = AVIF_PIXEL_FORMAT_YUV400;
230 break;
231 }
232
233 image = avifImageCreate(width, height, bit_depth, format);
234 if(IS_NULL_PTR(image))
235 {
237 "Failed to create AVIF image for writing [%s]\n",
238 filename);
239 rc = 1;
240 goto out;
241 }
242
244 "Exporting AVIF image [%s] "
245 "[width: %" G_GSIZE_FORMAT ", height: %" G_GSIZE_FORMAT ", bit depth: %" G_GSIZE_FORMAT ", comp: %s, quality: %u]\n",
246 filename,
247 width,
248 height,
249 bit_depth,
250 avif_get_compression_string(d->compression_type),
251 d->quality);
252
253 if(imgid > 0)
254 {
255 gboolean use_icc = FALSE;
256
257 /*
258 * Set these in advance so any upcoming RGB -> YUV use the proper
259 * coefficients.
260 */
261 switch(over_type)
262 {
264 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
265 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
266 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT601;
267 break;
269 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
270 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_BT709;
271 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
272 break;
274 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
275 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_LINEAR;
276 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT709;
277 break;
279 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
280 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_LINEAR;
281 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;
282 break;
284 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
285 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084;
286 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;
287 break;
289 image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT2020;
290 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_HLG;
291 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_BT2020_NCL;
292 break;
294 image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432;
295 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SMPTE2084;
296 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL;
297 break;
299 image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432;
300 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_HLG;
301 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL;
302 break;
304 image->colorPrimaries = AVIF_COLOR_PRIMARIES_SMPTE432;
305 image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
306 image->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL;
307 break;
308 default:
309 break;
310 }
311
312 // no change from default, unspecified CICP (2/2/2)
313 if(image->colorPrimaries == AVIF_COLOR_PRIMARIES_UNSPECIFIED)
314 {
315 use_icc = TRUE;
316 }
317
318 dt_print(DT_DEBUG_IMAGEIO, "[avif colorprofile profile: %s - %s]\n",
319 dt_colorspaces_get_name(over_type, filename),
320 use_icc ? "icc" : "nclx");
321
322 if(use_icc)
323 {
326 &over_type,
327 over_filename);
328 cmsHPROFILE out_profile = cp->profile;
329
330 cmsSaveProfileToMem(out_profile, 0, &icc_profile_len);
331 if(icc_profile_len > 0)
332 {
333 icc_profile_data = malloc(sizeof(uint8_t) * icc_profile_len);
334 if(IS_NULL_PTR(icc_profile_data))
335 {
336 rc = 1;
337 goto out;
338 }
339 cmsSaveProfileToMem(out_profile, icc_profile_data, &icc_profile_len);
340 (void)avifImageSetProfileICC(image, icc_profile_data, icc_profile_len);
341 }
342 }
343 }
344
345 /*
346 * Set the YUV range before conversion.
347 *
348 * Limited range (aka "studio range", "studio swing", etc) is simply when you
349 * cut off the ends of the actual range you have to avoid the actual minimum
350 * and maximum of the signal. For example, instead of having full range 8bpc
351 * ([0-255]) in each channel, you'd only use [16-235]. Anything 16 or below
352 * is treated as a 0.0 signal, and anything 235 or higher is treated as a 1.0
353 * signal.
354 *
355 * The *reason* this exists, is largely vestigial from the analog era.
356 *
357 * For picture we always want the full range.
358 */
359 image->yuvRange = AVIF_RANGE_FULL;
360
361 avifRGBImageSetDefaults(&rgb, image);
362 rgb.format = AVIF_RGB_FORMAT_RGB;
363
364 (void)avifRGBImageAllocatePixels(&rgb);
365
366 const float max_channel_f = (float)((1 << bit_depth) - 1);
367
368 const size_t rowbytes = rgb.rowBytes;
369
370 const float *const restrict in_data = (const float *)in;
371 uint8_t *const restrict out = (uint8_t *)rgb.pixels;
372
373 switch(bit_depth)
374 {
375 case 12:
376 case 10:
377 {
378 __OMP_PARALLEL_FOR_SIMD__(collapse(2))
379 for(size_t y = 0; y < height; y++)
380 {
381 for(size_t x = 0; x < width; x++)
382 {
383 const float *in_pixel = &in_data[(size_t)4 * ((y * width) + x)];
384 uint16_t *out_pixel = (uint16_t *)&out[(y * rowbytes) + (3 * sizeof(uint16_t) * x)];
385
386 out_pixel[0] = (uint16_t)roundf(CLAMP(in_pixel[0] * max_channel_f, 0, max_channel_f));
387 out_pixel[1] = (uint16_t)roundf(CLAMP(in_pixel[1] * max_channel_f, 0, max_channel_f));
388 out_pixel[2] = (uint16_t)roundf(CLAMP(in_pixel[2] * max_channel_f, 0, max_channel_f));
389 }
390 }
391 break;
392 }
393 case 8:
394 {
395 __OMP_PARALLEL_FOR_SIMD__(collapse(2))
396 for(size_t y = 0; y < height; y++)
397 {
398 for(size_t x = 0; x < width; x++)
399 {
400 const float *in_pixel = &in_data[(size_t)4 * ((y * width) + x)];
401 uint8_t *out_pixel = (uint8_t *)&out[(y * rowbytes) + (3 * sizeof(uint8_t) * x)];
402
403 out_pixel[0] = (uint8_t)roundf(CLAMP(in_pixel[0] * max_channel_f, 0, max_channel_f));
404 out_pixel[1] = (uint8_t)roundf(CLAMP(in_pixel[1] * max_channel_f, 0, max_channel_f));
405 out_pixel[2] = (uint8_t)roundf(CLAMP(in_pixel[2] * max_channel_f, 0, max_channel_f));
406 }
407 }
408 break;
409 }
410 default:
411 dt_control_log(_("invalid AVIF bit depth!"));
412 rc = 1;
413 goto out;
414 }
415
416 (void)avifImageRGBToYUV(image, &rgb);
417
418 if(exif && exif_len > 0)
419 (void)avifImageSetMetadataExif(image, exif, exif_len);
420
421 /* TODO: workaround; remove when exiv2 implements AVIF write support and update flags() */
422 char *xmp_string = dt_exif_xmp_read_string(imgid);
423 size_t xmp_len;
424 if(xmp_string && (xmp_len = strlen(xmp_string)) > 0)
425 {
426 (void)avifImageSetMetadataXMP(image, (const uint8_t *)xmp_string, xmp_len);
427 dt_free(xmp_string);
428 }
429
430 encoder = avifEncoderCreate();
431 if(IS_NULL_PTR(encoder))
432 {
434 "Failed to create AVIF encoder for image [%s]\n",
435 filename);
436 rc = 1;
437 goto out;
438 }
439
440 switch(d->compression_type)
441 {
443 /* It isn't recommend to use the extremities */
444 encoder->speed = AVIF_SPEED_SLOWEST + 1;
445
446 encoder->minQuantizer = AVIF_QUANTIZER_LOSSLESS;
447 encoder->maxQuantizer = AVIF_QUANTIZER_LOSSLESS;
448
449 break;
450 case AVIF_COMP_LOSSY:
451 encoder->speed = AVIF_SPEED_DEFAULT;
452
453 encoder->maxQuantizer = 100 - d->quality;
454 encoder->maxQuantizer = CLAMP(encoder->maxQuantizer, 0, 63);
455
456 encoder->minQuantizer = 64 - d->quality;
457 encoder->minQuantizer = CLAMP(encoder->minQuantizer, 0, 63);
458 break;
459 }
460
461 /*
462 * Tiling reduces the image quality but it has a negligible impact on
463 * still images.
464 *
465 * The minimum size for a tile is 512x512. We use a default tile size of
466 * 1024x1024.
467 */
468 switch(d->tiling)
469 {
470 case AVIF_TILING_ON:
471 {
472 size_t width_tile_size = AVIF_DEFAULT_TILE_SIZE;
473 size_t height_tile_size = AVIF_DEFAULT_TILE_SIZE;
474 size_t max_threads;
475
476 if(width >= 6144)
477 {
478 width_tile_size = AVIF_MIN_TILE_SIZE * 4;
479 }
480 else if (width >= 8192) {
481 width_tile_size = AVIF_MAX_TILE_SIZE;
482 }
483 if(height >= 6144)
484 {
485 height_tile_size = AVIF_MIN_TILE_SIZE * 4;
486 }
487 else if (height >= 8192) {
488 height_tile_size = AVIF_MAX_TILE_SIZE;
489 }
490
491 encoder->tileColsLog2 = floor_log2(width / width_tile_size) / 2;
492 encoder->tileRowsLog2 = floor_log2(height / height_tile_size) / 2;
493
494 /*
495 * This should be set to the final number of tiles, based on
496 * encoder->tileColsLog2 and encoder->tileRowsLog2.
497 */
498 max_threads = (1 << encoder->tileRowsLog2) * (1 << encoder->tileColsLog2);
499
500 encoder->maxThreads = MIN(max_threads, dt_get_num_openmp_threads());
501 }
502 case AVIF_TILING_OFF:
503 break;
504 }
505
507 "[avif quality: %u => maxQuantizer: %u, minQuantizer: %u, "
508 "tileColsLog2: %u, tileRowsLog2: %u, threads: %u]\n",
509 d->quality,
510 encoder->maxQuantizer,
511 encoder->minQuantizer,
512 encoder->tileColsLog2,
513 encoder->tileRowsLog2,
514 encoder->maxThreads);
515
516 avifRWData output = AVIF_DATA_EMPTY;
517
518 result = avifEncoderWrite(encoder, image, &output);
519 if(result != AVIF_RESULT_OK)
520 {
522 "Failed to encode AVIF image [%s]: %s\n",
523 filename, avifResultToString(result));
524 rc = 1;
525 goto out;
526 }
527
528 if(output.size == 0 || IS_NULL_PTR(output.data))
529 {
531 "AVIF encoder returned empty data for [%s]\n",
532 filename);
533 rc = 1;
534 goto out;
535 }
536
537 /*
538 * Write image to disk
539 */
540 FILE *f = NULL;
541 size_t cnt = 0;
542
543 f = g_fopen(filename, "wb");
544 if(IS_NULL_PTR(f))
545 {
546 rc = 1;
547 goto out;
548 }
549
550 cnt = fwrite(output.data, 1, output.size, f);
551 fclose(f);
552 if(cnt != output.size)
553 {
554 g_unlink(filename);
555 rc = 1;
556 goto out;
557 }
558
559 rc = 0; /* success */
560out:
561 avifRGBImageFreePixels(&rgb);
562 avifImageDestroy(image);
563 avifEncoderDestroy(encoder);
564 avifRWDataFree(&output);
565 dt_free(icc_profile_data);
566
567 return rc;
568}
569
570
572{
573 return sizeof(dt_imageio_avif_t);
574}
575
577{
579
580 if(IS_NULL_PTR(d))
581 {
582 return NULL;
583 }
584
585 d->bit_depth = dt_conf_get_int("plugins/imageio/format/avif/bpp");
586 if(d->bit_depth != 10 && d->bit_depth != 12)
587 d->bit_depth = 8;
588
589 d->color_mode = dt_conf_get_int("plugins/imageio/format/avif/color_mode");
590 d->compression_type = dt_conf_get_int("plugins/imageio/format/avif/compression_type");
591
592 switch(d->compression_type)
593 {
595 d->quality = 100;
596 break;
597 case AVIF_COMP_LOSSY:
598 d->quality = dt_conf_get_int("plugins/imageio/format/avif/quality");
599 if(d->quality > 100)
600 {
601 d->quality = 100;
602 }
603 break;
604 }
605
606 d->tiling = !dt_conf_get_bool("plugins/imageio/format/avif/tiling");
607
608 return d;
609}
610
612 const void *params,
613 const int size)
614{
615 if(size != self->params_size(self))
616 return 1;
617 const dt_imageio_avif_t *d = (dt_imageio_avif_t *)params;
618
620 dt_bauhaus_combobox_set(g->bit_depth, d->bit_depth);
621 dt_bauhaus_combobox_set(g->color_mode, d->color_mode);
622 dt_bauhaus_combobox_set(g->tiling, d->tiling);
623 dt_bauhaus_combobox_set(g->compression_type, d->compression_type);
624 dt_bauhaus_slider_set(g->quality, d->quality);
625
626 return 0;
627}
628
631{
632 dt_free(params);
633}
634
635
637{
638 return 32; /* always request float */
639}
640
642{
644}
645
647{
648 return "image/avif";
649}
650
652{
653 return "avif";
654}
655
656const char *name()
657{
658 return _("AVIF (8/10/12-bit)");
659}
660
662{
663 /*
664 * As of exiv2 0.27.5 there is no write support for the AVIF format, so
665 * we do not return the XMP supported flag currently.
666 * Once exiv2 write support is there, the flag can be returned, and the
667 * direct XMP embedding workaround using avifImageSetMetadataXMP() above
668 * can be removed.
669 */
670 return 0; /* FORMAT_FLAGS_SUPPORT_XMP; */
671}
672
673static void bit_depth_changed(GtkWidget *widget, gpointer user_data)
674{
675 const uint32_t idx = dt_bauhaus_combobox_get(widget);
676
677 dt_conf_set_int("plugins/imageio/format/avif/bpp", avif_bit_depth[idx].bit_depth);
678}
679
680static void color_mode_changed(GtkWidget *widget, gpointer user_data)
681{
682 const enum avif_color_mode_e color_mode = dt_bauhaus_combobox_get(widget);
683
684 dt_conf_set_int("plugins/imageio/format/avif/color_mode", color_mode);
685}
686
687static void tiling_changed(GtkWidget *widget, gpointer user_data)
688{
689 const enum avif_tiling_e tiling = dt_bauhaus_combobox_get(widget);
690
691 dt_conf_set_bool("plugins/imageio/format/avif/tiling", !tiling);
692}
693
694static void compression_type_changed(GtkWidget *widget, gpointer user_data)
695{
696 const enum avif_compression_type_e compression_type = dt_bauhaus_combobox_get(widget);
697 dt_imageio_module_format_t *module = (dt_imageio_module_format_t *)user_data;
698 dt_imageio_avif_gui_t *gui = (dt_imageio_avif_gui_t *)module->gui_data;
699
700 dt_conf_set_int("plugins/imageio/format/avif/compression_type", compression_type);
701
702 switch(compression_type)
703 {
705 gtk_widget_set_sensitive(gui->quality, FALSE);
706 break;
707 case AVIF_COMP_LOSSY:
708 gtk_widget_set_sensitive(gui->quality, TRUE);
709 break;
710 }
711}
712
713static void quality_changed(GtkWidget *slider, gpointer user_data)
714{
715 const uint32_t quality = (int)dt_bauhaus_slider_get(slider);
716 dt_conf_set_int("plugins/imageio/format/avif/quality", quality);
717}
718
720{
723 const uint32_t bit_depth = dt_conf_get_int("plugins/imageio/format/avif/bit_depth");
724 const enum avif_color_mode_e color_mode = dt_conf_get_int("plugins/imageio/format/avif/color_mode");
725 const enum avif_tiling_e tiling = !dt_conf_get_bool("plugins/imageio/format/avif/tiling");
726 const enum avif_compression_type_e compression_type = dt_conf_get_int("plugins/imageio/format/avif/compression_type");
727 const uint32_t quality = dt_conf_get_int("plugins/imageio/format/avif/quality");
728
729 self->gui_data = (void *)gui;
730
731 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
732
733 /*
734 * Bit depth combo box
735 */
737
738 dt_bauhaus_widget_set_label(gui->bit_depth, N_("bit depth"));
739 size_t idx = 0;
740 for(size_t i = 0; !IS_NULL_PTR(avif_bit_depth[i].name); i++)
741 {
744 {
745 idx = i;
746 }
747 }
749
750 gtk_widget_set_tooltip_text(gui->bit_depth,
751 _("color information stored in an image, higher is better"));
752
753 gtk_box_pack_start(GTK_BOX(self->widget), gui->bit_depth, TRUE, TRUE, 0);
754
755 /*
756 * Color mode combo box
757 */
759 dt_bauhaus_widget_set_label(gui->color_mode, _("color mode"));
761 _("rgb colors"));
763 _("grayscale"));
764 dt_bauhaus_combobox_set(gui->color_mode, color_mode);
765
766 gtk_widget_set_tooltip_text(gui->color_mode,
767 _("saving as grayscale will reduce the size for black & white images"));
768
769 gtk_box_pack_start(GTK_BOX(self->widget),
770 gui->color_mode,
771 TRUE,
772 TRUE,
773 0);
774 /*
775 * Tiling combo box
776 */
778 dt_bauhaus_widget_set_label(gui->tiling, N_("tiling"));
780 _("on"));
782 _("off"));
784
785 gtk_widget_set_tooltip_text(gui->tiling,
786 _("tile an image into segments.\n"
787 "\n"
788 "makes encoding faster. the impact on quality reduction "
789 "is negligible, but increases the file size."));
790
791 gtk_box_pack_start(GTK_BOX(self->widget),
792 gui->tiling,
793 TRUE,
794 TRUE,
795 0);
796
797 /*
798 * Compression type combo box
799 */
801 dt_bauhaus_widget_set_label(gui->compression_type, N_("compression type"));
806 dt_bauhaus_combobox_set(gui->compression_type, compression_type);
807
808 gtk_widget_set_tooltip_text(gui->compression_type,
809 _("the compression for the image"));
810
811 gtk_box_pack_start(GTK_BOX(self->widget),
812 gui->compression_type,
813 TRUE,
814 TRUE,
815 0);
816
817 /*
818 * Quality combo box
819 */
821 dt_confgen_get_int("plugins/imageio/format/avif/quality", DT_MIN), /* min */
822 dt_confgen_get_int("plugins/imageio/format/avif/quality", DT_MAX), /* max */
823 1, /* step */
824 dt_confgen_get_int("plugins/imageio/format/avif/quality", DT_DEFAULT), /* default */
825 0); /* digits */
826 dt_bauhaus_widget_set_label(gui->quality, N_("quality"));
827 dt_bauhaus_slider_set_default(gui->quality, dt_confgen_get_int("plugins/imageio/format/avif/quality", DT_DEFAULT));
829
830 gtk_widget_set_tooltip_text(gui->quality,
831 _("the quality of an image, less quality means fewer details.\n"
832 "\n"
833 "the following applies only to lossy setting\n"
834 "\n"
835 "pixelformat based on quality:\n"
836 "\n"
837 " 91% - 100% -> YUV444\n"
838 " 81% - 90% -> YUV422\n"
839 " 5% - 80% -> YUV420\n"));
840
841 if(quality > 0 && quality <= 100)
842 {
843 dt_bauhaus_slider_set(gui->quality, quality);
844 }
845 gtk_box_pack_start(GTK_BOX(self->widget), gui->quality, TRUE, TRUE, 0);
846
847 switch(compression_type)
848 {
850 gtk_widget_set_sensitive(gui->quality, FALSE);
851 break;
852 case AVIF_COMP_LOSSY:
853 break;
854 }
855
856 g_signal_connect(G_OBJECT(gui->bit_depth),
857 "value-changed",
858 G_CALLBACK(bit_depth_changed),
859 NULL);
860 g_signal_connect(G_OBJECT(gui->color_mode),
861 "value-changed",
862 G_CALLBACK(color_mode_changed),
863 (gpointer)self);
864 g_signal_connect(G_OBJECT(gui->tiling),
865 "value-changed",
866 G_CALLBACK(tiling_changed),
867 (gpointer)self);
868 g_signal_connect(G_OBJECT(gui->compression_type),
869 "value-changed",
870 G_CALLBACK(compression_type_changed),
871 (gpointer)self);
872 g_signal_connect(G_OBJECT(gui->quality),
873 "value-changed",
874 G_CALLBACK(quality_changed),
875 NULL);
876}
877
879{
880 dt_free(self->gui_data);
881}
882
884{
886
887 const enum avif_color_mode_e color_mode = dt_confgen_get_int("plugins/imageio/format/avif/color_mode", DT_DEFAULT);
888 const enum avif_tiling_e tiling = !dt_confgen_get_bool("plugins/imageio/format/avif/tiling", DT_DEFAULT);
889 const enum avif_compression_type_e compression_type = dt_confgen_get_int("plugins/imageio/format/avif/compression_type", DT_DEFAULT);
890 const uint32_t quality = dt_confgen_get_int("plugins/imageio/format/avif/quality", DT_DEFAULT);
891
892 dt_bauhaus_combobox_set(gui->bit_depth, 0); //8bpp
893 dt_bauhaus_combobox_set(gui->color_mode, color_mode);
895 dt_bauhaus_combobox_set(gui->compression_type, compression_type);
896 dt_bauhaus_slider_set(gui->quality, quality);
897
898 compression_type_changed(GTK_WIDGET(gui->compression_type), self);
899 quality_changed(GTK_WIDGET(gui->quality), self);
900 bit_depth_changed(GTK_WIDGET(gui->bit_depth), self);
901}
902// clang-format off
903// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
904// vim: shiftwidth=2 expandtab tabstop=2 cindent
905// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
906// 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:646
size_t params_size(dt_imageio_module_format_t *self)
Definition avif.c:571
#define AVIF_MIN_TILE_SIZE
Definition avif.c:57
static void bit_depth_changed(GtkWidget *widget, gpointer user_data)
Definition avif.c:673
void gui_reset(dt_imageio_module_format_t *self)
Definition avif.c:883
avif_compression_type_e
Definition avif.c:64
@ AVIF_COMP_LOSSY
Definition avif.c:66
@ AVIF_COMP_LOSSLESS
Definition avif.c:65
void gui_init(dt_imageio_module_format_t *self)
Definition avif.c:719
#define AVIF_DEFAULT_TILE_SIZE
Definition avif.c:59
const char * extension(dt_imageio_module_data_t *data)
Definition avif.c:651
uint32_t bit_depth
Definition avif.c:103
int set_params(dt_imageio_module_format_t *self, const void *params, const int size)
Definition avif.c:611
char * name
Definition avif.c:102
static int floor_log2(int i)
Definition avif.c:136
#define AVIF_MAX_TILE_SIZE
Definition avif.c:58
void cleanup(dt_imageio_module_format_t *self)
Definition avif.c:170
avif_color_mode_e
Definition avif.c:76
@ AVIF_COLOR_MODE_RGB
Definition avif.c:77
@ AVIF_COLOR_MODE_GRAYSCALE
Definition avif.c:78
void free_params(dt_imageio_module_format_t *self, dt_imageio_module_data_t *params)
Definition avif.c:629
int levels(struct dt_imageio_module_data_t *data)
Definition avif.c:641
void init(dt_imageio_module_format_t *self)
Definition avif.c:157
static void color_mode_changed(GtkWidget *widget, gpointer user_data)
Definition avif.c:680
void * get_params(dt_imageio_module_format_t *self)
Definition avif.c:576
static void tiling_changed(GtkWidget *widget, gpointer user_data)
Definition avif.c:687
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:174
static void compression_type_changed(GtkWidget *widget, gpointer user_data)
Definition avif.c:694
avif_tiling_e
Definition avif.c:70
@ AVIF_TILING_ON
Definition avif.c:71
@ AVIF_TILING_OFF
Definition avif.c:72
static const struct @38 avif_bit_depth[]
void gui_cleanup(dt_imageio_module_format_t *self)
Definition avif.c:878
static const char * avif_get_compression_string(enum avif_compression_type_e comp)
Definition avif.c:122
static void quality_changed(GtkWidget *slider, gpointer user_data)
Definition avif.c:713
void dt_bauhaus_slider_set_default(GtkWidget *widget, float def)
Definition bauhaus.c:1491
float dt_bauhaus_slider_get(GtkWidget *widget)
Definition bauhaus.c:3280
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2136
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
Definition bauhaus.c:3331
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_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:1632
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1698
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
Definition bauhaus.c:3407
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:1824
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
static const float x
const float f
const char * dt_colorspaces_get_name(dt_colorspaces_color_profile_type_t type, const char *filename)
Printable name for a profile identity, without touching the profile list.
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
static dt_aligned_pixel_t rgb
const dt_colormatrix_t dt_aligned_pixel_t out
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)
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
@ DT_MAX
Definition conf.h:137
@ DT_MIN
Definition conf.h:136
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
#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)
@ DT_DEBUG_IMAGEIO
Definition logging.h:68
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
#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
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
#define DT_MODULE(MODVER)
Instantiate the version handshake every module must export. Use once, at file scope,...
#define __OMP_PARALLEL_FOR_SIMD__(...)
Definition openmp.h:96
dt_colorspaces_color_profile_type_t
@ DT_COLORSPACE_SRGB
sRGB – registered TWICE, and the two entries are not interchangeable.
@ DT_COLORSPACE_REC709
@ DT_COLORSPACE_HLG_P3
@ DT_COLORSPACE_PQ_P3
@ DT_COLORSPACE_PQ_REC2020
@ DT_COLORSPACE_HLG_REC2020
@ DT_COLORSPACE_LIN_REC2020
@ DT_COLORSPACE_DISPLAY_P3
@ DT_COLORSPACE_LIN_REC709
One registered profile: its identity, its LCMS handle, and where it sits in each combo box.
cmsHPROFILE profile
the actual profile; NULL for the three category entries
GtkWidget * tiling
Definition avif.c:97
GtkWidget * compression_type
Definition avif.c:95
GtkWidget * quality
Definition avif.c:96
GtkWidget * color_mode
Definition avif.c:94
GtkWidget * bit_depth
Definition avif.c:93
uint32_t compression_type
Definition avif.c:86
uint32_t tiling
Definition avif.c:88
uint32_t quality
Definition avif.c:87
dt_imageio_module_data_t global
Definition avif.c:83
uint32_t bit_depth
Definition avif.c:84
uint32_t color_mode
Definition avif.c:85
GModule *GtkWidget * widget
#define MIN(a, b)
Definition thinplate.c:32
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,...