#ifdef __cplusplus
extern "C" {
#endif
-#include "mm_util_imgp.h"
+
+#include <glib.h>
#include "gif_lib.h"
+#include "mm_util_imgp.h"
/**
@addtogroup UTILITY
* Write data attached to encoding callback
*/
typedef struct {
- unsigned long long size;
+ unsigned long size;
void **mem;
} write_data;
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 */
*/
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
*
*/
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
}
#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;
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;
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;
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;
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;
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;
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