diff options
author | Taehyub Kim <taehyub.kim@samsung.com> | 2020-05-29 11:40:37 +0900 |
---|---|---|
committer | Hermet Park <chuneon.park@samsung.com> | 2020-05-29 11:40:37 +0900 |
commit | df06418b6f39f3b8d73631bda33308b67736bb9d (patch) | |
tree | 956a06a4a860168cf9462204b9cd356d84dc9614 /src/modules/evas | |
parent | f88494aa2c2f7ad6edb9da5d626b9042db86f6c9 (diff) | |
download | efl-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
Diffstat (limited to 'src/modules/evas')
-rw-r--r-- | src/modules/evas/image_loaders/webp/evas_image_load_webp.c | 257 |
1 files changed, 224 insertions, 33 deletions
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 }; |