summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTaehyub Kim <taehyub.kim@samsung.com>2020-05-29 11:40:37 +0900
committerHermet Park <chuneon.park@samsung.com>2020-05-29 11:40:37 +0900
commitdf06418b6f39f3b8d73631bda33308b67736bb9d (patch)
tree956a06a4a860168cf9462204b9cd356d84dc9614
parentf88494aa2c2f7ad6edb9da5d626b9042db86f6c9 (diff)
Support WebP Animation Image Files
Summary: Support WebP Animate Format Imaeg Files. To support webp animation, apply webp animation decoder. Test Plan: 1. compile src/exmaple/elementary/image_webp_example_01.c and 02.c 2. run the samples Reviewers: Hermet, kimcinoo, jsuya, bu5hm4n Reviewed By: Hermet, kimcinoo, jsuya Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D11876
-rwxr-xr-xdata/elementary/images/animated_webp_image.webpbin0 -> 4764 bytes
-rw-r--r--data/elementary/images/static_webp_image.webpbin0 -> 10474 bytes
-rw-r--r--src/examples/elementary/image_webp_example_01.c38
-rw-r--r--src/examples/elementary/image_webp_example_02.c41
-rw-r--r--src/examples/elementary/meson.build2
-rw-r--r--src/lib/evas/meson.build3
-rw-r--r--src/modules/evas/image_loaders/webp/evas_image_load_webp.c257
7 files changed, 307 insertions, 34 deletions
diff --git a/data/elementary/images/animated_webp_image.webp b/data/elementary/images/animated_webp_image.webp
new file mode 100755
index 0000000000..5b44046e2c
--- /dev/null
+++ b/data/elementary/images/animated_webp_image.webp
Binary files differ
diff --git a/data/elementary/images/static_webp_image.webp b/data/elementary/images/static_webp_image.webp
new file mode 100644
index 0000000000..0da983e2ce
--- /dev/null
+++ b/data/elementary/images/static_webp_image.webp
Binary files differ
diff --git a/src/examples/elementary/image_webp_example_01.c b/src/examples/elementary/image_webp_example_01.c
new file mode 100644
index 0000000000..24bc79ae72
--- /dev/null
+++ b/src/examples/elementary/image_webp_example_01.c
@@ -0,0 +1,38 @@
1//Compile with:
2//gcc -g image_webp_example_01.c -o image_webp_example_01 `pkg-config --cflags --libs elementary`
3
4#include <Elementary.h>
5
6int
7elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
8{
9 Evas_Object *win, *image;
10 char buf[PATH_MAX];
11
12 elm_app_info_set(elm_main, "elementary", "images/static_webp_image.webp");
13 elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
14
15 win = elm_win_util_standard_add("WebP Image", "WebP Image");
16 elm_win_autodel_set(win, EINA_TRUE);
17
18 snprintf(buf, sizeof(buf), "%s/images/static_webp_image.webp", elm_app_data_dir_get());
19
20 image = elm_image_add(win);
21 if (!elm_image_file_set(image, buf, NULL))
22 {
23 printf("error: could not load image \"%s\"\n", buf);
24 return -1;
25 }
26
27 evas_object_size_hint_weight_set(image, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
28 elm_win_resize_object_add(win, image);
29 evas_object_show(image);
30
31 evas_object_resize(win, 320, 320);
32 evas_object_show(win);
33
34 elm_run();
35
36 return 0;
37}
38ELM_MAIN()
diff --git a/src/examples/elementary/image_webp_example_02.c b/src/examples/elementary/image_webp_example_02.c
new file mode 100644
index 0000000000..3bfaf4a71c
--- /dev/null
+++ b/src/examples/elementary/image_webp_example_02.c
@@ -0,0 +1,41 @@
1//Compile with:
2//gcc -g image_webp_example_02.c -o image_webp_example_02 `pkg-config --cflags --libs elementary`
3
4#include <Elementary.h>
5
6int
7elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
8{
9 Evas_Object *win, *image;
10 char buf[PATH_MAX];
11
12 elm_app_info_set(elm_main, "elementary", "images/animated_webp_image.webp");
13 elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
14
15 win = elm_win_util_standard_add("WebP Image", "WebP Image");
16 elm_win_autodel_set(win, EINA_TRUE);
17
18 snprintf(buf, sizeof(buf), "%s/images/animated_webp_image.webp", elm_app_data_dir_get());
19
20 image = elm_image_add(win);
21 if (!elm_image_file_set(image, buf, NULL))
22 {
23 printf("error: could not load image \"%s\"\n", buf);
24 return -1;
25 }
26
27 elm_image_animated_set(image, EINA_TRUE);
28 elm_image_animated_play_set(image, EINA_TRUE);
29
30 evas_object_size_hint_weight_set(image, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
31 elm_win_resize_object_add(win, image);
32 evas_object_show(image);
33
34 evas_object_resize(win, 320, 320);
35 evas_object_show(win);
36
37 elm_run();
38
39 return 0;
40}
41ELM_MAIN()
diff --git a/src/examples/elementary/meson.build b/src/examples/elementary/meson.build
index 7876285349..7abffa8a2f 100644
--- a/src/examples/elementary/meson.build
+++ b/src/examples/elementary/meson.build
@@ -46,6 +46,8 @@ examples = [
46 'hoversel_example_01', 46 'hoversel_example_01',
47 'icon_example_01', 47 'icon_example_01',
48 'image_example_01', 48 'image_example_01',
49 'image_webp_example_01',
50 'image_webp_example_02',
49 'index_example_01', 51 'index_example_01',
50 'index_example_02', 52 'index_example_02',
51 'inwin_example', 53 'inwin_example',
diff --git a/src/lib/evas/meson.build b/src/lib/evas/meson.build
index 3b49e2bea6..2196952d21 100644
--- a/src/lib/evas/meson.build
+++ b/src/lib/evas/meson.build
@@ -8,6 +8,7 @@ png = dependency('libpng')
8tiff = dependency('libtiff-4', required: get_option('evas-loaders-disabler').contains('tiff') == false) 8tiff = dependency('libtiff-4', required: get_option('evas-loaders-disabler').contains('tiff') == false)
9giflib = cc.find_library('gif') 9giflib = cc.find_library('gif')
10webp = dependency('libwebp', required: get_option('evas-loaders-disabler').contains('webp') == false) 10webp = dependency('libwebp', required: get_option('evas-loaders-disabler').contains('webp') == false)
11webpdemux = dependency('libwebpdemux', required: get_option('evas-loaders-disabler').contains('webp') == false)
11libopenjp2 = dependency('libopenjp2', required: get_option('evas-loaders-disabler').contains('jp2k') == false) 12libopenjp2 = dependency('libopenjp2', required: get_option('evas-loaders-disabler').contains('jp2k') == false)
12 13
13evas_image_loaders_file = [ 14evas_image_loaders_file = [
@@ -25,7 +26,7 @@ evas_image_loaders_file = [
25 ['tgv', 'shared', [rg_etc, lz4]], 26 ['tgv', 'shared', [rg_etc, lz4]],
26 ['tiff', 'shared', [tiff]], 27 ['tiff', 'shared', [tiff]],
27 ['wbmp', 'shared', []], 28 ['wbmp', 'shared', []],
28 ['webp', 'shared', [webp]], 29 ['webp', 'shared', [webp, webpdemux]],
29 ['xpm', 'shared', []] 30 ['xpm', 'shared', []]
30] 31]
31 32
diff --git a/src/modules/evas/image_loaders/webp/evas_image_load_webp.c b/src/modules/evas/image_loaders/webp/evas_image_load_webp.c
index bd082455a2..8026e0c880 100644
--- a/src/modules/evas/image_loaders/webp/evas_image_load_webp.c
+++ b/src/modules/evas/image_loaders/webp/evas_image_load_webp.c
@@ -5,10 +5,30 @@
5#include <stdio.h> 5#include <stdio.h>
6#include <string.h> 6#include <string.h>
7#include <webp/decode.h> 7#include <webp/decode.h>
8#include <webp/demux.h>
8 9
9#include "evas_common_private.h" 10#include "evas_common_private.h"
10#include "evas_private.h" 11#include "evas_private.h"
11 12
13typedef struct _Loader_Info
14{
15 Eina_File *f;
16 Evas_Image_Load_Opts *opts;
17 Evas_Image_Animated *animated;
18 WebPAnimDecoder *dec;
19 void *map;
20 Eina_Array *frames;
21}Loader_Info;
22
23// WebP Frame Information
24typedef struct _Image_Frame
25{
26 int index;
27 int timestamp;
28 double delay;
29 uint8_t *data;
30}Image_Frame;
31
12static Eina_Bool 32static Eina_Bool
13evas_image_load_file_check(Eina_File *f, void *map, 33evas_image_load_file_check(Eina_File *f, void *map,
14 unsigned int *w, unsigned int *h, Eina_Bool *alpha, 34 unsigned int *w, unsigned int *h, Eina_Bool *alpha,
@@ -38,16 +58,95 @@ evas_image_load_file_check(Eina_File *f, void *map,
38 58
39static void * 59static void *
40evas_image_load_file_open_webp(Eina_File *f, Eina_Stringshare *key EINA_UNUSED, 60evas_image_load_file_open_webp(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
41 Evas_Image_Load_Opts *opts EINA_UNUSED, 61 Evas_Image_Load_Opts *opts,
42 Evas_Image_Animated *animated EINA_UNUSED, 62 Evas_Image_Animated *animated,
43 int *error EINA_UNUSED) 63 int *error)
64{
65 Loader_Info *loader = calloc(1, sizeof (Loader_Info));
66 if (!loader)
67 {
68 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
69 return NULL;
70 }
71 loader->f = eina_file_dup(f);
72 loader->opts = opts;
73 loader->animated = animated;
74 return loader;
75}
76
77static void
78_free_all_frame(Loader_Info *loader)
79{
80 Image_Frame *frame;
81
82 if (!loader->frames) return;
83
84 for (unsigned int i = 0; i < eina_array_count(loader->frames); ++i)
85 {
86 frame = eina_array_data_get(loader->frames, i);
87 if (frame->data)
88 {
89 free(frame->data);
90 frame->data = NULL;
91 }
92 free(frame);
93 }
94}
95
96
97static void
98evas_image_load_file_close_webp(void *loader_data)
44{ 99{
45 return f; 100 // Free Allocated Data
101 Loader_Info *loader = loader_data;
102 _free_all_frame(loader);
103 eina_array_free(loader->frames);
104 if (loader->dec) WebPAnimDecoderDelete(loader->dec);
105 if ((loader->map) && (loader->f))
106 eina_file_map_free(loader->f, loader->map);
107 if (loader->f) eina_file_close(loader->f);
108 free(loader);
46} 109}
47 110
111
48static void 112static void
49evas_image_load_file_close_webp(void *loader_data EINA_UNUSED) 113_new_frame(Loader_Info *loader, uint8_t *data, int width, int height, int index,
114 int pre_timestamp, int cur_timestamp)
115{
116 // Allocate Frame Data
117 Image_Frame *frame;
118
119 frame = calloc(1, sizeof(Image_Frame));
120 if (!frame) return;
121
122 frame->data = calloc(width * height * 4, sizeof(uint8_t));
123 if (!frame->data)
124 {
125 free(frame);
126 return;
127 }
128
129 frame->index = index;
130 frame->timestamp = cur_timestamp;
131 frame->delay = ((double)(cur_timestamp - pre_timestamp)/1000.0);
132 memcpy(frame->data, data, width * height * 4);
133
134 eina_array_push(loader->frames, frame);
135}
136
137static Image_Frame *
138_find_frame(Loader_Info *loader, int index)
50{ 139{
140 // Find Frame
141 Image_Frame *frame;
142
143 if (!loader->frames) return NULL;
144
145 frame = eina_array_data_get(loader->frames, index - 1);
146 if (frame->index == index)
147 return frame;
148
149 return NULL;
51} 150}
52 151
53static Eina_Bool 152static Eina_Bool
@@ -55,20 +154,96 @@ evas_image_load_file_head_webp(void *loader_data,
55 Emile_Image_Property *prop, 154 Emile_Image_Property *prop,
56 int *error) 155 int *error)
57{ 156{
58 Eina_File *f = loader_data; 157 Loader_Info *loader = loader_data;
59 Eina_Bool r; 158 Evas_Image_Animated *animated = loader->animated;
159 Eina_File *f = loader->f;
60 void *data; 160 void *data;
61 161
62 *error = EVAS_LOAD_ERROR_NONE; 162 *error = EVAS_LOAD_ERROR_NONE;
63 163
64 data = eina_file_map_all(f, EINA_FILE_RANDOM); 164 data = eina_file_map_all(f, EINA_FILE_RANDOM);
165 loader->map = data;
65 166
66 r = evas_image_load_file_check(f, data, 167 if (!evas_image_load_file_check(f, data,
67 &prop->w, &prop->h, &prop->alpha, 168 &prop->w, &prop->h, &prop->alpha,
68 error); 169 error))
170 {
171 ERR("Image File is Invalid");
172 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
173 return EINA_FALSE;
174 }
69 175
70 if (data) eina_file_map_free(f, data); 176 // Init WebP Data
71 return r; 177 WebPData webp_data;
178 WebPDataInit(&webp_data);
179
180 // Assign Data
181 webp_data.bytes = data;
182 webp_data.size = eina_file_size_get(f);
183
184 // Set Decode Option
185 WebPAnimDecoderOptions dec_options;
186 WebPAnimDecoderOptionsInit(&dec_options);
187 dec_options.color_mode = MODE_BGRA;
188
189 // Create WebPAnimation Decoder
190 WebPAnimDecoder *dec = WebPAnimDecoderNew(&webp_data, &dec_options);
191 if (!dec)
192 {
193 ERR("WebP Decoder Creation is Failed");
194 *error = EVAS_LOAD_ERROR_GENERIC;
195 return EINA_FALSE;
196 }
197 loader->dec = dec;
198
199 // Get WebP Animation Info
200 WebPAnimInfo anim_info;
201 if (!WebPAnimDecoderGetInfo(dec, &anim_info))
202 {
203 ERR("Getting WebP Information is Failed");
204 *error = EVAS_LOAD_ERROR_GENERIC;
205 return EINA_FALSE;
206 }
207
208 uint8_t* buf;
209 int pre_timestamp = 0;
210 int cur_timestamp = 0;
211 int index = 1;
212
213 // Set Frame Array
214 loader->frames = eina_array_new(anim_info.frame_count);
215 if (!loader->frames)
216 {
217 ERR("Frame Array Allocation is Faild");
218 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
219 return EINA_FALSE;
220 }
221
222 // Decode Frames
223 while (WebPAnimDecoderHasMoreFrames(dec))
224 {
225 if (!WebPAnimDecoderGetNext(dec, &buf, &cur_timestamp))
226 {
227 ERR("WebP Decoded Frame Get is Failed");
228 *error = EVAS_LOAD_ERROR_GENERIC;
229 return EINA_FALSE;
230 }
231 _new_frame(loader, buf, anim_info.canvas_width, anim_info.canvas_height, index,
232 pre_timestamp, cur_timestamp);
233 pre_timestamp = cur_timestamp;
234 index++;
235 }
236
237 // Set Animation Info
238 if (anim_info.frame_count > 1)
239 {
240 animated->animated = 1;
241 animated->loop_count = anim_info.loop_count;
242 animated->loop_hint = EVAS_IMAGE_ANIMATED_HINT_LOOP;
243 animated->frame_count = anim_info.frame_count;
244 }
245
246 return EINA_TRUE;
72} 247}
73 248
74static Eina_Bool 249static Eina_Bool
@@ -77,37 +252,53 @@ evas_image_load_file_data_webp(void *loader_data,
77 void *pixels, 252 void *pixels,
78 int *error) 253 int *error)
79{ 254{
80 Eina_File *f = loader_data; 255 Loader_Info *loader = loader_data;
81 void *data = NULL; 256 Evas_Image_Animated *animated = loader->animated;
82 void *decoded = NULL; 257
258 *error = EVAS_LOAD_ERROR_NONE;
259
83 void *surface = NULL; 260 void *surface = NULL;
84 int width, height; 261 int width, height;
262 int index = 0;
85 263
86 data = eina_file_map_all(f, EINA_FILE_SEQUENTIAL); 264 index = animated->cur_frame;
87 265
266 // Find Cur Frame
267 if (index == 0)
268 index = 1;
269 Image_Frame *frame = _find_frame(loader, index);
270 if (frame == NULL) return EINA_FALSE;
271
272 WebPAnimInfo anim_info;
273 WebPAnimDecoderGetInfo(loader->dec, &anim_info);
274 width = anim_info.canvas_width;
275 height = anim_info.canvas_height;
276
277 // Render Frame
88 surface = pixels; 278 surface = pixels;
279 memcpy(surface, frame->data, width * height * 4);
280 prop->premul = EINA_TRUE;
89 281
90 decoded = WebPDecodeBGRA(data, eina_file_size_get(f), &width, &height); 282 return EINA_TRUE;
91 if (!decoded) 283}
92 {
93 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
94 goto free_data;
95 }
96 *error = EVAS_LOAD_ERROR_NONE;
97 284
98 if ((int) prop->w != width || 285static double
99 (int) prop->h != height) 286evas_image_load_frame_duration_webp(void *loader_data,
100 goto free_data; 287 int start_frame,
288 int frame_num)
289{
290 Loader_Info *loader = loader_data;
291 Evas_Image_Animated *animated = loader->animated;
101 292
102 // XXX: this copy of the surface is inefficient 293 if (!animated->animated) return -1.0;
103 memcpy(surface, decoded, width * height * 4); 294 if (frame_num < 0) return -1.0;
104 prop->premul = EINA_TRUE; 295 if (start_frame < 1) return -1.0;
105 296
106 free_data: 297 // Calculate Duration of Current Frame
107 if (data) eina_file_map_free(f, data); 298 Image_Frame *frame = _find_frame(loader, start_frame);
108 free(decoded); 299 if (frame == NULL) return -1.0;
109 300
110 return EINA_TRUE; 301 return frame->delay;
111} 302}
112 303
113static Evas_Image_Load_Func evas_image_load_webp_func = 304static Evas_Image_Load_Func evas_image_load_webp_func =
@@ -118,7 +309,7 @@ static Evas_Image_Load_Func evas_image_load_webp_func =
118 (void*) evas_image_load_file_head_webp, 309 (void*) evas_image_load_file_head_webp,
119 NULL, 310 NULL,
120 (void*) evas_image_load_file_data_webp, 311 (void*) evas_image_load_file_data_webp,
121 NULL, 312 evas_image_load_frame_duration_webp,
122 EINA_TRUE, 313 EINA_TRUE,
123 EINA_FALSE 314 EINA_FALSE
124}; 315};