From df06418b6f39f3b8d73631bda33308b67736bb9d Mon Sep 17 00:00:00 2001 From: Taehyub Kim Date: Fri, 29 May 2020 11:40:37 +0900 Subject: [PATCH] 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 --- .../images/animated_webp_image.webp | Bin 0 -> 4764 bytes data/elementary/images/static_webp_image.webp | Bin 0 -> 10474 bytes .../elementary/image_webp_example_01.c | 38 +++ .../elementary/image_webp_example_02.c | 41 +++ src/examples/elementary/meson.build | 2 + src/lib/evas/meson.build | 3 +- .../image_loaders/webp/evas_image_load_webp.c | 263 +++++++++++++++--- 7 files changed, 310 insertions(+), 37 deletions(-) create mode 100755 data/elementary/images/animated_webp_image.webp create mode 100644 data/elementary/images/static_webp_image.webp create mode 100644 src/examples/elementary/image_webp_example_01.c create mode 100644 src/examples/elementary/image_webp_example_02.c diff --git a/data/elementary/images/animated_webp_image.webp b/data/elementary/images/animated_webp_image.webp new file mode 100755 index 0000000000000000000000000000000000000000..5b44046e2c8ca21ac7f5821317dfbcb172334b12 GIT binary patch literal 4764 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 b&&Z-)Og^hE*22=oeg$Y(!iu%s#c=-zAK+%p literal 0 HcmV?d00001 diff --git a/data/elementary/images/static_webp_image.webp b/data/elementary/images/static_webp_image.webp new file mode 100644 index 0000000000000000000000000000000000000000..0da983e2ce5335eb13a7b793a1403588617dde3c GIT binary patch literal 10474 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 literal 0 HcmV?d00001 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 + +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 + +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 #include #include +#include #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) { - return f; + 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 -evas_image_load_file_close_webp(void *loader_data EINA_UNUSED) +_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) +{ + // 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 +_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,39 +252,55 @@ evas_image_load_file_data_webp(void *loader_data, void *pixels, int *error) { - Eina_File *f = loader_data; - void *data = NULL; - void *decoded = NULL; - void *surface = NULL; - int width, height; + Loader_Info *loader = loader_data; + Evas_Image_Animated *animated = loader->animated; - data = eina_file_map_all(f, EINA_FILE_SEQUENTIAL); - - surface = pixels; - - 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; - if ((int) prop->w != width || - (int) prop->h != height) - goto free_data; + void *surface = NULL; + int width, height; + int index = 0; - // XXX: this copy of the surface is inefficient - memcpy(surface, decoded, width * height * 4); + 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; - free_data: - if (data) eina_file_map_free(f, data); - free(decoded); - return EINA_TRUE; } +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; + + if (!animated->animated) return -1.0; + if (frame_num < 0) return -1.0; + if (start_frame < 1) return -1.0; + + // Calculate Duration of Current Frame + Image_Frame *frame = _find_frame(loader, start_frame); + if (frame == NULL) return -1.0; + + return frame->delay; +} + static Evas_Image_Load_Func evas_image_load_webp_func = { EVAS_IMAGE_LOAD_VERSION, @@ -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 };