4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Vineeth T M <vineeth.tm@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
26 #include "mm_util_gif.h"
27 #include "mm_util_private.h"
31 #define COLORMAP_FREE(map) { if (map != NULL) { GifFreeMapObject(map); map = NULL; } }
32 #define GRAPHIC_EXT_BLOCK_SIZE 4
41 GifFileType *GifFile; /**< GifFile opened */
43 unsigned int loop_count;
44 void **enc_buffer; /**< Encoded output data attached to callback */
45 size_t *enc_buffer_size;
49 static int __read_function(GifFileType *gft, GifByteType *data, int size)
51 gif_io_buf_s *io_buf = (gif_io_buf_s *) gft->UserData;
53 mm_util_retvm_if(!io_buf || !io_buf->buf || io_buf->buf_size == 0, 0, "Invalid io_buf");
54 mm_util_retvm_if(!data, 0, "Invalid data");
55 mm_util_retvm_if(size <= 0, 0, "Invalid size [%d]", size);
56 mm_util_retvm_if(io_buf->pos + size > io_buf->buf_size, 0, "Invalid read due to buffer overflow [%zu/%d/%zu].", io_buf->pos, size, io_buf->buf_size);
58 memcpy(data, io_buf->buf + io_buf->pos, size);
64 static int __gif_open(const char *file_path, void *memory, const size_t src_size, gif_io_buf_s *io_buf, GifFileType **gif_image)
66 mm_util_retvm_if(!MMUTIL_STRING_VALID(file_path) && (memory == NULL), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid gif image");
68 if (MMUTIL_STRING_VALID(file_path)) {
69 mm_util_sec_debug("read from file [%s]", file_path);
70 if ((*gif_image = DGifOpenFileName(file_path, NULL)) == NULL) {
71 mm_util_error("could not open Gif File");
72 return MM_UTIL_ERROR_INVALID_OPERATION;
75 mm_util_debug("read from memory");
76 if ((*gif_image = DGifOpen(io_buf, __read_function, NULL)) == NULL) {
77 mm_util_error("could not open Gif File");
78 return MM_UTIL_ERROR_INVALID_OPERATION;
82 return MM_UTIL_ERROR_NONE;
85 static void __gif_free_frame_buffer(GifRowType *frame_buffer, unsigned int size)
92 for (idx = 0; idx < size; idx++)
93 g_free(frame_buffer[idx]);
98 static int __gif_generate_frame_buffer(GifFileType *gif_image, GifRowType **screen_buf)
102 GifRowType* _screen_buf = NULL;
104 _screen_buf = g_new0(GifRowType, gif_image->SHeight);
106 row_size = gif_image->SWidth * sizeof(GifPixelType); /* Size in bytes one row. */
107 _screen_buf[0] = g_malloc0(row_size);
109 for (idx = 0; idx < (int)(gif_image->SWidth); idx++) /* Set its color to BackGround. */
110 _screen_buf[0][idx] = gif_image->SBackGroundColor;
112 for (idx = 1; idx < (int)(gif_image->SHeight); idx++) {
113 /* Allocate the other rows, and set their color to background too: */
114 _screen_buf[idx] = g_memdup2(_screen_buf[0], row_size);
117 *screen_buf = _screen_buf;
119 return MM_UTIL_ERROR_NONE;
122 static gboolean __gif_is_good_frame(GifFileType *gif_image)
124 mm_util_debug("Frame pos: %d, %d size: %dx%d", gif_image->Image.Left, gif_image->Image.Top, gif_image->Image.Width, gif_image->Image.Height);
126 if (gif_image->Image.Top < 0 || gif_image->Image.Left < 0 || gif_image->Image.Width <= 0 || gif_image->Image.Height <= 0) {
127 mm_util_error("Frame has wrong dimensions");
131 if (gif_image->Image.Left + gif_image->Image.Width > gif_image->SWidth || gif_image->Image.Top + gif_image->Image.Height > gif_image->SHeight) {
132 mm_util_debug("Frame is not full screen frame");
139 static int __gif_fill_frame_buffer(GifFileType *gif_image, GifRowType *frame_buffer)
143 unsigned int Row = (unsigned int)gif_image->Image.Top; /* Image Position relative to Screen. */
144 unsigned int Col = (unsigned int)gif_image->Image.Left;
145 unsigned int Width = (unsigned int)gif_image->Image.Width;
146 unsigned int Height = (unsigned int)gif_image->Image.Height;
147 unsigned int interlaced_offset[] = { 0, 4, 2, 1 }, interlaced_jumps[] = {
150 if (gif_image->Image.Interlace) {
151 /* Need to perform 4 passes on the images: */
152 for (i = 0; i < 4; i++)
153 for (j = Row + interlaced_offset[i]; j < Row + Height; j += interlaced_jumps[i]) {
154 if (DGifGetLine(gif_image, &frame_buffer[j][Col], Width) == GIF_ERROR) {
155 mm_util_error("could not get line (%u)", gif_image->Error);
156 return MM_UTIL_ERROR_INVALID_OPERATION;
160 for (i = 0; i < Height; i++) {
161 if (DGifGetLine(gif_image, &frame_buffer[Row++][Col], Width) == GIF_ERROR) {
162 mm_util_error("could not get line (%u)", gif_image->Error);
163 return MM_UTIL_ERROR_INVALID_OPERATION;
168 return MM_UTIL_ERROR_NONE;
171 static int __gif_get_extension(GifFileType *gif_image)
174 GifByteType *extension = NULL;
176 /* for skip any extension blocks in file */
177 if (DGifGetExtension(gif_image, &ExtCode, &extension) == GIF_ERROR) {
178 mm_util_error("could not get extension (%u)", gif_image->Error);
179 return MM_UTIL_ERROR_INVALID_OPERATION;
181 while (extension != NULL) {
182 if (DGifGetExtensionNext(gif_image, &extension) == GIF_ERROR) {
183 mm_util_error("could not get next extension (%u)", gif_image->Error);
184 return MM_UTIL_ERROR_INVALID_OPERATION;
188 return MM_UTIL_ERROR_NONE;
191 static int __gif_convert_to_rgba(void **data, ColorMapObject *color_map, GifRowType *frame_buffer, unsigned int width, unsigned int height)
195 GifColorType *color_map_entry;
200 *data = g_malloc0(width * height * 4);
202 buffer = (GifByteType *) *data;
203 for (i = 0; i < height; i++) {
204 gif_row = frame_buffer[i];
205 for (j = 0; j < width; j++) {
206 color_map_entry = &color_map->Colors[gif_row[j]];
207 *buffer++ = color_map_entry->Red;
208 *buffer++ = color_map_entry->Green;
209 *buffer++ = color_map_entry->Blue;
214 return MM_UTIL_ERROR_NONE;
217 static int __read_gif(const char *file_path, void *memory, const size_t src_size, mm_util_image_h *decoded)
219 int ret = MM_UTIL_ERROR_NONE;
221 GifRecordType record_type = UNDEFINED_RECORD_TYPE;
222 GifRowType *frame_buffer = NULL;
223 GifFileType *GifFile;
224 gboolean is_found = FALSE;
225 ColorMapObject *ColorMap = NULL;
226 gif_io_buf_s io_buf = { memory, src_size, 0 };
227 void *image_buffer = NULL;
229 mm_util_retvm_if(!decoded, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image handle");
233 ret = __gif_open(file_path, memory, src_size, &io_buf, &GifFile);
234 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_open failed");
236 mm_util_retvm_if(GifFile->SWidth <= 0 || GifFile->SHeight <= 0, MM_UTIL_ERROR_INVALID_OPERATION, "Gif File wrong decode width & height");
238 ret = __gif_generate_frame_buffer(GifFile, &frame_buffer);
239 if (ret != MM_UTIL_ERROR_NONE) {
240 mm_util_debug("__gif_generate_frame_buffer failed");
244 /* Scan the content of the GIF file and load the image(s) in: */
246 if (DGifGetRecordType(GifFile, &record_type) == GIF_ERROR) {
247 mm_util_error("could not get record type (%u)", GifFile->Error);
248 ret = MM_UTIL_ERROR_INVALID_OPERATION;
251 switch (record_type) {
252 case IMAGE_DESC_RECORD_TYPE:
254 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
255 mm_util_error("could not get image description");
256 ret = MM_UTIL_ERROR_INVALID_OPERATION;
260 if (!__gif_is_good_frame(GifFile)) {
261 mm_util_debug("Image is not confined to screen dimension, aborted.");
262 ret = MM_UTIL_ERROR_INVALID_OPERATION;
268 ret = __gif_fill_frame_buffer(GifFile, frame_buffer);
269 if (ret != MM_UTIL_ERROR_NONE) {
270 mm_util_error("__gif_generate_frame_buffer failed");
274 case EXTENSION_RECORD_TYPE:
275 /* currently, we don't use extension value, it needs to play animation */
276 ret = __gif_get_extension(GifFile);
277 if (ret != MM_UTIL_ERROR_NONE)
280 case TERMINATE_RECORD_TYPE:
283 /* should be trapped by DGifGetRecordType. */
286 } while (record_type != TERMINATE_RECORD_TYPE && !is_found);
288 ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap);
289 if (ColorMap == NULL) {
290 mm_util_error("Gif Image does not have a colormap");
291 ret = MM_UTIL_ERROR_INVALID_OPERATION;
295 /* decompress image with colormap(256) */
296 ret = __gif_convert_to_rgba(&image_buffer, ColorMap, frame_buffer, GifFile->SWidth, GifFile->SHeight);
297 if (ret != MM_UTIL_ERROR_NONE) {
298 mm_util_error("could not convert gif to rgba");
299 ret = MM_UTIL_ERROR_INVALID_OPERATION;
303 ret = mm_image_create_image(GifFile->SWidth, GifFile->SHeight, MM_UTIL_COLOR_RGBA, image_buffer, GifFile->SWidth * GifFile->SHeight * 4, decoded);
304 g_free(image_buffer);
307 __gif_free_frame_buffer(frame_buffer, GifFile->SHeight);
309 if (DGifCloseFile(GifFile, NULL) == GIF_ERROR) {
310 mm_util_error("could not close file");
311 ret = MM_UTIL_ERROR_INVALID_OPERATION;
319 int mm_util_decode_from_gif_file(const char *file_path, mm_util_image_h *decoded)
321 mm_util_retvm_if(!MMUTIL_STRING_VALID(file_path), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid file_path");
323 return __read_gif(file_path, NULL, 0, decoded);
326 int mm_util_decode_from_gif_memory(void *memory, const size_t src_size, mm_util_image_h *decoded)
328 mm_util_retvm_if(!memory, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid memory");
329 mm_util_retvm_if(!src_size, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid src_size");
331 return __read_gif(NULL, memory, src_size, decoded);
334 static int __write_function(GifFileType *gft, const GifByteType *data, int size)
336 gif_io_buf_s *io_buf = (gif_io_buf_s *) gft->UserData;
338 mm_util_retvm_if(!io_buf, 0, "Invalid io_buf");
339 mm_util_retvm_if(!data, 0, "Invalid data");
340 mm_util_retvm_if(size <= 0, 0, "Invalid size");
342 io_buf->buf = (void *)realloc(io_buf->buf, sizeof(GifByteType) * (io_buf->buf_size + size));
343 mm_util_retvm_if(!io_buf->buf, 0, "Memory allocation failed");
345 memcpy(io_buf->buf + io_buf->buf_size, data, size);
346 io_buf->buf_size += size;
351 static const int DEFAULT_COLORMAP_SIZE = (1 << 8);
353 static void __gif_extract_rgb(mm_image_info_s *gif_image, unsigned long num_of_pixels, GifByteType **red, GifByteType **green, GifByteType **blue)
356 GifByteType *redP = NULL, *greenP = NULL, *blueP = NULL;
357 GifByteType *buffer = (GifByteType*)gif_image->data;
361 redP = g_new0(GifByteType, num_of_pixels);
362 greenP = g_new0(GifByteType, num_of_pixels);
363 blueP = g_new0(GifByteType, num_of_pixels);
369 for (i = 0; i < gif_image->height; i++) {
370 for (j = 0; j < gif_image->width; j++) {
372 *greenP++ = *buffer++;
373 *blueP++ = *buffer++;
379 static int __gif_make_color_map(mm_image_info_s *gif_image, ColorMapObject **color_map, GifByteType **intermediate_image, unsigned long *intermediate_image_size)
382 int colormap_size = DEFAULT_COLORMAP_SIZE;
383 GifByteType *red = NULL, *green = NULL, *blue = NULL;
384 unsigned long num_of_pixels = 0;
385 ColorMapObject *gif_color_map = NULL;
386 GifByteType *out_buffer = NULL;
388 mm_util_retvm_if(!gif_image, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid gif_image");
389 mm_util_retvm_if(!color_map, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid color_map");
390 mm_util_retvm_if(!intermediate_image, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid intermediate_image");
391 mm_util_retvm_if(!intermediate_image_size, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid intermediate_image_size");
393 num_of_pixels = gif_image->width * gif_image->height;
395 if ((gif_color_map = GifMakeMapObject(colormap_size, NULL)) == NULL) {
396 mm_util_error("failed to make color map");
397 return MM_UTIL_ERROR_INVALID_OPERATION;
400 __gif_extract_rgb(gif_image, num_of_pixels, &red, &green, &blue);
402 /* allocate output buffer */
403 out_buffer = g_new0(GifByteType, num_of_pixels);
405 ret = GifQuantizeBuffer(gif_image->width, gif_image->height, &colormap_size, red, green, blue, out_buffer, gif_color_map->Colors);
410 if (ret == GIF_ERROR) {
411 mm_util_error("failed to quantize buffer");
412 COLORMAP_FREE(gif_color_map);
414 return MM_UTIL_ERROR_INVALID_OPERATION;
417 *color_map = gif_color_map;
418 *intermediate_image = out_buffer;
419 *intermediate_image_size = num_of_pixels * sizeof(GifByteType);
421 return MM_UTIL_ERROR_NONE;
424 static int __gif_encode_open_mem(gif_file_s *gif_file)
427 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
429 gif_file->io_buf.buf = NULL;
430 gif_file->io_buf.buf_size = 0;
432 if ((gif_file->GifFile = EGifOpen(&(gif_file->io_buf), __write_function, NULL)) == NULL) {
433 mm_util_error("could not open File");
434 return MM_UTIL_ERROR_INVALID_OPERATION;
437 return MM_UTIL_ERROR_NONE;
440 static int __gif_encode_close_file(GifFileType *gft)
442 int gif_error = E_GIF_SUCCEEDED;
444 mm_util_retvm_if(!gft, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
446 if (EGifCloseFile(gft, &gif_error) == GIF_ERROR) {
447 mm_util_error("could not close file (%d) ", gif_error);
448 return MM_UTIL_ERROR_INVALID_OPERATION;
451 return MM_UTIL_ERROR_NONE;
454 static int __write_gif_to_file(gif_file_s *handle, const char *path)
456 int ret = MM_UTIL_ERROR_NONE;
459 mm_util_retvm_if(!handle, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid handle");
460 mm_util_retvm_if((!handle->io_buf.buf || handle->io_buf.buf_size == 0), MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid io_buf");
461 mm_util_retvm_if(!MMUTIL_STRING_VALID(path), MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid path");
463 ret = mm_util_safe_fopen(path, "wb", &fp);
464 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_safe_fopen fail (%d)", ret);
466 ret = mm_util_safe_fwrite(fp, handle->io_buf.buf, handle->io_buf.buf_size);
467 if (ret != MM_UTIL_ERROR_NONE)
468 mm_util_error("mm_util_safe_fwrite fail (%d)", ret);
470 mm_util_safe_fclose(fp);
475 static int __write_gif_to_buffer(gif_file_s *handle, void **buffer, size_t *buffer_size)
477 mm_util_retvm_if(!handle, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid handle");
478 mm_util_retvm_if(!handle->io_buf.buf || handle->io_buf.buf_size == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid io_buf");
479 mm_util_retvm_if(!buffer || !buffer_size, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid buffer");
481 *buffer = g_memdup2(handle->io_buf.buf, handle->io_buf.buf_size);
482 *buffer_size = handle->io_buf.buf_size;
484 return MM_UTIL_ERROR_NONE;
487 static int __gif_image_write_image(gif_file_s *gif_file, mm_image_info_s *gif_image)
489 int ret = MM_UTIL_ERROR_NONE;
490 ColorMapObject *color_map = NULL;
491 GifByteType *intermediate_image = NULL;
492 unsigned long intermediate_image_size = 0;
493 unsigned long idx = 0;
495 mm_util_retvm_if(!gif_file, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid gif_file");
496 mm_util_retvm_if(!gif_image, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid gif_image");
497 mm_util_retvm_if(!gif_image->data, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid gif_image->data");
499 /* Make local color map */
500 ret = __gif_make_color_map(gif_image, &color_map, &intermediate_image, &intermediate_image_size);
501 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_make_color_map failed");
503 if (EGifPutImageDesc(gif_file->GifFile, 0, 0, gif_image->width, gif_image->height,
504 FALSE, color_map) == GIF_ERROR) {
505 mm_util_error("EGifPutImageDesc failed due to %s", GifErrorString(gif_file->GifFile->Error));
506 COLORMAP_FREE(color_map);
507 g_free(intermediate_image);
508 return MM_UTIL_ERROR_INVALID_OPERATION;
511 COLORMAP_FREE(color_map);
512 mm_util_debug("pixel count: %lu", (intermediate_image_size / sizeof(GifPixelType)));
514 for (idx = 0; idx < (intermediate_image_size / sizeof(GifPixelType)); idx++) {
515 GifPixelType pixel = (GifPixelType)intermediate_image[idx];
516 if (EGifPutPixel(gif_file->GifFile, pixel) == GIF_ERROR) {
517 mm_util_error("EGifPutPixel failed due to %s", GifErrorString(gif_file->GifFile->Error));
518 ret = MM_UTIL_ERROR_INVALID_OPERATION;
523 /* release intermediate_image */
524 g_free(intermediate_image);
529 static int __gif_image_create_ext_block(int function, int byte_count, ExtensionBlock **ext_block)
531 ExtensionBlock *_ext_block = NULL;
533 mm_util_retvm_if(byte_count == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
534 mm_util_retvm_if(ext_block == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
536 /* get allocated extension block */
537 _ext_block = g_new0(ExtensionBlock, 1);
539 _ext_block->Function = function;
540 _ext_block->ByteCount = byte_count;
541 _ext_block->Bytes = g_new0(GifByteType, byte_count);
543 *ext_block = _ext_block;
545 return MM_UTIL_ERROR_NONE;
548 static void __gif_image_destroy_ext_block(ExtensionBlock *ext_block)
553 g_free(ext_block->Bytes);
557 static int __gif_image_write_ext_block(gif_file_s *gif_file, unsigned int delay_time)
559 int ret = MM_UTIL_ERROR_NONE;
560 ExtensionBlock *_ext_block = NULL;
561 GraphicsControlBlock graphic_control_block;
563 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
565 ret = __gif_image_create_ext_block(GRAPHICS_EXT_FUNC_CODE, GRAPHIC_EXT_BLOCK_SIZE, &_ext_block);
566 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_image_create_ext_block failed");
568 /* use fixed graphics control */
569 graphic_control_block.DisposalMode = DISPOSAL_UNSPECIFIED;
570 graphic_control_block.UserInputFlag = FALSE;
571 graphic_control_block.TransparentColor = NO_TRANSPARENT_COLOR;
572 graphic_control_block.DelayTime = delay_time;
574 EGifGCBToExtension(&graphic_control_block, _ext_block->Bytes);
576 if (EGifPutExtension(gif_file->GifFile, _ext_block->Function, _ext_block->ByteCount, _ext_block->Bytes) == GIF_ERROR) {
577 mm_util_error("EGifPutExtension failed due to %s", GifErrorString(gif_file->GifFile->Error));
578 ret = MM_UTIL_ERROR_INVALID_OPERATION;
581 /* release extension blocks */
582 __gif_image_destroy_ext_block(_ext_block);
584 return MM_UTIL_ERROR_NONE;
587 static int __gif_image_write_loop_count(gif_file_s *gif_file, unsigned int loop_count)
589 #define EXT_BLCOK_COUNT 2
590 #define APP_EXT_BLOCK_DATA "NETSCAPE2.0"
591 #define APP_EXT_BLOCK_SIZE strlen(APP_EXT_BLOCK_DATA)
592 #define SUB_BLOCK_SIZE 3
593 int ret = MM_UTIL_ERROR_NONE;
594 ExtensionBlock *app_ext_block = NULL;
595 ExtensionBlock *app_sub_block = NULL;
597 ret = __gif_image_create_ext_block(APPLICATION_EXT_FUNC_CODE, APP_EXT_BLOCK_SIZE, &app_ext_block);
598 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_image_create_ext_block failed");
600 memcpy(app_ext_block->Bytes, APP_EXT_BLOCK_DATA, APP_EXT_BLOCK_SIZE);
602 ret = __gif_image_create_ext_block(CONTINUE_EXT_FUNC_CODE, SUB_BLOCK_SIZE, &app_sub_block);
603 if (ret != MM_UTIL_ERROR_NONE) {
604 mm_util_error("__gif_image_create_ext_block failed");
608 app_sub_block->Bytes[0] = 1; /* index of sub block for netscape */
609 app_sub_block->Bytes[1] = loop_count & 0xff;
610 app_sub_block->Bytes[2] = (loop_count >> 8) & 0xff;
612 if (EGifPutExtensionLeader(gif_file->GifFile, app_ext_block->Function) == GIF_ERROR) {
613 mm_util_error("EGifPutExtensionLeader failed");
614 ret = MM_UTIL_ERROR_INVALID_OPERATION;
618 if (EGifPutExtensionBlock(gif_file->GifFile, app_ext_block->ByteCount, app_ext_block->Bytes) == GIF_ERROR) {
619 mm_util_error("EGifPutExtensionBlock(app_ext_block) failed");
620 ret = MM_UTIL_ERROR_INVALID_OPERATION;
624 if (EGifPutExtensionBlock(gif_file->GifFile, app_sub_block->ByteCount, app_sub_block->Bytes) == GIF_ERROR) {
625 mm_util_error("EGifPutExtensionBlock(app_sub_block) failed");
626 ret = MM_UTIL_ERROR_INVALID_OPERATION;
630 if (EGifPutExtensionTrailer(gif_file->GifFile) == GIF_ERROR) {
631 mm_util_error("EGifPutExtensionTrailer failed");
632 ret = MM_UTIL_ERROR_INVALID_OPERATION;
637 __gif_image_destroy_ext_block(app_ext_block);
638 __gif_image_destroy_ext_block(app_sub_block);
643 int mm_util_gif_encode_create(mm_gif_file_h *gif_file_h)
645 gif_file_s *gif_file = NULL;
647 mm_util_retvm_if(!gif_file_h, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid gif_file_h");
649 gif_file = g_new0(gif_file_s, 1);
651 gif_file->loop_count = 1;
653 *gif_file_h = (mm_gif_file_h)gif_file;
655 return MM_UTIL_ERROR_NONE;
658 int mm_util_gif_encode_set_loop_count(mm_gif_file_h gif_file_h, unsigned int loop_count)
660 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
662 mm_util_retvm_if(!gif_file, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid gif_file_h");
664 gif_file->loop_count = loop_count;
666 return MM_UTIL_ERROR_NONE;
669 static int __mm_util_gif_encode_start(mm_gif_file_h gif_file_h, unsigned int width, unsigned int height)
671 int ret = MM_UTIL_ERROR_NONE;
672 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
674 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid gif_file_h");
675 mm_util_retvm_if(gif_file->GifFile != NULL, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
679 ret = __gif_encode_open_mem(gif_file);
680 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_encode_open_mem failed");
682 /* To initialize data after GifFile opened */
683 EGifSetGifVersion(gif_file->GifFile, TRUE);
685 /* Write screen description */
686 if (EGifPutScreenDesc(gif_file->GifFile, width, height, 8 /* color_res */, 0 /* background_color */, NULL) == GIF_ERROR) {
687 mm_util_error("could not put screen description");
688 __gif_encode_close_file(gif_file->GifFile);
689 return MM_UTIL_ERROR_INVALID_OPERATION;
692 /* Write extension block for loop count */
693 ret = __gif_image_write_loop_count(gif_file, gif_file->loop_count);
694 if (ret != MM_UTIL_ERROR_NONE) {
695 __gif_encode_close_file(gif_file->GifFile);
696 mm_util_error("__gif_image_write_loop_count failed");
703 int mm_util_gif_encode_add_image(mm_gif_file_h gif_file_h, mm_image_info_s *gif_image_h)
705 int ret = MM_UTIL_ERROR_NONE;
706 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
707 mm_image_info_s *gif_image = (mm_image_info_s *)gif_image_h;
710 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid gif_file_h");
711 mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
712 mm_util_retvm_if((gif_image->width == 0) || (gif_image->height == 0), MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
713 mm_util_retvm_if(gif_image->data == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
714 mm_util_retvm_if(gif_image->color != MM_UTIL_COLOR_RGBA, MM_UTIL_ERROR_NOT_SUPPORTED_FORMAT, "not supported color [%d]", gif_image->color);
716 if (gif_file->GifFile == NULL) {
717 mm_util_warn("first added image, __mm_util_gif_encode_start is needed");
718 ret = __mm_util_gif_encode_start(gif_file_h, gif_image->width, gif_image->height);
719 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__mm_util_gif_encode_start failed");
722 /* Write graphic control block */
723 ret = __gif_image_write_ext_block(gif_file, gif_image->delay_time / 10);
724 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_image_write_ext_block failed");
726 /* Write image description & data */
727 ret = __gif_image_write_image(gif_file, gif_image);
728 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_image_write_image failed");
730 gif_file->GifFile->ImageCount++;
732 return MM_UTIL_ERROR_NONE;
735 int mm_util_gif_encode_save_to_file(mm_gif_file_h gif_file_h, const char *path)
737 int ret = MM_UTIL_ERROR_NONE;
738 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
740 mm_util_retvm_if(!gif_file_h, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid gif_file_h");
741 mm_util_retvm_if(!MMUTIL_STRING_VALID(path), MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid path");
742 mm_util_retvm_if(!gif_file->GifFile, MM_UTIL_ERROR_INVALID_PARAMETER, "Encoding has not started");
743 mm_util_retvm_if(gif_file->GifFile->ImageCount <= 0, MM_UTIL_ERROR_INVALID_PARAMETER, "No frame has encoded");
747 ret = __gif_encode_close_file(gif_file->GifFile);
748 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_encode_close_file failed");
749 gif_file->GifFile = NULL;
751 ret = __write_gif_to_file(gif_file, path);
752 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__write_gif_to_file failed (%d)", ret);
754 MMUTIL_SAFE_FREE(gif_file->io_buf.buf);
755 gif_file->io_buf.buf_size = 0;
760 int mm_util_gif_encode_save_to_buffer(mm_gif_file_h gif_file_h, void **buffer, size_t *buffer_size)
762 int ret = MM_UTIL_ERROR_NONE;
763 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
765 mm_util_retvm_if(!gif_file_h, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid gif_file_h");
766 mm_util_retvm_if(!buffer || !buffer_size, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid buffer");
767 mm_util_retvm_if(!gif_file->GifFile, MM_UTIL_ERROR_INVALID_PARAMETER, "Encoding has not started");
768 mm_util_retvm_if(gif_file->GifFile->ImageCount <= 0, MM_UTIL_ERROR_INVALID_PARAMETER, "No frame has encoded");
772 ret = __gif_encode_close_file(gif_file->GifFile);
773 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_encode_close_file failed");
774 gif_file->GifFile = NULL;
776 ret = __write_gif_to_buffer(gif_file, buffer, buffer_size);
777 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__write_gif_to_buffer failed (%d)", ret);
779 MMUTIL_SAFE_FREE(gif_file->io_buf.buf);
780 gif_file->io_buf.buf_size = 0;
785 int mm_util_encode_to_gif_file(mm_util_image_h *images, const unsigned int image_count, const char *file_path)
787 int ret = MM_UTIL_ERROR_NONE;
788 mm_image_info_s **_images = (mm_image_info_s **)images;
790 mm_gif_file_h gif_file_h = NULL;
794 mm_util_retvm_if(images == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid images");
795 mm_util_retvm_if(image_count == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid image_count");
796 mm_util_retvm_if(!MMUTIL_STRING_VALID(file_path), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid file_path");
798 ret = mm_util_gif_encode_create(&gif_file_h);
799 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_create failed %d", ret);
801 for (i = 0; i < image_count; i++) {
802 ret = mm_util_gif_encode_add_image(gif_file_h, _images[i]);
803 if (ret != MM_UTIL_ERROR_NONE) {
804 mm_util_error("mm_util_gif_encode_add_image failed");
805 mm_util_gif_encode_destroy(gif_file_h);
810 ret = mm_util_gif_encode_save_to_file(gif_file_h, file_path);
811 if (ret != MM_UTIL_ERROR_NONE)
812 mm_util_error("mm_util_gif_encode_save_to_file failed (%d)", ret);
814 mm_util_gif_encode_destroy(gif_file_h);
821 int mm_util_encode_to_gif_memory(mm_util_image_h *images, const unsigned int image_count, void **buffer, size_t *size)
823 int ret = MM_UTIL_ERROR_NONE;
824 mm_image_info_s **_images = (mm_image_info_s **)images;
826 mm_gif_file_h gif_file_h = NULL;
830 mm_util_retvm_if(images == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid images");
831 mm_util_retvm_if(image_count == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid image_count");
832 mm_util_retvm_if(buffer == NULL || size == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
834 ret = mm_util_gif_encode_create(&gif_file_h);
835 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_create failed %d", ret);
837 for (i = 0; i < image_count; i++) {
838 ret = mm_util_gif_encode_add_image(gif_file_h, _images[i]);
839 if (ret != MM_UTIL_ERROR_NONE) {
840 mm_util_error("mm_util_gif_encode_add_image failed");
841 mm_util_gif_encode_destroy(gif_file_h);
846 ret = mm_util_gif_encode_save_to_buffer(gif_file_h, buffer, size);
847 if (ret != MM_UTIL_ERROR_NONE)
848 mm_util_error("mm_util_gif_encode_save_to_buffer failed (%d)", ret);
850 mm_util_gif_encode_destroy(gif_file_h);
857 void mm_util_gif_encode_destroy(mm_gif_file_h gif_file_h)
859 int ret = MM_UTIL_ERROR_NONE;
860 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
862 mm_util_retm_if(gif_file == NULL, "Invalid parameter");
864 if (gif_file->GifFile) {
865 ret = __gif_encode_close_file(gif_file->GifFile);
866 mm_util_retm_if(ret != MM_UTIL_ERROR_NONE, "__gif_encode_close_file failed");
869 g_free(gif_file->filename);
870 MMUTIL_SAFE_FREE(gif_file->io_buf.buf);
874 anim_enc_module_t *anim_enc_module_register(void)
876 anim_enc_module_t *module = NULL;
880 module = g_new0(anim_enc_module_t, 1);
882 module->create = (ANIM_ENC_CREATE)mm_util_gif_encode_create;
883 module->set_bgcolor = NULL;
884 module->set_loop_count = (ANIM_ENC_SET_LOOP_COUNT)mm_util_gif_encode_set_loop_count;
885 module->set_lossless = NULL;
886 module->add_image = (ANIM_ENC_ADD_IMAGE)mm_util_gif_encode_add_image;
887 module->save_to_file = (ANIM_ENC_SAVE_TO_FILE)mm_util_gif_encode_save_to_file;
888 module->save_to_buffer = (ANIM_ENC_SAVE_TO_BUFFER)mm_util_gif_encode_save_to_buffer;
889 module->destroy = (ANIM_ENC_DESTROY)mm_util_gif_encode_destroy;