Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
imageio_avif.c
Go to the documentation of this file.
1/*
2 * This file is part of darktable,
3 * Copyright (C) 2019-2020 Andreas Schneider.
4 * Copyright (C) 2020, 2025 Aurélien PIERRE.
5 * Copyright (C) 2020 Benoit Brummer.
6 * Copyright (C) 2020 Hubert Kowalski.
7 * Copyright (C) 2020-2021 Pascal Obry.
8 * Copyright (C) 2021 Daniel Vogelbacher.
9 * Copyright (C) 2021 Miloš Komarčević.
10 * Copyright (C) 2022 Martin Bařinka.
11 * Copyright (C) 2022 Philipp Lutz.
12 * Copyright (C) 2023 Alynx Zhou.
13 * Copyright (C) 2025 Peter Kovář.
14 *
15 * darktable is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
19 *
20 * darktable is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with darktable. If not, see <http://www.gnu.org/licenses/>.
27 */
28
29#include "common/image.h"
30#include <avif/avif.h>
31#ifdef HAVE_CONFIG_H
32#include "config.h"
33#endif
34
35#include <inttypes.h>
36#include <memory.h>
37#include <stdio.h>
38#include <strings.h>
39
40#include "metadata/exif.h"
41#include "develop/develop.h"
42#include "imageio_avif.h"
43
45 const char *filename,
47{
49 avifImage avif_image = {0};
50 avifImage *avif = NULL;
51 avifRGBImage rgb = {
52 .format = AVIF_RGB_FORMAT_RGB,
53 };
54 avifDecoder *decoder = NULL;
55 avifResult result;
56
57 decoder = avifDecoderCreate();
58 if(IS_NULL_PTR(decoder))
59 {
60 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] failed to create decoder for `%s'\n", filename);
62 goto out;
63 }
64
65 result = avifDecoderReadFile(decoder, &avif_image, filename);
66 if(result != AVIF_RESULT_OK)
67 {
68 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] failed to parse `%s': %s\n", filename, avifResultToString(result));
70 goto out;
71 }
72 avif = &avif_image;
73
74 /* This will set the depth from the avif */
75 avifRGBImageSetDefaults(&rgb, avif);
76
77 rgb.format = AVIF_RGB_FORMAT_RGB;
78
79 (void)avifRGBImageAllocatePixels(&rgb);
80
81 result = avifImageYUVToRGB(avif, &rgb);
82 if(result != AVIF_RESULT_OK)
83 {
84 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] failed to convert `%s' from YUV to RGB: %s\n", filename,
85 avifResultToString(result));
87 goto out;
88 }
89
90 const size_t width = rgb.width;
91 const size_t height = rgb.height;
92 /* If `> 8', all plane ptrs are 'uint16_t *' */
93 const size_t bit_depth = rgb.depth;
94
95 /* Initialize cached image buffer */
96 img->width = width;
97 img->height = height;
98
99 img->dsc.channels = 4;
100 img->dsc.datatype = TYPE_FLOAT;
101 img->dsc.bpp = 4 * sizeof(float);
102 img->dsc.cst = IOP_CS_RGB;
103 img->dsc.filters = 0u;
104 img->flags &= ~DT_IMAGE_RAW;
105 img->flags &= ~DT_IMAGE_S_RAW;
106
107 switch(bit_depth) {
108 case 12:
109 case 10:
110 img->flags |= DT_IMAGE_HDR;
111 img->flags &= ~DT_IMAGE_LDR;
112 break;
113 case 8:
114 img->flags |= DT_IMAGE_LDR;
115 img->flags &= ~DT_IMAGE_HDR;
116 break;
117 default:
118 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] invalid bit depth for `%s'\n", filename);
120 goto out;
121 }
122
123 img->loader = LOADER_AVIF;
124
125 if(IS_NULL_PTR(mbuf))
126 {
127 ret = DT_IMAGEIO_OK;
128 goto out;
129 }
130
131 float *mipbuf = (float *)dt_mipmap_cache_alloc(mbuf, img);
132 if(IS_NULL_PTR(mipbuf))
133 {
134 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] failed to allocate mipmap buffer for `%s'\n", filename);
136 goto out;
137 }
138
139 const float max_channel_f = (float)((1 << bit_depth) - 1);
140
141 const size_t rowbytes = rgb.rowBytes;
142
143 const uint8_t *const restrict in = (const uint8_t *)rgb.pixels;
144
145 switch (bit_depth) {
146 case 12:
147 case 10: {
148 __OMP_PARALLEL_FOR_SIMD__(collapse(2))
149 for (size_t y = 0; y < height; y++)
150 {
151 for (size_t x = 0; x < width; x++)
152 {
153 uint16_t *in_pixel = (uint16_t *)&in[(y * rowbytes) + (3 * sizeof(uint16_t) * x)];
154 float *out_pixel = &mipbuf[(size_t)4 * ((y * width) + x)];
155
156 /* max_channel_f is 255.0f for 8bit */
157 out_pixel[0] = ((float)in_pixel[0]) * (1.0f / max_channel_f);
158 out_pixel[1] = ((float)in_pixel[1]) * (1.0f / max_channel_f);
159 out_pixel[2] = ((float)in_pixel[2]) * (1.0f / max_channel_f);
160 out_pixel[3] = 0.0f; /* alpha */
161 }
162 }
163 break;
164 }
165 case 8: {
166 __OMP_PARALLEL_FOR_SIMD__(collapse(2))
167 for (size_t y = 0; y < height; y++)
168 {
169 for (size_t x = 0; x < width; x++)
170 {
171 uint8_t *in_pixel = (uint8_t *)&in[(y * rowbytes) + (3 * sizeof(uint8_t) * x)];
172 float *out_pixel = &mipbuf[(size_t)4 * ((y * width) + x)];
173
174 /* max_channel_f is 255.0f for 8bit */
175 out_pixel[0] = (float)(in_pixel[0]) * (1.0f / max_channel_f);
176 out_pixel[1] = (float)(in_pixel[1]) * (1.0f / max_channel_f);
177 out_pixel[2] = (float)(in_pixel[2]) * (1.0f / max_channel_f);
178 out_pixel[3] = 0.0f; /* alpha */
179 }
180 }
181 break;
182 }
183 default:
184 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] invalid bit depth for `%s'\n", filename);
186 goto out;
187 }
188
189 /* Get the ICC profile if available */
190 avifRWData *icc = &(avif->icc);
191 if(icc->size && icc->data)
192 {
193 img->profile = (uint8_t *)g_malloc0(icc->size);
194 memcpy(img->profile, icc->data, icc->size);
195 img->profile_size = icc->size;
196 }
197 ret = DT_IMAGEIO_OK;
198out:
199 avifRGBImageFreePixels(&rgb);
200 avifDecoderDestroy(decoder);
201
202 return ret;
203}
204
205int dt_imageio_avif_read_profile(const char *filename, uint8_t **out, dt_colorspaces_cicp_t *cicp)
206{
207 /* set default return values */
208 int size = 0;
209 *out = NULL;
210 cicp->color_primaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED;
211 cicp->transfer_characteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED;
212 cicp->matrix_coefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED;
213
214 avifDecoder *decoder = NULL;
215 avifImage avif_image = {0};
216 avifResult result;
217
218 decoder = avifDecoderCreate();
219 if(IS_NULL_PTR(decoder))
220 {
221 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] failed to create decoder for `%s'\n", filename);
222 goto out;
223 }
224
225 result = avifDecoderReadFile(decoder, &avif_image, filename);
226 if(result != AVIF_RESULT_OK)
227 {
228 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] failed to parse `%s': %s\n", filename, avifResultToString(result));
229 goto out;
230 }
231
232 if(avif_image.icc.size > 0)
233 {
234 avifRWData *icc = &avif_image.icc;
235
236 if(IS_NULL_PTR(icc->data)) goto out;
237
238 *out = (uint8_t *)g_malloc0(icc->size);
239 memcpy(*out, icc->data, icc->size);
240 size = icc->size;
241 }
242 else
243 {
244 cicp->color_primaries = avif_image.colorPrimaries;
245 cicp->transfer_characteristics = avif_image.transferCharacteristics;
246 cicp->matrix_coefficients = avif_image.matrixCoefficients;
247
248 /* fix up mistagged legacy AVIFs */
249 if(avif_image.colorPrimaries == AVIF_COLOR_PRIMARIES_BT709)
250 {
251 gboolean over = FALSE;
252
253 /* mistagged Rec. 709 AVIFs exported before dt 3.6 */
254 if(avif_image.transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_BT470M
255 && avif_image.matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_BT709)
256 {
257 /* must be actual Rec. 709 instead of 2.2 gamma*/
258 cicp->transfer_characteristics = AVIF_TRANSFER_CHARACTERISTICS_BT709;
259 over = TRUE;
260 }
261
262 if(over)
263 {
264 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] overriding nclx color profile for `%s': 1/%d/%d to 1/%d/%d\n",
265 filename, avif_image.transferCharacteristics, avif_image.matrixCoefficients,
267 }
268 }
269 }
270
271out:
272 avifDecoderDestroy(decoder);
273
274 return size;
275}
276
277// clang-format off
278// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
279// vim: shiftwidth=2 expandtab tabstop=2 cindent
280// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
281// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
uint32_t bit_depth
Definition avif.c:103
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
@ IOP_CS_RGB
static const float x
static dt_aligned_pixel_t rgb
const dt_colormatrix_t dt_aligned_pixel_t out
What a photograph says about itself: the EXIF, IPTC and XMP tags a camera and a cataloguer write,...
@ TYPE_FLOAT
Definition format.h:56
dt_imageio_retval_t
Definition image.h:91
@ DT_IMAGEIO_OK
Definition image.h:92
@ DT_IMAGEIO_CACHE_FULL
Definition image.h:95
@ DT_IMAGEIO_FILE_CORRUPTED
Definition image.h:94
@ DT_IMAGE_HDR
Definition image.h:126
@ DT_IMAGE_LDR
Definition image.h:122
@ LOADER_AVIF
Definition image.h:293
int dt_imageio_avif_read_profile(const char *filename, uint8_t **out, dt_colorspaces_cicp_t *cicp)
dt_imageio_retval_t dt_imageio_open_avif(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf)
@ 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
void * dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img)
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 __OMP_PARALLEL_FOR_SIMD__(...)
Definition openmp.h:96
The three ITU-T H.273 code points that describe a colour space without an ICC profile.
dt_colorspaces_cicp_matrix_coefficients_t matrix_coefficients
dt_colorspaces_cicp_transfer_characteristics_t transfer_characteristics
dt_colorspaces_cicp_color_primaries_t color_primaries
int32_t height
Definition image.h:397
dt_image_loader_t loader
Definition image.h:417
int32_t flags
Definition image.h:401
int32_t width
Definition image.h:397
uint32_t profile_size
Definition image.h:423
dt_iop_buffer_dsc_t dsc
Definition image.h:419
uint8_t * profile
Definition image.h:422
uint32_t filters
Definition format.h:89
unsigned int channels
Definition format.h:83
dt_iop_buffer_type_t datatype
Definition format.h:85