summaryrefslogtreecommitdiff
path: root/src/modules/evas
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/modules/evas
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/modules/evas')
-rw-r--r--src/modules/evas/image_loaders/heif/evas_image_load_heif.c300
1 files changed, 300 insertions, 0 deletions
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