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)
266 return __read_gif(decoded, fpath, NULL, 0);
269 int mm_util_decode_from_gif_memory(void *memory, const size_t src_size, mm_image_info_s *decoded)
273 return __read_gif(decoded, NULL, memory, src_size);
276 static int __write_function(GifFileType *gft, const GifByteType *data, int size)
278 gif_mem_s *write_data_ptr = (gif_mem_s *) gft->UserData;
280 mm_util_retvm_if(size <= 0, 0, "Failed to write memory due to size(%d).", size);
281 mm_util_retvm_if(write_data_ptr == NULL, 0, "Failed to write memory due to invalid output data.");
283 write_data_ptr->mem = (void *)realloc(write_data_ptr->mem, (write_data_ptr->size + size));
284 mm_util_retvm_if(write_data_ptr->mem == NULL, 0, "Failed to write memory due to allocation failure.");
286 memcpy(write_data_ptr->mem + write_data_ptr->size, data, size);
287 write_data_ptr->size += size;
292 static const int DEFAULT_COLORMAP_SIZE = (1 << 8);
294 static int __gif_extract_rgb(mm_image_info_s *gif_image, unsigned long num_of_pixels, GifByteType **red, GifByteType **green, GifByteType **blue)
297 GifByteType *redP, *greenP, *blueP;
298 GifByteType *buffer = (GifByteType*)gif_image->data;
302 RGB_ALLOC(redP, greenP, blueP, num_of_pixels, sizeof(GifByteType));
307 mm_util_retvm_if((redP == NULL || greenP == NULL || blueP == NULL), MM_UTIL_ERROR_OUT_OF_MEMORY, "Memory allocation failed");
309 for (i = 0; i < gif_image->height; i++) {
310 for (j = 0; j < gif_image->width; j++) {
312 *greenP++ = *buffer++;
313 *blueP++ = *buffer++;
318 return MM_UTIL_ERROR_NONE;
321 int __gif_make_color_map(mm_image_info_s *gif_image, ColorMapObject **color_map, GifByteType **intermediate_image, unsigned long *intermediate_image_size)
323 int ret = MM_UTIL_ERROR_NONE;
324 int colormap_size = DEFAULT_COLORMAP_SIZE;
325 GifByteType *red = NULL, *green = NULL, *blue = NULL;
327 mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
329 unsigned long num_of_pixels = gif_image->width * gif_image->height;
331 /* make colormap and quantization for the color table of gif */
332 ret = __gif_extract_rgb(gif_image, num_of_pixels, &red, &green, &blue);
333 if (ret != MM_UTIL_ERROR_NONE) {
334 mm_util_error("To extract rgb from image is failed");
338 if ((*color_map = GifMakeMapObject(colormap_size, NULL)) == NULL) {
339 mm_util_error("To make color map is failed");
340 ret = MM_UTIL_ERROR_INVALID_OPERATION;
344 /* allocate output buffer */
345 *intermediate_image = (GifByteType *) calloc(1, num_of_pixels * sizeof(GifByteType));
346 if (*intermediate_image == NULL) {
347 mm_util_error("Memory allocation failed");
348 ret = MM_UTIL_ERROR_INVALID_OPERATION;
351 *intermediate_image_size = num_of_pixels * sizeof(GifByteType);
353 if (GifQuantizeBuffer(gif_image->width, gif_image->height, &colormap_size, red, green, blue, *intermediate_image, (*color_map)->Colors) == GIF_ERROR) {
354 mm_util_error("could not quantize buffer");
355 ret = MM_UTIL_ERROR_INVALID_OPERATION;
361 if (*intermediate_image)
362 MMUTIL_SAFE_FREE(*intermediate_image);
364 *intermediate_image_size = 0;
365 COLORMAP_FREE(*color_map);
367 RGB_FREE(red, green, blue);
372 static int _gif_encode_open_file(GifFileType **gft)
375 mm_util_retvm_if(gft == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
377 if ((*gft = EGifOpenFileName(GIF_TMP_FILE, 0, NULL)) == NULL) {
378 mm_util_error("could not open file");
379 return MM_UTIL_ERROR_INVALID_OPERATION;
382 return MM_UTIL_ERROR_NONE;
385 int _gif_encode_open_mem(gif_file_s *gif_file)
388 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
390 gif_file->write_data_ptr.mem = NULL;
391 gif_file->write_data_ptr.size = 0;
393 if ((gif_file->GifFile = EGifOpen(&(gif_file->write_data_ptr), __write_function, NULL)) == NULL) {
394 mm_util_error("could not open File");
395 return MM_UTIL_ERROR_INVALID_OPERATION;
398 return MM_UTIL_ERROR_NONE;
401 static int _gif_encode_close_file(GifFileType *gft)
404 mm_util_retvm_if(gft == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
406 if (EGifCloseFile(gft, NULL) == GIF_ERROR) {
407 mm_util_error("could not close file");
408 return MM_UTIL_ERROR_INVALID_OPERATION;
412 return MM_UTIL_ERROR_NONE;
415 int _gif_encode_move_to_file(const char *dst)
417 int ret = MM_UTIL_ERROR_NONE;
418 GFile *source = g_file_new_for_path(GIF_TMP_FILE);
419 GFile *destination = g_file_new_for_path(dst);
420 GError *error = NULL;
422 if (source == NULL || destination == NULL) {
423 mm_util_error("could not open file");
425 g_object_unref(source);
427 g_object_unref(destination);
428 return MM_UTIL_ERROR_INVALID_OPERATION;
431 gboolean result = g_file_copy(source, destination, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &error);
433 mm_util_error("g_file_copy failed: %s", error ? error->message : "none");
434 ret = MM_UTIL_ERROR_INVALID_OPERATION;
439 g_object_unref(source);
440 g_object_unref(destination);
445 int _gif_encode_move_to_mem(const unsigned char *src, size_t src_size, void **dst, size_t *dst_size)
447 unsigned char *buffer = NULL;
448 mm_util_retvm_if(src == NULL || dst == NULL || dst_size == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
449 mm_util_retvm_if(src_size == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
451 mm_util_debug("src_size: %u", src_size);
453 buffer = (unsigned char *)calloc(1, src_size);
454 mm_util_retvm_if(buffer == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "memory allocation failed");
456 memcpy(buffer, src, src_size);
459 *dst_size = src_size;
461 return MM_UTIL_ERROR_NONE;
464 int _gif_image_write_image(gif_file_s *gif_file, mm_image_info_s *gif_image)
466 int ret = MM_UTIL_ERROR_NONE;
467 ColorMapObject *color_map = NULL;
468 GifByteType *intermediate_image = NULL;
469 unsigned long intermediate_image_size = 0;
470 unsigned long idx = 0;
472 mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
473 mm_util_retvm_if(gif_image->data == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
475 /* Make local color map */
476 ret = __gif_make_color_map(gif_image, &color_map, &intermediate_image, &intermediate_image_size);
477 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_make_color_map failed");
479 if (EGifPutImageDesc(gif_file->GifFile, 0, 0, gif_image->width, gif_image->height,
480 FALSE, color_map) == GIF_ERROR) {
481 mm_util_error("EGifPutImageDesc failed due to %s", GifErrorString(gif_file->GifFile->Error));
482 COLORMAP_FREE(color_map);
483 MMUTIL_SAFE_FREE(intermediate_image);
484 return MM_UTIL_ERROR_INVALID_OPERATION;
486 /* release color map */
487 COLORMAP_FREE(color_map);
489 mm_util_debug("put pixel count: %lu", (intermediate_image_size / sizeof(GifPixelType)));
491 for (idx = 0; idx < (intermediate_image_size / sizeof(GifPixelType)); idx++) {
492 GifPixelType pixel = (GifPixelType)intermediate_image[idx];
493 if (EGifPutPixel(gif_file->GifFile, pixel) == GIF_ERROR) {
494 mm_util_error("could not put pixel");
495 return MM_UTIL_ERROR_INVALID_OPERATION;
499 /* release intermediate_image */
500 MMUTIL_SAFE_FREE(intermediate_image);
502 return MM_UTIL_ERROR_NONE;
505 int _gif_image_create_ext_block(int function, int byte_count, ExtensionBlock **ext_block)
507 ExtensionBlock *_ext_block = NULL;
509 mm_util_retvm_if(byte_count == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
510 mm_util_retvm_if(ext_block == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
512 /* get allocated extention block */
513 _ext_block = (ExtensionBlock *)calloc(1, sizeof(ExtensionBlock));
514 if (_ext_block == NULL) {
515 mm_util_error("Memory allocation failed");
517 return MM_UTIL_ERROR_OUT_OF_MEMORY;
520 _ext_block->Function = function;
521 _ext_block->ByteCount = byte_count;
522 _ext_block->Bytes = (GifByteType *)calloc(1, (sizeof(GifByteType) * byte_count));
523 if (_ext_block->Bytes == NULL) {
524 mm_util_error("Memory allocation failed");
525 MMUTIL_SAFE_FREE(_ext_block);
526 return MM_UTIL_ERROR_OUT_OF_MEMORY;
529 *ext_block = _ext_block;
530 return MM_UTIL_ERROR_NONE;
533 int _gif_image_write_ext_block(gif_file_s *gif_file, unsigned int delay_time)
535 int ret = MM_UTIL_ERROR_NONE;
536 ExtensionBlock *_ext_block = NULL;
537 GraphicsControlBlock graphic_control_block;
539 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
541 ret = _gif_image_create_ext_block(GRAPHICS_EXT_FUNC_CODE, GRAPHIC_EXT_BLOCK_SIZE, &_ext_block);
542 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_image_alloc_ext_block failed");
543 mm_util_retvm_if(_ext_block->Bytes == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "_gif_image_alloc_ext_block failed");
545 /* use fixed graphics control */
546 graphic_control_block.DisposalMode = MM_UTIL_GIF_DISPOSAL_UNSPECIFIED;
547 graphic_control_block.UserInputFlag = FALSE;
548 graphic_control_block.TransparentColor = NO_TRANSPARENT_COLOR;
549 graphic_control_block.DelayTime = delay_time;
551 EGifGCBToExtension(&graphic_control_block, _ext_block->Bytes);
553 if (EGifPutExtension(gif_file->GifFile, _ext_block->Function, _ext_block->ByteCount, _ext_block->Bytes) == GIF_ERROR) {
554 mm_util_error("EGifPutExtension failed due to %s", GifErrorString(gif_file->GifFile->Error));
555 ret = MM_UTIL_ERROR_INVALID_OPERATION;
558 /* release extension blocks */
559 if (_ext_block != NULL) {
560 MMUTIL_SAFE_FREE(_ext_block->Bytes);
561 MMUTIL_SAFE_FREE(_ext_block);
564 return MM_UTIL_ERROR_NONE;
567 int mm_util_gif_encode_create(mm_gif_file_h *gif_file_h)
569 gif_file_s *gif_file = NULL;
571 mm_util_retvm_if(gif_file_h == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
573 gif_file = (gif_file_s *)calloc(1, sizeof(gif_file_s));
574 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "Memory allocation failed");
576 /* initialize data before set */
577 *gif_file_h = (mm_gif_file_h)gif_file;
579 return MM_UTIL_ERROR_NONE;
582 int mm_util_gif_encode_set_file(mm_gif_file_h gif_file_h, const char *file_name)
584 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
586 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
587 mm_util_retvm_if(file_name == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
588 mm_util_retvm_if(strlen(file_name) == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
589 mm_util_retvm_if(gif_file->GifFile != NULL, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
591 gif_file->filename = g_strdup(file_name);
592 mm_util_retvm_if(gif_file->filename == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "Memory allocation failed");
594 return MM_UTIL_ERROR_NONE;
597 int mm_util_gif_encode_set_mem(mm_gif_file_h gif_file_h, void **data, size_t *data_size)
599 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
601 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
602 mm_util_retvm_if(data == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
603 mm_util_retvm_if(data_size == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
604 mm_util_retvm_if(gif_file->GifFile != NULL, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
606 gif_file->enc_buffer = data;
607 gif_file->enc_buffer_size = data_size;
609 return MM_UTIL_ERROR_NONE;
612 static int _mm_util_gif_encode_start(mm_gif_file_h gif_file_h, unsigned long width, unsigned long height)
614 int ret = MM_UTIL_ERROR_NONE;
615 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
617 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
618 mm_util_retvm_if(gif_file->GifFile != NULL, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has already started");
622 if (gif_file->filename != NULL) {
623 ret = _gif_encode_open_file(&gif_file->GifFile);
624 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_encode_open_file failed");
625 } else if (gif_file->enc_buffer != NULL && gif_file->enc_buffer_size != NULL) {
626 ret = _gif_encode_open_mem(gif_file);
627 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_encode_open_mem failed");
629 mm_util_error("could not find output");
630 return MM_UTIL_ERROR_INVALID_OPERATION;
633 /* To initialize data after GifFile opened */
634 EGifSetGifVersion(gif_file->GifFile, TRUE);
636 /* Write screen description */
637 if (EGifPutScreenDesc(gif_file->GifFile, width, height, 8 /* color_res */, 0 /* background_color */, NULL) == GIF_ERROR) {
638 mm_util_error("could not put screen description");
639 _gif_encode_close_file(gif_file->GifFile);
640 return MM_UTIL_ERROR_INVALID_OPERATION;
644 return MM_UTIL_ERROR_NONE;
647 int mm_util_gif_encode_add_image(mm_gif_file_h gif_file_h, mm_image_info_s *gif_image_h)
649 int ret = MM_UTIL_ERROR_NONE;
650 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
651 mm_image_info_s *gif_image = (mm_image_info_s *)gif_image_h;
654 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
655 mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
656 mm_util_retvm_if((gif_image->width == 0) || (gif_image->height == 0), MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
657 mm_util_retvm_if(gif_image->data == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
659 if (gif_file->GifFile == NULL) {
660 mm_util_warn("first added image, _mm_util_gif_encode_start is needed");
661 ret = _mm_util_gif_encode_start(gif_file_h, gif_image->width, gif_image->height);
662 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_mm_util_gif_encode_start failed");
665 /* Write graphic control block */
666 ret = _gif_image_write_ext_block(gif_file, gif_image->delay_time);
667 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_image_write_ext_block failed");
669 /* Write image description & data */
670 ret = _gif_image_write_image(gif_file, gif_image);
671 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_image_write_image failed");
673 gif_file->GifFile->ImageCount++;
675 return MM_UTIL_ERROR_NONE;
678 int mm_util_gif_encode_save(mm_gif_file_h gif_file_h)
680 int ret = MM_UTIL_ERROR_NONE;
681 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
683 mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
684 mm_util_retvm_if(gif_file->GifFile == NULL, MM_UTIL_ERROR_INVALID_OPERATION, "Encoding has not started");
685 mm_util_retvm_if(gif_file->GifFile->ImageCount <= 0, MM_UTIL_ERROR_INVALID_OPERATION, "No frame has encoded");
689 ret = _gif_encode_close_file(gif_file->GifFile);
690 gif_file->GifFile = NULL;
691 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_encode_close_file failed");
693 if (gif_file->filename != NULL) {
694 ret = _gif_encode_move_to_file(gif_file->filename);
695 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__move_tmp_to_origin failed");
696 } else if (gif_file->write_data_ptr.mem != NULL) {
697 ret = _gif_encode_move_to_mem(gif_file->write_data_ptr.mem, gif_file->write_data_ptr.size,
698 gif_file->enc_buffer, gif_file->enc_buffer_size);
699 MMUTIL_SAFE_FREE(gif_file->write_data_ptr.mem);
700 gif_file->write_data_ptr.size = 0;
701 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_gif_encode_move_to_origin_mem failed");
704 return MM_UTIL_ERROR_NONE;
707 int mm_util_encode_to_gif_file(mm_image_info_s **images, const unsigned int image_count, const char *path)
709 int ret = MM_UTIL_ERROR_NONE;
711 mm_gif_file_h gif_file_h = NULL;
715 mm_util_retvm_if(images == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
716 mm_util_retvm_if(image_count == 0, MM_UTIL_ERROR_INVALID_OPERATION, "Invalid parameter");
717 mm_util_retvm_if(path == NULL, MM_UTIL_ERROR_INVALID_OPERATION, "Invalid parameter");
719 ret = mm_util_gif_encode_create(&gif_file_h);
720 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_create failed %d", ret);
722 ret = mm_util_gif_encode_set_file(gif_file_h, path);
723 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_set_file failed %d", ret);
725 ret = _mm_util_gif_encode_start(gif_file_h, images[0]->width, images[0]->height);
726 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_mm_util_gif_encode_start failed");
728 for (i = 0; i < image_count; i++) {
729 ret = mm_util_gif_encode_add_image(gif_file_h, images[i]);
730 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_add_image failed");
733 ret = mm_util_gif_encode_save(gif_file_h);
734 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_save failed");
738 return MM_UTIL_ERROR_NONE;
741 int mm_util_encode_to_gif_memory(mm_image_info_s **images, const unsigned int image_count, void **buffer, size_t *size)
743 int ret = MM_UTIL_ERROR_NONE;
745 mm_gif_file_h gif_file_h = NULL;
749 mm_util_retvm_if(images == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
750 mm_util_retvm_if(image_count == 0, MM_UTIL_ERROR_INVALID_OPERATION, "Invalid parameter");
751 mm_util_retvm_if(buffer == NULL || size == NULL, MM_UTIL_ERROR_INVALID_OPERATION, "Invalid parameter");
753 ret = mm_util_gif_encode_create(&gif_file_h);
754 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_create failed %d", ret);
756 ret = mm_util_gif_encode_set_mem(gif_file_h, buffer, size);
757 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_set_mem failed %d", ret);
759 ret = _mm_util_gif_encode_start(gif_file_h, images[0]->width, images[0]->height);
760 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "_mm_util_gif_encode_start failed");
762 for (i = 0; i < image_count; i++) {
763 ret = mm_util_gif_encode_add_image(gif_file_h, images[i]);
764 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_add_image failed");
767 ret = mm_util_gif_encode_save(gif_file_h);
768 mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "mm_util_gif_encode_save failed");
772 return MM_UTIL_ERROR_NONE;
775 void mm_util_gif_encode_destroy(mm_gif_file_h gif_file_h)
777 int ret = MM_UTIL_ERROR_NONE;
778 gif_file_s *gif_file = (gif_file_s *)gif_file_h;
780 mm_util_retm_if(gif_file == NULL, "Invalid parameter");
782 if (gif_file->GifFile != NULL) {
783 ret = _gif_encode_close_file(gif_file->GifFile);
784 mm_util_retm_if(ret != MM_UTIL_ERROR_NONE, "_gif_encode_close_file failed");
787 MMUTIL_SAFE_G_FREE(gif_file->filename);
788 MMUTIL_SAFE_FREE(gif_file->write_data_ptr.mem);