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 "control/control.h"
41#include "common/exif.h"
42#include "control/conf.h"
43#include "develop/develop.h"
44#include "imageio.h"
45#include "imageio_avif.h"
46
48 const char *filename,
50{
52 avifImage avif_image = {0};
53 avifImage *avif = NULL;
54 avifRGBImage rgb = {
55 .format = AVIF_RGB_FORMAT_RGB,
56 };
57 avifDecoder *decoder = NULL;
58 avifResult result;
59
60 decoder = avifDecoderCreate();
61 if(IS_NULL_PTR(decoder))
62 {
63 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] failed to create decoder for `%s'\n", filename);
65 goto out;
66 }
67
68 result = avifDecoderReadFile(decoder, &avif_image, filename);
69 if(result != AVIF_RESULT_OK)
70 {
71 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] failed to parse `%s': %s\n", filename, avifResultToString(result));
73 goto out;
74 }
75 avif = &avif_image;
76
77 /* This will set the depth from the avif */
78 avifRGBImageSetDefaults(&rgb, avif);
79
80 rgb.format = AVIF_RGB_FORMAT_RGB;
81
82 (void)avifRGBImageAllocatePixels(&rgb);
83
84 result = avifImageYUVToRGB(avif, &rgb);
85 if(result != AVIF_RESULT_OK)
86 {
87 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] failed to convert `%s' from YUV to RGB: %s\n", filename,
88 avifResultToString(result));
90 goto out;
91 }
92
93 const size_t width = rgb.width;
94 const size_t height = rgb.height;
95 /* If `> 8', all plane ptrs are 'uint16_t *' */
96 const size_t bit_depth = rgb.depth;
97
98 /* Initialize cached image buffer */
99 img->width = width;
100 img->height = height;
101
102 img->dsc.channels = 4;
103 img->dsc.datatype = TYPE_FLOAT;
104 img->dsc.bpp = 4 * sizeof(float);
105 img->dsc.cst = IOP_CS_RGB;
106 img->dsc.filters = 0u;
107 img->flags &= ~DT_IMAGE_RAW;
108 img->flags &= ~DT_IMAGE_S_RAW;
109
110 switch(bit_depth) {
111 case 12:
112 case 10:
113 img->flags |= DT_IMAGE_HDR;
114 img->flags &= ~DT_IMAGE_LDR;
115 break;
116 case 8:
117 img->flags |= DT_IMAGE_LDR;
118 img->flags &= ~DT_IMAGE_HDR;
119 break;
120 default:
121 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] invalid bit depth for `%s'\n", filename);
123 goto out;
124 }
125
126 img->loader = LOADER_AVIF;
127
128 if(IS_NULL_PTR(mbuf))
129 {
130 ret = DT_IMAGEIO_OK;
131 goto out;
132 }
133
134 float *mipbuf = (float *)dt_mipmap_cache_alloc(mbuf, img);
135 if(IS_NULL_PTR(mipbuf))
136 {
137 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] failed to allocate mipmap buffer for `%s'\n", filename);
139 goto out;
140 }
141
142 const float max_channel_f = (float)((1 << bit_depth) - 1);
143
144 const size_t rowbytes = rgb.rowBytes;
145
146 const uint8_t *const restrict in = (const uint8_t *)rgb.pixels;
147
148 switch (bit_depth) {
149 case 12:
150 case 10: {
151 __OMP_PARALLEL_FOR_SIMD__(collapse(2))
152 for (size_t y = 0; y < height; y++)
153 {
154 for (size_t x = 0; x < width; x++)
155 {
156 uint16_t *in_pixel = (uint16_t *)&in[(y * rowbytes) + (3 * sizeof(uint16_t) * x)];
157 float *out_pixel = &mipbuf[(size_t)4 * ((y * width) + x)];
158
159 /* max_channel_f is 255.0f for 8bit */
160 out_pixel[0] = ((float)in_pixel[0]) * (1.0f / max_channel_f);
161 out_pixel[1] = ((float)in_pixel[1]) * (1.0f / max_channel_f);
162 out_pixel[2] = ((float)in_pixel[2]) * (1.0f / max_channel_f);
163 out_pixel[3] = 0.0f; /* alpha */
164 }
165 }
166 break;
167 }
168 case 8: {
169 __OMP_PARALLEL_FOR_SIMD__(collapse(2))
170 for (size_t y = 0; y < height; y++)
171 {
172 for (size_t x = 0; x < width; x++)
173 {
174 uint8_t *in_pixel = (uint8_t *)&in[(y * rowbytes) + (3 * sizeof(uint8_t) * x)];
175 float *out_pixel = &mipbuf[(size_t)4 * ((y * width) + x)];
176
177 /* max_channel_f is 255.0f for 8bit */
178 out_pixel[0] = (float)(in_pixel[0]) * (1.0f / max_channel_f);
179 out_pixel[1] = (float)(in_pixel[1]) * (1.0f / max_channel_f);
180 out_pixel[2] = (float)(in_pixel[2]) * (1.0f / max_channel_f);
181 out_pixel[3] = 0.0f; /* alpha */
182 }
183 }
184 break;
185 }
186 default:
187 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] invalid bit depth for `%s'\n", filename);
189 goto out;
190 }
191
192 /* Get the ICC profile if available */
193 avifRWData *icc = &(avif->icc);
194 if(icc->size && icc->data)
195 {
196 img->profile = (uint8_t *)g_malloc0(icc->size);
197 memcpy(img->profile, icc->data, icc->size);
198 img->profile_size = icc->size;
199 }
200 ret = DT_IMAGEIO_OK;
201out:
202 avifRGBImageFreePixels(&rgb);
203 avifDecoderDestroy(decoder);
204
205 return ret;
206}
207
208int dt_imageio_avif_read_profile(const char *filename, uint8_t **out, dt_colorspaces_cicp_t *cicp)
209{
210 /* set default return values */
211 int size = 0;
212 *out = NULL;
213 cicp->color_primaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED;
214 cicp->transfer_characteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED;
215 cicp->matrix_coefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED;
216
217 avifDecoder *decoder = NULL;
218 avifImage avif_image = {0};
219 avifResult result;
220
221 decoder = avifDecoderCreate();
222 if(IS_NULL_PTR(decoder))
223 {
224 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] failed to create decoder for `%s'\n", filename);
225 goto out;
226 }
227
228 result = avifDecoderReadFile(decoder, &avif_image, filename);
229 if(result != AVIF_RESULT_OK)
230 {
231 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] failed to parse `%s': %s\n", filename, avifResultToString(result));
232 goto out;
233 }
234
235 if(avif_image.icc.size > 0)
236 {
237 avifRWData *icc = &avif_image.icc;
238
239 if(IS_NULL_PTR(icc->data)) goto out;
240
241 *out = (uint8_t *)g_malloc0(icc->size);
242 memcpy(*out, icc->data, icc->size);
243 size = icc->size;
244 }
245 else
246 {
247 cicp->color_primaries = avif_image.colorPrimaries;
248 cicp->transfer_characteristics = avif_image.transferCharacteristics;
249 cicp->matrix_coefficients = avif_image.matrixCoefficients;
250
251 /* fix up mistagged legacy AVIFs */
252 if(avif_image.colorPrimaries == AVIF_COLOR_PRIMARIES_BT709)
253 {
254 gboolean over = FALSE;
255
256 /* mistagged Rec. 709 AVIFs exported before dt 3.6 */
257 if(avif_image.transferCharacteristics == AVIF_TRANSFER_CHARACTERISTICS_BT470M
258 && avif_image.matrixCoefficients == AVIF_MATRIX_COEFFICIENTS_BT709)
259 {
260 /* must be actual Rec. 709 instead of 2.2 gamma*/
261 cicp->transfer_characteristics = AVIF_TRANSFER_CHARACTERISTICS_BT709;
262 over = TRUE;
263 }
264
265 if(over)
266 {
267 dt_print(DT_DEBUG_IMAGEIO, "[avif_open] overriding nclx color profile for `%s': 1/%d/%d to 1/%d/%d\n",
268 filename, avif_image.transferCharacteristics, avif_image.matrixCoefficients,
270 }
271 }
272 }
273
274out:
275 avifDecoderDestroy(decoder);
276
277 return size;
278}
279
280// clang-format off
281// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
282// vim: shiftwidth=2 expandtab tabstop=2 cindent
283// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
284// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
uint32_t bit_depth
Definition avif.c:97
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
@ IOP_CS_RGB
static dt_aligned_pixel_t rgb
const dt_colormatrix_t dt_aligned_pixel_t out
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
@ DT_DEBUG_IMAGEIO
Definition darktable.h:733
#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
@ TYPE_FLOAT
Definition format.h:46
dt_imageio_retval_t
Definition image.h:78
@ DT_IMAGEIO_OK
Definition image.h:79
@ DT_IMAGEIO_CACHE_FULL
Definition image.h:82
@ DT_IMAGEIO_FILE_CORRUPTED
Definition image.h:81
@ DT_IMAGE_HDR
Definition image.h:113
@ DT_IMAGE_LDR
Definition image.h:109
@ LOADER_AVIF
Definition image.h:233
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)
static const float x
void * dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img)
size_t size
Definition mipmap_cache.c:3
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:315
dt_image_loader_t loader
Definition image.h:335
int32_t flags
Definition image.h:319
int32_t width
Definition image.h:315
uint32_t profile_size
Definition image.h:341
dt_iop_buffer_dsc_t dsc
Definition image.h:337
uint8_t * profile
Definition image.h:340
uint32_t filters
Definition format.h:60
unsigned int channels
Definition format.h:54
dt_iop_buffer_type_t datatype
Definition format.h:56