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_gif_private.h"
28 #include "mm_util_private.h"
31 #define GIF_TMP_FILE "/tmp/.libmm_gif.gif"
33 #define COLORMAP_FREE(map) { if (map != NULL) { GifFreeMapObject(map); map = NULL; } }
34 #define RGB_ALLOC(r, g, b, number, size) { r = calloc(1, number * size); g = calloc(1, number * size); b = calloc(1, number * size); }
35 #define RGB_FREE(r, g, b) { MMUTIL_SAFE_FREE(r); MMUTIL_SAFE_FREE(g); MMUTIL_SAFE_FREE(b); }
37 #define GRAPHIC_EXT_BLOCK_SIZE 4
39 static int __convert_gif_to_rgba(void **data, ColorMapObject *color_map, GifRowType *screen_buffer, unsigned long width, unsigned long height)
43 GifColorType *color_map_entry;
48 if ((*data = (void *)calloc(1, width * height * 4)) == NULL) {
49 mm_util_error("Failed to allocate memory required, aborted.");
50 return MM_UTIL_ERROR_OUT_OF_MEMORY;
53 buffer = (GifByteType *) *data;
54 for (i = 0; i < height; i++) {
55 gif_row = screen_buffer[i];
56 for (j = 0; j < width; j++) {
57 color_map_entry = &color_map->Colors[gif_row[j]];
58 *buffer++ = color_map_entry->Red;
59 *buffer++ = color_map_entry->Green;
60 *buffer++ = color_map_entry->Blue;
64 return MM_UTIL_ERROR_NONE;
67 static int __read_function(GifFileType *gft, GifByteType *data, int size)
69 gif_mem_s *read_data_ptr = (gif_mem_s *) gft->UserData;
71 mm_util_retvm_if(size <= 0, 0, "Failed to read memory due to size(%d).", size);
72 mm_util_retvm_if(read_data_ptr == NULL, 0, "Failed to read memory due to invalid input data.");
73 mm_util_retvm_if(read_data_ptr->mem == NULL, 0, "Failed to read memory due to invalid input buffer.");
74 mm_util_retvm_if(read_data_ptr->size + size > read_data_ptr->mem_size, 0, "Failed to read memory due to buffer overflow(%zu/%d/%zu).", read_data_ptr->size, size, read_data_ptr->mem_size);
76 memcpy(data, read_data_ptr->mem + read_data_ptr->size, size);
77 read_data_ptr->size += size;
82 static int __read_gif(mm_image_info_s *decoded, const char *filename, void *memory, const size_t src_size)
84 int ret = MM_UTIL_ERROR_NONE;
86 int ExtCode, i, j, Row, Col, Width, Height;
88 GifRecordType record_type;
89 GifRowType *screen_buffer = NULL;
91 unsigned int image_num = 0;
92 ColorMapObject *ColorMap;
93 gif_mem_s read_data_ptr;
98 if ((GifFile = DGifOpenFileName(filename, NULL)) == NULL) {
99 mm_util_error("could not open Gif File");
100 return MM_UTIL_ERROR_INVALID_OPERATION;
103 read_data_ptr.mem = memory;
104 read_data_ptr.mem_size = src_size;
105 read_data_ptr.size = 0;
106 if ((GifFile = DGifOpen(&read_data_ptr, __read_function, NULL)) == NULL) {
107 mm_util_error("could not open Gif File");
108 return MM_UTIL_ERROR_INVALID_OPERATION;
111 mm_util_error("Gif File wrong decode parameters");
112 return MM_UTIL_ERROR_INVALID_OPERATION;
114 if (GifFile->SWidth <= 0 || GifFile->SHeight <= 0) {
115 mm_util_error("Gif File wrong decode width & height");
116 return MM_UTIL_ERROR_INVALID_OPERATION;
118 decoded->width = GifFile->SWidth;
119 decoded->height = GifFile->SHeight;
120 decoded->size = (unsigned long long)GifFile->SWidth * (unsigned long long)GifFile->SHeight * 4;
122 if ((screen_buffer = (GifRowType *)
123 calloc(1, GifFile->SHeight * sizeof(GifRowType))) == NULL) {
124 mm_util_error("Failed to allocate memory required, aborted.");
125 ret = MM_UTIL_ERROR_INVALID_OPERATION;
129 Size = GifFile->SWidth * sizeof(GifPixelType); /* Size in bytes one row. */
130 if ((screen_buffer[0] = (GifRowType) calloc(1, Size)) == NULL) { /* First row. */
131 mm_util_error("Failed to allocate memory required, aborted.");
132 ret = MM_UTIL_ERROR_INVALID_OPERATION;
136 for (i = 0; i < (int)(GifFile->SWidth); i++) /* Set its color to BackGround. */
137 screen_buffer[0][i] = GifFile->SBackGroundColor;
138 for (i = 1; i < (int)(GifFile->SHeight); i++) {
139 /* Allocate the other rows, and set their color to background too: */
140 if ((screen_buffer[i] = (GifRowType) calloc(1, Size)) == NULL) {
141 mm_util_error("Failed to allocate memory required, aborted.");
142 ret = MM_UTIL_ERROR_INVALID_OPERATION;
146 memcpy(screen_buffer[i], screen_buffer[0], Size);
149 /* Scan the content of the GIF file and load the image(s) in: */
151 if (DGifGetRecordType(GifFile, &record_type) == GIF_ERROR) {
152 mm_util_error("could not get record type");
153 ret = MM_UTIL_ERROR_INVALID_OPERATION;
156 switch (record_type) {
157 case IMAGE_DESC_RECORD_TYPE:
158 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
159 mm_util_error("could not get image description");
160 ret = MM_UTIL_ERROR_INVALID_OPERATION;
163 if (GifFile->Image.Top < 0 || GifFile->Image.Left < 0 || GifFile->Image.Width <= 0 || GifFile->Image.Height <= 0) {
164 mm_util_error("Gif File wrong decode width & height");
165 ret = MM_UTIL_ERROR_INVALID_OPERATION;
168 Row = GifFile->Image.Top; /* Image Position relative to Screen. */
169 Col = GifFile->Image.Left;
170 Width = GifFile->Image.Width;
171 Height = GifFile->Image.Height;
172 mm_util_debug("Image %d at (%d, %d) [%dx%d]", image_num + 1, Col, Row, Width, Height);
173 if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth || GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
174 mm_util_debug("Image %d is not confined to screen dimension, aborted.", image_num + 1);
175 ret = MM_UTIL_ERROR_INVALID_OPERATION;
179 if (GifFile->Image.Interlace) {
180 int interlaced_offset[] = { 0, 4, 2, 1 }, interlaced_jumps[] = {
182 /* Need to perform 4 passes on the images: */
183 for (i = 0; i < 4; i++)
184 for (j = Row + interlaced_offset[i]; j < Row + Height; j += interlaced_jumps[i]) {
185 if (DGifGetLine(GifFile, &screen_buffer[j][Col], Width) == GIF_ERROR) {
186 mm_util_error("could not get line");
187 ret = MM_UTIL_ERROR_INVALID_OPERATION;
192 for (i = 0; i < Height; i++) {
193 if (DGifGetLine(GifFile, &screen_buffer[Row++][Col], Width) == GIF_ERROR) {
194 mm_util_error("could not get line");
195 ret = MM_UTIL_ERROR_INVALID_OPERATION;
201 case EXTENSION_RECORD_TYPE:
203 GifByteType *extension;
204 /* Skip any extension blocks in file: */
205 if (DGifGetExtension(GifFile, &ExtCode, &extension) == GIF_ERROR) {
206 mm_util_error("could not get extension");
207 ret = MM_UTIL_ERROR_INVALID_OPERATION;
210 while (extension != NULL) {
211 if (DGifGetExtensionNext(GifFile, &extension) == GIF_ERROR) {
212 mm_util_error("could not get next extension");
213 ret = MM_UTIL_ERROR_INVALID_OPERATION;
219 case TERMINATE_RECORD_TYPE:
221 default: /* Should be trapped by DGifGetRecordType. */
226 } while (record_type != TERMINATE_RECORD_TYPE);
228 ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap);
229 if (ColorMap == NULL) {
230 mm_util_error("Gif Image does not have a colormap");
231 ret = MM_UTIL_ERROR_INVALID_OPERATION;
235 ret = __convert_gif_to_rgba(&decoded->data, ColorMap, screen_buffer, GifFile->SWidth, GifFile->SHeight);
236 if (ret != MM_UTIL_ERROR_NONE) {
237 mm_util_error("could not convert gif to rgba");
238 ret = MM_UTIL_ERROR_INVALID_OPERATION;
242 ret = MM_UTIL_ERROR_NONE;
245 if (screen_buffer[0])
246 (void)free(screen_buffer[0]);
247 for (i = 1; i < (int)(GifFile->SHeight); i++) {
248 if (screen_buffer[i])
249 (void)free(screen_buffer[i]);
251 (void)free(screen_buffer);
253 if (DGifCloseFile(GifFile, NULL) == GIF_ERROR) {
254 mm_util_error("could not close file");
255 ret = MM_UTIL_ERROR_INVALID_OPERATION;
262 int mm_util_decode_from_gif_file(const char *fpath, mm_image_info_s *decoded)
264 mm_util_retvm_if(!MMUTIL_STRING_VALID(fpath), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid fpath");
265 mm_util_retvm_if((decoded == NULL), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid color image");
269 return __read_gif(decoded, fpath, NULL, 0);
272 int mm_util_decode_from_gif_memory(void *memory, const size_t src_size, mm_image_info_s *decoded)
274 mm_util_retvm_if(memory == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid memory");
275 mm_util_retvm_if((decoded == NULL), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid color image");
279 return __read_gif(decoded, NULL, memory, src_size);
282 static int __write_function(GifFileType *gft, const GifByteType *data, int size)
284 gif_mem_s *write_data_ptr = (gif_mem_s *) gft->UserData;
286 mm_util_retvm_if(size <= 0, 0, "Failed to write memory due to size(%d).", size);
287 mm_util_retvm_if(write_data_ptr == NULL, 0, "Failed to write memory due to invalid output data.");
289 write_data_ptr->mem = (void *)realloc(write_data_ptr->mem, (write_data_ptr->size + size));
290 mm_util_retvm_if(write_data_ptr->mem == NULL, 0, "Failed to write memory due to allocation failure.");
292 memcpy(write_data_ptr->mem + write_data_ptr->size, data, size);
293 write_data_ptr->size += size;
298 static const int DEFAULT_COLORMAP_SIZE = (1 << 8);
300 static int __gif_extract_rgb(mm_image_info_s *gif_image, unsigned long num_of_pixels, GifByteType **red, GifByteType **green, GifByteType **blue)
303 GifByteType *redP, *greenP, *blueP;
304 GifByteType *buffer = (GifByteType*)gif_image->data;
308 RGB_ALLOC(redP, greenP, blueP, num_of_pixels, sizeof(GifByteType));
313 mm_util_retvm_if((redP == NULL || greenP == NULL || blueP == NULL), MM_UTIL_ERROR_OUT_OF_MEMORY, "Memory allocation failed");
315 for (i = 0; i < gif_image->height; i++) {
316 for (j = 0; j < gif_image->width; j++) {
318 *greenP++ = *buffer++;
319 *blueP++ = *buffer++;
324 return MM_UTIL_ERROR_NONE;
327 int __gif_make_color_map(mm_image_info_s *gif_image, ColorMapObject **color_map, GifByteType **intermediate_image, unsigned long *intermediate_image_size)
329 int ret = MM_UTIL_ERROR_NONE;
330 int colormap_size = DEFAULT_COLORMAP_SIZE;
331 GifByteType *red = NULL, *green = NULL, *blue = NULL;
333 mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
335 unsigned long num_of_pixels = gif_image->width * gif_image->height;
337 /* make colormap and quantization for the color table of gif */
338 ret = __gif_extract_rgb(gif_image, num_of_pixels, &red, &green, &blue);
339 if (ret != MM_UTIL_ERROR_NONE) {
340 mm_util_error("To extract rgb from image is failed");
344 if ((*color_map = GifMakeMapObject(colormap_size, NULL)) == NULL) {
345 mm_util_error("To make color map is failed");
346 ret = MM_UTIL_ERROR_INVALID_OPERATION;
350 /* allocate output buffer */
351 *intermediate_image = (GifByteType *) calloc(1, num_of_pixels * sizeof(GifByteType));
352 if (*intermediate_image == NULL) {
353 mm_util_error("Memory allocation failed");
354 ret = MM_UTIL_ERROR_INVALID_OPERATION;
357 *intermediate_image_size = num_of_pixels * sizeof(GifByteType);
359 if (GifQuantizeBuffer(gif_image->width, gif_image->height, &colormap_size, red, green, blue, *intermediate_image, (*color_map)->Colors) == GIF_ERROR) {
360 mm_util_error("could not quantize buffer");
361 ret = MM_UTIL_ERROR_INVALID_OPERATION;
367 if (*intermediate_image)
368 MMUTIL_SAFE_FREE(*intermediate_image);
370 *intermediate_image_size = 0;
371 COLORMAP_FREE(*color_map);
373 RGB_FREE(red, green, blue);
378 static int _gif_encode_open_file(GifFileType **gft)
381 mm_util_retvm_if(gft == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
383 if ((*gft = EGifOpenFileName(GIF_TMP_FILE, 0, NULL)) == NULL) {
384 mm_util_error("could not open file");
385 return MM_UTIL_ERROR_INVALID_OPERATION;
388 return MM_UTIL_ERROR_NONE;
391 int _gif_encode_open_mem(gif_file_s *gif_file)
394 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
396 gif_file->write_data_ptr.mem = NULL;
397 gif_file->write_data_ptr.size = 0;
399 if ((gif_file->GifFile = EGifOpen(&(gif_file->write_data_ptr), __write_function, NULL)) == NULL) {
400 mm_util_error("could not open File");
401 return MM_UTIL_ERROR_INVALID_OPERATION;
404 return MM_UTIL_ERROR_NONE;
407 static int _gif_encode_close_file(GifFileType *gft)
410 mm_util_retvm_if(gft == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
412 if (EGifCloseFile(gft, NULL) == GIF_ERROR) {
413 mm_util_error("could not close file");
414 return MM_UTIL_ERROR_INVALID_OPERATION;
418 return MM_UTIL_ERROR_NONE;
421 int _gif_encode_move_to_file(const char *dst)
423 int ret = MM_UTIL_ERROR_NONE;
424 GFile *source = g_file_new_for_path(GIF_TMP_FILE);
425 GFile *destination = g_file_new_for_path(dst);
426 GError *error = NULL;
428 if (source == NULL || destination == NULL) {
429 mm_util_error("could not open file");
431 g_object_unref(source);
433 g_object_unref(destination);
434 return MM_UTIL_ERROR_INVALID_OPERATION;
437 gboolean result = g_file_copy(source, destination, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &error);
439 mm_util_error("g_file_copy failed: %s", error ? error->message : "none");
440 ret = MM_UTIL_ERROR_INVALID_OPERATION;
445 g_object_unref(source);
446 g_object_unref(destination);
451 int _gif_encode_move_to_mem(const unsigned char *src, size_t src_size, void **dst, size_t *dst_size)
453 unsigned char *buffer = NULL;
454 mm_util_retvm_if(src == NULL || dst == NULL || dst_size == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
455 mm_util_retvm_if(src_size == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
457 mm_util_debug("src_size: %u", src_size);
459 buffer = (unsigned char *)calloc(1, src_size);
460 mm_util_retvm_if(buffer == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "memory allocation failed");
462 memcpy(buffer, src, src_size);
465 *dst_size = src_size;
467 return MM_UTIL_ERROR_NONE;
470 int _gif_image_write_image(gif_file_s *gif_file, mm_image_info_s *gif_image)
472 int ret = MM_UTIL_ERROR_NONE;
473 ColorMapObject *color_map = NULL;
474 GifByteType *intermediate_image = NULL;
475 unsigned long intermediate_image_size = 0;
476 unsigned long idx = 0;
478 mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
479 mm_util_retvm_if(gif_image->data == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
481 /* Make local color map */
482 ret = __gif_make_color_map(gif_image, &color_map, &intermediate_image, &intermediate_image_size);
483 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_make_color_map failed");
485 if (EGifPutImageDesc(gif_file->GifFile, 0, 0, gif_image->width, gif_image->height,
486 FALSE, color_map) == GIF_ERROR) {
487 mm_util_error("EGifPutImageDesc failed due to %s", GifErrorString(gif_file->GifFile->Error));
488 COLORMAP_FREE(color_map);
489 MMUTIL_SAFE_FREE(intermediate_image);
490 return MM_UTIL_ERROR_INVALID_OPERATION;
492 /* release color map */
493 COLORMAP_FREE(color_map);
495 mm_util_debug("put pixel count: %lu", (intermediate_image_size / sizeof(GifPixelType)));
497 for (idx = 0; idx < (intermediate_image_size / sizeof(GifPixelType)); idx++) {
498 GifPixelType pixel = (GifPixelType)intermediate_image[idx];
499 if (EGifPutPixel(gif_file->GifFile, pixel) == GIF_ERROR) {
500 mm_util_error("could not put pixel");
501 return MM_UTIL_ERROR_INVALID_OPERATION;
505 /* release intermediate_image */
506 MMUTIL_SAFE_FREE(intermediate_image);
508 return MM_UTIL_ERROR_NONE;
511 int _gif_image_create_ext_block(int function, int byte_count, ExtensionBlock **ext_block)
513 ExtensionBlock *_ext_block = NULL;
515 mm_util_retvm_if(byte_count == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
516 mm_util_retvm_if(ext_block == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
518 /* get allocated extention block */
519 _ext_block = (ExtensionBlock *)calloc(1, sizeof(ExtensionBlock));
520 if (_ext_block == NULL) {
521 mm_util_error("Memory allocation failed");
523 return MM_UTIL_ERROR_OUT_OF_MEMORY;
526 _ext_block->Function = function;
527 _ext_block->ByteCount = byte_count;
528 _ext_block->Bytes = (GifByteType *)calloc(1, (sizeof(GifByteType) * byte_count));
529 if (_ext_block->Bytes == NULL) {
530 mm_util_error("Memory allocation failed");
531 MMUTIL_SAFE_FREE(_ext_block);
532 return MM_UTIL_ERROR_OUT_OF_MEMORY;
535 *ext_block = _ext_block;
536 return MM_UTIL_ERROR_NONE;
539 int _gif_image_write_ext_block(gif_file_s *gif_file, unsigned int delay_time)
541 int ret = MM_UTIL_ERROR_NONE;
542 ExtensionBlock *_ext_block = NULL;
543 GraphicsControlBlock graphic_control_block;
545 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
547 ret = _gif_image_create_ext_block(GRAPHICS_EXT_FUNC_CODE, GRAPHIC_EXT_BLOCK_SIZE, &_ext_block);
548 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_image_alloc_ext_block failed");
549 mm_util_retvm_if(_ext_block->Bytes == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "_gif_image_alloc_ext_block failed");
551 /* use fixed graphics control */
552 graphic_control_block.DisposalMode = MM_UTIL_GIF_DISPOSAL_UNSPECIFIED;
553 graphic_control_block.UserInputFlag = FALSE;
554 graphic_control_block.TransparentColor = NO_TRANSPARENT_COLOR;
555 graphic_control_block.DelayTime = delay_time;
557 EGifGCBToExtension(&graphic_control_block, _ext_block->Bytes);
559 if (EGifPutExtension(gif_file->GifFile, _ext_block->Function, _ext_block->ByteCount, _ext_block->Bytes) == GIF_ERROR) {
560 mm_util_error("EGifPutExtension failed due to %s", GifErrorString(gif_file->GifFile->Error));
561 ret = MM_UTIL_ERROR_INVALID_OPERATION;
564 /* release extension blocks */
565 if (_ext_block != NULL) {
566 MMUTIL_SAFE_FREE(_ext_block->Bytes);
567 MMUTIL_SAFE_FREE(_ext_block);
570 return MM_UTIL_ERROR_NONE;
573 int mm_util_gif_encode_create(mm_gif_file_h *gif_file_h)
575 gif_file_s *gif_file = NULL;
577 mm_util_retvm_if(gif_file_h == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
579 gif_file = (gif_file_s *)calloc(1, sizeof(gif_file_s));
580 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "Memory allocation failed");
582 /* initialize data before set */
583 *gif_file_h = (mm_gif_file_h)gif_file;
585 return MM_UTIL_ERROR_NONE;
588 int mm_util_gif_encode_set_file(mm_gif_file_h gif_file_h, const char *file_name)
590 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
592 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
593 mm_util_retvm_if(file_name == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
594 mm_util_retvm_if(strlen(file_name) == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
595 mm_util_retvm_if(gif_file->GifFile != NULL, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
597 gif_file->filename = g_strdup(file_name);
598 mm_util_retvm_if(gif_file->filename == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "Memory allocation failed");
600 return MM_UTIL_ERROR_NONE;
603 int mm_util_gif_encode_set_mem(mm_gif_file_h gif_file_h, void **data, size_t *data_size)
605 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
607 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
608 mm_util_retvm_if(data == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
609 mm_util_retvm_if(data_size == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
610 mm_util_retvm_if(gif_file->GifFile != NULL, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
612 gif_file->enc_buffer = data;
613 gif_file->enc_buffer_size = data_size;
615 return MM_UTIL_ERROR_NONE;
618 static int _mm_util_gif_encode_start(mm_gif_file_h gif_file_h, unsigned long width, unsigned long height)
620 int ret = MM_UTIL_ERROR_NONE;
621 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
623 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
624 mm_util_retvm_if(gif_file->GifFile != NULL, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
628 if (gif_file->filename != NULL) {
629 ret = _gif_encode_open_file(&gif_file->GifFile);
630 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_encode_open_file failed");
631 } else if (gif_file->enc_buffer != NULL && gif_file->enc_buffer_size != NULL) {
632 ret = _gif_encode_open_mem(gif_file);
633 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_encode_open_mem failed");
635 mm_util_error("could not find output");
636 return MM_UTIL_ERROR_INVALID_OPERATION;
639 /* To initialize data after GifFile opened */
640 EGifSetGifVersion(gif_file->GifFile, TRUE);
642 /* Write screen description */
643 if (EGifPutScreenDesc(gif_file->GifFile, width, height, 8 /* color_res */, 0 /* background_color */, NULL) == GIF_ERROR) {
644 mm_util_error("could not put screen description");
645 _gif_encode_close_file(gif_file->GifFile);
646 return MM_UTIL_ERROR_INVALID_OPERATION;
650 return MM_UTIL_ERROR_NONE;
653 int mm_util_gif_encode_add_image(mm_gif_file_h gif_file_h, mm_image_info_s *gif_image_h)
655 int ret = MM_UTIL_ERROR_NONE;
656 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
657 mm_image_info_s *gif_image = (mm_image_info_s *)gif_image_h;
660 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
661 mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
662 mm_util_retvm_if((gif_image->width == 0) || (gif_image->height == 0), MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
663 mm_util_retvm_if(gif_image->data == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
665 if (gif_file->GifFile == NULL) {
666 mm_util_warn("first added image, _mm_util_gif_encode_start is needed");
667 ret = _mm_util_gif_encode_start(gif_file_h, gif_image->width, gif_image->height);
668 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_mm_util_gif_encode_start failed");
671 /* Write graphic control block */
672 ret = _gif_image_write_ext_block(gif_file, gif_image->delay_time);
673 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_image_write_ext_block failed");
675 /* Write image description & data */
676 ret = _gif_image_write_image(gif_file, gif_image);
677 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_image_write_image failed");
679 gif_file->GifFile->ImageCount++;
681 return MM_UTIL_ERROR_NONE;
684 int mm_util_gif_encode_save(mm_gif_file_h gif_file_h)
686 int ret = MM_UTIL_ERROR_NONE;
687 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
689 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
690 mm_util_retvm_if(gif_file->GifFile == NULL, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has not started");
691 mm_util_retvm_if(gif_file->GifFile->ImageCount <= 0, MM_UTIL_ERROR_INVALID_OPERATION, "No frame has encoded");
695 ret = _gif_encode_close_file(gif_file->GifFile);
696 gif_file->GifFile = NULL;
697 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_encode_close_file failed");
699 if (gif_file->filename != NULL) {
700 ret = _gif_encode_move_to_file(gif_file->filename);
701 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__move_tmp_to_origin failed");
702 } else if (gif_file->write_data_ptr.mem != NULL) {
703 ret = _gif_encode_move_to_mem(gif_file->write_data_ptr.mem, gif_file->write_data_ptr.size,
704 gif_file->enc_buffer, gif_file->enc_buffer_size);
705 MMUTIL_SAFE_FREE(gif_file->write_data_ptr.mem);
706 gif_file->write_data_ptr.size = 0;
707 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_encode_move_to_origin_mem failed");
710 return MM_UTIL_ERROR_NONE;
713 int mm_util_encode_to_gif_file(mm_image_info_s **images, const unsigned int image_count, const char *path)
715 int ret = MM_UTIL_ERROR_NONE;
717 mm_gif_file_h gif_file_h = NULL;
721 mm_util_retvm_if(images == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
722 mm_util_retvm_if(image_count == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
723 mm_util_retvm_if(path == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
725 ret = mm_util_gif_encode_create(&gif_file_h);
726 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_create failed %d", ret);
728 ret = mm_util_gif_encode_set_file(gif_file_h, path);
729 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_set_file failed %d", ret);
731 ret = _mm_util_gif_encode_start(gif_file_h, images[0]->width, images[0]->height);
732 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_mm_util_gif_encode_start failed");
734 for (i = 0; i < image_count; i++) {
735 ret = mm_util_gif_encode_add_image(gif_file_h, images[i]);
736 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_add_image failed");
739 ret = mm_util_gif_encode_save(gif_file_h);
740 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_save failed");
744 return MM_UTIL_ERROR_NONE;
747 int mm_util_encode_to_gif_memory(mm_image_info_s **images, const unsigned int image_count, void **buffer, size_t *size)
749 int ret = MM_UTIL_ERROR_NONE;
751 mm_gif_file_h gif_file_h = NULL;
755 mm_util_retvm_if(images == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
756 mm_util_retvm_if(image_count == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
757 mm_util_retvm_if(buffer == NULL || size == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
759 ret = mm_util_gif_encode_create(&gif_file_h);
760 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_create failed %d", ret);
762 ret = mm_util_gif_encode_set_mem(gif_file_h, buffer, size);
763 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_set_mem failed %d", ret);
765 ret = _mm_util_gif_encode_start(gif_file_h, images[0]->width, images[0]->height);
766 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_mm_util_gif_encode_start failed");
768 for (i = 0; i < image_count; i++) {
769 ret = mm_util_gif_encode_add_image(gif_file_h, images[i]);
770 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_add_image failed");
773 ret = mm_util_gif_encode_save(gif_file_h);
774 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_save failed");
778 return MM_UTIL_ERROR_NONE;
781 void mm_util_gif_encode_destroy(mm_gif_file_h gif_file_h)
783 int ret = MM_UTIL_ERROR_NONE;
784 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
786 mm_util_retm_if(gif_file == NULL, "Invalid parameter");
788 if (gif_file->GifFile != NULL) {
789 ret = _gif_encode_close_file(gif_file->GifFile);
790 mm_util_retm_if(ret != MM_UTIL_ERROR_NONE, "_gif_encode_close_file failed");
793 MMUTIL_SAFE_G_FREE(gif_file->filename);
794 MMUTIL_SAFE_FREE(gif_file->write_data_ptr.mem);