summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorthierry1970 <thierry@ordissimo.com>2021-02-06 15:45:42 +0000
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2021-02-06 18:58:04 +0000
commit97f95e736269fcdf5511077135ede9b37dd06854 (patch)
tree9f8f74e8bb9b6cd2341210ea5becd9c141a3c520 /src
parentec4ef6911591b0ce47616438dfd34626d9302537 (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.c7
-rw-r--r--src/lib/evas/file/evas_module.c4
-rw-r--r--src/lib/evas/meson.build2
-rw-r--r--src/modules/evas/image_loaders/heif/evas_image_load_heif.c300
-rw-r--r--src/tests/evas/evas_test_image.c5
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[] =
167static const char *loaders_name[] = 171static 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
173struct evas_image_foreach_loader_data 178struct 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);
202EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, eet); 202EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, eet);
203EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, generic); 203EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, generic);
204EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, gif); 204EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, gif);
205EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, heif);
205EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, ico); 206EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, ico);
206EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, jpeg); 207EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, jpeg);
207EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, jp2k); 208EVAS_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
11webpdemux = dependency('libwebpdemux', version: ['>=0.5.0'], required: get_option('evas-loaders-disabler').contains('webp') == false) 11webpdemux = dependency('libwebpdemux', version: ['>=0.5.0'], required: get_option('evas-loaders-disabler').contains('webp') == false)
12libopenjp2 = dependency('libopenjp2', required: get_option('evas-loaders-disabler').contains('jp2k') == false) 12libopenjp2 = dependency('libopenjp2', required: get_option('evas-loaders-disabler').contains('jp2k') == false)
13libavif = dependency('libavif', required: get_option('evas-loaders-disabler').contains('avif') == false, version: '>= 0.8.2') 13libavif = dependency('libavif', required: get_option('evas-loaders-disabler').contains('avif') == false, version: '>= 0.8.2')
14heif= dependency('libheif', required: get_option('evas-loaders-disabler').contains('heif') == false)
14 15
15evas_image_loaders_file = [ 16evas_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
27static 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
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
55evas_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
138static Eina_Bool
139evas_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
226on_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
246static 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
258static int
259module_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
274static void
275module_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
284static 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
295EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, heif);
296
297
298#ifndef EVAS_STATIC_BUILD_HEIF
299EVAS_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
58EFL_START_TEST(evas_object_image_loader) 63EFL_START_TEST(evas_object_image_loader)