gif_io_buf_s io_buf;
} gif_file_s;
-static int __convert_gif_to_rgba(void **data, ColorMapObject *color_map, GifRowType *screen_buffer, unsigned int width, unsigned int height)
-{
- unsigned long i, j;
- GifRowType gif_row;
- GifColorType *color_map_entry;
- GifByteType *buffer;
-
- mm_util_fenter();
-
- if ((*data = (void *)calloc(1, width * height * 4)) == NULL) {
- mm_util_error("Failed to allocate memory required, aborted.");
- return MM_UTIL_ERROR_OUT_OF_MEMORY;
- }
-
- buffer = (GifByteType *) *data;
- for (i = 0; i < height; i++) {
- gif_row = screen_buffer[i];
- for (j = 0; j < width; j++) {
- color_map_entry = &color_map->Colors[gif_row[j]];
- *buffer++ = color_map_entry->Red;
- *buffer++ = color_map_entry->Green;
- *buffer++ = color_map_entry->Blue;
- *buffer++ = 255;
- }
- }
- return MM_UTIL_ERROR_NONE;
-}
-
static int __read_function(GifFileType *gft, GifByteType *data, int size)
{
gif_io_buf_s *io_buf = (gif_io_buf_s *) gft->UserData;
return size;
}
-static int __read_gif(const char *file_path, void *memory, const size_t src_size, mm_util_image_h *decoded)
+static int __gif_open(const char *file_path, void *memory, const size_t src_size, gif_io_buf_s *io_buf, GifFileType **gif_image)
{
- int ret = MM_UTIL_ERROR_NONE;
-
- int ExtCode, i, j, Row, Col, Width, Height;
- size_t Size = 0;
- GifRecordType record_type;
- GifRowType *screen_buffer = NULL;
- GifFileType *GifFile;
- unsigned int image_num = 0;
- ColorMapObject *ColorMap;
- gif_io_buf_s io_buf = { memory, src_size, 0 };
- void *_data = NULL;
-
mm_util_retvm_if(!MMUTIL_STRING_VALID(file_path) && (memory == NULL), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid gif image");
- mm_util_retvm_if(!decoded, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image handle");
-
- mm_util_fenter();
if (MMUTIL_STRING_VALID(file_path)) {
mm_util_sec_debug("read from file [%s]", file_path);
- if ((GifFile = DGifOpenFileName(file_path, NULL)) == NULL) {
+ if ((*gif_image = DGifOpenFileName(file_path, NULL)) == NULL) {
mm_util_error("could not open Gif File");
return MM_UTIL_ERROR_INVALID_OPERATION;
}
} else {
mm_util_debug("read from memory");
- if ((GifFile = DGifOpen(&io_buf, __read_function, NULL)) == NULL) {
+ if ((*gif_image = DGifOpen(io_buf, __read_function, NULL)) == NULL) {
mm_util_error("could not open Gif File");
return MM_UTIL_ERROR_INVALID_OPERATION;
}
}
- if (GifFile->SWidth <= 0 || GifFile->SHeight <= 0) {
- mm_util_error("Gif File wrong decode width & height");
+ return MM_UTIL_ERROR_NONE;
+}
+
+static void __gif_free_frame_buffer(GifRowType *frame_buffer, unsigned int size)
+{
+ int idx = 0;
+
+ if (!frame_buffer)
+ return;
+
+ for (idx = 0; idx < (int)size; idx++)
+ MMUTIL_SAFE_FREE(frame_buffer[idx]);
+ free(frame_buffer);
+}
+
+static int __gif_generate_frame_buffer(GifFileType *gif_image, GifRowType **screen_buf)
+{
+ int idx = 0;
+ size_t row_size = 0;
+ GifRowType* _screen_buf = NULL;
+
+ _screen_buf = (GifRowType *)calloc(1, gif_image->SHeight * sizeof(GifRowType));
+ mm_util_retvm_if(!_screen_buf, MM_UTIL_ERROR_OUT_OF_MEMORY, "Failed to allocate memory required, aborted.");
+
+ row_size = gif_image->SWidth * sizeof(GifPixelType); /* Size in bytes one row. */
+ if ((_screen_buf[0] = (GifRowType) calloc(1, row_size)) == NULL) { /* First row. */
+ mm_util_error("Failed to allocate memory required, aborted.");
+ MMUTIL_SAFE_FREE(_screen_buf);
return MM_UTIL_ERROR_INVALID_OPERATION;
}
- if ((screen_buffer = (GifRowType *)calloc(1, GifFile->SHeight * sizeof(GifRowType))) == NULL) {
- mm_util_error("Failed to allocate memory required, aborted.");
- ret = MM_UTIL_ERROR_INVALID_OPERATION;
- goto error;
+ for (idx = 0; idx < (int)(gif_image->SWidth); idx++) /* Set its color to BackGround. */
+ _screen_buf[0][idx] = gif_image->SBackGroundColor;
+
+ for (idx = 1; idx < (int)(gif_image->SHeight); idx++) {
+ /* Allocate the other rows, and set their color to background too: */
+ if ((_screen_buf[idx] = (GifRowType) calloc(1, row_size)) == NULL) {
+ mm_util_error("Failed to allocate memory required, aborted.");
+ __gif_free_frame_buffer(_screen_buf, idx - 1);
+ return MM_UTIL_ERROR_INVALID_OPERATION;
+ }
+
+ memcpy(_screen_buf[idx], _screen_buf[0], row_size);
}
- Size = GifFile->SWidth * sizeof(GifPixelType); /* Size in bytes one row. */
- if ((screen_buffer[0] = (GifRowType) calloc(1, Size)) == NULL) { /* First row. */
+ *screen_buf = _screen_buf;
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+static gboolean __gif_is_good_frame(GifFileType *gif_image)
+{
+ 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);
+
+ if (gif_image->Image.Top < 0 || gif_image->Image.Left < 0 || gif_image->Image.Width <= 0 || gif_image->Image.Height <= 0) {
+ mm_util_error("Frame has wrong dimensions");
+ return FALSE;
+ }
+
+ if (gif_image->Image.Left + gif_image->Image.Width > gif_image->SWidth || gif_image->Image.Top + gif_image->Image.Height > gif_image->SHeight) {
+ mm_util_debug("Frame is not full screen frame");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int __gif_fill_frame_buffer(GifFileType *gif_image, GifRowType *frame_buffer)
+{
+ unsigned int i, j;
+
+ unsigned int Row = (unsigned int)gif_image->Image.Top; /* Image Position relative to Screen. */
+ unsigned int Col = (unsigned int)gif_image->Image.Left;
+ unsigned int Width = (unsigned int)gif_image->Image.Width;
+ unsigned int Height = (unsigned int)gif_image->Image.Height;
+ unsigned int interlaced_offset[] = { 0, 4, 2, 1 }, interlaced_jumps[] = {
+ 8, 8, 4, 2};
+
+ if (gif_image->Image.Interlace) {
+ /* Need to perform 4 passes on the images: */
+ for (i = 0; i < 4; i++)
+ for (j = Row + interlaced_offset[i]; j < Row + Height; j += interlaced_jumps[i]) {
+ if (DGifGetLine(gif_image, &frame_buffer[j][Col], Width) == GIF_ERROR) {
+ mm_util_error("could not get line (%u)", gif_image->Error);
+ return MM_UTIL_ERROR_INVALID_OPERATION;
+ }
+ }
+ } else {
+ for (i = 0; i < Height; i++) {
+ if (DGifGetLine(gif_image, &frame_buffer[Row++][Col], Width) == GIF_ERROR) {
+ mm_util_error("could not get line (%u)", gif_image->Error);
+ return MM_UTIL_ERROR_INVALID_OPERATION;
+ }
+ }
+ }
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+static int __gif_get_extension(GifFileType *gif_image)
+{
+ int ExtCode = 0;
+ GifByteType *extension = NULL;
+
+ /* for skip any extension blocks in file */
+ if (DGifGetExtension(gif_image, &ExtCode, &extension) == GIF_ERROR) {
+ mm_util_error("could not get extension (%u)", gif_image->Error);
+ return MM_UTIL_ERROR_INVALID_OPERATION;
+ }
+ while (extension != NULL) {
+ if (DGifGetExtensionNext(gif_image, &extension) == GIF_ERROR) {
+ mm_util_error("could not get next extension (%u)", gif_image->Error);
+ return MM_UTIL_ERROR_INVALID_OPERATION;
+ }
+ }
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+static int __gif_convert_to_rgba(void **data, ColorMapObject *color_map, GifRowType *frame_buffer, unsigned int width, unsigned int height)
+{
+ unsigned int i, j;
+ GifRowType gif_row;
+ GifColorType *color_map_entry;
+ GifByteType *buffer;
+
+ mm_util_fenter();
+
+ if ((*data = (void *)calloc(1, width * height * 4)) == NULL) {
mm_util_error("Failed to allocate memory required, aborted.");
- ret = MM_UTIL_ERROR_INVALID_OPERATION;
- goto error;
+ return MM_UTIL_ERROR_OUT_OF_MEMORY;
}
- for (i = 0; i < (int)(GifFile->SWidth); i++) /* Set its color to BackGround. */
- screen_buffer[0][i] = GifFile->SBackGroundColor;
- for (i = 1; i < (int)(GifFile->SHeight); i++) {
- /* Allocate the other rows, and set their color to background too: */
- if ((screen_buffer[i] = (GifRowType) calloc(1, Size)) == NULL) {
- mm_util_error("Failed to allocate memory required, aborted.");
- ret = MM_UTIL_ERROR_INVALID_OPERATION;
- goto error;
+ buffer = (GifByteType *) *data;
+ for (i = 0; i < height; i++) {
+ gif_row = frame_buffer[i];
+ for (j = 0; j < width; j++) {
+ color_map_entry = &color_map->Colors[gif_row[j]];
+ *buffer++ = color_map_entry->Red;
+ *buffer++ = color_map_entry->Green;
+ *buffer++ = color_map_entry->Blue;
+ *buffer++ = 255;
}
+ }
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+static int __read_gif(const char *file_path, void *memory, const size_t src_size, mm_util_image_h *decoded)
+{
+ int ret = MM_UTIL_ERROR_NONE;
+
+ GifRecordType record_type = UNDEFINED_RECORD_TYPE;
+ GifRowType *frame_buffer = NULL;
+ GifFileType *GifFile;
+ gboolean is_found = FALSE;
+ ColorMapObject *ColorMap = NULL;
+ gif_io_buf_s io_buf = { memory, src_size, 0 };
+ void *image_buffer = NULL;
+
+ mm_util_retvm_if(!decoded, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image handle");
+
+ mm_util_fenter();
- memcpy(screen_buffer[i], screen_buffer[0], Size);
+ ret = __gif_open(file_path, memory, src_size, &io_buf, &GifFile);
+ mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "__gif_open failed");
+
+ mm_util_retvm_if(GifFile->SWidth <= 0 || GifFile->SHeight <= 0, MM_UTIL_ERROR_INVALID_OPERATION, "Gif File wrong decode width & height");
+
+ ret = __gif_generate_frame_buffer(GifFile, &frame_buffer);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ mm_util_debug("__gif_generate_frame_buffer failed");
+ goto error;
}
/* Scan the content of the GIF file and load the image(s) in: */
do {
if (DGifGetRecordType(GifFile, &record_type) == GIF_ERROR) {
- mm_util_error("could not get record type");
+ mm_util_error("could not get record type (%u)", GifFile->Error);
ret = MM_UTIL_ERROR_INVALID_OPERATION;
goto error;
}
switch (record_type) {
case IMAGE_DESC_RECORD_TYPE:
+ /* get frame data */
if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
mm_util_error("could not get image description");
ret = MM_UTIL_ERROR_INVALID_OPERATION;
goto error;
}
- if (GifFile->Image.Top < 0 || GifFile->Image.Left < 0 || GifFile->Image.Width <= 0 || GifFile->Image.Height <= 0) {
- mm_util_error("Gif File wrong decode width & height");
+
+ if (!__gif_is_good_frame(GifFile)) {
+ mm_util_debug("Image is not confined to screen dimension, aborted.");
ret = MM_UTIL_ERROR_INVALID_OPERATION;
goto error;
}
- Row = GifFile->Image.Top; /* Image Position relative to Screen. */
- Col = GifFile->Image.Left;
- Width = GifFile->Image.Width;
- Height = GifFile->Image.Height;
- mm_util_debug("Image %d at (%d, %d) [%dx%d]", image_num + 1, Col, Row, Width, Height);
- if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth || GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
- mm_util_debug("Image %d is not confined to screen dimension, aborted.", image_num + 1);
- ret = MM_UTIL_ERROR_INVALID_OPERATION;
+
+ is_found = TRUE;
+
+ ret = __gif_fill_frame_buffer(GifFile, frame_buffer);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ mm_util_error("__gif_generate_frame_buffer failed");
goto error;
}
- image_num++;
- if (GifFile->Image.Interlace) {
- int interlaced_offset[] = { 0, 4, 2, 1 }, interlaced_jumps[] = {
- 8, 8, 4, 2};
- /* Need to perform 4 passes on the images: */
- for (i = 0; i < 4; i++)
- for (j = Row + interlaced_offset[i]; j < Row + Height; j += interlaced_jumps[i]) {
- if (DGifGetLine(GifFile, &screen_buffer[j][Col], Width) == GIF_ERROR) {
- mm_util_error("could not get line");
- ret = MM_UTIL_ERROR_INVALID_OPERATION;
- goto error;
- }
- }
- } else {
- for (i = 0; i < Height; i++) {
- if (DGifGetLine(GifFile, &screen_buffer[Row++][Col], Width) == GIF_ERROR) {
- mm_util_error("could not get line");
- ret = MM_UTIL_ERROR_INVALID_OPERATION;
- goto error;
- }
- }
- }
break;
case EXTENSION_RECORD_TYPE:
- {
- GifByteType *extension;
- /* Skip any extension blocks in file: */
- if (DGifGetExtension(GifFile, &ExtCode, &extension) == GIF_ERROR) {
- mm_util_error("could not get extension");
- ret = MM_UTIL_ERROR_INVALID_OPERATION;
- goto error;
- }
- while (extension != NULL) {
- if (DGifGetExtensionNext(GifFile, &extension) == GIF_ERROR) {
- mm_util_error("could not get next extension");
- ret = MM_UTIL_ERROR_INVALID_OPERATION;
- goto error;
- }
- }
- }
+ /* currently, we don't use extension value, it needs to play animation */
+ ret = __gif_get_extension(GifFile);
+ if (ret != MM_UTIL_ERROR_NONE)
+ goto error;
break;
case TERMINATE_RECORD_TYPE:
break;
- default: /* Should be trapped by DGifGetRecordType. */
+ default:
+ /* should be trapped by DGifGetRecordType. */
break;
}
- if (image_num > 0)
- break;
- } while (record_type != TERMINATE_RECORD_TYPE);
+ } while (record_type != TERMINATE_RECORD_TYPE && !is_found);
ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap);
if (ColorMap == NULL) {
goto error;
}
- ret = __convert_gif_to_rgba(&_data, ColorMap, screen_buffer, GifFile->SWidth, GifFile->SHeight);
+ /* decompress image with colormap(256) */
+ ret = __gif_convert_to_rgba(&image_buffer, ColorMap, frame_buffer, GifFile->SWidth, GifFile->SHeight);
if (ret != MM_UTIL_ERROR_NONE) {
mm_util_error("could not convert gif to rgba");
ret = MM_UTIL_ERROR_INVALID_OPERATION;
goto error;
}
- ret = mm_image_create_image(GifFile->SWidth, GifFile->SHeight, MM_UTIL_COLOR_RGBA, _data, GifFile->SWidth * GifFile->SHeight * 4, decoded);
- MMUTIL_SAFE_FREE(_data);
+ ret = mm_image_create_image(GifFile->SWidth, GifFile->SHeight, MM_UTIL_COLOR_RGBA, image_buffer, GifFile->SWidth * GifFile->SHeight * 4, decoded);
+ MMUTIL_SAFE_FREE(image_buffer);
error:
- if (screen_buffer) {
- if (screen_buffer[0])
- (void)free(screen_buffer[0]);
- for (i = 1; i < (int)(GifFile->SHeight); i++) {
- if (screen_buffer[i])
- (void)free(screen_buffer[i]);
- }
- (void)free(screen_buffer);
- }
+ __gif_free_frame_buffer(frame_buffer, GifFile->SHeight);
+
if (DGifCloseFile(GifFile, NULL) == GIF_ERROR) {
mm_util_error("could not close file");
ret = MM_UTIL_ERROR_INVALID_OPERATION;