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)
downloadefl-df06418b6f39f3b8d73631bda33308b67736bb9d.tar.gz
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 @@
+//Compile with:
+//gcc -g image_webp_example_01.c -o image_webp_example_01 `pkg-config --cflags --libs elementary`
+
+#include <Elementary.h>
+
+int
+elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
+{
+ Evas_Object *win, *image;
+ char buf[PATH_MAX];
+
+ elm_app_info_set(elm_main, "elementary", "images/static_webp_image.webp");
+ elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
+
+ win = elm_win_util_standard_add("WebP Image", "WebP Image");
+ elm_win_autodel_set(win, EINA_TRUE);
+
+ snprintf(buf, sizeof(buf), "%s/images/static_webp_image.webp", elm_app_data_dir_get());
+
+ image = elm_image_add(win);
+ if (!elm_image_file_set(image, buf, NULL))
+ {
+ printf("error: could not load image \"%s\"\n", buf);
+ return -1;
+ }
+
+ evas_object_size_hint_weight_set(image, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ elm_win_resize_object_add(win, image);
+ evas_object_show(image);
+
+ evas_object_resize(win, 320, 320);
+ evas_object_show(win);
+
+ elm_run();
+
+ return 0;
+}
+ELM_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 @@
+//Compile with:
+//gcc -g image_webp_example_02.c -o image_webp_example_02 `pkg-config --cflags --libs elementary`
+
+#include <Elementary.h>
+
+int
+elm_main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
+{
+ Evas_Object *win, *image;
+ char buf[PATH_MAX];
+
+ elm_app_info_set(elm_main, "elementary", "images/animated_webp_image.webp");
+ elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
+
+ win = elm_win_util_standard_add("WebP Image", "WebP Image");
+ elm_win_autodel_set(win, EINA_TRUE);
+
+ snprintf(buf, sizeof(buf), "%s/images/animated_webp_image.webp", elm_app_data_dir_get());
+
+ image = elm_image_add(win);
+ if (!elm_image_file_set(image, buf, NULL))
+ {
+ printf("error: could not load image \"%s\"\n", buf);
+ return -1;
+ }
+
+ elm_image_animated_set(image, EINA_TRUE);
+ elm_image_animated_play_set(image, EINA_TRUE);
+
+ evas_object_size_hint_weight_set(image, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ elm_win_resize_object_add(win, image);
+ evas_object_show(image);
+
+ evas_object_resize(win, 320, 320);
+ evas_object_show(win);
+
+ elm_run();
+
+ return 0;
+}
+ELM_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 = [
'hoversel_example_01',
'icon_example_01',
'image_example_01',
+ 'image_webp_example_01',
+ 'image_webp_example_02',
'index_example_01',
'index_example_02',
'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')
tiff = dependency('libtiff-4', required: get_option('evas-loaders-disabler').contains('tiff') == false)
giflib = cc.find_library('gif')
webp = dependency('libwebp', required: get_option('evas-loaders-disabler').contains('webp') == false)
+webpdemux = dependency('libwebpdemux', required: get_option('evas-loaders-disabler').contains('webp') == false)
libopenjp2 = dependency('libopenjp2', required: get_option('evas-loaders-disabler').contains('jp2k') == false)
evas_image_loaders_file = [
@@ -25,7 +26,7 @@ evas_image_loaders_file = [
['tgv', 'shared', [rg_etc, lz4]],
['tiff', 'shared', [tiff]],
['wbmp', 'shared', []],
- ['webp', 'shared', [webp]],
+ ['webp', 'shared', [webp, webpdemux]],
['xpm', 'shared', []]
]
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 @@
#include <stdio.h>
#include <string.h>
#include <webp/decode.h>
+#include <webp/demux.h>
#include "evas_common_private.h"
#include "evas_private.h"
+typedef struct _Loader_Info
+{
+ Eina_File *f;
+ Evas_Image_Load_Opts *opts;
+ Evas_Image_Animated *animated;
+ WebPAnimDecoder *dec;
+ void *map;
+ Eina_Array *frames;
+}Loader_Info;
+
+// WebP Frame Information
+typedef struct _Image_Frame
+{
+ int index;
+ int timestamp;
+ double delay;
+ uint8_t *data;
+}Image_Frame;
+
static Eina_Bool
evas_image_load_file_check(Eina_File *f, void *map,
unsigned int *w, unsigned int *h, Eina_Bool *alpha,
@@ -38,16 +58,95 @@ evas_image_load_file_check(Eina_File *f, void *map,
static void *
evas_image_load_file_open_webp(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
- Evas_Image_Load_Opts *opts EINA_UNUSED,
- Evas_Image_Animated *animated EINA_UNUSED,
- int *error EINA_UNUSED)
+ Evas_Image_Load_Opts *opts,
+ Evas_Image_Animated *animated,
+ int *error)
+{
+ Loader_Info *loader = calloc(1, sizeof (Loader_Info));
+ if (!loader)
+ {
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return NULL;
+ }
+ loader->f = eina_file_dup(f);
+ loader->opts = opts;
+ loader->animated = animated;
+ return loader;
+}
+
+static void
+_free_all_frame(Loader_Info *loader)
+{
+ Image_Frame *frame;
+
+ if (!loader->frames) return;
+
+ for (unsigned int i = 0; i < eina_array_count(loader->frames); ++i)
+ {
+ frame = eina_array_data_get(loader->frames, i);
+ if (frame->data)
+ {
+ free(frame->data);
+ frame->data = NULL;
+ }
+ free(frame);
+ }
+}
+
+
+static void
+evas_image_load_file_close_webp(void *loader_data)
{
- return f;
+ // Free Allocated Data
+ Loader_Info *loader = loader_data;
+ _free_all_frame(loader);
+ eina_array_free(loader->frames);
+ if (loader->dec) WebPAnimDecoderDelete(loader->dec);
+ if ((loader->map) && (loader->f))
+ eina_file_map_free(loader->f, loader->map);
+ if (loader->f) eina_file_close(loader->f);
+ free(loader);
}
+
static void
-evas_image_load_file_close_webp(void *loader_data EINA_UNUSED)
+_new_frame(Loader_Info *loader, uint8_t *data, int width, int height, int index,
+ int pre_timestamp, int cur_timestamp)
+{
+ // Allocate Frame Data
+ Image_Frame *frame;
+
+ frame = calloc(1, sizeof(Image_Frame));
+ if (!frame) return;
+
+ frame->data = calloc(width * height * 4, sizeof(uint8_t));
+ if (!frame->data)
+ {
+ free(frame);
+ return;
+ }
+
+ frame->index = index;
+ frame->timestamp = cur_timestamp;
+ frame->delay = ((double)(cur_timestamp - pre_timestamp)/1000.0);
+ memcpy(frame->data, data, width * height * 4);
+
+ eina_array_push(loader->frames, frame);
+}
+
+static Image_Frame *
+_find_frame(Loader_Info *loader, int index)
{
+ // Find Frame
+ Image_Frame *frame;
+
+ if (!loader->frames) return NULL;
+
+ frame = eina_array_data_get(loader->frames, index - 1);
+ if (frame->index == index)
+ return frame;
+
+ return NULL;
}
static Eina_Bool
@@ -55,20 +154,96 @@ evas_image_load_file_head_webp(void *loader_data,
Emile_Image_Property *prop,
int *error)
{
- Eina_File *f = loader_data;
- Eina_Bool r;
+ Loader_Info *loader = loader_data;
+ Evas_Image_Animated *animated = loader->animated;
+ Eina_File *f = loader->f;
void *data;
*error = EVAS_LOAD_ERROR_NONE;
data = eina_file_map_all(f, EINA_FILE_RANDOM);
+ loader->map = data;
- r = evas_image_load_file_check(f, data,
+ if (!evas_image_load_file_check(f, data,
&prop->w, &prop->h, &prop->alpha,
- error);
+ error))
+ {
+ ERR("Image File is Invalid");
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
- if (data) eina_file_map_free(f, data);
- return r;
+ // Init WebP Data
+ WebPData webp_data;
+ WebPDataInit(&webp_data);
+
+ // Assign Data
+ webp_data.bytes = data;
+ webp_data.size = eina_file_size_get(f);
+
+ // Set Decode Option
+ WebPAnimDecoderOptions dec_options;
+ WebPAnimDecoderOptionsInit(&dec_options);
+ dec_options.color_mode = MODE_BGRA;
+
+ // Create WebPAnimation Decoder
+ WebPAnimDecoder *dec = WebPAnimDecoderNew(&webp_data, &dec_options);
+ if (!dec)
+ {
+ ERR("WebP Decoder Creation is Failed");
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ return EINA_FALSE;
+ }
+ loader->dec = dec;
+
+ // Get WebP Animation Info
+ WebPAnimInfo anim_info;
+ if (!WebPAnimDecoderGetInfo(dec, &anim_info))
+ {
+ ERR("Getting WebP Information is Failed");
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ return EINA_FALSE;
+ }
+
+ uint8_t* buf;
+ int pre_timestamp = 0;
+ int cur_timestamp = 0;
+ int index = 1;
+
+ // Set Frame Array
+ loader->frames = eina_array_new(anim_info.frame_count);
+ if (!loader->frames)
+ {
+ ERR("Frame Array Allocation is Faild");
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
+ }
+
+ // Decode Frames
+ while (WebPAnimDecoderHasMoreFrames(dec))
+ {
+ if (!WebPAnimDecoderGetNext(dec, &buf, &cur_timestamp))
+ {
+ ERR("WebP Decoded Frame Get is Failed");
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ return EINA_FALSE;
+ }
+ _new_frame(loader, buf, anim_info.canvas_width, anim_info.canvas_height, index,
+ pre_timestamp, cur_timestamp);
+ pre_timestamp = cur_timestamp;
+ index++;
+ }
+
+ // Set Animation Info
+ if (anim_info.frame_count > 1)
+ {
+ animated->animated = 1;
+ animated->loop_count = anim_info.loop_count;
+ animated->loop_hint = EVAS_IMAGE_ANIMATED_HINT_LOOP;
+ animated->frame_count = anim_info.frame_count;
+ }
+
+ return EINA_TRUE;
}
static Eina_Bool
@@ -77,37 +252,53 @@ evas_image_load_file_data_webp(void *loader_data,
void *pixels,
int *error)
{
- Eina_File *f = loader_data;
- void *data = NULL;
- void *decoded = NULL;
+ Loader_Info *loader = loader_data;
+ Evas_Image_Animated *animated = loader->animated;
+
+ *error = EVAS_LOAD_ERROR_NONE;
+
void *surface = NULL;
int width, height;
+ int index = 0;
- data = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
+ index = animated->cur_frame;
+ // Find Cur Frame
+ if (index == 0)
+ index = 1;
+ Image_Frame *frame = _find_frame(loader, index);
+ if (frame == NULL) return EINA_FALSE;
+
+ WebPAnimInfo anim_info;
+ WebPAnimDecoderGetInfo(loader->dec, &anim_info);
+ width = anim_info.canvas_width;
+ height = anim_info.canvas_height;
+
+ // Render Frame
surface = pixels;
+ memcpy(surface, frame->data, width * height * 4);
+ prop->premul = EINA_TRUE;
- decoded = WebPDecodeBGRA(data, eina_file_size_get(f), &width, &height);
- if (!decoded)
- {
- *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
- goto free_data;
- }
- *error = EVAS_LOAD_ERROR_NONE;
+ return EINA_TRUE;
+}
- if ((int) prop->w != width ||
- (int) prop->h != height)
- goto free_data;
+static double
+evas_image_load_frame_duration_webp(void *loader_data,
+ int start_frame,
+ int frame_num)
+{
+ Loader_Info *loader = loader_data;
+ Evas_Image_Animated *animated = loader->animated;
- // XXX: this copy of the surface is inefficient
- memcpy(surface, decoded, width * height * 4);
- prop->premul = EINA_TRUE;
+ if (!animated->animated) return -1.0;
+ if (frame_num < 0) return -1.0;
+ if (start_frame < 1) return -1.0;
- free_data:
- if (data) eina_file_map_free(f, data);
- free(decoded);
+ // Calculate Duration of Current Frame
+ Image_Frame *frame = _find_frame(loader, start_frame);
+ if (frame == NULL) return -1.0;
- return EINA_TRUE;
+ return frame->delay;
}
static Evas_Image_Load_Func evas_image_load_webp_func =
@@ -118,7 +309,7 @@ static Evas_Image_Load_Func evas_image_load_webp_func =
(void*) evas_image_load_file_head_webp,
NULL,
(void*) evas_image_load_file_data_webp,
- NULL,
+ evas_image_load_frame_duration_webp,
EINA_TRUE,
EINA_FALSE
};