diff options
author | thierry1970 <thierry@ordissimo.com> | 2021-02-06 15:45:42 +0000 |
---|---|---|
committer | Carsten Haitzler (Rasterman) <raster@rasterman.com> | 2021-02-06 18:58:04 +0000 |
commit | 97f95e736269fcdf5511077135ede9b37dd06854 (patch) | |
tree | 9f8f74e8bb9b6cd2341210ea5becd9c141a3c520 /src | |
parent | ec4ef6911591b0ce47616438dfd34626d9302537 (diff) |
Added the heif loader
Summary: that supports images : *.heif, *hiec and *.avif I have disabled *.avif images, there is already a loader.
Reviewers: stefan_schmidt, raster
Subscribers: raster, vtorri, cedric, #reviewers, #committers
Tags: #efl
Differential Revision: https://phab.enlightenment.org/D12135
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/evas/common/evas_image_load.c | 7 | ||||
-rw-r--r-- | src/lib/evas/file/evas_module.c | 4 | ||||
-rw-r--r-- | src/lib/evas/meson.build | 2 | ||||
-rw-r--r-- | src/modules/evas/image_loaders/heif/evas_image_load_heif.c | 300 | ||||
-rw-r--r-- | src/tests/evas/evas_test_image.c | 5 |
5 files changed, 317 insertions, 1 deletions
diff --git a/src/lib/evas/common/evas_image_load.c b/src/lib/evas/common/evas_image_load.c index 8ed04dda2e..797fae37ea 100644 --- a/src/lib/evas/common/evas_image_load.c +++ b/src/lib/evas/common/evas_image_load.c | |||
@@ -69,6 +69,10 @@ static const struct ext_loader_s loaders[] = | |||
69 | MATCHING(".avif", "avif"), | 69 | MATCHING(".avif", "avif"), |
70 | MATCHING(".avifs", "avif"), | 70 | MATCHING(".avifs", "avif"), |
71 | 71 | ||
72 | MATCHING(".heif", "heif"), | ||
73 | MATCHING(".heic", "heif"), | ||
74 | // MATCHING(".avif", "heif"), | ||
75 | |||
72 | /* xcf - gefenric */ | 76 | /* xcf - gefenric */ |
73 | MATCHING(".xcf", "generic"), | 77 | MATCHING(".xcf", "generic"), |
74 | MATCHING(".xcf.gz", "generic"), | 78 | MATCHING(".xcf.gz", "generic"), |
@@ -167,7 +171,8 @@ static const struct ext_loader_s loaders[] = | |||
167 | static const char *loaders_name[] = | 171 | static const char *loaders_name[] = |
168 | { /* in order of most likely needed */ | 172 | { /* in order of most likely needed */ |
169 | "png", "jpeg", "eet", "xpm", "tiff", "gif", "svg", "webp", "pmaps", | 173 | "png", "jpeg", "eet", "xpm", "tiff", "gif", "svg", "webp", "pmaps", |
170 | "bmp", "tga", "wbmp", "ico", "psd", "jp2k", "dds", "avif", "generic" | 174 | "bmp", "tga", "wbmp", "ico", "psd", "jp2k", "dds", "avif", "heif", |
175 | "generic" | ||
171 | }; | 176 | }; |
172 | 177 | ||
173 | struct evas_image_foreach_loader_data | 178 | struct evas_image_foreach_loader_data |
diff --git a/src/lib/evas/file/evas_module.c b/src/lib/evas/file/evas_module.c index 6292c1bb42..1362a004d8 100644 --- a/src/lib/evas/file/evas_module.c +++ b/src/lib/evas/file/evas_module.c | |||
@@ -202,6 +202,7 @@ EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, dds); | |||
202 | EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, eet); | 202 | EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, eet); |
203 | EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, generic); | 203 | EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, generic); |
204 | EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, gif); | 204 | EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, gif); |
205 | EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, heif); | ||
205 | EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, ico); | 206 | EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, ico); |
206 | EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, jpeg); | 207 | EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, jpeg); |
207 | EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, jp2k); | 208 | EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, jp2k); |
@@ -307,6 +308,9 @@ static const struct { | |||
307 | #ifdef EVAS_STATIC_BUILD_GIF | 308 | #ifdef EVAS_STATIC_BUILD_GIF |
308 | EVAS_EINA_STATIC_MODULE_USE(image_loader, gif), | 309 | EVAS_EINA_STATIC_MODULE_USE(image_loader, gif), |
309 | #endif | 310 | #endif |
311 | #ifdef EVAS_STATIC_BUILD_HEIF | ||
312 | EVAS_EINA_STATIC_MODULE_USE(image_loader, heif), | ||
313 | #endif | ||
310 | #ifdef EVAS_STATIC_BUILD_ICO | 314 | #ifdef EVAS_STATIC_BUILD_ICO |
311 | EVAS_EINA_STATIC_MODULE_USE(image_loader, ico), | 315 | EVAS_EINA_STATIC_MODULE_USE(image_loader, ico), |
312 | #endif | 316 | #endif |
diff --git a/src/lib/evas/meson.build b/src/lib/evas/meson.build index 8dcfd98713..1bf5fa0801 100644 --- a/src/lib/evas/meson.build +++ b/src/lib/evas/meson.build | |||
@@ -11,6 +11,7 @@ webp = dependency('libwebp', version: ['>=0.5.0'], required: get_option('evas-lo | |||
11 | webpdemux = dependency('libwebpdemux', version: ['>=0.5.0'], required: get_option('evas-loaders-disabler').contains('webp') == false) | 11 | webpdemux = dependency('libwebpdemux', version: ['>=0.5.0'], required: get_option('evas-loaders-disabler').contains('webp') == false) |
12 | libopenjp2 = dependency('libopenjp2', required: get_option('evas-loaders-disabler').contains('jp2k') == false) | 12 | libopenjp2 = dependency('libopenjp2', required: get_option('evas-loaders-disabler').contains('jp2k') == false) |
13 | libavif = dependency('libavif', required: get_option('evas-loaders-disabler').contains('avif') == false, version: '>= 0.8.2') | 13 | libavif = dependency('libavif', required: get_option('evas-loaders-disabler').contains('avif') == false, version: '>= 0.8.2') |
14 | heif= dependency('libheif', required: get_option('evas-loaders-disabler').contains('heif') == false) | ||
14 | 15 | ||
15 | evas_image_loaders_file = [ | 16 | evas_image_loaders_file = [ |
16 | ['avif', 'shared', [libavif]], | 17 | ['avif', 'shared', [libavif]], |
@@ -18,6 +19,7 @@ evas_image_loaders_file = [ | |||
18 | ['eet', 'static', [eet]], | 19 | ['eet', 'static', [eet]], |
19 | ['generic', 'shared', [rt]], | 20 | ['generic', 'shared', [rt]], |
20 | ['gif', 'shared', [giflib]], | 21 | ['gif', 'shared', [giflib]], |
22 | ['heif', 'shared', [heif]], | ||
21 | ['ico', 'shared', []], | 23 | ['ico', 'shared', []], |
22 | ['jpeg', 'static', [jpeg]], | 24 | ['jpeg', 'static', [jpeg]], |
23 | ['jp2k', 'shared', [libopenjp2]], | 25 | ['jp2k', 'shared', [libopenjp2]], |
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 new file mode 100644 index 0000000000..bc9f2a1e06 --- /dev/null +++ b/src/modules/evas/image_loaders/heif/evas_image_load_heif.c | |||
@@ -0,0 +1,300 @@ | |||
1 | #define _XOPEN_SOURCE 600 | ||
2 | |||
3 | #ifdef HAVE_CONFIG_H | ||
4 | # include <config.h> | ||
5 | #endif | ||
6 | |||
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> | ||
23 | |||
24 | #include "evas_common_private.h" | ||
25 | #include "evas_private.h" | ||
26 | |||
27 | static int _evas_loader_heif_log_dom = -1; | ||
28 | |||
29 | #ifdef ERR | ||
30 | # undef ERR | ||
31 | #endif | ||
32 | #define ERR(...) EINA_LOG_DOM_ERR(_evas_loader_heif_log_dom, __VA_ARGS__) | ||
33 | |||
34 | #ifdef INF | ||
35 | # undef INF | ||
36 | #endif | ||
37 | #define INF(...) EINA_LOG_DOM_INFO(_evas_loader_heif_log_dom, __VA_ARGS__) | ||
38 | |||
39 | |||
40 | static void * | ||
41 | evas_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 | |||
49 | static void | ||
50 | evas_image_load_file_close_heif(void *loader_data EINA_UNUSED) | ||
51 | { | ||
52 | } | ||
53 | |||
54 | static Eina_Bool | ||
55 | evas_image_load_file_head_heif(void *loader_data, | ||
56 | Emile_Image_Property *prop, | ||
57 | int *error) | ||
58 | { | ||
59 | Eina_File *f = loader_data; | ||
60 | void *map; | ||
61 | size_t length; | ||
62 | struct heif_error err; | ||
63 | struct heif_context* hc = NULL; | ||
64 | struct heif_image_handle* hdl = NULL; | ||
65 | struct heif_image* img = NULL; | ||
66 | Eina_Bool r = EINA_FALSE; | ||
67 | |||
68 | *error = EVAS_LOAD_ERROR_NONE; | ||
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; | ||
75 | prop->h = 0; | ||
76 | |||
77 | if (!map || length < 1) | ||
78 | { | ||
79 | *error = EVAS_LOAD_ERROR_CORRUPT_FILE; | ||
80 | goto on_error; | ||
81 | } | ||
82 | |||
83 | hc = heif_context_alloc(); | ||
84 | if (!hc) { | ||
85 | INF("cannot allocate heif_context"); | ||
86 | *error = EVAS_LOAD_ERROR_CORRUPT_FILE; | ||
87 | goto on_error; | ||
88 | } | ||
89 | |||
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 | |||
97 | err = heif_context_get_primary_image_handle(hc, &hdl); | ||
98 | if (err.code != heif_error_Ok) { | ||
99 | INF("%s", err.message); | ||
100 | *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; | ||
101 | goto on_error; | ||
102 | } | ||
103 | |||
104 | int has_alpha = heif_image_handle_has_alpha_channel(hdl); | ||
105 | |||
106 | err = heif_decode_image(hdl, &img, heif_colorspace_RGB, | ||
107 | has_alpha ? heif_chroma_interleaved_RGBA : heif_chroma_interleaved_RGB, | ||
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 | |||
115 | prop->w = heif_image_get_width(img, heif_channel_interleaved); | ||
116 | prop->h = heif_image_get_height(img, heif_channel_interleaved); | ||
117 | if (has_alpha != 3) | ||
118 | prop->alpha = 1; | ||
119 | |||
120 | r = EINA_TRUE; | ||
121 | |||
122 | on_error: | ||
123 | if (img) { | ||
124 | heif_image_release(img); | ||
125 | } | ||
126 | |||
127 | if (hdl) { | ||
128 | heif_image_handle_release(hdl); | ||
129 | } | ||
130 | |||
131 | if (hc) { | ||
132 | heif_context_free(hc); | ||
133 | } | ||
134 | eina_file_map_free(f, map); | ||
135 | return r; | ||
136 | } | ||
137 | |||
138 | static Eina_Bool | ||
139 | evas_image_load_file_data_heif(void *loader_data, | ||
140 | Emile_Image_Property *prop, | ||
141 | void *pixels, | ||
142 | int *error) | ||
143 | { | ||
144 | Eina_File *f = loader_data; | ||
145 | |||
146 | void *map; | ||
147 | size_t length; | ||
148 | struct heif_error err; | ||
149 | struct heif_context* hc = NULL; | ||
150 | struct heif_image_handle* hdl = NULL; | ||
151 | struct heif_image* img = NULL; | ||
152 | unsigned int x, y; | ||
153 | int stride, bps = 3; | ||
154 | const uint8_t* data; | ||
155 | uint8_t* dd = (uint8_t*)pixels, *ds = NULL; | ||
156 | Eina_Bool result = EINA_FALSE; | ||
157 | |||
158 | map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL); | ||
159 | length = eina_file_size_get(f); | ||
160 | *error = EVAS_LOAD_ERROR_CORRUPT_FILE; | ||
161 | if (!map || length < 1) | ||
162 | goto on_error; | ||
163 | |||
164 | *error = EVAS_LOAD_ERROR_GENERIC; | ||
165 | result = EINA_FALSE; | ||
166 | |||
167 | hc = heif_context_alloc(); | ||
168 | if (!hc) { | ||
169 | INF("cannot allocate heif_context"); | ||
170 | *error = EVAS_LOAD_ERROR_CORRUPT_FILE; | ||
171 | goto on_error; | ||
172 | } | ||
173 | |||
174 | err = heif_context_read_from_memory_without_copy(hc, map, length, NULL); | ||
175 | if (err.code != heif_error_Ok) { | ||
176 | INF("%s", err.message); | ||
177 | *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; | ||
178 | goto on_error; | ||
179 | } | ||
180 | |||
181 | err = heif_context_get_primary_image_handle(hc, &hdl); | ||
182 | if (err.code != heif_error_Ok) { | ||
183 | INF("%s", err.message); | ||
184 | *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; | ||
185 | goto on_error; | ||
186 | } | ||
187 | |||
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); | ||
198 | ds = (uint8_t*)data; | ||
199 | for (y = 0; y < prop->h; y++) | ||
200 | for (x = 0; x < prop->w; x++) | ||
201 | { | ||
202 | if (bps == 3) | ||
203 | { | ||
204 | dd[3] = 0xff; | ||
205 | dd[0] = ds[2]; | ||
206 | dd[1] = ds[1]; | ||
207 | dd[2] = ds[0]; | ||
208 | ds+=3; | ||
209 | dd+=4; | ||
210 | } | ||
211 | else | ||
212 | { | ||
213 | dd[0] = ds[2]; | ||
214 | dd[1] = ds[1]; | ||
215 | dd[2] = ds[0]; | ||
216 | dd[3] = ds[3]; | ||
217 | ds+=4; | ||
218 | dd+=4; | ||
219 | } | ||
220 | } | ||
221 | result = EINA_TRUE; | ||
222 | |||
223 | *error = EVAS_LOAD_ERROR_NONE; | ||
224 | prop->premul = EINA_TRUE; | ||
225 | |||
226 | on_error: | ||
227 | |||
228 | if (map) eina_file_map_free(f, map); | ||
229 | |||
230 | if (img) { | ||
231 | // Do not free the image here when we pass it to gdk-pixbuf, as its memory will still be used by gdk-pixbuf. | ||
232 | heif_image_release(img); | ||
233 | } | ||
234 | |||
235 | if (hdl) { | ||
236 | heif_image_handle_release(hdl); | ||
237 | } | ||
238 | |||
239 | if (hc) { | ||
240 | heif_context_free(hc); | ||
241 | } | ||
242 | |||
243 | return result; | ||
244 | } | ||
245 | |||
246 | static const Evas_Image_Load_Func evas_image_load_heif_func = { | ||
247 | EVAS_IMAGE_LOAD_VERSION, | ||
248 | evas_image_load_file_open_heif, | ||
249 | evas_image_load_file_close_heif, | ||
250 | (void*) evas_image_load_file_head_heif, | ||
251 | NULL, | ||
252 | (void*) evas_image_load_file_data_heif, | ||
253 | NULL, | ||
254 | EINA_TRUE, | ||
255 | EINA_FALSE | ||
256 | }; | ||
257 | |||
258 | static int | ||
259 | module_open(Evas_Module *em) | ||
260 | { | ||
261 | if (!em) return 0; | ||
262 | _evas_loader_heif_log_dom = eina_log_domain_register | ||
263 | ("evas-heif", EVAS_DEFAULT_LOG_COLOR); | ||
264 | if (_evas_loader_heif_log_dom < 0) | ||
265 | { | ||
266 | EINA_LOG_ERR("Can not create a module log domain."); | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | em->functions = (void *)(&evas_image_load_heif_func); | ||
271 | return 1; | ||
272 | } | ||
273 | |||
274 | static void | ||
275 | module_close(Evas_Module *em EINA_UNUSED) | ||
276 | { | ||
277 | if (_evas_loader_heif_log_dom >= 0) | ||
278 | { | ||
279 | eina_log_domain_unregister(_evas_loader_heif_log_dom); | ||
280 | _evas_loader_heif_log_dom = -1; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static Evas_Module_Api evas_modapi = | ||
285 | { | ||
286 | EVAS_MODULE_API_VERSION, | ||
287 | "heif", | ||
288 | "none", | ||
289 | { | ||
290 | module_open, | ||
291 | module_close | ||
292 | } | ||
293 | }; | ||
294 | |||
295 | EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, heif); | ||
296 | |||
297 | |||
298 | #ifndef EVAS_STATIC_BUILD_HEIF | ||
299 | EVAS_EINA_MODULE_DEFINE(image_loader, heif); | ||
300 | #endif | ||
diff --git a/src/tests/evas/evas_test_image.c b/src/tests/evas/evas_test_image.c index c2530632a3..5753651f30 100644 --- a/src/tests/evas/evas_test_image.c +++ b/src/tests/evas/evas_test_image.c | |||
@@ -53,6 +53,11 @@ static const char *exts[] = { | |||
53 | ,"jpeg" | 53 | ,"jpeg" |
54 | ,"jpg" | 54 | ,"jpg" |
55 | #endif | 55 | #endif |
56 | #ifdef BUILD_LOADER_HEIF | ||
57 | ,"heif" | ||
58 | ,"heic" | ||
59 | // ,"avif" | ||
60 | #endif | ||
56 | }; | 61 | }; |
57 | 62 | ||
58 | EFL_START_TEST(evas_object_image_loader) | 63 | EFL_START_TEST(evas_object_image_loader) |