Add new version gif encoder(V2) 39/141039/11
authorJiyong Min <jiyong.min@samsung.com>
Fri, 28 Jul 2017 00:01:29 +0000 (09:01 +0900)
committerJiyong Min <jiyong.min@samsung.com>
Thu, 3 Aug 2017 06:45:24 +0000 (15:45 +0900)
 - Add new version gif encode api
  It reduce memory usage by encoding gif frame by frame.
  (After fixing capi, old version will be removed.)
 - At new version it support customized color map, disposal mode and tp color.

Change-Id: Ia7a64d77e321c1f89b69525a9e74f92a3f5ee368
Signed-off-by: Jiyong Min <jiyong.min@samsung.com>
gif/include/mm_util_gif.h
gif/include/mm_util_gif_private.h [new file with mode: 0755]
gif/mm_util_gif.c
imgp/include/mm_util_debug.h
packaging/libmm-utility.spec

index 6bb47ce..cb313b6 100755 (executable)
 #ifdef __cplusplus
 extern "C" {
 #endif
-#include "mm_util_imgp.h"
+
+#include <glib.h>
 #include "gif_lib.h"
+#include "mm_util_imgp.h"
 
 /**
     @addtogroup UTILITY
@@ -48,7 +50,7 @@ typedef struct {
  * Write data attached to encoding callback
  */
 typedef struct {
-       unsigned long long size;
+       unsigned long size;
        void **mem;
 } write_data;
 
@@ -83,6 +85,24 @@ typedef struct {
        void *data;                             /**< Data */
 } mm_util_gif_frame_data;
 
+#ifdef GIF_ENCODER_V2
+#define GRAPHIC_EXT_BLOCK_SIZE 4
+#define APP_EXT_BLOCK_SIZE             11
+#define APP_EXT_BLOCK_DATA             "NETSCAPE2.0"
+#define SUB_BLOCK_SIZE 3
+#define NETSCAPE_SUB_BLOCK_INDEX       1
+
+typedef struct {
+       unsigned char red;
+       unsigned char green;
+       unsigned char blue;
+} mm_util_gif_color_s;
+
+typedef struct gif_image_s* mm_gif_image_h;
+
+typedef struct gif_file_s* mm_gif_file_h;
+#endif
+
 typedef struct {
        unsigned long width;                      /**< Width */
        unsigned long height;                     /**< Height */
@@ -121,44 +141,6 @@ int mm_util_decode_from_gif_file(mm_util_gif_data * decoded, const char *filenam
  */
 int mm_util_decode_from_gif_memory(mm_util_gif_data * decoded, void **memory);
 
-#if 0
-/**
- * This function gets the width of the decoded image.
- * This should be called after the actual decoding.
- *
- * @param data       [in]     pointer of mm_util_gif_data.
- * @return                    Width of the decoded image.
- * @remark
- * @see                       mm_util_gif_data
- * @since                     R1, 1.0
- */
-unsigned long mm_util_gif_decode_get_width(mm_util_gif_data * data);
-
-/**
- * This function gets the height of the decoded image.
- * This should be called after the actual decoding.
- *
- * @param data       [in]     pointer of mm_util_gif_data.
- * @return                    Height of the decoded image.
- * @remark
- * @see                       mm_util_gif_data
- * @since                     R1, 1.0
- */
-unsigned long mm_util_gif_decode_get_height(mm_util_gif_data * data);
-
-/**
- * This function gets the size of the decoded image.
- * This should be called after the actual decoding.
- *
- * @param data       [in]     pointer of mm_util_gif_data.
- * @return                    Size of the decoded image.
- * @remark
- * @see                       mm_util_gif_data
- * @since                     R1, 1.0
- */
-unsigned long long mm_util_gif_decode_get_size(mm_util_gif_data * data);
-#endif
-
 /**
  * This function creates gif file for output file
  *
@@ -210,90 +192,247 @@ int mm_util_encode_gif(mm_util_gif_data *encoded);
  */
 int mm_util_encode_close_gif(mm_util_gif_data *encoded);
 
+#ifdef GIF_ENCODER_V2
+/**
+ * This function creates the handle of the single image(frame).
+ *
+ * @param gif_file_h           [in]            the handle of the gif data.
+ * @param gif_image_h  [out]   the handle of the single image.
+ * @return                             This function returns zero on success, or negative value with error code.
+ * @remark
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_image_destory
+ * @post                                       mm_util_gif_image_destory
+ */
+int mm_util_gif_image_create(mm_gif_file_h gif_file_h, mm_gif_image_h *gif_image_h);
+
+/**
+ * This function sets the position of the single image(frame).
+ *
+ * @param gif_image_h  [in]            the handle of the single image.
+ * @param left                 [in]            the left of the single image.
+ * @param top                  [in]            the top of the single image.
+ * @param width                        [in]            the width of the single image.
+ * @param height                       [in]            the height of the single image.
+ * @return                             This function returns zero on success, or negative value with error code.
+ * @remark
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_image_create
+ * @pre                                        mm_util_gif_image_create
+ */
+int mm_util_gif_image_set_position(mm_gif_image_h gif_image_h, int left, int top, int width, int height);
+
+/**
+ * This function sets the disposal mode(graphic control) of the single image(frame).
+ *
+ * @param gif_image_h  [in]            the handle of the single image.
+ * @param disposal_mode        [in]            the disposal mode of the single image.
+ * @return                             This function returns zero on success, or negative value with error code.
+ * @remark
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_image_create
+ * @pre                                        mm_util_gif_image_create
+ */
+int mm_util_gif_image_set_disposal_mode(mm_gif_image_h gif_image_h, const mm_util_gif_disposal disposal_mode);
+
 /**
- * This function sets width of the encoded image.
+ * This function sets the delay time of the single image(frame).
  *
- * @param data               [in]     pointer of mm_util_gif_data.
- * @param width              [in]     width of the encoded image.
- * @return                            None.
+ * @param gif_image_h  [in]            the handle of the single image.
+ * @param delay_time           [in]            the delay time of the single image.
+ * @return                             This function returns zero on success, or negative value with error code.
  * @remark
- * @see                               mm_util_gif_data
- * @since                             R1, 1.0
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_image_create
+ * @pre                                        mm_util_gif_image_create
  */
-void mm_util_gif_encode_set_width(mm_util_gif_data * data, unsigned long width);
+int mm_util_gif_image_set_delay_time(mm_gif_image_h gif_image_h, const int delay_time);
 
 /**
- * This function sets height of the encoded image.
+ * This function sets the buffer of the single image(frame).
  *
- * @param data               [in]     pointer of mm_util_gif_data.
- * @param height             [in]     height of the encoded image.
- * @return                            None.
+ * @param gif_image_h  [in]            the handle of the single image.
+ * @param image_data   [in]            the buffer which has image data.
+ * @param size                 [in]            the length of the buffer.
+ * @return                             This function returns zero on success, or negative value with error code.
  * @remark
- * @see                               mm_util_gif_data
- * @since                             R1, 1.0
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_image_create
+ * @pre                                        mm_util_gif_image_create
  */
-void mm_util_gif_encode_set_height(mm_util_gif_data * data, unsigned long height);
+int mm_util_gif_image_set_image(mm_gif_image_h gif_image_h, unsigned char *image_data, unsigned long size);
 
 /**
- * This function sets number of images of the encoded gif image.
+ * This function destroys the handle of the single image(frame).
  *
- * @param data               [in]     pointer of mm_util_gif_data.
- * @param height             [in]     Image count of the encoded image.
- * @return                            None.
+ * @param gif_image_h  [in]            the handle of the single image.
+ * @return                             None.
  * @remark
- * @see                               mm_util_gif_data
- * @since                             R1, 1.0
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_image_create
+ * @pre                                        mm_util_gif_image_create
  */
-void mm_util_gif_encode_set_image_count(mm_util_gif_data * data, unsigned int image_count);
+void mm_util_gif_image_destory(mm_gif_image_h gif_image_h);
 
 /**
- * This function sets the time delay after which the particular image of the gif should be displayed.
+ * This function creates the handle of gif data.
  *
- * @param data               [in]     pointer of mm_util_gif_frame_data.
- * @param delay_time         [in]     time delay of the frame in the encoded image in 0.01sec units.
- * @return                            None.
+ * @param gif_file_h           [in]            the handle of the gif data.
+ * @return                             This function returns zero on success, or negative value with error code.
  * @remark
- * @see                               mm_util_gif_frame_data
- * @since                             R1, 1.0
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_encode_destroy
+ * @post                                       mm_util_gif_encode_destroy
  */
-void mm_util_gif_encode_set_frame_delay_time(mm_util_gif_frame_data * frame, unsigned long long delay_time);
+int mm_util_gif_encode_create(mm_gif_file_h *gif_file_h);
 
 /**
- * This function sets the disposal mode of each frame in the gif as defined by mm_util_gif_disposal.
+ * This function sets the filepath to save encoded gif.
  *
- * @param data               [in]     pointer of mm_util_gif_frame_data.
- * @param disposal_mode      [in]     Disposal mode of the frame in the encoded image.
- * @return                            None.
+ * @param gif_file_h           [in]            the handle of the gif data.
+ * @param file_name            [in]            the filepath to save encoded image.
+ * @return                             This function returns zero on success, or negative value with error code.
  * @remark
- * @see                               mm_util_gif_frame_data
- * @since                             R1, 1.0
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_encode_create
+ * @pre                                        mm_util_gif_encode_create
  */
-void mm_util_gif_encode_set_frame_disposal_mode(mm_util_gif_frame_data *frame, mm_util_gif_disposal disposal_mode);
+int mm_util_gif_encode_set_file(mm_gif_file_h gif_file_h, const char *file_name);
 
 /**
- * This function sets the position of each frame in the gif.
+ * This function sets the buffer to save encoded gif.
  *
- * @param data               [in]     pointer of mm_util_gif_frame_data.
- * @param x                  [in]     x position of the frame in the encoded image.
- * @param y                  [in]     y position of the frame in the encoded image.
- * @return                            None.
+ * @param gif_file_h           [in]            the handle of the gif data.
+ * @param data                 [in]            the buffer to save encoded image.
+ * @return                             This function returns zero on success, or negative value with error code.
  * @remark
- * @see                               mm_util_gif_frame_data
- * @since                             R1, 1.0
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_encode_create
+ * @pre                                        mm_util_gif_encode_create
  */
-void mm_util_gif_encode_set_frame_position(mm_util_gif_frame_data *frame, unsigned long x, unsigned long y);
+int mm_util_gif_encode_set_mem(mm_gif_file_h gif_file_h, void **data, unsigned long *data_size);
 
 /**
- * This function sets the transparent color for the frame in the gif.
+ * This function sets the resolution(width, height) for gif.
  *
- * @param data               [in]     pointer of mm_util_gif_frame_data.
- * @param transparent_color  [in]     The color in the frame which should be transparent.
- * @return                            None.
+ * @param gif_file_h           [in]            the handle of the gif data.
+ * @param width                        [in]            the width of the image to encode.
+ * @param height                       [in]            the height of the image to encode.
+ * @return                             This function returns zero on success, or negative value with error code.
  * @remark
- * @see                               mm_util_gif_frame_data
- * @since                             R1, 1.0
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_encode_create
+ * @pre                                        mm_util_gif_encode_create
  */
-void mm_util_gif_encode_set_frame_transparency_color(mm_util_gif_frame_data *frame, GifColorType transparent_color);
+int mm_util_gif_encode_set_resolution(mm_gif_file_h gif_file_h, const int width, const int height);
+
+/**
+ * This function sets the times to play animated gif repeatly.
+ * If set the repeat mode to false, play animated gif once.
+ * else set the repeat to true, play animated gif infinately.
+ * If set the repeat_count as 1, animated gif was played one more times. It mean that animated gif will be played two times.
+ *
+ * @param gif_file_h           [in]            the handle of the gif data.
+ * @param repeat                       [in]            the repeat mode to play animated gif.
+ * @param repeat_count [in]            the times to play animated gif repeatly.
+ * @return                             This function returns zero on success, or negative value with error code.
+ * @remark
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_encode_create
+ * @pre                                        mm_util_gif_encode_create
+ */
+int mm_util_gif_encode_set_repeat(mm_gif_file_h gif_file_h, gboolean repeat_mode, unsigned short repeat_count);
+
+/**
+ * This function starts encoding image.
+ *
+ * @param gif_file_h           [in]            the handle of the gif data.
+ * @param bg_color             [in]            the background color of the image to encode.
+ * @return                             This function returns zero on success, or negative value with error code.
+ * @remark
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_encode_create
+ * @post                                       mm_util_gif_encode_add_image
+ */
+int mm_util_gif_encode_start(mm_gif_file_h gif_file_h);
+
+/**
+ * This function encodes the single image(frame).
+ *
+ * @param gif_file_h           [in]            the handle of the gif data.
+ * @param gif_image_h  [in]            the handle of the single image to encode.
+ * @return                             This function returns zero on success, or negative value with error code.
+ * @remark
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_encode_create
+ * @pre                                        mm_util_gif_encode_start
+ * @post                                       mm_util_gif_encode_save
+ */
+int mm_util_gif_encode_add_image(mm_gif_file_h gif_file_h, mm_gif_image_h gif_image_h);
+
+/**
+ * This function saves encoded image.
+ *
+ * @param gif_file_h           [in]            the handle of the gif data.
+ * @return                             This function returns zero on success, or negative value with error code.
+ * @remark
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_encode_create
+ * @pre                                        mm_util_gif_encode_add_image
+ */
+int mm_util_gif_encode_save(mm_gif_file_h gif_file_h);
+
+/**
+ * This function sets image into gif handle, the image will be encoded when @mm_util_gif_encode() is called.
+ *
+ * @param gif_file_h           [in]            the handle of the gif data.
+ * @param gif_image_h  [in]            the handle of the image to set into gif handle.
+ * @return                             This function returns zero on success, or negative value with error code.
+ * @remark
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_encode_create
+ * @pre                                        mm_util_gif_encode_add_image
+ */
+int mm_util_gif_enocde_set_image_handle(mm_gif_file_h gif_file_h, mm_gif_image_h gif_image_h);
+
+/**
+ * This function gets image from gif handle, can change the values in image after call this function.
+ *
+ * @param gif_file_h           [in]            the handle of the gif data.
+ * @param gif_file_h           [in]            the index of the image.
+ * @param gif_image_h  [out]   the handle of the image to get from gif handle.
+ * @return                             This function returns zero on success, or negative value with error code.
+ * @remark
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_encode_create
+ * @pre                                        mm_util_gif_encode_add_image
+ */
+int mm_util_gif_enocde_get_image_handle(mm_gif_file_h gif_file_h, int index, mm_gif_image_h *gif_image_h);
+
+/**
+ * This function encodes gif image with images set into gif handle.
+ *
+ * @param gif_file_h           [in]            the handle of the gif data.
+ * @return                             This function returns zero on success, or negative value with error code.
+ * @remark
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_encode_create
+ * @pre                                        mm_util_gif_encode_add_image
+ */
+int mm_util_gif_encode(mm_gif_file_h gif_file_h);
+
+/**
+ * This function destroys the handle of gif data.
+ *
+ * @param gif_image_h  [in]            the handle of gif data.
+ * @return                             None.
+ * @remark
+ * @since                              R1, 2.0
+ * @see                                        mm_util_gif_encode_create
+ * @pre                                        mm_util_gif_encode_create
+ */
+void mm_util_gif_encode_destroy(mm_gif_file_h gif_file_h);
+#endif
 
 #ifdef __cplusplus
 }
diff --git a/gif/include/mm_util_gif_private.h b/gif/include/mm_util_gif_private.h
new file mode 100755 (executable)
index 0000000..d032df5
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * libmm-utility
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Vineeth T M <vineeth.tm@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __MM_UTIL_GIF_PRIVATE_H__
+#define __MM_UTIL_GIF_PRIVATE_H__
+
+#include <glib.h>
+#include <gif_lib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+       /* for giflib, Same as SavedImage */
+       GifImageDesc image_desc;
+       void *image_data;
+       unsigned long image_data_size;
+       int ext_block_count;
+       ExtensionBlock *ext_blocks;
+
+       /* for libmm */
+       GifWord width;
+       GifWord height;
+       gboolean has_color_map;
+       gboolean has_transparent;
+       GifColorType transparent_color;
+       GraphicsControlBlock graphic_control_block;
+       GifByteType *intermediate_image;
+       unsigned long intermediate_image_size;
+} gif_image_s;
+
+typedef struct {
+       GifFileType *GifFile;                     /**< GifFile opened */
+       char *filename;
+       void **enc_buffer;                        /**< Encoded output data attached to callback */
+       unsigned long *enc_buffer_size;
+       unsigned char *buffer;
+       write_data write_data_ptr;                /**< Encoded output data attached to callback */
+       gboolean is_started;
+
+       int saved_image_count;
+       gif_image_s **saved_image;
+       GifWord width;
+       GifWord height;
+       GifWord color_res;
+       GifWord background_color;
+       ColorMapObject *color_map;
+       gboolean is_repeat;
+       unsigned short repeat_count;
+} gif_file_s;
+
+#ifdef __cplusplus
+}
+#endif
+#endif   /*__MM_UTIL_GIF_PRIVATE_H__*/
index 635727d..3f42c4e 100755 (executable)
 #include <system_info.h>
 
 #include "mm_util_gif.h"
+#include "mm_util_gif_private.h"
 #include "mm_util_debug.h"
 
+#include <limits.h>
+#define GIF_TMP_FILE   "/tmp/libmm_gif.gif"
+
+#define COLORMAP_FREE(map)                     { if (map != NULL) { GifFreeMapObject(map); map = NULL; } }
+#define RGB_ALLOC(r, g, b, number, size)       { r = calloc(1, number * size); g = calloc(1, number * size); b = calloc(1, number * size); }
+#define RGB_FREE(r, g, b)                                      { MMUTIL_SAFE_FREE(r); MMUTIL_SAFE_FREE(g); MMUTIL_SAFE_FREE(b); }
+
 static int __convert_gif_to_rgba(mm_util_gif_data *decoded, ColorMapObject *color_map, GifRowType *screen_buffer, unsigned long width, unsigned long height)
 {
        unsigned long i, j;
@@ -47,17 +55,18 @@ static int __convert_gif_to_rgba(mm_util_gif_data *decoded, ColorMapObject *colo
        if ((decoded->frames = (mm_util_gif_frame_data **) realloc(decoded->frames, sizeof(mm_util_gif_frame_data *)))
                == NULL) {
                mm_util_error("Failed to allocate memory required, aborted.");
-               return MM_UTIL_ERROR_INVALID_OPERATION;
+               return MM_UTIL_ERROR_OUT_OF_MEMORY;
        }
+
        if ((decoded->frames[0] = (mm_util_gif_frame_data *) calloc(1, sizeof(mm_util_gif_frame_data)))
                == NULL) {
                mm_util_error("Failed to allocate memory required, aborted.");
-               return MM_UTIL_ERROR_INVALID_OPERATION;
+               return MM_UTIL_ERROR_OUT_OF_MEMORY;
        }
 
        if ((decoded->frames[0]->data = (void *)malloc(width * height * 4)) == NULL) {
                mm_util_error("Failed to allocate memory required, aborted.");
-               return MM_UTIL_ERROR_INVALID_OPERATION;
+               return MM_UTIL_ERROR_OUT_OF_MEMORY;
        }
 
        buffer = (GifByteType *) decoded->frames[0]->data;
@@ -277,23 +286,6 @@ int mm_util_decode_from_gif_memory(mm_util_gif_data *decoded, void **memory)
        return ret;
 }
 
-#if 0
-unsigned long mm_util_decode_get_width(mm_util_gif_data *data)
-{
-       return data->width;
-}
-
-unsigned long mm_util_decode_get_height(mm_util_gif_data *data)
-{
-       return data->height;
-}
-
-unsigned long long mm_util_decode_get_size(mm_util_gif_data *data)
-{
-       return data->size;
-}
-#endif
-
 static void __load_rgb_from_buffer(GifByteType *buffer, GifByteType **red, GifByteType **green, GifByteType **blue, unsigned long width, unsigned long height)
 {
        unsigned long i, j;
@@ -323,7 +315,6 @@ static void __load_rgb_from_buffer(GifByteType *buffer, GifByteType **red, GifBy
        return;
 }
 
-#define ABS(x)    ((x) > 0 ? (x) : (-(x)))
 static int __save_buffer_to_gif(GifFileType *GifFile, GifByteType *OutputBuffer, ColorMapObject *OutputColorMap, mm_util_gif_frame_data * frame)
 {
        unsigned long i, j, pixels = 0;
@@ -447,8 +438,6 @@ int mm_util_encode_close_gif(mm_util_gif_data *encoded)
        return MM_UTIL_ERROR_NONE;
 }
 
-#define RGB_FREE(r, g, b) { free(r); free(g); free(b); }
-
 static int __write_gif(mm_util_gif_data *encoded)
 {
        int ColorMapSize;
@@ -484,20 +473,20 @@ static int __write_gif(mm_util_gif_data *encoded)
 
                if ((OutputColorMap = GifMakeMapObject(ColorMapSize, NULL)) == NULL) {
                        mm_util_error("could not map object");
-                       RGB_FREE((char *)red, (char *)green, (char *)blue);
+                       RGB_FREE(red, green, blue);
                        free(OutputBuffer);
                        mm_util_encode_close_gif(encoded);
                        return MM_UTIL_ERROR_INVALID_OPERATION;
                }
                if (GifQuantizeBuffer(encoded->frames[i]->width, encoded->frames[i]->height, &ColorMapSize, red, green, blue, OutputBuffer, OutputColorMap->Colors) == GIF_ERROR) {
                        mm_util_error("could not quantize buffer");
-                       RGB_FREE((char *)red, (char *)green, (char *)blue);
+                       RGB_FREE(red, green, blue);
                        free(OutputBuffer);
                        GifFreeMapObject(OutputColorMap);
                        mm_util_encode_close_gif(encoded);
                        return MM_UTIL_ERROR_INVALID_OPERATION;
                }
-               RGB_FREE((char *)red, (char *)green, (char *)blue);
+               RGB_FREE(red, green, blue);
 
                encoded->frames[i]->transparent_color.Red = 0xff;
                encoded->frames[i]->transparent_color.Green = 0xff;
@@ -540,39 +529,915 @@ int mm_util_encode_gif(mm_util_gif_data *encoded)
        return ret;
 }
 
-void mm_util_gif_encode_set_width(mm_util_gif_data *data, unsigned long width)
+#ifdef GIF_ENCODER_V2
+static const int DEFAULT_COLORMAP_SIZE = (1 << 8);
+
+int _gif_image_alloc_glob_ext_block(GifFileType *gif_file, int function, int byte_count, ExtensionBlock **ext_block);
+
+static int __gif_extract_rgb(gif_image_s *gif_image, unsigned long num_of_pixels, GifByteType **red, GifByteType **green, GifByteType **blue)
 {
-       data->width = width;
+       GifWord i, j;
+       GifByteType *redP, *greenP, *blueP;
+       GifByteType *buffer = (GifByteType*)gif_image->image_data;
+
+       mm_util_debug("__gif_extract_rgb_from_image");
+
+       RGB_ALLOC(redP, greenP, blueP, num_of_pixels, sizeof(GifByteType));
+
+       *red = redP;
+       *green = greenP;
+       *blue = blueP;
+       mm_util_retvm_if((redP == NULL || greenP == NULL || blueP == NULL), MM_UTIL_ERROR_OUT_OF_MEMORY, "Memory allocation failed");
+
+       for (i = 0; i < gif_image->image_desc.Height; i++) {
+               for (j = 0; j < gif_image->image_desc.Width; j++) {
+                       *redP++ = *buffer++;
+                       *greenP++ = *buffer++;
+                       *blueP++ = *buffer++;
+                       buffer++;
+               }
+       }
+
+       return MM_UTIL_ERROR_NONE;
 }
 
-void mm_util_gif_encode_set_height(mm_util_gif_data *data, unsigned long height)
+int __gif_make_color_map(gif_image_s *gif_image)
 {
-       data->height = height;
+       int ret = MM_UTIL_ERROR_NONE;
+       int colormap_size = DEFAULT_COLORMAP_SIZE;
+       GifByteType *red = NULL, *green = NULL, *blue = NULL;
+
+       mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       unsigned long num_of_pixels = gif_image->width * gif_image->height;
+
+       /* make colormap and quantization for the color table of gif */
+       ret = __gif_extract_rgb(gif_image, num_of_pixels, &red, &green, &blue);
+       if (ret != MM_UTIL_ERROR_NONE) {
+               mm_util_error("To extract rgb from image is  failed");
+               goto FAIL;
+       }
+
+       if ((gif_image->image_desc.ColorMap = GifMakeMapObject(colormap_size, NULL)) == NULL) {
+               mm_util_error("To make color map is  failed");
+               ret = MM_UTIL_ERROR_INVALID_OPERATION;
+               goto FAIL;
+       }
+
+       /* allocate output buffer */
+       gif_image->intermediate_image = (GifByteType *) calloc(1, num_of_pixels * sizeof(GifByteType));
+       if (gif_image->intermediate_image == NULL) {
+               mm_util_error("Memory allocation failed");
+               ret = MM_UTIL_ERROR_INVALID_OPERATION;
+               goto FAIL;
+       }
+       gif_image->intermediate_image_size = num_of_pixels * sizeof(GifByteType);
+
+       if (GifQuantizeBuffer(gif_image->image_desc.Width, gif_image->image_desc.Height, &colormap_size, red, green, blue, gif_image->intermediate_image, gif_image->image_desc.ColorMap->Colors) == GIF_ERROR) {
+               mm_util_error("could not quantize buffer");
+               ret = MM_UTIL_ERROR_INVALID_OPERATION;
+               goto FAIL;
+       }
+       goto SUCCESS;
+
+FAIL:
+       if (gif_image->intermediate_image) {
+               free(gif_image->intermediate_image);
+               gif_image->intermediate_image = NULL;
+       }
+       gif_image->intermediate_image_size = 0;
+       COLORMAP_FREE(gif_image->image_desc.ColorMap);
+SUCCESS:
+       RGB_FREE(red, green, blue);
+
+       return ret;
 }
 
-void mm_util_gif_encode_set_image_count(mm_util_gif_data *data, unsigned int image_count)
+int __gif_get_index_in_colormap(ColorMapObject * color_map, GifColorType get_color, int *index)
 {
-       data->image_count = image_count;
+       int i = 0;
+       mm_util_retvm_if(color_map == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       *index =  -1;
+
+       for (i = 0; i < color_map->ColorCount; i++) {
+               if(color_map->Colors[i].Red == get_color.Red &&
+                       color_map->Colors[i].Green == get_color.Green &&
+                       color_map->Colors[i].Blue == get_color.Blue) {
+                       *index =  i;
+                       break;
+               }
+       }
+
+       return MM_UTIL_ERROR_NONE;
 }
 
-void mm_util_gif_encode_set_frame_delay_time(mm_util_gif_frame_data *frame, unsigned long long delay_time)
+int _gif_encode_open_file(gif_file_s *gif_file)
 {
-       frame->delay_time = delay_time;
+       mm_util_fenter();
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       if ((gif_file->GifFile = EGifOpenFileName(GIF_TMP_FILE, 0, NULL)) == NULL) {
+               mm_util_error("could not open file");
+               return MM_UTIL_ERROR_INVALID_OPERATION;
+       }
+
+       return MM_UTIL_ERROR_NONE;
 }
 
-void mm_util_gif_encode_set_frame_disposal_mode(mm_util_gif_frame_data *frame, mm_util_gif_disposal disposal_mode)
+int _gif_encode_open_mem(gif_file_s *gif_file)
 {
-       frame->disposal_mode = disposal_mode;
+       mm_util_fenter();
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       gif_file->write_data_ptr.mem = (void**)&(gif_file->buffer);
+       gif_file->write_data_ptr.size = 0;
+
+       if ((gif_file->GifFile = EGifOpen(&(gif_file->write_data_ptr), __write_function, NULL)) == NULL) {
+               mm_util_error("could not open File");
+               return MM_UTIL_ERROR_INVALID_OPERATION;
+       }
+
+       return MM_UTIL_ERROR_NONE;
 }
 
-void mm_util_gif_encode_set_frame_position(mm_util_gif_frame_data *frame, unsigned long x, unsigned long y)
+int _gif_encode_init(gif_file_s *gif_file)
 {
-       frame->x = x;
-       frame->y = y;
+       int ret = MM_UTIL_ERROR_NONE;
+       ExtensionBlock *_ext_block = NULL;
+
+       mm_util_fenter();
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       if (gif_file->is_repeat) {
+               /* set netscape 2.0 application data to play animated gif */
+               ret = _gif_image_alloc_glob_ext_block(gif_file->GifFile, APPLICATION_EXT_FUNC_CODE, APP_EXT_BLOCK_SIZE, &_ext_block);
+               mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_image_alloc_ext_block failed");
+               mm_util_retvm_if(_ext_block->Bytes == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "_gif_image_alloc_ext_block failed");
+
+               memcpy(_ext_block->Bytes, APP_EXT_BLOCK_DATA, APP_EXT_BLOCK_SIZE);
+
+               /* write sub block of application data to play animated gif  with repeat count */
+               ret = _gif_image_alloc_glob_ext_block(gif_file->GifFile, CONTINUE_EXT_FUNC_CODE, SUB_BLOCK_SIZE, &_ext_block);
+               mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_image_alloc_ext_block failed");
+               mm_util_retvm_if(_ext_block->Bytes == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "_gif_image_alloc_ext_block failed");
+               _ext_block->Bytes[0] = NETSCAPE_SUB_BLOCK_INDEX;
+               if (gif_file->repeat_count == 0) {
+                       _ext_block->Bytes[1] = 0x00;
+                       _ext_block->Bytes[2] = 0x00;
+               } else {
+                       _ext_block->Bytes[1] = (gif_file->repeat_count & 0xff);
+                       _ext_block->Bytes[2] = ((gif_file->repeat_count >> 8) & 0xff);
+               }
+       } else {
+               /* change gif version to 89a due to extension blocks. */
+               EGifSetGifVersion(gif_file->GifFile, TRUE);
+       }
+
+       return MM_UTIL_ERROR_NONE;
 }
 
-void mm_util_gif_encode_set_frame_transparency_color(mm_util_gif_frame_data *frame, GifColorType transparent_color)
+int _gif_encode_close_file(gif_file_s *gif_file)
 {
-       frame->is_transparent = true;
-       frame->transparent_color = transparent_color;
+       mm_util_fenter();
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_file->GifFile == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       if (EGifCloseFile(gif_file->GifFile, NULL) == GIF_ERROR) {
+               mm_util_error("could not close file");
+               return MM_UTIL_ERROR_INVALID_OPERATION;
+       }
+       gif_file->GifFile = NULL;
+
+       return MM_UTIL_ERROR_NONE;
 }
+
+int _gif_encode_move_to_origin(const char *origin)
+{
+       const char *command = "/bin/cp";
+       long ARG_MAX = sysconf(_SC_ARG_MAX);
+       char *command_line = NULL;
+
+       mm_util_retvm_if((((long)strlen(command) + (long)strlen(GIF_TMP_FILE) + (long)strlen(origin) + 3) >= ARG_MAX),
+               MM_UTIL_ERROR_INVALID_OPERATION, "command is too long");
+
+       command_line = (char *)calloc(1, ARG_MAX);
+       mm_util_retvm_if(command_line == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "memory allocation failed");
+
+       snprintf(command_line, ARG_MAX, "%s %s %s", command, GIF_TMP_FILE, origin);
+
+       mm_util_debug("[MV COMMAND: %s]", command_line);
+       WEXITSTATUS(system(command_line));
+
+       MMUTIL_SAFE_FREE(command_line);
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int _gif_encode_move_to_origin_mem(const unsigned char *src, unsigned long src_size, void **dst, unsigned long *dst_size)
+{
+       unsigned char *buffer = NULL;
+       mm_util_retvm_if(src == NULL || dst == NULL || dst_size == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(src_size == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       buffer = (unsigned char *)calloc(1, src_size);
+       mm_util_retvm_if(buffer == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "memory allocation failed");
+
+       mm_util_debug("src_size: %lu", src_size);
+
+       memcpy(buffer, src, src_size);
+
+       *dst = buffer;
+       *dst_size = src_size;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int _gif_image_write_image_desc(gif_file_s *gif_file, gif_image_s *gif_image)
+{
+       mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_image->image_data == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       if (EGifPutImageDesc(gif_file->GifFile, gif_image->image_desc.Left, gif_image->image_desc.Top,
+               gif_image->image_desc.Width, gif_image->image_desc.Height, gif_image->image_desc.Interlace,
+               gif_image->image_desc.ColorMap) == GIF_ERROR) {
+               mm_util_error("EGifPutImageDesc failed due to %s", GifErrorString(gif_file->GifFile->Error));
+               return MM_UTIL_ERROR_INVALID_OPERATION;
+       }
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int _gif_image_write_image_data(gif_file_s *gif_file, gif_image_s *gif_image)
+{
+       unsigned long idx = 0;
+       mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_image->image_data == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       /* encode OutputBuffer to GifFile */
+       unsigned char *ptr = gif_image->intermediate_image;
+       mm_util_retvm_if(gif_image->intermediate_image == NULL, MM_UTIL_ERROR_INVALID_OPERATION, "Intermediate_image is null");
+
+       mm_util_debug("put pixel count: %lu", (gif_image->intermediate_image_size / sizeof(GifPixelType)));
+
+       for (idx = 0; idx < (gif_image->intermediate_image_size / sizeof(GifPixelType)); idx++) {
+               GifPixelType pixel = (GifPixelType)ptr[idx];
+               if (EGifPutPixel(gif_file->GifFile, pixel) == GIF_ERROR) {
+                       mm_util_error("could not put pixel");
+                       return MM_UTIL_ERROR_INVALID_OPERATION;
+               }
+       }
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int _gif_image_alloc_ext_block(gif_image_s *gif_image, int function, int byte_count, ExtensionBlock **ext_block)
+{
+       int i = 0;
+       ExtensionBlock *_ext_block = NULL;
+
+       mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(byte_count == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(ext_block == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       if (gif_image->ext_blocks == NULL) {
+               gif_image->ext_blocks = (ExtensionBlock *)calloc(1, sizeof(ExtensionBlock));
+               if (gif_image->ext_blocks == NULL) {
+                       mm_util_error("Memory allocation failed");
+                       *ext_block = NULL;
+                       return MM_UTIL_ERROR_OUT_OF_MEMORY;
+               }
+       } else {
+               /* check exist function block */
+               for (i = 0; i < gif_image->ext_block_count; i++) {
+                       _ext_block = &gif_image->ext_blocks[i];
+                       if (_ext_block != NULL && _ext_block->Function == function) {
+                               mm_util_error("[Not Error] Ext block has already exist");
+                               *ext_block = _ext_block;
+                               return MM_UTIL_ERROR_NONE;
+                       }
+               }
+               ExtensionBlock *realloc_ptr = (ExtensionBlock *)realloc(gif_image->ext_blocks, (sizeof(ExtensionBlock) * (gif_image->ext_block_count + 1)));
+               if (realloc_ptr == NULL) {
+                       mm_util_error("Memory reallocation failed");
+                       *ext_block = NULL;
+                       return MM_UTIL_ERROR_OUT_OF_MEMORY;
+               }
+               gif_image->ext_blocks = realloc_ptr;
+       }
+
+       /* get allocated extention block */
+       _ext_block = &gif_image->ext_blocks[gif_image->ext_block_count];
+
+       _ext_block->Function = function;
+       _ext_block->ByteCount = byte_count;
+       _ext_block->Bytes = (GifByteType *)calloc(1, (sizeof(GifByteType) * byte_count));
+       if (_ext_block->Bytes == NULL) {
+               mm_util_error("Memory allocation failed");
+               /* free all ext_blocks, TODO: free current ext_blocks */
+               for (i = 0; i < gif_image->ext_block_count; i++) {
+                       _ext_block = &gif_image->ext_blocks[i];
+                       MMUTIL_SAFE_FREE(_ext_block->Bytes);
+               }
+               MMUTIL_SAFE_FREE(gif_image->ext_blocks);
+               gif_image->ext_block_count = 0;
+               return MM_UTIL_ERROR_OUT_OF_MEMORY;
+       }
+
+       gif_image->ext_block_count++;
+
+       *ext_block = _ext_block;
+       return MM_UTIL_ERROR_NONE;
+}
+
+int _gif_image_write_ext_blocks(gif_file_s *gif_file, gif_image_s *gif_image)
+{
+       int ret = MM_UTIL_ERROR_NONE;
+       int i = 0;
+       ExtensionBlock *_ext_block = NULL;
+
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       ret = _gif_image_alloc_ext_block(gif_image, GRAPHICS_EXT_FUNC_CODE, GRAPHIC_EXT_BLOCK_SIZE, &_ext_block);
+       mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_image_alloc_ext_block failed");
+       mm_util_retvm_if(_ext_block->Bytes == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "_gif_image_alloc_ext_block failed");
+
+       EGifGCBToExtension(&gif_image->graphic_control_block, _ext_block->Bytes);
+
+       for (i = 0; i < gif_image->ext_block_count; i++) {
+               _ext_block = &gif_image->ext_blocks[i];
+               mm_util_retvm_if(_ext_block == NULL, MM_UTIL_ERROR_INVALID_OPERATION, "extension block is empty");
+
+               if (EGifPutExtension(gif_file->GifFile, _ext_block->Function, _ext_block->ByteCount, _ext_block->Bytes) == GIF_ERROR) {
+                       mm_util_error("EGifPutExtension failed due to %s", GifErrorString(gif_file->GifFile->Error));
+                       return MM_UTIL_ERROR_INVALID_OPERATION;
+               }
+       }
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int _gif_image_alloc_glob_ext_block(GifFileType *gif_file, int function, int byte_count, ExtensionBlock **ext_block)
+{
+       int i = 0;
+       ExtensionBlock *_ext_block = NULL;
+
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(byte_count == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(ext_block == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       if (gif_file->ExtensionBlocks == NULL) {
+               gif_file->ExtensionBlocks = (ExtensionBlock *)calloc(1, sizeof(ExtensionBlock));
+               if (gif_file->ExtensionBlocks == NULL) {
+                       mm_util_error("Memory allocation failed");
+                       *ext_block = NULL;
+                       return MM_UTIL_ERROR_OUT_OF_MEMORY;
+               }
+       } else {
+               /* check exist function block */
+               for (i = 0; i < gif_file->ExtensionBlockCount; i++) {
+                       _ext_block = &gif_file->ExtensionBlocks[i];
+                       if (_ext_block != NULL && _ext_block->Function == function) {
+                               mm_util_error("[Not Error] Ext block has already exist");
+                               *ext_block = _ext_block;
+                               return MM_UTIL_ERROR_NONE;
+                       }
+               }
+               ExtensionBlock *realloc_ptr = (ExtensionBlock *)realloc(gif_file->ExtensionBlocks, (sizeof(ExtensionBlock) * (gif_file->ExtensionBlockCount + 1)));
+               if (realloc_ptr == NULL) {
+                       mm_util_error("Memory reallocation failed");
+                       *ext_block = NULL;
+                       return MM_UTIL_ERROR_OUT_OF_MEMORY;
+               }
+               gif_file->ExtensionBlocks = realloc_ptr;
+       }
+
+       /* get allocated extention block */
+       _ext_block = &gif_file->ExtensionBlocks[gif_file->ExtensionBlockCount];
+
+       _ext_block->Function = function;
+       _ext_block->ByteCount = byte_count;
+       _ext_block->Bytes = (GifByteType *)calloc(1, (sizeof(GifByteType) * byte_count));
+       if (_ext_block->Bytes == NULL) {
+               mm_util_error("Memory allocation failed");
+               /* free all ext_blocks, TODO: free current ext_blocks */
+               for (i = 0; i < gif_file->ExtensionBlockCount; i++) {
+                       _ext_block = &gif_file->ExtensionBlocks[i];
+                       MMUTIL_SAFE_FREE(_ext_block->Bytes);
+               }
+               MMUTIL_SAFE_FREE(gif_file->ExtensionBlocks);
+               gif_file->ExtensionBlockCount = 0;
+               return MM_UTIL_ERROR_OUT_OF_MEMORY;
+       }
+
+       gif_file->ExtensionBlockCount++;
+
+       *ext_block = _ext_block;
+       return MM_UTIL_ERROR_NONE;
+}
+
+int _gif_image_write_glob_ext_blocks(gif_file_s *gif_file)
+{
+       int i = 0;
+       ExtensionBlock *_ext_block = NULL;
+
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       for (i = 0; i < gif_file->GifFile->ExtensionBlockCount; i++) {
+               _ext_block = &gif_file->GifFile->ExtensionBlocks[i];
+               mm_util_retvm_if(_ext_block == NULL, MM_UTIL_ERROR_NONE, "extension block is empty");
+
+               if (_ext_block->Function != CONTINUE_EXT_FUNC_CODE) {
+                       if (EGifPutExtensionLeader(gif_file->GifFile, _ext_block->Function) == GIF_ERROR) {
+                               mm_util_error("EGifPutExtensionLeader failed due to %s", GifErrorString(gif_file->GifFile->Error));
+                               return MM_UTIL_ERROR_INVALID_OPERATION;
+                       }
+               }
+               if (EGifPutExtensionBlock(gif_file->GifFile, _ext_block->ByteCount, _ext_block->Bytes) == GIF_ERROR) {
+                       mm_util_error("EGifPutExtensionBlock failed due to %s", GifErrorString(gif_file->GifFile->Error));
+                       return MM_UTIL_ERROR_INVALID_OPERATION;
+               }
+               if (i == gif_file->GifFile->ExtensionBlockCount - 1 || (_ext_block + 1)->Function != CONTINUE_EXT_FUNC_CODE) {
+                       if (EGifPutExtensionTrailer(gif_file->GifFile) == GIF_ERROR) {
+                               mm_util_error("EGifPutExtensionTrailer failed due to %s", GifErrorString(gif_file->GifFile->Error));
+                               return MM_UTIL_ERROR_INVALID_OPERATION;
+                       }
+               }
+       }
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_image_create(mm_gif_file_h gif_file_h, mm_gif_image_h *gif_image_h)
+{
+       gif_file_s *gif_file = (gif_file_s *)gif_file_h;
+       gif_image_s *pImage = NULL;
+
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       pImage = (gif_image_s *)calloc(1, sizeof(gif_image_s));
+       mm_util_retvm_if(pImage == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "Memory allocation failed");
+
+       /* init image when it is allocated */
+       /* set default width & height */
+       pImage->width = pImage->image_desc.Width = gif_file->width;
+       pImage->height =  pImage->image_desc.Height = gif_file->height;
+       pImage->image_desc.Interlace = FALSE;   /* don't change this,  fixed value */
+       pImage->ext_block_count = 0;
+       pImage->ext_blocks = NULL;
+       pImage->has_color_map = FALSE;
+       pImage->has_transparent = FALSE;
+       pImage->graphic_control_block.DisposalMode = MM_UTIL_GIF_DISPOSAL_UNSPECIFIED;
+       pImage->graphic_control_block.UserInputFlag = FALSE;
+       pImage->graphic_control_block.TransparentColor = NO_TRANSPARENT_COLOR;
+
+       *gif_image_h = (mm_gif_image_h)pImage;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_image_set_position(mm_gif_image_h gif_image_h, int left, int top, int width, int height)
+{
+       gif_image_s *gif_image = (gif_image_s *)gif_image_h;
+
+       mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(left < 0 || top < 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(width <= 0 || height <= 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(left + width > gif_image->width, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(top + height > gif_image->height, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       mm_util_info("%s l = %d, t = %d, w= %d, h = %d", __func__, left, top, width, height);
+
+       gif_image->image_desc.Left = left;
+       gif_image->image_desc.Top = top;
+       gif_image->image_desc.Width = width;
+       gif_image->image_desc.Height = height;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_image_set_disposal_mode(mm_gif_image_h gif_image_h, const mm_util_gif_disposal disposal_mode)
+{
+       gif_image_s *gif_image = (gif_image_s *)gif_image_h;
+
+       mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       mm_util_info("%s mode = %d", __func__, disposal_mode);
+
+       gif_image->graphic_control_block.DisposalMode = (int)disposal_mode;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_image_set_delay_time(mm_gif_image_h gif_image_h, const int delay_time)
+{
+       gif_image_s *gif_image = (gif_image_s *)gif_image_h;
+
+       mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(delay_time == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       mm_util_info("%s mode = %lu", __func__, delay_time);
+
+       gif_image->graphic_control_block.DelayTime = delay_time;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_image_set_tp_color(mm_gif_image_h gif_image_h, const mm_util_gif_color_s tp_color)
+{
+       gif_image_s *gif_image = (gif_image_s *)gif_image_h;
+
+       mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       gif_image->has_transparent = TRUE;
+       gif_image->transparent_color.Red = tp_color.red;
+       gif_image->transparent_color.Green = tp_color.green;
+       gif_image->transparent_color.Blue = tp_color.blue;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_image_set_color_map(mm_gif_image_h gif_image_h, int number_of_colors, mm_util_gif_color_s *colors)
+{
+       gif_image_s *gif_image = (gif_image_s *)gif_image_h;
+
+       mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(number_of_colors == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(colors == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       mm_util_info("%s ptr = %p, size = %lu", __func__, colors, number_of_colors);
+
+       GifColorType *color_map = (GifColorType*)colors;
+
+       gif_image->image_desc.ColorMap = GifMakeMapObject(number_of_colors, color_map);
+       mm_util_retvm_if(gif_image->image_desc.ColorMap == NULL, MM_UTIL_ERROR_INVALID_OPERATION, "To make color map is  failed");
+       gif_image->has_color_map = TRUE;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_image_set_image(mm_gif_image_h gif_image_h, unsigned char *image_data, unsigned long size)
+{
+       gif_image_s *gif_image = (gif_image_s *)gif_image_h;
+
+       mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(image_data == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(size == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       mm_util_info("%s ptr = %p, size = %lu", __func__, image_data, size);
+
+       gif_image->image_data = image_data;
+       gif_image->image_data_size = size;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+void mm_util_gif_image_destory(mm_gif_image_h gif_image_h)
+{
+       int  i = 0;
+       ExtensionBlock *_ext_block = NULL;
+       gif_image_s *gif_image = (gif_image_s *)gif_image_h;
+
+       mm_util_retm_if(gif_image == NULL, "Invalid parameter");
+
+       /* release color map */
+       COLORMAP_FREE(gif_image->image_desc.ColorMap);
+
+       /* release extension blocks */
+       if (gif_image->ext_blocks != NULL) {
+               for (i = 0; i < gif_image->ext_block_count; i++) {
+                       _ext_block = &gif_image->ext_blocks[i];
+                       MMUTIL_SAFE_FREE(_ext_block->Bytes);
+               }
+               MMUTIL_SAFE_FREE(gif_image->ext_blocks);
+       }
+
+       /* release intermediate_image */
+       MMUTIL_SAFE_FREE(gif_image->intermediate_image);
+       MMUTIL_SAFE_FREE(gif_image);
+}
+
+int mm_util_gif_encode_create(mm_gif_file_h *gif_file_h)
+{
+       gif_file_s *gif_file = NULL;
+
+       mm_util_retvm_if(gif_file_h == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       gif_file = (gif_file_s *)calloc(1, sizeof(gif_file_s));
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "Memory allocation failed");
+
+       /* initialize data before set */
+       gif_file->color_res = 8;
+       gif_file->background_color = 0;
+       gif_file->color_map = NULL;
+       gif_file->is_started = FALSE;
+       gif_file->is_repeat = FALSE;
+       gif_file->repeat_count = 0;
+
+       *gif_file_h = (mm_gif_file_h)gif_file;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_encode_set_file(mm_gif_file_h gif_file_h, const char *file_name)
+{
+       gif_file_s *gif_file = (gif_file_s *)gif_file_h;
+
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(file_name == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(strlen(file_name) == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_file->is_started, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
+
+       gif_file->filename = g_strdup(file_name);
+       mm_util_retvm_if(gif_file->filename == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "Memory allocation failed");
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_encode_set_mem(mm_gif_file_h gif_file_h, void **data, unsigned long *data_size)
+{
+       gif_file_s *gif_file = (gif_file_s *)gif_file_h;
+
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(data == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(data_size == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_file->is_started, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
+
+       gif_file->enc_buffer = data;
+       gif_file->enc_buffer_size = data_size;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_encode_set_resolution(mm_gif_file_h gif_file_h, const int width, const int height)
+{
+       gif_file_s *gif_file = (gif_file_s *)gif_file_h;
+
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(width == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(height == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_file->is_started, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
+
+       mm_util_info("%s w = %lu, h = %lu", __func__, width, height);
+
+       gif_file->width = width;
+       gif_file->height = height;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+#if 0
+int mm_util_gif_encode_set_bg_color(mm_gif_file_h gif_file_h, const mm_util_gif_color_s bg_color)
+{
+       gif_file_s *gif_file = (gif_file_s *)gif_file_h;
+       GifColorType *colors = NULL;
+       int color_count = 1 << gif_file->color_res;
+
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       colors = (GifColorType *)calloc(1, color_count * sizeof(GifColorType));
+       mm_util_retvm_if(colors == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "memory allocation failed");
+
+       colors[0].Red = bg_color.red;
+       colors[0].Green = bg_color.green;
+       colors[0].Blue = bg_color.blue;
+
+       gif_file->color_map = GifMakeMapObject(color_count, colors);
+       mm_util_retvm_if(gif_file->color_map == NULL, MM_UTIL_ERROR_INVALID_OPERATION, "could not make color map");
+
+       gif_file->background_color = 0; /* index of color map */
+
+       return MM_UTIL_ERROR_NONE;
+}
+#endif
+
+int mm_util_gif_encode_set_repeat(mm_gif_file_h gif_file_h, gboolean repeat_mode, unsigned short repeat_count)
+{
+       gif_file_s *gif_file = (gif_file_s *)gif_file_h;
+
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_file->is_started, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
+
+       mm_util_info("%s repeat = %d, count = %d", __func__, repeat_mode, repeat_count);
+
+       gif_file->is_repeat = repeat_mode;
+       gif_file->repeat_count = repeat_count;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_encode_start(mm_gif_file_h gif_file_h)
+{
+       int ret = MM_UTIL_ERROR_NONE;
+       gif_file_s *gif_file = (gif_file_s *)gif_file_h;
+
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_file->is_started, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
+
+       mm_util_fenter();
+
+       if (gif_file->filename != NULL) {
+               ret = _gif_encode_open_file(gif_file);
+               mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_encode_open_file failed");
+       } else if (gif_file->enc_buffer != NULL && gif_file->enc_buffer_size != NULL) {
+               ret = _gif_encode_open_mem(gif_file);
+               mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_encode_open_mem failed");
+       } else {
+               mm_util_error("could not find output");
+               return MM_UTIL_ERROR_INVALID_OPERATION;
+       }
+
+       /* To initialize data after GifFile opened */
+       ret = _gif_encode_init(gif_file);
+       mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_encode_init failed");
+
+       /* Write screen description */
+       if (EGifPutScreenDesc(gif_file->GifFile, gif_file->width, gif_file->height,
+               gif_file->color_res, gif_file->background_color, gif_file->color_map) == GIF_ERROR) {
+               mm_util_error("could not put screen description");
+               _gif_encode_close_file(gif_file);
+               return MM_UTIL_ERROR_INVALID_OPERATION;
+       }
+
+       /* Write global extension blocks */
+       ret = _gif_image_write_glob_ext_blocks(gif_file);
+       mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_image_write_glob_ext_blocks failed");
+
+       gif_file->is_started = TRUE;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_encode_add_image(mm_gif_file_h gif_file_h, mm_gif_image_h gif_image_h)
+{
+       int ret = MM_UTIL_ERROR_NONE;
+       gif_file_s *gif_file = (gif_file_s *)gif_file_h;
+       gif_image_s *gif_image = (gif_image_s *)gif_image_h;
+
+       mm_util_fenter();
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       if (gif_file->is_started == FALSE) {
+               mm_util_info("first added image, mm_util_gif_encode_start is needed");
+               mm_util_gif_encode_start(gif_file_h);
+       }
+
+       /* Make local color map */
+       if (gif_image->has_color_map == FALSE) {
+               ret = __gif_make_color_map(gif_image);
+               mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_make_color_map failed");
+       }
+
+       if (gif_image->has_transparent) {
+               ret = __gif_get_index_in_colormap(gif_image->image_desc.ColorMap, 
+                       gif_image->transparent_color, &gif_image->graphic_control_block.TransparentColor);
+               mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_get_index_in_colormap failed");
+       }
+
+       /* Write extension blocks */
+       ret = _gif_image_write_ext_blocks(gif_file, gif_image);
+       mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_image_write_ext_blocks failed");
+
+       /* Write image description */
+       ret = _gif_image_write_image_desc(gif_file, gif_image);\
+       mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_image_write_image_desc failed");
+
+       /* Write image data */
+       ret = _gif_image_write_image_data(gif_file, gif_image);
+       mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_image_write_image_data failed");
+
+       gif_file->GifFile->ImageCount++;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_encode_save(mm_gif_file_h gif_file_h)
+{
+       int ret = MM_UTIL_ERROR_NONE;
+       gif_file_s *gif_file = (gif_file_s *)gif_file_h;
+
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(!gif_file->is_started, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has not started");
+
+       mm_util_fenter();
+
+       ret = _gif_encode_close_file(gif_file);
+       mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_encode_close_file failed");
+
+       if (gif_file->filename != NULL) {
+               ret= _gif_encode_move_to_origin(gif_file->filename);
+               mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__move_tmp_to_origin failed");
+       } else if (gif_file->write_data_ptr.mem != NULL) {
+               ret = _gif_encode_move_to_origin_mem(gif_file->buffer, gif_file->write_data_ptr.size,
+                       gif_file->enc_buffer, gif_file->enc_buffer_size);
+               MMUTIL_SAFE_FREE(gif_file->buffer);
+               gif_file->write_data_ptr.size = 0;
+               mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_encode_move_to_origin_mem failed");
+       }
+
+       gif_file->is_started = FALSE;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+
+int mm_util_gif_enocde_set_image_handle(mm_gif_file_h gif_file_h, mm_gif_image_h gif_image_h)
+{
+       gif_file_s *gif_file = (gif_file_s *)gif_file_h;
+       gif_image_s *gif_image = (gif_image_s *)gif_image_h;
+
+       mm_util_fenter();
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_file->is_started, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
+
+       if (gif_file->saved_image == NULL) {
+               gif_file->saved_image = (gif_image_s **)calloc(1, sizeof(mm_gif_image_h));
+               mm_util_retvm_if(gif_file->saved_image == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "memory allocation failed");
+       } else {
+               gif_image_s **tmp = (gif_image_s **)realloc(gif_file->saved_image, sizeof(mm_gif_image_h) * (gif_file->saved_image_count + 1));
+               mm_util_retvm_if(tmp == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "memory allocation failed");
+               gif_file->saved_image = tmp;
+       }
+
+       gif_file->saved_image[gif_file->saved_image_count] = gif_image;
+       gif_file->saved_image_count++;
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_enocde_get_image_handle(mm_gif_file_h gif_file_h, int index, mm_gif_image_h *gif_image_h)
+{
+       gif_file_s *gif_file = (gif_file_s *)gif_file_h;
+
+       mm_util_fenter();
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_image_h == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_file->is_started, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
+
+       if (index < gif_file->saved_image_count) {
+               *gif_image_h = (mm_gif_image_h)gif_file->saved_image[index];
+       } else {
+               *gif_image_h = NULL;
+       }
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_gif_encode(mm_gif_file_h gif_file_h)
+{
+       int ret = MM_UTIL_ERROR_NONE;
+       int i = 0;
+
+       gif_file_s *gif_file = (gif_file_s *)gif_file_h;
+       mm_gif_image_h gif_image = NULL;
+
+       mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
+       mm_util_retvm_if(gif_file->saved_image == NULL, MM_UTIL_ERROR_INVALID_OPERATION, "Invalid parameter");
+
+       ret = mm_util_gif_encode_start(gif_file_h);
+       mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_start failed");
+
+       for (i = 0; i < gif_file->saved_image_count; i++) {
+               gif_image = (mm_gif_image_h)gif_file->saved_image[i];
+               ret = mm_util_gif_encode_add_image(gif_file_h, gif_image);
+               mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_add_image failed");
+               mm_util_gif_image_destory(gif_image);
+       }
+
+       ret = mm_util_gif_encode_save(gif_file_h);
+       mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_save failed");
+
+       return MM_UTIL_ERROR_NONE;
+}
+
+void mm_util_gif_encode_destroy(mm_gif_file_h gif_file_h)
+{
+       int ret = MM_UTIL_ERROR_NONE;
+       int i = 0;
+       gif_file_s *gif_file = (gif_file_s *)gif_file_h;
+
+       mm_util_retm_if(gif_file == NULL, "Invalid parameter");
+       mm_util_retm_if(gif_file->GifFile == NULL, "GifFile is already closed");
+
+       if (gif_file->GifFile != NULL) {
+               ret = _gif_encode_close_file(gif_file);
+               mm_util_retm_if(ret != MM_UTIL_ERROR_NONE, "_gif_encode_close_file failed");
+       }
+
+       if (gif_file->saved_image != NULL) {
+               for (i = 0; i < gif_file->saved_image_count; i++) {
+                       mm_gif_image_h tmp = (mm_gif_image_h)gif_file->saved_image[i];
+                       mm_util_gif_image_destory(tmp);
+               }
+               MMUTIL_SAFE_FREE(gif_file->saved_image);
+       }
+
+       COLORMAP_FREE(gif_file->color_map);
+
+       MMUTIL_SAFE_FREE(gif_file->filename);
+       MMUTIL_SAFE_FREE(gif_file->buffer);
+}
+#endif
index e72aca6..ce8afe9 100755 (executable)
@@ -75,6 +75,7 @@ extern "C"
                } \\r
        } while (0)\r
 \r
+#define MMUTIL_SAFE_FREE(x)                            { if (x) { free(x); x = NULL; } }\r
 /**\r
 * @}\r
 */\r
index 2882b4e..27b1457 100755 (executable)
@@ -1,6 +1,6 @@
 Name:       libmm-utility
 Summary:    Multimedia Framework Utility Library
-Version:    0.33
+Version:    0.34
 Release:    0
 Group:      System/Libraries
 License:    Apache-2.0
@@ -54,6 +54,7 @@ export CFLAGS+=" -Wextra -Wno-array-bounds"
 export CFLAGS+=" -Wno-ignored-qualifiers -Wno-unused-parameter -Wshadow"
 export CFLAGS+=" -Wwrite-strings -Wswitch-default"
 export CFLAGS+=" -Werror"
+export CFLAGS+=" -DGIF_ENCODER_V2"
 CFLAGS="$CFLAGS -DEXPORT_API=\"__attribute__((visibility(\\\"default\\\")))\" -D_MM_PROJECT_FLOATER" \
 LDFLAGS="$LDFLAGS -Wl,--rpath=%{_libdir} -Wl,--hash-style=both -Wl,--as-needed" \
 %reconfigure