Adding initial structure for unittest
[platform/core/multimedia/libmm-utility.git] / gif / mm_util_gif.c
1 /*
2  * libmm-utility
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Vineeth T M <vineeth.tm@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  */
21
22 #include <string.h>
23 #include <gio/gio.h>
24 #include <gif_lib.h>
25
26 #include "mm_util_gif.h"
27 #include "mm_util_gif_private.h"
28 #include "mm_util_private.h"
29
30 #include <limits.h>
31 #define GIF_TMP_FILE    "/tmp/.libmm_gif.gif"
32
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); }
36
37 #define GRAPHIC_EXT_BLOCK_SIZE  4
38
39 static int __convert_gif_to_rgba(void **data, ColorMapObject *color_map, GifRowType *screen_buffer, unsigned long width, unsigned long height)
40 {
41         unsigned long i, j;
42         GifRowType gif_row;
43         GifColorType *color_map_entry;
44         GifByteType *buffer;
45
46         mm_util_fenter();
47
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;
51         }
52
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;
61                         *buffer++ = 255;
62                 }
63         }
64         return MM_UTIL_ERROR_NONE;
65 }
66
67 static int __read_function(GifFileType *gft, GifByteType *data, int size)
68 {
69         gif_mem_s *read_data_ptr = (gif_mem_s *) gft->UserData;
70
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);
75
76         memcpy(data, read_data_ptr->mem + read_data_ptr->size, size);
77         read_data_ptr->size += size;
78
79         return size;
80 }
81
82 static int __read_gif(mm_image_info_s *decoded, const char *filename, void *memory, const size_t src_size)
83 {
84         int ret = MM_UTIL_ERROR_NONE;
85
86         int ExtCode, i, j, Row, Col, Width, Height;
87         size_t Size = 0;
88         GifRecordType record_type;
89         GifRowType *screen_buffer = NULL;
90         GifFileType *GifFile;
91         unsigned int image_num = 0;
92         ColorMapObject *ColorMap;
93         gif_mem_s read_data_ptr;
94
95         mm_util_fenter();
96
97         if (filename) {
98                 if ((GifFile = DGifOpenFileName(filename, NULL)) == NULL) {
99                         mm_util_error("could not open Gif File");
100                         return MM_UTIL_ERROR_INVALID_OPERATION;
101                 }
102         } else if (memory) {
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;
109                 }
110         } else {
111                 mm_util_error("Gif File wrong decode parameters");
112                 return MM_UTIL_ERROR_INVALID_OPERATION;
113         }
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;
117         }
118         decoded->width = GifFile->SWidth;
119         decoded->height = GifFile->SHeight;
120         decoded->size = (unsigned long long)GifFile->SWidth * (unsigned long long)GifFile->SHeight * 4;
121
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;
126                 goto error;
127         }
128
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;
133                 goto error;
134         }
135
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;
143                         goto error;
144                 }
145
146                 memcpy(screen_buffer[i], screen_buffer[0], Size);
147         }
148
149         /* Scan the content of the GIF file and load the image(s) in: */
150         do {
151                 if (DGifGetRecordType(GifFile, &record_type) == GIF_ERROR) {
152                         mm_util_error("could not get record type");
153                         ret = MM_UTIL_ERROR_INVALID_OPERATION;
154                         goto error;
155                 }
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;
161                                 goto error;
162                         }
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;
166                                 goto error;
167                         }
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;
176                                 goto error;
177                         }
178                         image_num++;
179                         if (GifFile->Image.Interlace) {
180                                 int interlaced_offset[] = { 0, 4, 2, 1 }, interlaced_jumps[] = {
181                                 8, 8, 4, 2};
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;
188                                                         goto error;
189                                                 }
190                                         }
191                         } else {
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;
196                                                 goto error;
197                                         }
198                                 }
199                         }
200                         break;
201                 case EXTENSION_RECORD_TYPE:
202                         {
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;
208                                         goto error;
209                                 }
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;
214                                                 goto error;
215                                         }
216                                 }
217                         }
218                         break;
219                 case TERMINATE_RECORD_TYPE:
220                         break;
221                 default:                                /* Should be trapped by DGifGetRecordType. */
222                         break;
223                 }
224                 if (image_num > 0)
225                         break;
226         } while (record_type != TERMINATE_RECORD_TYPE);
227
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;
232                 goto error;
233         }
234
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;
239                 goto error;
240         }
241
242         ret = MM_UTIL_ERROR_NONE;
243 error:
244         if (screen_buffer) {
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]);
250                 }
251                 (void)free(screen_buffer);
252         }
253         if (DGifCloseFile(GifFile, NULL) == GIF_ERROR) {
254                 mm_util_error("could not close file");
255                 ret = MM_UTIL_ERROR_INVALID_OPERATION;
256         }
257
258         mm_util_fleave();
259         return ret;
260 }
261
262 int mm_util_decode_from_gif_file(const char *fpath, mm_image_info_s *decoded)
263 {
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");
266
267         mm_util_fenter();
268
269         return __read_gif(decoded, fpath, NULL, 0);
270 }
271
272 int mm_util_decode_from_gif_memory(void *memory, const size_t src_size, mm_image_info_s *decoded)
273 {
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");
276
277         mm_util_fenter();
278
279         return __read_gif(decoded, NULL, memory, src_size);
280 }
281
282 static int __write_function(GifFileType *gft, const GifByteType *data, int size)
283 {
284         gif_mem_s *write_data_ptr = (gif_mem_s *) gft->UserData;
285
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.");
288
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.");
291
292         memcpy(write_data_ptr->mem + write_data_ptr->size, data, size);
293         write_data_ptr->size += size;
294
295         return size;
296 }
297
298 static const int DEFAULT_COLORMAP_SIZE = (1 << 8);
299
300 static int __gif_extract_rgb(mm_image_info_s *gif_image, unsigned long num_of_pixels, GifByteType **red, GifByteType **green, GifByteType **blue)
301 {
302         GifWord i, j;
303         GifByteType *redP, *greenP, *blueP;
304         GifByteType *buffer = (GifByteType*)gif_image->data;
305
306         mm_util_fenter();
307
308         RGB_ALLOC(redP, greenP, blueP, num_of_pixels, sizeof(GifByteType));
309
310         *red = redP;
311         *green = greenP;
312         *blue = blueP;
313         mm_util_retvm_if((redP == NULL || greenP == NULL || blueP == NULL), MM_UTIL_ERROR_OUT_OF_MEMORY, "Memory allocation failed");
314
315         for (i = 0; i < gif_image->height; i++) {
316                 for (j = 0; j < gif_image->width; j++) {
317                         *redP++ = *buffer++;
318                         *greenP++ = *buffer++;
319                         *blueP++ = *buffer++;
320                         buffer++;
321                 }
322         }
323
324         return MM_UTIL_ERROR_NONE;
325 }
326
327 int __gif_make_color_map(mm_image_info_s *gif_image, ColorMapObject **color_map, GifByteType **intermediate_image, unsigned long *intermediate_image_size)
328 {
329         int ret = MM_UTIL_ERROR_NONE;
330         int colormap_size = DEFAULT_COLORMAP_SIZE;
331         GifByteType *red = NULL, *green = NULL, *blue = NULL;
332
333         mm_util_retvm_if(gif_image == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
334
335         unsigned long num_of_pixels = gif_image->width * gif_image->height;
336
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");
341                 goto FAIL;
342         }
343
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;
347                 goto FAIL;
348         }
349
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;
355                 goto FAIL;
356         }
357         *intermediate_image_size = num_of_pixels * sizeof(GifByteType);
358
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;
362                 goto FAIL;
363         }
364         goto SUCCESS;
365
366 FAIL:
367         if (*intermediate_image)
368                 MMUTIL_SAFE_FREE(*intermediate_image);
369
370         *intermediate_image_size = 0;
371         COLORMAP_FREE(*color_map);
372 SUCCESS:
373         RGB_FREE(red, green, blue);
374
375         return ret;
376 }
377
378 static int _gif_encode_open_file(GifFileType **gft)
379 {
380         mm_util_fenter();
381         mm_util_retvm_if(gft == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
382
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;
386         }
387
388         return MM_UTIL_ERROR_NONE;
389 }
390
391 int _gif_encode_open_mem(gif_file_s *gif_file)
392 {
393         mm_util_fenter();
394         mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
395
396         gif_file->write_data_ptr.mem = NULL;
397         gif_file->write_data_ptr.size = 0;
398
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;
402         }
403
404         return MM_UTIL_ERROR_NONE;
405 }
406
407 static int _gif_encode_close_file(GifFileType *gft)
408 {
409         mm_util_fenter();
410         mm_util_retvm_if(gft == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
411
412         if (EGifCloseFile(gft, NULL) == GIF_ERROR) {
413                 mm_util_error("could not close file");
414                 return MM_UTIL_ERROR_INVALID_OPERATION;
415         }
416         gft = NULL;
417
418         return MM_UTIL_ERROR_NONE;
419 }
420
421 int _gif_encode_move_to_file(const char *dst)
422 {
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;
427
428         if (source == NULL || destination == NULL) {
429                 mm_util_error("could not open file");
430                 if (source)
431                         g_object_unref(source);
432                 if (destination)
433                         g_object_unref(destination);
434                 return MM_UTIL_ERROR_INVALID_OPERATION;
435         }
436
437         gboolean result = g_file_copy(source, destination, G_FILE_COPY_OVERWRITE, NULL, NULL, NULL, &error);
438         if (!result) {
439                 mm_util_error("g_file_copy failed: %s", error ? error->message : "none");
440                 ret = MM_UTIL_ERROR_INVALID_OPERATION;
441         }
442
443         if (error)
444                 g_error_free(error);
445         g_object_unref(source);
446         g_object_unref(destination);
447
448         return ret;
449 }
450
451 int _gif_encode_move_to_mem(const unsigned char *src, size_t src_size, void **dst, size_t *dst_size)
452 {
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");
456
457         mm_util_debug("src_size: %u", src_size);
458
459         buffer = (unsigned char *)calloc(1, src_size);
460         mm_util_retvm_if(buffer == NULL, MM_UTIL_ERROR_OUT_OF_MEMORY, "memory allocation failed");
461
462         memcpy(buffer, src, src_size);
463
464         *dst = buffer;
465         *dst_size = src_size;
466
467         return MM_UTIL_ERROR_NONE;
468 }
469
470 int _gif_image_write_image(gif_file_s *gif_file, mm_image_info_s *gif_image)
471 {
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;
477
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");
480
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");
484
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;
491         }
492         /* release color map */
493         COLORMAP_FREE(color_map);
494
495         mm_util_debug("put pixel count: %lu", (intermediate_image_size / sizeof(GifPixelType)));
496
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;
502                 }
503         }
504
505         /* release intermediate_image */
506         MMUTIL_SAFE_FREE(intermediate_image);
507
508         return MM_UTIL_ERROR_NONE;
509 }
510
511 int _gif_image_create_ext_block(int function, int byte_count, ExtensionBlock **ext_block)
512 {
513         ExtensionBlock *_ext_block = NULL;
514
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");
517
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");
522                 *ext_block = NULL;
523                 return MM_UTIL_ERROR_OUT_OF_MEMORY;
524         }
525
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;
533         }
534
535         *ext_block = _ext_block;
536         return MM_UTIL_ERROR_NONE;
537 }
538
539 int _gif_image_write_ext_block(gif_file_s *gif_file, unsigned int delay_time)
540 {
541         int ret = MM_UTIL_ERROR_NONE;
542         ExtensionBlock *_ext_block = NULL;
543         GraphicsControlBlock graphic_control_block;
544
545         mm_util_retvm_if(gif_file == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
546
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");
550
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;
556
557         EGifGCBToExtension(&graphic_control_block, _ext_block->Bytes);
558
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;
562         }
563
564         /* release extension blocks */
565         if (_ext_block != NULL) {
566                 MMUTIL_SAFE_FREE(_ext_block->Bytes);
567                 MMUTIL_SAFE_FREE(_ext_block);
568         }
569
570         return MM_UTIL_ERROR_NONE;
571 }
572
573 int mm_util_gif_encode_create(mm_gif_file_h *gif_file_h)
574 {
575         gif_file_s *gif_file = NULL;
576
577         mm_util_retvm_if(gif_file_h == NULL, MM_UTIL_ERROR_INVALID_PARAMETER, "Invalid parameter");
578
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");
581
582         /* initialize data before set */
583         *gif_file_h = (mm_gif_file_h)gif_file;
584
585         return MM_UTIL_ERROR_NONE;
586 }
587
588 int mm_util_gif_encode_set_file(mm_gif_file_h gif_file_h, const char *file_name)
589 {
590         gif_file_s *gif_file = (gif_file_s *)gif_file_h;
591
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");
596
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");
599
600         return MM_UTIL_ERROR_NONE;
601 }
602
603 int mm_util_gif_encode_set_mem(mm_gif_file_h gif_file_h, void **data, size_t *data_size)
604 {
605         gif_file_s *gif_file = (gif_file_s *)gif_file_h;
606
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");
611
612         gif_file->enc_buffer = data;
613         gif_file->enc_buffer_size = data_size;
614
615         return MM_UTIL_ERROR_NONE;
616 }
617
618 static int _mm_util_gif_encode_start(mm_gif_file_h gif_file_h, unsigned long width, unsigned long height)
619 {
620         int ret = MM_UTIL_ERROR_NONE;
621         gif_file_s *gif_file = (gif_file_s *)gif_file_h;
622
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");
625
626         mm_util_fenter();
627
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");
634         } else {
635                 mm_util_error("could not find output");
636                 return MM_UTIL_ERROR_INVALID_OPERATION;
637         }
638
639         /* To initialize data after GifFile opened */
640         EGifSetGifVersion(gif_file->GifFile, TRUE);
641
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;
647         }
648
649         mm_util_fleave();
650         return MM_UTIL_ERROR_NONE;
651 }
652
653 int mm_util_gif_encode_add_image(mm_gif_file_h gif_file_h, mm_image_info_s *gif_image_h)
654 {
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;
658
659         mm_util_fenter();
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");
664
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");
669         }
670
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");
674
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");
678
679         gif_file->GifFile->ImageCount++;
680
681         return MM_UTIL_ERROR_NONE;
682 }
683
684 int mm_util_gif_encode_save(mm_gif_file_h gif_file_h)
685 {
686         int ret = MM_UTIL_ERROR_NONE;
687         gif_file_s *gif_file = (gif_file_s *)gif_file_h;
688
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");
692
693         mm_util_fenter();
694
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");
698
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");
708         }
709
710         return MM_UTIL_ERROR_NONE;
711 }
712
713 int mm_util_encode_to_gif_file(mm_image_info_s **images, const unsigned int image_count, const char *path)
714 {
715         int ret = MM_UTIL_ERROR_NONE;
716         int i = 0;
717         mm_gif_file_h gif_file_h = NULL;
718
719         mm_util_fenter();
720
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");
724
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);
727
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);
730
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");
733
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");
737         }
738
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");
741
742         mm_util_fleave();
743
744         return MM_UTIL_ERROR_NONE;
745 }
746
747 int mm_util_encode_to_gif_memory(mm_image_info_s **images, const unsigned int image_count, void **buffer, size_t *size)
748 {
749         int ret = MM_UTIL_ERROR_NONE;
750         int i = 0;
751         mm_gif_file_h gif_file_h = NULL;
752
753         mm_util_fenter();
754
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");
758
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);
761
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);
764
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");
767
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");
771         }
772
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");
775
776         mm_util_fleave();
777
778         return MM_UTIL_ERROR_NONE;
779 }
780
781 void mm_util_gif_encode_destroy(mm_gif_file_h gif_file_h)
782 {
783         int ret = MM_UTIL_ERROR_NONE;
784         gif_file_s *gif_file = (gif_file_s *)gif_file_h;
785
786         mm_util_retm_if(gif_file == NULL, "Invalid parameter");
787
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");
791         }
792
793         MMUTIL_SAFE_G_FREE(gif_file->filename);
794         MMUTIL_SAFE_FREE(gif_file->write_data_ptr.mem);
795 }