Add encoding function for animated GIF and WEBP 71/240871/9 accepted/tizen/unified/20200906.032707 submit/tizen/20200904.051854
authorjiyong.min <jiyong.min@samsung.com>
Wed, 12 Aug 2020 08:42:50 +0000 (17:42 +0900)
committerJiyong Min <jiyong.min@samsung.com>
Fri, 4 Sep 2020 03:28:48 +0000 (03:28 +0000)
Change-Id: Ic74c359b845687ef2245c8d20e1cdace4d04eae0

CMakeLists.txt
packaging/capi-media-image-util.spec
src/image_util_encode.c
test/image_util_testsuite.c

index b7ce508..f3f6264 100644 (file)
@@ -9,7 +9,7 @@ SET(INC_DIR include)
 INCLUDE_DIRECTORIES(${INC_DIR})
 
 # for package file
-SET(dependents "dlog mmutil-magick mmutil-common mmutil-gif mmutil-jpeg mmutil-imgp capi-base-common capi-media-tool glib-2.0")
+SET(dependents "dlog mmutil-magick mmutil-common mmutil-gif mmutil-jpeg mmutil-imgp mmutil-anim capi-base-common capi-media-tool glib-2.0")
 SET(pc_dependents "capi-base-common capi-media-tool")
 INCLUDE(FindPkgConfig)
 pkg_check_modules(${fw_name} REQUIRED ${dependents})
index 65b79bf..082a5e5 100644 (file)
@@ -12,6 +12,7 @@ BuildRequires:  pkgconfig(mmutil-jpeg)
 BuildRequires:  pkgconfig(mmutil-imgp)
 BuildRequires:  pkgconfig(mmutil-gif)
 BuildRequires:  pkgconfig(mmutil-magick)
+BuildRequires:  pkgconfig(mmutil-anim)
 BuildRequires:  pkgconfig(capi-base-common)
 BuildRequires:  pkgconfig(capi-media-tool)
 BuildRequires:  pkgconfig(glib-2.0)
index 3323220..4901f56 100644 (file)
@@ -19,6 +19,7 @@
 #include <mm_util_gif.h>
 #include <mm_util_magick.h>
 #include <mm_util_image.h>
+#include <mm_util_anim.h>
 
 #include <image_util.h>
 #include <image_util_private.h>
@@ -775,6 +776,75 @@ int image_util_agif_encode_destroy(image_util_agif_encode_h handle)
        return IMAGE_UTIL_ERROR_NONE;
 }
 
+int image_util_anim_encode_create(image_util_anim_type_e image_type, image_util_anim_encode_h *handle)
+{
+       int ret = IMAGE_UTIL_ERROR_NONE;
+       mm_util_anim_enc_h anim_enc = NULL;
+
+       image_util_retvm_if(!handle, IMAGE_UTIL_ERROR_INVALID_PARAMETER, "Invalid Handle");
+
+       ret = mm_util_anim_enc_create((mm_util_anim_codec_type)image_type, &anim_enc);
+       if (ret != MM_UTIL_ERROR_NONE) {
+               image_util_error("mm_util_anim_enc_create is failed (%d)", ret);
+               return _image_error_capi(ret);
+       }
+
+       *handle = (image_util_anim_encode_h)anim_enc;
+
+       return ret;
+}
+
+int image_util_anim_encode_set_loop_count(image_util_anim_encode_h handle, unsigned int loop_count)
+{
+       return _image_error_capi(mm_util_anim_enc_set_loop_count((mm_util_anim_enc_h)handle, loop_count));
+}
+
+int image_util_anim_encode_set_background_color(image_util_anim_encode_h handle, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+       return _image_error_capi(mm_util_anim_enc_set_bgcolor((mm_util_anim_enc_h)handle, r, g, b, a));
+}
+
+int image_util_anim_encode_set_lossless(image_util_anim_encode_h handle, bool lossless)
+{
+       return _image_error_capi(mm_util_anim_enc_set_lossless((mm_util_anim_enc_h)handle, lossless));
+}
+
+int image_util_anim_encode_add_frame(image_util_anim_encode_h handle, image_util_image_h image, unsigned int time_delay)
+{
+       int ret = IMAGE_UTIL_ERROR_NONE;
+       image_util_retvm_if(!handle, IMAGE_UTIL_ERROR_INVALID_PARAMETER, "Invalid Handle");
+
+       ret = mm_image_set_delay_time((mm_util_image_h)image, time_delay);
+       if (ret != MM_UTIL_ERROR_NONE) {
+               image_util_error("mm_image_set_delay_time is failed (%d)", ret);
+               return _image_error_capi(ret);
+       }
+
+       return _image_error_capi(mm_util_anim_enc_add_image((mm_util_anim_enc_h)handle, image));
+}
+
+int image_util_anim_encode_save_to_file(image_util_anim_encode_h handle, const char *file_path)
+{
+       int ret = _check_encode_path(file_path);
+       image_util_retvm_if(ret != IMAGE_UTIL_ERROR_NONE, ret, "Invalid file_path");
+
+       return _image_error_capi(mm_util_anim_enc_save_to_file((mm_util_anim_enc_h)handle, file_path));
+}
+
+int image_util_anim_encode_save_to_buffer(image_util_anim_encode_h handle, unsigned char **buffer, size_t *buffer_size)
+{
+       return _image_error_capi(mm_util_anim_enc_save_to_buffer((mm_util_anim_enc_h)handle, buffer, buffer_size));
+}
+
+int image_util_anim_encode_destroy(image_util_anim_encode_h handle)
+{
+       image_util_retvm_if(!handle, IMAGE_UTIL_ERROR_INVALID_PARAMETER, "Invalid Handle");
+
+       mm_util_anim_enc_destroy((mm_util_anim_enc_h)handle);
+
+       return IMAGE_UTIL_ERROR_NONE;
+}
+
 /* LCOV_EXCL_START */
 #ifdef TIZEN_FEATURE_COMPATIBILITY
 int image_util_encode_jpeg(const unsigned char *buffer, int width, int height, image_util_colorspace_e colorspace, int quality, const char *path)
index 6c97a2a..f08a625 100644 (file)
@@ -32,7 +32,7 @@
 
 /* commons for testsuite */
 #define MAX_STRING_LEN                 PATH_MAX
-#define MAX_AGIF_CNT                   100                     /* supports MAX_AGIF_CNT agif frames */
+#define MAX_AGIF_CNT                   100                     /* supports MAX_AGIF_CNT agif and animation frames */
 #define IMAGE_UTIL_COLOR_NUM   IMAGE_UTIL_COLORSPACE_NV61 + 1
 
 #define SAFE_FREE(src)                 { g_free(src); src = NULL; }
@@ -57,6 +57,7 @@
 #define FILE_FOR_AUTO                          tzplatform_mkpath(TZ_USER_CONTENT, "imgutil_test_auto")
 #define FILE_FOR_ENCODE                                tzplatform_mkpath(TZ_USER_CONTENT, "imgutil_test_encode")
 #define FILE_FOR_ENCODE_AGIF           tzplatform_mkpath(TZ_USER_CONTENT, "imgutil_test_encode_agif")
+#define FILE_FOR_ENCODE_ANIM           tzplatform_mkpath(TZ_USER_CONTENT, "imgutil_test_encode_anim")
 
 #define IMAGE_UTIL_TYPE_MAX                    IMAGE_UTIL_WEBP
 
@@ -68,6 +69,7 @@ typedef enum {
        DECODE_MENU,
        ENCODE_MENU,
        ENCODE_AGIF_MENU,
+       ENCODE_ANIM_MENU,
        TRANSFORM_MENU,
 
        /* set menu */
@@ -80,6 +82,7 @@ typedef enum {
        SET_CONVERT_MENU,
        SET_CROP_MENU,
        SET_DELAY_MENU,
+       SET_BG_COLOR_MENU,
        SET_DIR_MENU,
        SET_DOWNSCALE_MENU,
        SET_QUALITY_MENU,
@@ -87,6 +90,7 @@ typedef enum {
        SET_ROTATE_MENU,
        SET_SIZE_MENU,
        SET_TYPE_MENU,
+       SET_ANIM_TYPE_MENU,
        SET_LAST_MENU,
 } test_menu_state_e;
 
@@ -102,6 +106,13 @@ typedef struct {
 } test_size_s;
 
 typedef struct {
+       unsigned char r;
+       unsigned char g;
+       unsigned char b;
+       unsigned char a;
+} test_color_s;
+
+typedef struct {
        /* for input path or dir */
        char *path;
 
@@ -144,6 +155,16 @@ typedef struct {
        gboolean use_buffer;
 } test_encode_agif_params_s;
 
+/* for encode animation parameters */
+typedef struct {
+       image_util_anim_type_e type;
+       int delay;
+       unsigned int loop_count;
+       bool lossless;
+       test_color_s bg_color;  // rgba
+       gboolean use_buffer;
+} test_encode_anim_params_s;
+
 /* for transform parameters */
 typedef struct {
        gboolean has_convert_color;
@@ -173,14 +194,17 @@ static test_complex_data_s g_encode_result;
 /* encode a-gif */
 static test_encode_agif_params_s g_encode_agif_params;
 static test_complex_data_s g_encode_agif_result;
+/* encode anim */
+static test_encode_anim_params_s g_encode_anim_params;
+static test_complex_data_s g_encode_anim_result;
 /* transform */
 static test_transform_params_s g_transform_params;
 static test_complex_data_s g_transform_result;
 
 /* for menu queue */
 static GQueue *g_queue_menu = NULL;
-/* for images queue to encode a-gif */
-static GQueue *g_queue_agif_images = NULL;
+/* for images queue to encode a-gif and animation */
+static GQueue *g_queue_anim_images = NULL;
 /* for input data queue */
 static GQueue *g_queue_data = NULL;
 
@@ -366,6 +390,47 @@ static void __display_encode_agif_menu(void)
 }
 
 typedef enum {
+       ENCODE_ANIM_SET_DIR = 0,
+       ENCODE_ANIM_SET_TYPE,
+       ENCODE_ANIM_SET_DELAY,
+       ENCODE_ANIM_SET_BG_COLOR,
+       ENCODE_ANIM_SET_LOSSLESS,
+       ENCODE_ANIM_SAVE_TO_FILE,
+       ENCODE_ANIM_SAVE_TO_BUFFER,
+       ENCODE_ANIM_MENU_MAX,
+} test_encode_anim_menu_e;
+
+typedef struct {
+       test_encode_anim_menu_e e;
+       const char *t;
+} test_encode_anim_menu_s;
+
+static const test_encode_anim_menu_s g_disp_encode_anim_menu[ENCODE_ANIM_MENU_MAX] = {
+       { ENCODE_ANIM_SET_DIR,                  "set directory" },
+       { ENCODE_ANIM_SET_TYPE,                 "set animation type (mand. default = webp)" },
+       { ENCODE_ANIM_SET_DELAY,                "set delay time (mand. default = 100)" },
+       { ENCODE_ANIM_SET_BG_COLOR,             "set background color (opt.)" },
+       { ENCODE_ANIM_SET_LOSSLESS,             "set lossless (opt. default = 0(false=lossy))" },
+       { ENCODE_ANIM_SAVE_TO_FILE,             "add frame by frame and save to file" },
+       { ENCODE_ANIM_SAVE_TO_BUFFER,   "add frame by frame and save to buffer" },
+};
+
+static void __display_encode_anim_menu(void)
+{
+       unsigned int idx = 0;
+       g_print("\n");
+       g_print("====================================================\n");
+       g_print("   image-util Core-API test: Encode ANIMATION menu v%s\n", VERSION);
+       g_print("----------------------------------------------------\n");
+       for (idx = 0; idx < ENCODE_ANIM_MENU_MAX; idx++)
+               g_print("%u. %s\n", g_disp_encode_anim_menu[idx].e, g_disp_encode_anim_menu[idx].t);
+       g_print("b. back\n");
+       g_print("q. quit\n");
+       g_print("----------------------------------------------------\n");
+       g_print("====================================================\n");
+}
+
+typedef enum {
        TRANSFORM_SET_CONVERT = 0,
        TRANSFORM_SET_CROP,
        TRANSFORM_SET_RESIZE,
@@ -411,6 +476,7 @@ typedef enum {
        TEST_DECODE,
        TEST_ENCODE,
        TEST_ENCODE_AGIF,
+       TEST_ENCODE_ANIM,
        TEST_TRANSFORM,
        SET_PATH,
        MAIN_MENU_MAX,
@@ -426,6 +492,7 @@ static const test_main_menu_s g_disp_main_menu[MAIN_MENU_MAX] = {
        { TEST_DECODE,                  "test decode" },
        { TEST_ENCODE,                  "test encode" },
        { TEST_ENCODE_AGIF,             "test encode a-gif" },
+       { TEST_ENCODE_ANIM,             "test encode animation" },
        { TEST_TRANSFORM,               "test transform" },
        { SET_PATH,                             "set path" },
 };
@@ -456,6 +523,9 @@ static void __display_menu(test_menu_state_e menu_state)
        case ENCODE_AGIF_MENU:
                __display_encode_agif_menu();
                break;
+       case ENCODE_ANIM_MENU:
+               __display_encode_anim_menu();
+               break;
        case TRANSFORM_MENU:
                __display_transform_menu();
                break;
@@ -491,6 +561,9 @@ static void __display_menu(test_menu_state_e menu_state)
        case SET_DELAY_MENU:
                __display_set("delay", "20~");
                break;
+       case SET_BG_COLOR_MENU:
+               __display_set("background color", "(r),(g),(b),(a) 255,0,0,0");
+               break;
        case SET_DOWNSCALE_MENU:
                __display_set("downscale", "0(1/1), 1(1/2), 2(1/4), 3(1/8)");
                break;
@@ -507,6 +580,9 @@ static void __display_menu(test_menu_state_e menu_state)
        case SET_TYPE_MENU:
                __display_set("image_type", "0:jpeg, 1:png, 2:gif, 3:bmp, 4:webp");
                break;
+       case SET_ANIM_TYPE_MENU:
+               __display_set("image_anim_type", "0:gif, 1:webp");
+               break;
        /* set menus */
 
        case MAIN_MENU:
@@ -669,7 +745,7 @@ static gboolean __decode_file_in_dir()
                return FALSE;
        }
 
-       g_queue_foreach(g_queue_agif_images, __decode_func, decoder);
+       g_queue_foreach(g_queue_anim_images, __decode_func, decoder);
 
        if (g_input_data.image_cnt == 0) {
                g_print("No valid image\n");
@@ -709,10 +785,10 @@ static gboolean __set_input_dir(const char *path)
                return FALSE;
        }
 
-       if (g_queue_agif_images)
-               g_queue_free_full(g_queue_agif_images, g_free);
+       if (g_queue_anim_images)
+               g_queue_free_full(g_queue_anim_images, g_free);
 
-       g_queue_agif_images = g_queue_new();
+       g_queue_anim_images = g_queue_new();
 
        /* push files of dir into queue */
        while (1) {
@@ -720,12 +796,12 @@ static gboolean __set_input_dir(const char *path)
                if (!filename)
                        break;
 
-               g_queue_insert_sorted(g_queue_agif_images, g_strdup_printf("%s/%s", path, filename), __sort_compare, NULL);
+               g_queue_insert_sorted(g_queue_anim_images, g_strdup_printf("%s/%s", path, filename), __sort_compare, NULL);
        }
 
        g_dir_close(dir);
 
-       if (g_queue_agif_images->length == 0) {
+       if (g_queue_anim_images->length == 0) {
                g_print("No test file in directory(%s)!\n", path);
                return FALSE;
        }
@@ -829,6 +905,49 @@ ERROR:
        return ret;
 }
 
+static gboolean __set_input_color(const char *data, test_color_s *color)
+{
+       gchar **params = NULL;
+       gboolean ret = FALSE;
+       unsigned int color_level = 0;
+
+       if (data == NULL || strlen(data) == 0)
+               return FALSE;
+
+       params = g_strsplit(data, ",", 0);
+
+       if (params == NULL || params[0] == NULL || params[1] == NULL || params[2] == NULL || params[3] == NULL)
+               return FALSE;
+
+       if (!__safe_atoui(params[0], &color_level) || color_level > 255) {
+               g_print("wrong red! %s\n", params[0]);
+               goto ERROR;
+       }
+       color->r = (unsigned char)color_level;
+       if (!__safe_atoui(params[1], &color_level) || color_level > 255) {
+               g_print("wrong green! %s\n", params[1]);
+               goto ERROR;
+       }
+       color->g = (unsigned char)color_level;
+       if (!__safe_atoui(params[2], &color_level) || color_level > 255) {
+               g_print("wrong blue! %s\n", params[0]);
+               goto ERROR;
+       }
+       color->b = (unsigned char)color_level;
+       if (!__safe_atoui(params[3], &color_level) || color_level > 255) {
+               g_print("wrong alpha! %s\n", params[1]);
+               goto ERROR;
+       }
+       color->a = (unsigned char)color_level;
+
+       ret = TRUE;
+
+ERROR:
+       g_strfreev(params);
+
+       return ret;
+}
+
 static int __get_raw_data(test_complex_data_s *test_data)
 {
        int ret = IMAGE_UTIL_ERROR_NONE;
@@ -915,6 +1034,33 @@ static void __get_encode_path(image_util_type_e image_type, const char *base, ch
 
        g_print("\t__get_encode_path: %s!\n", *path);
 }
+
+static const char *g_anim_image_exts[] = {
+       "gif",
+       "webp",
+};
+static void __get_encode_anim_path(image_util_anim_type_e anim_type, const char *base, char **path)
+{
+       char *_path = NULL;
+
+       switch (anim_type) {
+       case IMAGE_UTIL_ANIM_GIF:
+               /* fall through */
+       case IMAGE_UTIL_ANIM_WEBP:
+               // do noting...
+               break;
+       default:
+               g_print("Not supported encode animation format!\n");
+               return;
+       }
+
+       _path = g_strdup_printf("%s.%s", base,  g_anim_image_exts[anim_type]);
+
+       g_free(*path);
+       *path = _path;
+
+       g_print("\t__get_encode_path: %s!\n", *path);
+}
 /* internal functions for testsuite */
 
 
@@ -1562,6 +1708,78 @@ ERROR:
        return ret;
 }
 
+/* encode animated WEBP or GIF frame by frame
+ * input : use image_cnt & images
+ * output : use path or buffer(buffer_size)
+ */
+static int __run_encode_anim(test_encode_menu_e menu, test_complex_data_s *input,
+               test_encode_anim_params_s *params, test_complex_data_s *result)
+{
+       int ret = IMAGE_UTIL_ERROR_NONE;
+       image_util_agif_encode_h handle = NULL;
+       unsigned int i = 0;
+
+       if (!input || !params || !result) {
+               g_print("invalid parameter!!! input: %p, params: %p, result: %p\n", input, params, result);
+               return IMAGE_UTIL_ERROR_INVALID_PARAMETER;
+       }
+
+       ret = image_util_anim_encode_create(params->type, &handle);
+       if (ret != IMAGE_UTIL_ERROR_NONE) {
+               g_print("image_util_anim_encode_create failed %d\n", ret);
+               return ret;
+       }
+
+       ret = image_util_anim_encode_set_lossless(handle, params->lossless);
+       if (ret != IMAGE_UTIL_ERROR_NONE) {
+               g_print("image_util_anim_encode_set_lossless failed %d\n", ret);
+               return ret;
+       }
+
+       ret = image_util_anim_encode_set_background_color(handle, params->bg_color.r, params->bg_color.g,
+                                                                                       params->bg_color.b, params->bg_color.a);
+       if (ret != IMAGE_UTIL_ERROR_NONE) {
+               g_print("image_util_anim_encode_set_background_color failed %d\n", ret);
+               return ret;
+       }
+
+       for (i = 0; i < input->image_cnt; i++) {
+               ret = image_util_anim_encode_add_frame(handle, input->images[i], params->delay);
+               if (ret != IMAGE_UTIL_ERROR_NONE) {
+                       g_print("image_util_anim_encode_add_frame failed %d\n", ret);
+                       goto ERROR;
+               }
+       }
+
+       switch(menu) {
+       case ENCODE_AGIF_SAVE_TO_FILE:
+               ret = image_util_anim_encode_save_to_file(handle, result->path);
+               if (ret != IMAGE_UTIL_ERROR_NONE) {
+                       g_print("image_util_anim_encode_save_to_file failed %d\n", ret);
+                       break;
+               }
+               break;
+
+       case ENCODE_AGIF_SAVE_TO_BUFFER:
+               ret = image_util_anim_encode_save_to_buffer(handle, &result->buffer, &result->buffer_size);
+               if (ret != IMAGE_UTIL_ERROR_NONE) {
+                       g_print("image_util_anim_encode_save_to_buffer failed %d\n", ret);
+                       break;
+               }
+               __write_file(result->path, result->buffer, result->buffer_size);
+               SAFE_FREE(result->buffer);
+               break;
+       default:
+               g_print("wrong encode animation menu %u", menu);
+               break;
+       }
+
+ERROR:
+       image_util_anim_encode_destroy(handle);
+
+       return ret;
+}
+
 /* run transform with parameters
  * input/output : use only image_h
  */
@@ -2041,6 +2259,49 @@ static void __interpret_encode_agif(const char *cmd, unsigned int index)
        }
 }
 
+static void __interpret_encode_anim(const char *cmd, unsigned int index)
+{
+       int ret = 0;
+       test_complex_data_s *input_data = NULL;
+
+       switch(index) {
+       case ENCODE_ANIM_SET_DIR:
+               __menu_move(SET_DIR_MENU);
+               break;
+       case ENCODE_ANIM_SET_TYPE:
+               __menu_move(SET_ANIM_TYPE_MENU);
+               break;
+       case ENCODE_ANIM_SET_DELAY:
+               __menu_move(SET_DELAY_MENU);
+               break;
+       case ENCODE_ANIM_SET_BG_COLOR:
+               __menu_move(SET_BG_COLOR_MENU);
+               break;
+       case ENCODE_ANIM_SET_LOSSLESS:
+               __menu_move(SET_LOSSLESS_MENU);
+               break;
+       case ENCODE_ANIM_SAVE_TO_FILE:
+       case ENCODE_ANIM_SAVE_TO_BUFFER:
+               if (!__data_pop(&input_data)) {
+                       g_print("There is no test data for decode.\n");
+                       break;
+               }
+               __get_encode_anim_path(g_encode_anim_params.type, FILE_FOR_ENCODE_ANIM, &g_encode_anim_result.path);
+               ret = __run_encode_anim(index, input_data, &g_encode_anim_params, &g_encode_anim_result);
+               if (ret == IMAGE_UTIL_ERROR_NONE) {
+                       g_print("Success to encode image!!!\n");
+                       __data_push(&g_encode_anim_result);
+               } else {
+                       g_print("Fail to encode image!!!\n");
+                       __data_push(input_data);
+               }
+               break;
+       default:
+               g_print("wrong command! %s\n\n", cmd);
+               break;
+       }
+}
+
 static void __interpret_transform(const char *cmd, unsigned int index)
 {
        int ret = 0;
@@ -2123,8 +2384,13 @@ static gboolean __interpret_set_menu(test_menu_state_e menu_state, const char *c
                g_print("Success to set compression (%u)\n", g_encode_params.compression);
                break;
        case SET_LOSSLESS_MENU:
-               g_encode_params.lossless = (index == 0) ? false : true;
-               g_print("Success to set lossless (%u)\n", g_encode_params.lossless);
+               if (g_previous_menu == ENCODE_MENU) {
+                       g_encode_params.lossless = (index == 0) ? false : true;
+                       g_print("Success to set lossless (%u)\n", g_encode_params.lossless);
+               } else if (g_previous_menu == ENCODE_ANIM_MENU) {
+                       g_encode_anim_params.lossless = (index == 0) ? false : true;
+                       g_print("Success to set animation lossless (%u)\n", g_encode_anim_params.lossless);
+               }
                break;
        case SET_CONVERT_MENU:
                g_transform_params.convert_color = index;
@@ -2141,8 +2407,21 @@ static gboolean __interpret_set_menu(test_menu_state_e menu_state, const char *c
                                g_transform_params.crop_area.y, g_transform_params.crop_area.w, g_transform_params.crop_area.h);
                break;
        case SET_DELAY_MENU:
-               g_encode_agif_params.delay = index;
-               g_print("Success to set agif delay (%u)\n", g_encode_agif_params.delay);
+               if (g_previous_menu == ENCODE_AGIF_MENU) {
+                       g_encode_agif_params.delay = index;
+                       g_print("Success to set agif delay (%u)\n", g_encode_agif_params.delay);
+               } else if (g_previous_menu == ENCODE_ANIM_MENU) {
+                       g_encode_anim_params.delay = index;
+                       g_print("Success to set animation delay (%u)\n", g_encode_anim_params.delay);
+               }
+               break;
+       case SET_BG_COLOR_MENU:
+               if (!__set_input_color(cmd, &g_encode_anim_params.bg_color)) {
+                       g_print("wrong size! %s\n\n", cmd);
+                       return FALSE;
+               }
+               g_print("Success to set animation bg_color(%u,%u,%u,%u)\n", g_encode_anim_params.bg_color.r,
+                               g_encode_anim_params.bg_color.g, g_encode_anim_params.bg_color.b, g_encode_anim_params.bg_color.a);
                break;
        case SET_DOWNSCALE_MENU:
                g_decode_params.downscale = index;
@@ -2176,6 +2455,11 @@ static gboolean __interpret_set_menu(test_menu_state_e menu_state, const char *c
                __get_encode_path(g_encode_params.type, FILE_FOR_ENCODE, &g_encode_result.path);
                g_print("Success to set image_type (%u)\n", g_encode_params.type);
                break;
+       case SET_ANIM_TYPE_MENU:
+               g_encode_anim_params.type = index;
+               __get_encode_anim_path(g_encode_anim_params.type, FILE_FOR_ENCODE_ANIM, &g_encode_anim_result.path);
+               g_print("Success to set anim_type (%u)\n", g_encode_anim_params.type);
+               break;
        default:
                g_print("wrong command! %s\n\n", cmd);
                return FALSE;
@@ -2204,6 +2488,9 @@ static void __interpret_main(const char *cmd, unsigned int index)
        case TEST_ENCODE_AGIF:
                __menu_move(ENCODE_AGIF_MENU);
                break;
+       case TEST_ENCODE_ANIM:
+               __menu_move(ENCODE_ANIM_MENU);
+               break;
        case TEST_TRANSFORM:
                __menu_move(TRANSFORM_MENU);
                break;
@@ -2259,6 +2546,11 @@ static void __interpret_cmd(char *cmd)
                __interpret_encode_agif(cmd, index);
                break;
 
+       /* Encode ANIMATION menu */
+       case ENCODE_ANIM_MENU:
+               __interpret_encode_anim(cmd, index);
+               break;
+
        /* Transform menu */
        case TRANSFORM_MENU:
                __interpret_transform(cmd, index);
@@ -2341,6 +2633,7 @@ static void _init_data(void)
        memset(&g_decode_params, 0, sizeof(test_decode_params_s));
        memset(&g_encode_params, 0, sizeof(test_encode_params_s));
        memset(&g_encode_agif_params, 0, sizeof(test_encode_agif_params_s));
+       memset(&g_encode_anim_params, 0, sizeof(test_encode_anim_params_s));
        memset(&g_transform_params, 0, sizeof(test_transform_params_s));
 
        /* If you want to change default value, change the value here!!! */
@@ -2356,7 +2649,12 @@ static void _init_data(void)
        g_encode_params.compression = IMAGE_UTIL_PNG_COMPRESSION_6;
 
        /* encode_agif */
-       g_encode_agif_params.delay = 10;
+       g_encode_agif_params.delay = 100;
+
+       /* encode_anim */
+       g_encode_anim_params.type = IMAGE_UTIL_ANIM_WEBP;
+       g_encode_anim_params.lossless = false;
+       g_encode_anim_params.delay = 100;
 
        /* transform, not used yet */
        g_transform_params.convert_color = IMAGE_UTIL_COLORSPACE_RGB888;
@@ -2380,7 +2678,7 @@ static void _destroy_data(void)
        unsigned int i = 0;
 
        g_queue_free_full(g_queue_menu, g_free);
-       g_queue_free_full(g_queue_agif_images, g_free);
+       g_queue_free_full(g_queue_anim_images, g_free);
 
        g_free(g_input_data.path);
        g_free(g_input_data.buffer);