1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <stdio.h>
6
7 #include <avif/avif.h>
8
9 #include "Evas_Loader.h"
10 #include "evas_common_private.h"
11
12 typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
13 struct _Evas_Loader_Internal
14 {
15 Eina_File *f;
16 Evas_Image_Load_Opts *opts;
17 Evas_Image_Animated *animated;
18 avifDecoder *decoder;
19 double duration;
20 };
21
22 static int _evas_loader_avif_log_dom = -1;
23
24 #ifdef ERR
25 # undef ERR
26 #endif
27 #define ERR(...) EINA_LOG_DOM_ERR(_evas_loader_avif_log_dom, __VA_ARGS__)
28
29 #ifdef WRN
30 # undef WRN
31 #endif
32 #define WRN(...) EINA_LOG_DOM_WARN(_evas_loader_avif_log_dom, __VA_ARGS__)
33
34 #ifdef INF
35 # undef INF
36 #endif
37 #define INF(...) EINA_LOG_DOM_INFO(_evas_loader_avif_log_dom, __VA_ARGS__)
38
39 static Eina_Bool
evas_image_load_file_head_avif_internal(Evas_Loader_Internal * loader,Emile_Image_Property * prop,void * map,size_t length,int * error)40 evas_image_load_file_head_avif_internal(Evas_Loader_Internal *loader,
41 Emile_Image_Property *prop,
42 void *map, size_t length,
43 int *error)
44 {
45 Evas_Image_Animated *animated;
46 avifROData raw;
47 avifDecoder *decoder;
48 avifResult res;
49 Eina_Bool ret;
50
51 animated = loader->animated;
52
53 ret = EINA_FALSE;
54 prop->w = 0;
55 prop->h = 0;
56 prop->alpha = EINA_FALSE;
57
58 raw.size = length;
59 raw.data = (const uint8_t *)map;
60
61 decoder = avifDecoderCreate();
62 if (!decoder)
63 {
64 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
65 return ret;
66 }
67
68 res = avifDecoderParse(decoder, &raw);
69 if (res != AVIF_RESULT_OK)
70 {
71 ERR("avif file format invalid");
72 *error = EVAS_LOAD_ERROR_GENERIC;
73 goto destroy_decoder;
74 }
75
76 if (decoder->imageCount < 1)
77 {
78 ERR("avif file format invalid");
79 *error = EVAS_LOAD_ERROR_GENERIC;
80 goto destroy_decoder;
81 }
82
83 res = avifDecoderNextImage(decoder);
84 if (res != AVIF_RESULT_OK)
85 {
86 ERR("avif file format invalid");
87 *error = EVAS_LOAD_ERROR_GENERIC;
88 goto destroy_decoder;
89 }
90
91 prop->w = decoder->image->width;
92 prop->h = decoder->image->height;
93
94 /* if size is invalid, we exit */
95 if ((prop->w < 1) || (prop->h < 1) ||
96 (prop->w > IMG_MAX_SIZE) || (prop->h > IMG_MAX_SIZE) ||
97 IMG_TOO_BIG(prop->w, prop->h))
98 {
99 if (IMG_TOO_BIG(prop->w, prop->h))
100 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
101 else
102 *error= EVAS_LOAD_ERROR_GENERIC;
103 goto destroy_decoder;
104 }
105
106 prop->alpha = !!decoder->image->alphaPlane;
107
108 if (decoder->imageCount > 1)
109 {
110 animated->loop_hint = EVAS_IMAGE_ANIMATED_HINT_NONE;
111 animated->frame_count = decoder->imageCount;
112 animated->loop_count = 1;
113 animated->animated = EINA_TRUE;
114 loader->duration = decoder->duration / decoder->imageCount;
115 }
116
117 *error = EVAS_LOAD_ERROR_NONE;
118 ret = EINA_TRUE;
119
120 destroy_decoder:
121 avifDecoderDestroy(decoder);
122
123 return ret;
124 }
125
126 static Eina_Bool
evas_image_load_file_data_avif_internal(Evas_Loader_Internal * loader,void * pixels,void * map,size_t length,int * error)127 evas_image_load_file_data_avif_internal(Evas_Loader_Internal *loader,
128 void *pixels,
129 void *map, size_t length,
130 int *error)
131 {
132 avifRGBImage rgb;
133 avifDecoder *decoder;
134 avifResult res;
135 Evas_Image_Animated *animated;
136 Eina_Bool ret;
137
138 ret = EINA_FALSE;
139
140 /* FIXME: create decoder in evas_image_load_file_data_avif instead ? */
141 decoder = loader->decoder;
142 if (!decoder)
143 {
144 avifROData raw;
145 decoder = avifDecoderCreate();
146 if (!decoder)
147 {
148 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
149 return EINA_FALSE;
150 }
151
152 raw.size = length;
153 raw.data = (const uint8_t *)map;
154
155 res = avifDecoderParse(decoder, &raw);
156 if (res != AVIF_RESULT_OK)
157 {
158 *error = EVAS_LOAD_ERROR_GENERIC;
159 goto on_error;
160 }
161
162 loader->decoder = decoder;
163 }
164
165 animated = loader->animated;
166 if (animated->animated)
167 {
168 /* FIXME: next image instead ? */
169 res = avifDecoderNthImage(decoder, animated->cur_frame + 1);
170 if (res != AVIF_RESULT_OK)
171 {
172 *error = EVAS_LOAD_ERROR_GENERIC;
173 goto on_error;
174 }
175 }
176 else
177 {
178 res = avifDecoderNextImage(decoder);
179 if (res != AVIF_RESULT_OK)
180 {
181 *error = EVAS_LOAD_ERROR_GENERIC;
182 goto on_error;
183 }
184 }
185
186 avifRGBImageSetDefaults(&rgb, decoder->image);
187 #ifdef WORDS_BIGENDIAN
188 rgb.format = AVIF_RGB_FORMAT_ARGB;
189 #else
190 rgb.format = AVIF_RGB_FORMAT_BGRA;
191 #endif
192 rgb.depth = 8;
193 rgb.pixels = pixels;
194 rgb.rowBytes = 4 * decoder->image->width;
195
196 avifImageYUVToRGB(decoder->image, &rgb);
197
198 *error = EVAS_LOAD_ERROR_NONE;
199
200 ret = EINA_TRUE;
201
202 on_error:
203
204 return ret;
205 }
206
207 static void *
evas_image_load_file_open_avif(Eina_File * f,Eina_Stringshare * key EINA_UNUSED,Evas_Image_Load_Opts * opts,Evas_Image_Animated * animated,int * error)208 evas_image_load_file_open_avif(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
209 Evas_Image_Load_Opts *opts,
210 Evas_Image_Animated *animated,
211 int *error)
212 {
213 Evas_Loader_Internal *loader;
214
215 loader = calloc(1, sizeof (Evas_Loader_Internal));
216 if (!loader)
217 {
218 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
219 return NULL;
220 }
221
222 loader->f = f;
223 loader->opts = opts;
224 loader->animated = animated;
225
226 return loader;
227 }
228
229 static void
evas_image_load_file_close_avif(void * loader_data)230 evas_image_load_file_close_avif(void *loader_data)
231 {
232 Evas_Loader_Internal *loader;
233
234 loader = loader_data;
235 avifDecoderDestroy(loader->decoder);
236 free(loader_data);
237 }
238
239 static Eina_Bool
evas_image_load_file_head_avif(void * loader_data,Evas_Image_Property * prop,int * error)240 evas_image_load_file_head_avif(void *loader_data,
241 Evas_Image_Property *prop,
242 int *error)
243 {
244 Evas_Loader_Internal *loader = loader_data;
245 Eina_File *f;
246 void *map;
247 Eina_Bool val;
248
249 f = loader->f;
250
251 map = eina_file_map_all(f, EINA_FILE_RANDOM);
252 if (!map)
253 {
254 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
255 return EINA_FALSE;
256 }
257
258 val = evas_image_load_file_head_avif_internal(loader,
259 (Emile_Image_Property *)prop,
260 map, eina_file_size_get(f),
261 error);
262
263 eina_file_map_free(f, map);
264
265 return val;
266 }
267
268 static Eina_Bool
evas_image_load_file_data_avif(void * loader_data,Evas_Image_Property * prop EINA_UNUSED,void * pixels,int * error)269 evas_image_load_file_data_avif(void *loader_data,
270 Evas_Image_Property *prop EINA_UNUSED,
271 void *pixels,
272 int *error)
273 {
274 Evas_Loader_Internal *loader;
275 Eina_File *f;
276 void *map;
277 Eina_Bool val = EINA_FALSE;
278
279 loader = (Evas_Loader_Internal *)loader_data;
280 f = loader->f;
281
282 map = eina_file_map_all(f, EINA_FILE_WILLNEED);
283 if (!map)
284 {
285 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
286 goto on_error;
287 }
288
289 val = evas_image_load_file_data_avif_internal(loader,
290 pixels,
291 map, eina_file_size_get(f),
292 error);
293
294 eina_file_map_free(f, map);
295
296 on_error:
297 return val;
298 }
299
300 static double
evas_image_load_frame_duration_avif(void * loader_data,int start_frame,int frame_num)301 evas_image_load_frame_duration_avif(void *loader_data,
302 int start_frame,
303 int frame_num)
304 {
305 Evas_Loader_Internal *loader;
306 Evas_Image_Animated *animated;
307
308 loader = (Evas_Loader_Internal *)loader_data;
309 animated = loader->animated;
310
311 if (!animated->animated)
312 return -1.0;
313
314 if (frame_num < 0)
315 return -1.0;
316
317 if ((start_frame + frame_num) > animated->frame_count)
318 return -1.0;
319
320 if (frame_num < 1)
321 frame_num = 1;
322
323 return loader->duration;
324 }
325
326 static Evas_Image_Load_Func evas_image_load_avif_func =
327 {
328 EVAS_IMAGE_LOAD_VERSION,
329 evas_image_load_file_open_avif,
330 evas_image_load_file_close_avif,
331 evas_image_load_file_head_avif,
332 NULL,
333 evas_image_load_file_data_avif,
334 evas_image_load_frame_duration_avif,
335 EINA_TRUE,
336 EINA_TRUE
337 };
338
339 static int
module_open(Evas_Module * em)340 module_open(Evas_Module *em)
341 {
342 if (!em) return 0;
343
344 _evas_loader_avif_log_dom = eina_log_domain_register("evas-avif", EINA_COLOR_BLUE);
345 if (_evas_loader_avif_log_dom < 0)
346 {
347 EINA_LOG_ERR("Can not create a module log domain.");
348 return 0;
349 }
350
351 em->functions = (void *)(&evas_image_load_avif_func);
352
353 return 1;
354 }
355
356 static void
module_close(Evas_Module * em EINA_UNUSED)357 module_close(Evas_Module *em EINA_UNUSED)
358 {
359 if (_evas_loader_avif_log_dom >= 0)
360 {
361 eina_log_domain_unregister(_evas_loader_avif_log_dom);
362 _evas_loader_avif_log_dom = -1;
363 }
364 }
365
366 static Evas_Module_Api evas_modapi =
367 {
368 EVAS_MODULE_API_VERSION,
369 "avif",
370 "none",
371 {
372 module_open,
373 module_close
374 }
375 };
376
377 EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, avif);
378
379 #ifndef EVAS_STATIC_BUILD_AVIF
380 EVAS_EINA_MODULE_DEFINE(image_loader, avif);
381 #endif
382
383