summaryrefslogtreecommitdiff
path: root/src/modules
diff options
context:
space:
mode:
authorVincent Torri <vincent.torri@gmail.com>2021-04-09 21:09:05 +0100
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2021-04-09 21:09:05 +0100
commit77a3b908eda7323892b6c2b824a2ce638645b230 (patch)
tree4fd45bb603e9bb0033fed789d2e11a33dd33c2aa /src/modules
parent012d3cf7976b8aa26cad09eafcba211b9b960752 (diff)
improve heif loader: * efl coding style * faster head callback * faster copy of image data
Summary: and minor fix of some values in avif loader Test Plan: entice still can read heif Reviewers: raster Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12257
Diffstat (limited to 'src/modules')
-rw-r--r--src/modules/evas/image_loaders/avif/evas_image_load_avif.c4
-rw-r--r--src/modules/evas/image_loaders/heif/evas_image_load_heif.c434
2 files changed, 255 insertions, 183 deletions
diff --git a/src/modules/evas/image_loaders/avif/evas_image_load_avif.c b/src/modules/evas/image_loaders/avif/evas_image_load_avif.c
index e641473c89..e12690be8a 100644
--- a/src/modules/evas/image_loaders/avif/evas_image_load_avif.c
+++ b/src/modules/evas/image_loaders/avif/evas_image_load_avif.c
@@ -355,8 +355,8 @@ static Evas_Image_Load_Func evas_image_load_avif_func =
355 NULL, 355 NULL,
356 evas_image_load_file_data_avif, 356 evas_image_load_file_data_avif,
357 evas_image_load_frame_duration_avif, 357 evas_image_load_frame_duration_avif,
358 EINA_TRUE, 358 EINA_FALSE,
359 EINA_TRUE 359 EINA_FALSE
360}; 360};
361 361
362static int 362static int
diff --git a/src/modules/evas/image_loaders/heif/evas_image_load_heif.c b/src/modules/evas/image_loaders/heif/evas_image_load_heif.c
index bc9f2a1e06..a53ad3991c 100644
--- a/src/modules/evas/image_loaders/heif/evas_image_load_heif.c
+++ b/src/modules/evas/image_loaders/heif/evas_image_load_heif.c
@@ -1,28 +1,19 @@
1#define _XOPEN_SOURCE 600
2
3#ifdef HAVE_CONFIG_H 1#ifdef HAVE_CONFIG_H
4# include <config.h> 2# include <config.h>
5#endif 3#endif
6 4
7#include <stdlib.h>
8#include <stdio.h>
9#include <string.h>
10#include <errno.h>
11
12#include <math.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <unistd.h>
16#include <fcntl.h>
17
18#ifdef HAVE_NETINET_IN_H
19# include <netinet/in.h>
20#endif
21
22#include <libheif/heif.h> 5#include <libheif/heif.h>
23 6
7#include "Evas_Loader.h"
24#include "evas_common_private.h" 8#include "evas_common_private.h"
25#include "evas_private.h" 9
10typedef struct _Evas_Loader_Internal Evas_Loader_Internal;
11struct _Evas_Loader_Internal
12{
13 Eina_File *f;
14 Evas_Image_Load_Opts *opts;
15 struct heif_context* ctx;
16};
26 17
27static int _evas_loader_heif_log_dom = -1; 18static int _evas_loader_heif_log_dom = -1;
28 19
@@ -36,170 +27,159 @@ static int _evas_loader_heif_log_dom = -1;
36#endif 27#endif
37#define INF(...) EINA_LOG_DOM_INFO(_evas_loader_heif_log_dom, __VA_ARGS__) 28#define INF(...) EINA_LOG_DOM_INFO(_evas_loader_heif_log_dom, __VA_ARGS__)
38 29
39
40static void *
41evas_image_load_file_open_heif(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
42 Evas_Image_Load_Opts *opts EINA_UNUSED,
43 Evas_Image_Animated *animated EINA_UNUSED,
44 int *error EINA_UNUSED)
45{
46 return f;
47}
48
49static void
50evas_image_load_file_close_heif(void *loader_data EINA_UNUSED)
51{
52}
53
54static Eina_Bool 30static Eina_Bool
55evas_image_load_file_head_heif(void *loader_data, 31evas_image_load_file_head_heif_internal(Evas_Loader_Internal *loader EINA_UNUSED,
56 Emile_Image_Property *prop, 32 Emile_Image_Property *prop,
57 int *error) 33 void *map, size_t length,
34 int *error)
58{ 35{
59 Eina_File *f = loader_data; 36 struct heif_context *ctx;
60 void *map; 37 struct heif_image_handle *handle;
61 size_t length;
62 struct heif_error err; 38 struct heif_error err;
63 struct heif_context* hc = NULL; 39 Eina_Bool ret;
64 struct heif_image_handle* hdl = NULL;
65 struct heif_image* img = NULL;
66 Eina_Bool r = EINA_FALSE;
67 40
68 *error = EVAS_LOAD_ERROR_NONE; 41 ret = EINA_FALSE;
69
70 map = eina_file_map_all(f, EINA_FILE_RANDOM);
71 length = eina_file_size_get(f);
72
73 // init prop struct with some default null values
74 prop->w = 0; 42 prop->w = 0;
75 prop->h = 0; 43 prop->h = 0;
44 prop->alpha = EINA_FALSE;
76 45
77 if (!map || length < 1) 46 /* heif file must have a 12 bytes long header */
47 if ((length < 12) ||
48 (heif_check_filetype(map, length) == heif_filetype_no))
78 { 49 {
79 *error = EVAS_LOAD_ERROR_CORRUPT_FILE; 50 INF("HEIF header invalid");
80 goto on_error; 51 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
52 return ret;
81 } 53 }
82 54
83 hc = heif_context_alloc(); 55 ctx = heif_context_alloc();
84 if (!hc) { 56 if (!ctx)
85 INF("cannot allocate heif_context"); 57 {
86 *error = EVAS_LOAD_ERROR_CORRUPT_FILE; 58 INF("cannot allocate heif_context");
87 goto on_error; 59 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
88 } 60 return ret;
89 61 }
90 err = heif_context_read_from_memory_without_copy(hc, map, length, NULL);
91 if (err.code != heif_error_Ok) {
92 INF("%s", err.message);
93 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
94 goto on_error;
95 }
96 62
97 err = heif_context_get_primary_image_handle(hc, &hdl); 63 err = heif_context_read_from_memory_without_copy(ctx, map, length, NULL);
98 if (err.code != heif_error_Ok) { 64 if (err.code != heif_error_Ok)
99 INF("%s", err.message); 65 {
100 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; 66 INF("%s", err.message);
101 goto on_error; 67 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
68 goto free_ctx;
102 } 69 }
103 70
104 int has_alpha = heif_image_handle_has_alpha_channel(hdl); 71 err = heif_context_get_primary_image_handle(ctx, &handle);
72 if (err.code != heif_error_Ok)
73 {
74 INF("%s", err.message);
75 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
76 goto free_ctx;
77 }
105 78
106 err = heif_decode_image(hdl, &img, heif_colorspace_RGB, 79 prop->w = heif_image_handle_get_width(handle);
107 has_alpha ? heif_chroma_interleaved_RGBA : heif_chroma_interleaved_RGB, 80 prop->h = heif_image_handle_get_height(handle);
108 NULL);
109 if (err.code != heif_error_Ok) {
110 INF("%s", err.message);
111 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
112 goto on_error;
113 }
114 81
115 prop->w = heif_image_get_width(img, heif_channel_interleaved); 82 /* if size is invalid, we exit */
116 prop->h = heif_image_get_height(img, heif_channel_interleaved); 83 if ((prop->w < 1) || (prop->h < 1) ||
117 if (has_alpha != 3) 84 (prop->w > IMG_MAX_SIZE) || (prop->h > IMG_MAX_SIZE) ||
118 prop->alpha = 1; 85 IMG_TOO_BIG(prop->w, prop->h))
86 {
87 if (IMG_TOO_BIG(prop->w, prop->h))
88 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
89 else
90 *error= EVAS_LOAD_ERROR_GENERIC;
91 goto release_handle;
92 }
119 93
120 r = EINA_TRUE; 94 prop->alpha = !!heif_image_handle_has_alpha_channel(handle);
121 95
122 on_error: 96 *error = EVAS_LOAD_ERROR_NONE;
123 if (img) { 97 ret = EINA_TRUE;
124 heif_image_release(img);
125 }
126 98
127 if (hdl) { 99 release_handle:
128 heif_image_handle_release(hdl); 100 heif_image_handle_release(handle);
129 } 101 free_ctx:
102 heif_context_free(ctx);
130 103
131 if (hc) { 104 return ret;
132 heif_context_free(hc);
133 }
134 eina_file_map_free(f, map);
135 return r;
136} 105}
137 106
138static Eina_Bool 107static Eina_Bool
139evas_image_load_file_data_heif(void *loader_data, 108evas_image_load_file_data_heif_internal(Evas_Loader_Internal *loader,
140 Emile_Image_Property *prop, 109 Emile_Image_Property *prop,
141 void *pixels, 110 void *pixels,
142 int *error) 111 void *map, size_t length,
112 int *error)
143{ 113{
144 Eina_File *f = loader_data; 114 struct heif_context *ctx;
145 115 struct heif_image_handle *handle;
146 void *map; 116 struct heif_image *img;
147 size_t length;
148 struct heif_error err; 117 struct heif_error err;
149 struct heif_context* hc = NULL; 118 const unsigned char *data;
150 struct heif_image_handle* hdl = NULL; 119 unsigned char *dd;
151 struct heif_image* img = NULL; 120 unsigned char *ds;
152 unsigned int x, y; 121 int stride;
153 int stride, bps = 3; 122 unsigned int x;
154 const uint8_t* data; 123 unsigned int y;
155 uint8_t* dd = (uint8_t*)pixels, *ds = NULL; 124 Eina_Bool ret;
156 Eina_Bool result = EINA_FALSE; 125
157 126 ret = EINA_FALSE;
158 map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL); 127
159 length = eina_file_size_get(f); 128 ctx = loader->ctx;
160 *error = EVAS_LOAD_ERROR_CORRUPT_FILE; 129 if (!ctx)
161 if (!map || length < 1) 130 {
162 goto on_error; 131 ctx = heif_context_alloc();
163 132 if (!ctx)
164 *error = EVAS_LOAD_ERROR_GENERIC; 133 {
165 result = EINA_FALSE; 134 INF("cannot allocate heif_context");
166 135 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
167 hc = heif_context_alloc(); 136 return ret;
168 if (!hc) { 137 }
169 INF("cannot allocate heif_context"); 138
170 *error = EVAS_LOAD_ERROR_CORRUPT_FILE; 139 err = heif_context_read_from_memory_without_copy(ctx,
171 goto on_error; 140 map, length, NULL);
172 } 141 if (err.code != heif_error_Ok)
142 {
143 INF("%s", err.message);
144 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
145 heif_context_free(ctx);
146 return ret;
147 }
148
149 err = heif_context_get_primary_image_handle(ctx, &handle);
150 if (err.code != heif_error_Ok)
151 {
152 INF("%s", err.message);
153 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
154 heif_image_handle_release(handle);
155 heif_context_free(ctx);
156 return ret;
157 }
158
159 loader->ctx = ctx;
160 }
173 161
174 err = heif_context_read_from_memory_without_copy(hc, map, length, NULL); 162 err = heif_decode_image(handle, &img, heif_colorspace_RGB,
175 if (err.code != heif_error_Ok) { 163 prop->alpha ? heif_chroma_interleaved_RGBA
176 INF("%s", err.message); 164 : heif_chroma_interleaved_RGB,
177 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; 165 NULL);
178 goto on_error;
179 }
180 166
181 err = heif_context_get_primary_image_handle(hc, &hdl); 167 if (err.code != heif_error_Ok)
182 if (err.code != heif_error_Ok) { 168 {
183 INF("%s", err.message); 169 INF("%s", err.message);
184 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; 170 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
185 goto on_error; 171 goto on_error;
186 } 172 }
187 173
188 err = heif_decode_image(hdl, &img, heif_colorspace_RGB,
189 prop->alpha ? heif_chroma_interleaved_RGBA : heif_chroma_interleaved_RGB,
190 NULL);
191 if (err.code != heif_error_Ok) {
192 INF("%s", err.message);
193 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
194 goto on_error;
195 }
196 if (prop->alpha) bps = 4;
197 data = heif_image_get_plane_readonly(img, heif_channel_interleaved, &stride); 174 data = heif_image_get_plane_readonly(img, heif_channel_interleaved, &stride);
198 ds = (uint8_t*)data; 175
199 for (y = 0; y < prop->h; y++) 176 dd = (unsigned char *)pixels;
200 for (x = 0; x < prop->w; x++) 177 ds = (unsigned char *)data;
201 { 178 if (!prop->alpha)
202 if (bps == 3) 179 {
180 for (y = 0; y < prop->h; y++)
181 {
182 for (x = 0; x < prop->w; x++)
203 { 183 {
204 dd[3] = 0xff; 184 dd[3] = 0xff;
205 dd[0] = ds[2]; 185 dd[0] = ds[2];
@@ -208,7 +188,13 @@ evas_image_load_file_data_heif(void *loader_data,
208 ds+=3; 188 ds+=3;
209 dd+=4; 189 dd+=4;
210 } 190 }
211 else 191 }
192 }
193 else
194 {
195 for (y = 0; y < prop->h; y++)
196 {
197 for (x = 0; x < prop->w; x++)
212 { 198 {
213 dd[0] = ds[2]; 199 dd[0] = ds[2];
214 dd[1] = ds[1]; 200 dd[1] = ds[1];
@@ -217,50 +203,135 @@ evas_image_load_file_data_heif(void *loader_data,
217 ds+=4; 203 ds+=4;
218 dd+=4; 204 dd+=4;
219 } 205 }
220 } 206 }
221 result = EINA_TRUE; 207 }
208
209 ret = EINA_TRUE;
222 210
223 *error = EVAS_LOAD_ERROR_NONE; 211 *error = EVAS_LOAD_ERROR_NONE;
224 prop->premul = EINA_TRUE; 212 prop->premul = EINA_TRUE;
225 213
226on_error: 214 on_error:
215 return ret;
216}
227 217
228 if (map) eina_file_map_free(f, map);
229 218
230 if (img) { 219static void *
231 // Do not free the image here when we pass it to gdk-pixbuf, as its memory will still be used by gdk-pixbuf. 220evas_image_load_file_open_heif(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
232 heif_image_release(img); 221 Evas_Image_Load_Opts *opts,
233 } 222 Evas_Image_Animated *animated EINA_UNUSED,
223 int *error)
224{
225 Evas_Loader_Internal *loader;
234 226
235 if (hdl) { 227 loader = calloc(1, sizeof (Evas_Loader_Internal));
236 heif_image_handle_release(hdl); 228 if (!loader)
237 } 229 {
230 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
231 return NULL;
232 }
238 233
239 if (hc) { 234 loader->f = f;
240 heif_context_free(hc); 235 loader->opts = opts;
241 }
242 236
243 return result; 237 return loader;
238}
239
240static void
241evas_image_load_file_close_heif(void *loader_data)
242{
243 Evas_Loader_Internal *loader;
244
245 loader = loader_data;
246 /*
247 * in case _head() fails (because the file is not an heif one),
248 * loader is not filled and loader->ctx is NULL
249 */
250 if (loader->ctx)
251 heif_context_free(loader->ctx);
252 free(loader_data);
253}
254
255static Eina_Bool
256evas_image_load_file_head_heif(void *loader_data,
257 Evas_Image_Property *prop,
258 int *error)
259{
260 Evas_Loader_Internal *loader = loader_data;
261 Eina_File *f;
262 void *map;
263 Eina_Bool val;
264
265 f = loader->f;
266
267 map = eina_file_map_all(f, EINA_FILE_RANDOM);
268 if (!map)
269 {
270 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
271 return EINA_FALSE;
272 }
273
274 val = evas_image_load_file_head_heif_internal(loader,
275 (Emile_Image_Property *)prop,
276 map, eina_file_size_get(f),
277 error);
278
279 eina_file_map_free(f, map);
280
281 return val;
282}
283
284static Eina_Bool
285evas_image_load_file_data_heif(void *loader_data,
286 Evas_Image_Property *prop,
287 void *pixels,
288 int *error)
289{
290 Evas_Loader_Internal *loader;
291 Eina_File *f;
292 void *map;
293 Eina_Bool val = EINA_FALSE;
294
295 loader = (Evas_Loader_Internal *)loader_data;
296 f = loader->f;
297
298 map = eina_file_map_all(f, EINA_FILE_WILLNEED);
299 if (!map)
300 {
301 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
302 goto on_error;
303 }
304
305 val = evas_image_load_file_data_heif_internal(loader,
306 (Emile_Image_Property *)prop,
307 pixels,
308 map, eina_file_size_get(f),
309 error);
310
311 eina_file_map_free(f, map);
312
313 on_error:
314 return val;
244} 315}
245 316
246static const Evas_Image_Load_Func evas_image_load_heif_func = { 317static const Evas_Image_Load_Func evas_image_load_heif_func = {
247 EVAS_IMAGE_LOAD_VERSION, 318 EVAS_IMAGE_LOAD_VERSION,
248 evas_image_load_file_open_heif, 319 evas_image_load_file_open_heif,
249 evas_image_load_file_close_heif, 320 evas_image_load_file_close_heif,
250 (void*) evas_image_load_file_head_heif, 321 evas_image_load_file_head_heif,
251 NULL, 322 NULL,
252 (void*) evas_image_load_file_data_heif, 323 evas_image_load_file_data_heif,
253 NULL, 324 NULL,
254 EINA_TRUE, 325 EINA_FALSE,
255 EINA_FALSE 326 EINA_FALSE
256}; 327};
257 328
258static int 329static int
259module_open(Evas_Module *em) 330module_open(Evas_Module *em)
260{ 331{
261 if (!em) return 0; 332 if (!em) return 0;
262 _evas_loader_heif_log_dom = eina_log_domain_register 333
263 ("evas-heif", EVAS_DEFAULT_LOG_COLOR); 334 _evas_loader_heif_log_dom = eina_log_domain_register("evas-heif", EVAS_DEFAULT_LOG_COLOR);
264 if (_evas_loader_heif_log_dom < 0) 335 if (_evas_loader_heif_log_dom < 0)
265 { 336 {
266 EINA_LOG_ERR("Can not create a module log domain."); 337 EINA_LOG_ERR("Can not create a module log domain.");
@@ -268,6 +339,7 @@ module_open(Evas_Module *em)
268 } 339 }
269 340
270 em->functions = (void *)(&evas_image_load_heif_func); 341 em->functions = (void *)(&evas_image_load_heif_func);
342
271 return 1; 343 return 1;
272} 344}
273 345