From dd7595a3475407a7fa96a97393bae8c5220e8762 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Wed, 4 Jan 2012 18:41:13 +1000 Subject: Add the base Enlightenment Foundation Libraries - eina, eet, evas, ecore, embryo, and edje. Note that embryo wont be used, but I'm not sure yet if you can build edje without it. --- .../src/modules/loaders/gif/evas_image_load_gif.c | 1030 ++++++++++++++++++++ 1 file changed, 1030 insertions(+) create mode 100644 libraries/evas/src/modules/loaders/gif/evas_image_load_gif.c (limited to 'libraries/evas/src/modules/loaders/gif/evas_image_load_gif.c') diff --git a/libraries/evas/src/modules/loaders/gif/evas_image_load_gif.c b/libraries/evas/src/modules/loaders/gif/evas_image_load_gif.c new file mode 100644 index 0000000..976df0d --- /dev/null +++ b/libraries/evas/src/modules/loaders/gif/evas_image_load_gif.c @@ -0,0 +1,1030 @@ +#include "evas_common.h" +#include "evas_private.h" + +#include +#include +#include +#include + +#include + +typedef struct _Gif_Frame Gif_Frame; + +typedef enum _Frame_Load_Type +{ + LOAD_FRAME_NONE = 0, + LOAD_FRAME_INFO = 1, + LOAD_FRAME_DATA = 2, + LOAD_FRAME_DATA_INFO = 3 +} Frame_Load_Type; + +struct _Gif_Frame +{ + struct { + /* Image descriptor */ + int x; + int y; + int w; + int h; + int interlace; + } image_des; + + struct { + /* Graphic Control*/ + int disposal; + int transparent; + int delay; + int input; + } frame_info; +}; + +static Eina_Bool evas_image_load_file_data_gif_internal(Image_Entry *ie, Image_Entry_Frame *frame, int *error); + +static Eina_Bool evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4); +static Eina_Bool evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4); +static double evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, int start_frame, int frame_num) ; +static Eina_Bool evas_image_load_specific_frame(Image_Entry *ie, const char *file, int frame_index, int *error); + +static Evas_Image_Load_Func evas_image_load_gif_func = +{ + EINA_TRUE, + evas_image_load_file_head_gif, + evas_image_load_file_data_gif, + evas_image_load_frame_duration_gif +}; +#define byte2_to_int(a,b) (((b)<<8)|(a)) + +#define FRAME_MAX 1024 + +/* find specific frame in image entry */ +static Eina_Bool +_find_frame(Image_Entry *ie, int frame_index, Image_Entry_Frame **frame) +{ + Eina_List *l; + Image_Entry_Frame *hit_frame = NULL; + + if (!ie) return EINA_FALSE; + if (!ie->frames) return EINA_FALSE; + + EINA_LIST_FOREACH(ie->frames, l, hit_frame) + { + if (hit_frame->index == frame_index) + { + *frame = hit_frame; + return EINA_TRUE; + } + } + return EINA_FALSE; +} + +static Eina_Bool +_find_close_frame(Image_Entry *ie, int frame_index, Image_Entry_Frame **frame) +{ + int i; + Eina_Bool hit = EINA_FALSE; + i = frame_index -1; + + if (!ie) return EINA_FALSE; + if (!ie->frames) return EINA_FALSE; + + for (; i > 0; i--) + { + hit = _find_frame(ie, i, frame); + if (hit) + return EINA_TRUE; + } + return EINA_FALSE; +} + +static Eina_Bool +_evas_image_skip_frame(GifFileType *gif, int frame) +{ + int remain_frame = 0; + GifRecordType rec; + + if (!gif) return EINA_FALSE; + if (frame == 0) return EINA_TRUE; /* no need to skip */ + if (frame < 0 || frame > FRAME_MAX) return EINA_FALSE; + + remain_frame = frame; + + do + { + if (DGifGetRecordType(gif, &rec) == GIF_ERROR) return EINA_FALSE; + + if (rec == EXTENSION_RECORD_TYPE) + { + int ext_code; + GifByteType *ext; + + ext = NULL; + DGifGetExtension(gif, &ext_code, &ext); + while (ext) + { /*skip extention */ + ext = NULL; + DGifGetExtensionNext(gif, &ext); + } + } + + if (rec == IMAGE_DESC_RECORD_TYPE) + { + int img_code; + GifByteType *img; + + if (DGifGetImageDesc(gif) == GIF_ERROR) return EINA_FALSE; + + remain_frame --; + /* we have to count frame, so use DGifGetCode and skip decoding */ + if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR) return EINA_FALSE; + + while (img) + { + img = NULL; + DGifGetCodeNext(gif, &img); + } + if (remain_frame < 1) return EINA_TRUE; + } + if (rec == TERMINATE_RECORD_TYPE) return EINA_FALSE; /* end of file */ + + } while ((rec != TERMINATE_RECORD_TYPE) && (remain_frame > 0)); + return EINA_FALSE; +} + +static Eina_Bool +_evas_image_load_frame_graphic_info(Image_Entry_Frame *frame, GifByteType *ext) +{ + Gif_Frame *gif_frame = NULL; + if ((!frame) || (!ext)) return EINA_FALSE; + + gif_frame = (Gif_Frame *) frame->info; + + /* transparent */ + if ((ext[1] & 0x1) != 0) + gif_frame->frame_info.transparent = ext[4]; + else + gif_frame->frame_info.transparent = -1; + + gif_frame->frame_info.input = (ext[1] >>1) & 0x1; + gif_frame->frame_info.disposal = (ext[1] >>2) & 0x7; + gif_frame->frame_info.delay = byte2_to_int(ext[2], ext[3]); + return EINA_TRUE; +} + +static Eina_Bool +_evas_image_load_frame_image_des_info(GifFileType *gif, Image_Entry_Frame *frame) +{ + Gif_Frame *gif_frame = NULL; + if ((!gif) || (!frame)) return EINA_FALSE; + + gif_frame = (Gif_Frame *) frame->info; + gif_frame->image_des.x = gif->Image.Left; + gif_frame->image_des.y = gif->Image.Top; + gif_frame->image_des.w = gif->Image.Width; + gif_frame->image_des.h = gif->Image.Height; + gif_frame->image_des.interlace = gif->Image.Interlace; + return EINA_TRUE; +} + +static Eina_Bool +_evas_image_load_frame_image_data(Image_Entry *ie, GifFileType *gif, Image_Entry_Frame *frame, int *error) +{ + int w; + int h; + int x; + int y; + int i,j; + int bg; + int r; + int g; + int b; + int alpha; + double per; + double per_inc; + ColorMapObject *cmap; + GifRowType *rows; + int intoffset[] = { 0, 4, 2, 1 }; + int intjump[] = { 8, 8, 4, 2 }; + size_t siz; + int cache_w; + int cache_h; + int cur_h; + int cur_w; + int disposal = 0; + int bg_val = 0; + DATA32 *ptr; + Gif_Frame *gif_frame = NULL; + + if ((!gif) || (!frame)) return EINA_FALSE; + + gif_frame = (Gif_Frame *) frame->info; + w = gif->Image.Width; + h = gif->Image.Height; + x = gif->Image.Left; + y = gif->Image.Top; + cache_w = ie->w; + cache_h = ie->h; + + rows = malloc(h * sizeof(GifRowType *)); + if (!rows) + { + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + for (i = 0; i < h; i++) + { + rows[i] = NULL; + } + for (i = 0; i < h; i++) + { + rows[i] = malloc(w * sizeof(GifPixelType)); + if (!rows[i]) + { + for (i = 0; i < h; i++) + { + if (rows[i]) + { + free(rows[i]); + } + } + free(rows); + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + } + if (gif->Image.Interlace) + { + for (i = 0; i < 4; i++) + { + for (j = intoffset[i]; j < h; j += intjump[i]) + { + DGifGetLine(gif, rows[j], w); + } + } + } + else + { + for (i = 0; i < h; i++) + { + if (DGifGetLine(gif, rows[i], w) != GIF_OK) + { + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + goto error; + } + } + } + alpha = gif_frame->frame_info.transparent; + siz = cache_w *cache_h * sizeof(DATA32); + frame->data = malloc(siz); + if (!frame->data) + { + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + goto error; + } + ptr = frame->data; + bg = gif->SBackGroundColor; + cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap); + + if (!cmap) + { + DGifCloseFile(gif); + for (i = 0; i < h; i++) + { + free(rows[i]); + } + free(rows); + if (frame->data) free(frame->data); + *error = EVAS_LOAD_ERROR_CORRUPT_FILE; + return EINA_FALSE; + } + + /* get the background value */ + r = cmap->Colors[bg].Red; + g = cmap->Colors[bg].Green; + b = cmap->Colors[bg].Blue; + bg_val = ARGB_JOIN(0xff, r, g, b); + + per_inc = 100.0 / (((double)w) * h); + cur_h = h; + cur_w = w; + if (cur_h > cache_h) cur_h = cache_h; + if (cur_w > cache_w) cur_w = cache_w; + + if (frame->index > 1) + { + /* get previous frame only frame index is bigger than 1 */ + DATA32 *ptr_src; + Image_Entry_Frame *new_frame = NULL; + int cur_frame = frame->index; + int start_frame = 1; + int j = 0; + + if (_find_close_frame(ie, cur_frame, &new_frame)) + start_frame = new_frame->index + 1; + + if ((start_frame < 1) || (start_frame > cur_frame)) + { + *error = EVAS_LOAD_ERROR_CORRUPT_FILE; + goto error; + } + /* load previous frame of cur_frame */ + for (j = start_frame; j < cur_frame ; j++) + { + if (!evas_image_load_specific_frame(ie, ie->file, j, error)) + { + *error = EVAS_LOAD_ERROR_CORRUPT_FILE; + goto error; + } + } + if (!_find_frame(ie, cur_frame - 1, &new_frame)) + { + *error = EVAS_LOAD_ERROR_CORRUPT_FILE; + goto error; + } + else + { + Gif_Frame *gif_frame = NULL; + ptr_src = new_frame->data; + if (new_frame->info) + { + gif_frame = (Gif_Frame *)(new_frame->info); + disposal = gif_frame->frame_info.disposal; + } + switch(disposal) /* we only support disposal flag 0,1,2 */ + { + case 1: /* Do not dispose. need previous frame*/ + memcpy(ptr, ptr_src, siz); + /* composite frames */ + ptr = ptr + cache_w * y; + + for (i = 0; i < cur_h; i++) + { + ptr = ptr + x; + for (j = 0; j < cur_w; j++) + { + if (rows[i][j] == alpha) + { + ptr++ ; + } + else + { + r = cmap->Colors[rows[i][j]].Red; + g = cmap->Colors[rows[i][j]].Green; + b = cmap->Colors[rows[i][j]].Blue; + *ptr++ = ARGB_JOIN(0xff, r, g, b); + } + per += per_inc; + } + ptr = ptr + (cache_w - (x + cur_w)); + } + break; + case 2: /* Restore to background color */ + memcpy(ptr, ptr_src, siz); + /* composite frames */ + for (i = 0; i < cache_h; i++) + { + if ((i < y) || (i >= (y + cur_h))) + { + for (j = 0; j < cache_w; j++) + { + *ptr = bg_val; + ptr++; + } + } + else + { + int i1, j1; + i1 = i -y; + + for (j = 0; j < cache_w; j++) + { + j1 = j - x; + if ((j < x) || (j >= (x + cur_w))) + { + *ptr = bg_val; + ptr++; + } + else + { + r = cmap->Colors[rows[i1][j1]].Red; + g = cmap->Colors[rows[i1][j1]].Green; + b = cmap->Colors[rows[i1][j1]].Blue; + *ptr++ = ARGB_JOIN(0xff, r, g, b); + } + } + } + } + break; + case 0: /* No disposal specified */ + default: + memset(ptr, 0, siz); + for (i = 0; i < cache_h; i++) + { + if ((i < y) || (i >= (y + cur_h))) + { + for (j = 0; j < cache_w; j++) + { + *ptr = bg_val; + ptr++; + } + } + else + { + int i1, j1; + i1 = i -y; + + for (j = 0; j < cache_w; j++) + { + j1 = j - x; + if ((j < x) || (j >= (x + cur_w))) + { + *ptr = bg_val; + ptr++; + } + else + { + r = cmap->Colors[rows[i1][j1]].Red; + g = cmap->Colors[rows[i1][j1]].Green; + b = cmap->Colors[rows[i1][j1]].Blue; + *ptr++ = ARGB_JOIN(0xff, r, g, b); + } + } + } + } + break; + } + } + } + else /* first frame decoding */ + { + /* fill background color */ + for (i = 0; i < cache_h; i++) + { + if ((i < y) || (i >= (y + cur_h))) + { + for (j = 0; j < cache_w; j++) + { + *ptr = bg_val; + ptr++; + } + } + else + { + int i1, j1; + i1 = i -y; + + for (j = 0; j < cache_w; j++) + { + j1 = j - x; + if ((j < x) || (j >= (x + cur_w))) + { + *ptr = bg_val; + ptr++; + } + else + { + r = cmap->Colors[rows[i1][j1]].Red; + g = cmap->Colors[rows[i1][j1]].Green; + b = cmap->Colors[rows[i1][j1]].Blue; + *ptr++ = ARGB_JOIN(0xff, r, g, b); + } + } + } + } + } + + for (i = 0; i < h; i++) + { + if (rows[i]) free(rows[i]); + } + if (rows) free(rows); + frame->loaded = EINA_TRUE; + return EINA_TRUE; +error: + for (i = 0; i < h; i++) + { + if (rows[i]) free(rows[i]); + } + if (rows) free(rows); + return EINA_FALSE; +} + +static Eina_Bool +_evas_image_load_frame(Image_Entry *ie, GifFileType *gif, Image_Entry_Frame *frame, Frame_Load_Type type, int *error) +{ + GifRecordType rec; + int gra_res = 0, img_res = 0; + Eina_Bool res = EINA_FALSE; + Gif_Frame *gif_frame = NULL; + + if ((!gif) || (!frame)) return EINA_FALSE; + gif_frame = (Gif_Frame *) frame->info; + + if (type > LOAD_FRAME_DATA_INFO) return EINA_FALSE; + + do + { + if (DGifGetRecordType(gif, &rec) == GIF_ERROR) return EINA_FALSE; + if (rec == IMAGE_DESC_RECORD_TYPE) + { + img_res++; + break; + } + else if (rec == EXTENSION_RECORD_TYPE) + { + int ext_code; + GifByteType *ext; + + ext = NULL; + DGifGetExtension(gif, &ext_code, &ext); + while (ext) + { + if (ext_code == 0xf9) /* Graphic Control Extension */ + { + gra_res++; + /* fill frame info */ + if ((type == LOAD_FRAME_INFO) || (type == LOAD_FRAME_DATA_INFO)) + _evas_image_load_frame_graphic_info(frame,ext); + } + ext = NULL; + DGifGetExtensionNext(gif, &ext); + } + } + } while ((rec != TERMINATE_RECORD_TYPE) && (img_res == 0)); + if (img_res != 1) return EINA_FALSE; + if (DGifGetImageDesc(gif) == GIF_ERROR) return EINA_FALSE; + if ((type == LOAD_FRAME_INFO) || (type == LOAD_FRAME_DATA_INFO)) + _evas_image_load_frame_image_des_info(gif, frame); + + if ((type == LOAD_FRAME_DATA) || (type == LOAD_FRAME_DATA_INFO)) + { + res = _evas_image_load_frame_image_data(ie, gif,frame, error); + if (!res) return EINA_FALSE; + } + return EINA_TRUE; +} + + +/* set frame data to cache entry's data */ +static Eina_Bool +evas_image_load_file_data_gif_internal(Image_Entry *ie, Image_Entry_Frame *frame, int *error) +{ + int w; + int h; + int dst_x; + int dst_y; + DATA32 *dst; + DATA32 *src; + int cache_w, cache_h; + size_t siz; + Gif_Frame *gif_frame = NULL; + + gif_frame = (Gif_Frame *) frame->info; + cache_w = ie->w; + cache_h = ie->h; + w = gif_frame->image_des.w; + h = gif_frame->image_des.h; + dst_x = gif_frame->image_des.x; + dst_y = gif_frame->image_des.y; + + src = frame->data; + + if (!evas_cache_image_pixels(ie)) + { + evas_cache_image_surface_alloc(ie, cache_w, cache_h); + } + + if (!evas_cache_image_pixels(ie)) + { + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + + /* only copy real frame part */ + siz = cache_w * cache_h * sizeof(DATA32); + dst = evas_cache_image_pixels(ie); + + memcpy(dst, src, siz); + + evas_common_image_premul(ie); + + *error = EVAS_LOAD_ERROR_NONE; + return EINA_TRUE; +} + +static Eina_Bool +evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error) +{ + int fd; + GifFileType *gif; + GifRecordType rec; + int w; + int h; + int alpha; + int loop_count = -1; + + w = 0; + h = 0; + alpha = -1; + +#ifndef __EMX__ + fd = open(file, O_RDONLY); +#else + fd = open(file, O_RDONLY | O_BINARY); +#endif + if (fd < 0) + { + *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; + return EINA_FALSE; + } + + gif = DGifOpenFileHandle(fd); + if (!gif) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + + /* check logical screen size */ + w = gif->SWidth; + h = gif->SHeight; + + if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) || + IMG_TOO_BIG(w, h)) + { + DGifCloseFile(gif); + if (IMG_TOO_BIG(w, h)) + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + else + *error = EVAS_LOAD_ERROR_GENERIC; + return EINA_FALSE; + } + ie->w = w; + ie->h = h; + + do + { + if (DGifGetRecordType(gif, &rec) == GIF_ERROR) + { + /* PrintGifError(); */ + DGifCloseFile(gif); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + + /* image descript info */ + if (rec == IMAGE_DESC_RECORD_TYPE) + { + int img_code; + GifByteType *img; + + if (DGifGetImageDesc(gif) == GIF_ERROR) + { + /* PrintGifError(); */ + DGifCloseFile(gif); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + /* we have to count frame, so use DGifGetCode and skip decoding */ + if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR) + { + /* PrintGifError(); */ + DGifCloseFile(gif); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + while (img) + { + img = NULL; + DGifGetCodeNext(gif, &img); + } + } + else if (rec == EXTENSION_RECORD_TYPE) + { + int ext_code; + GifByteType *ext; + + ext = NULL; + DGifGetExtension(gif, &ext_code, &ext); + while (ext) + { + if (ext_code == 0xf9) /* Graphic Control Extension */ + { + if ((ext[1] & 1) && (alpha < 0)) alpha = (int)ext[4]; + } + else if (ext_code == 0xff) /* application extension */ + { + if (!strncmp ((char*)(&ext[1]), "NETSCAPE2.0", 11) || + !strncmp ((char*)(&ext[1]), "ANIMEXTS1.0", 11)) + { + ext=NULL; + DGifGetExtensionNext(gif, &ext); + + if (ext[1] == 0x01) + { + loop_count = ext[2] + (ext[3] << 8); + if (loop_count > 0) loop_count++; + } + } + } + + ext = NULL; + DGifGetExtensionNext(gif, &ext); + } + } + } while (rec != TERMINATE_RECORD_TYPE); + + if (alpha >= 0) ie->flags.alpha = 1; + + if (gif->ImageCount > 1) + { + ie->flags.animated = 1; + ie->loop_count = loop_count; + ie->loop_hint = EVAS_IMAGE_ANIMATED_HINT_LOOP; + ie->frame_count = gif->ImageCount; + ie->frames = NULL; + } + + DGifCloseFile(gif); + *error = EVAS_LOAD_ERROR_NONE; + return EINA_TRUE; +} + +static Eina_Bool +evas_image_load_specific_frame(Image_Entry *ie, const char *file, int frame_index, int *error) +{ + int fd; + GifFileType *gif; + Image_Entry_Frame *frame = NULL; + Gif_Frame *gif_frame = NULL; + +#ifndef __EMX__ + fd = open(file, O_RDONLY); +#else + fd = open(file, O_RDONLY | O_BINARY); +#endif + if (fd < 0) + { + *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; + return EINA_FALSE; + } + + gif = DGifOpenFileHandle(fd); + if (!gif) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + if (!_evas_image_skip_frame(gif, frame_index-1)) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + + frame = malloc(sizeof (Image_Entry_Frame)); + if (!frame) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + + gif_frame = malloc(sizeof (Gif_Frame)); + if (!gif_frame) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + frame->info = gif_frame; + frame->index = frame_index; + if (!_evas_image_load_frame(ie,gif, frame, LOAD_FRAME_DATA_INFO,error)) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + + ie->frames = eina_list_append(ie->frames, frame); + DGifCloseFile(gif); + return EINA_TRUE; +} + +static Eina_Bool +evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error) +{ + int cur_frame_index; + Image_Entry_Frame *frame = NULL; + Eina_Bool hit; + + if(!ie->flags.animated) + cur_frame_index = 1; + else + cur_frame_index = ie->cur_frame; + + if ((ie->flags.animated) && + ((cur_frame_index <0) || (cur_frame_index > FRAME_MAX) || (cur_frame_index > ie->frame_count))) + { + *error = EVAS_LOAD_ERROR_GENERIC; + return EINA_FALSE; + } + + /* first time frame is set to be 0. so default is 1 */ + if (cur_frame_index == 0) cur_frame_index++; + + /* Check current frame exists in hash table */ + hit = _find_frame(ie, cur_frame_index, &frame); + + /* if current frame exist in has table, check load flag */ + if (hit) + { + if (frame->loaded) + evas_image_load_file_data_gif_internal(ie,frame,error); + else + { + int fd; + GifFileType *gif; + +#ifndef __EMX__ + fd = open(file, O_RDONLY); +#else + fd = open(file, O_RDONLY | O_BINARY); +#endif + if (fd < 0) + { + *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; + return EINA_FALSE; + } + + gif = DGifOpenFileHandle(fd); + if (!gif) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + _evas_image_skip_frame(gif, cur_frame_index-1); + if (!_evas_image_load_frame(ie, gif, frame, LOAD_FRAME_DATA,error)) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + if (!evas_image_load_file_data_gif_internal(ie, frame, error)) + { + if (fd) close(fd); + *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; + return EINA_FALSE; + } + DGifCloseFile(gif); + *error = EVAS_LOAD_ERROR_NONE; + return EINA_TRUE; + } + } + /* current frame does is not exist */ + else + { + if (!evas_image_load_specific_frame(ie, file, cur_frame_index, error)) + { + return EINA_FALSE; + } + hit = EINA_FALSE; + frame = NULL; + hit = _find_frame(ie, cur_frame_index, &frame); + if (!hit) return EINA_FALSE; + if (!evas_image_load_file_data_gif_internal(ie, frame, error)) + { + *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; + return EINA_FALSE; + } + return EINA_TRUE; + } + return EINA_FALSE; +} + +static double +evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, const int start_frame, const int frame_num) +{ + int fd; + GifFileType *gif; + GifRecordType rec; + int done; + int current_frame = 1; + int remain_frames = frame_num; + double duration = 0; + int frame_count = 0; + + frame_count = ie->frame_count; + + if (!ie->flags.animated) return -1; + if ((start_frame + frame_num) > frame_count) return -1; + if (frame_num < 0) return -1; + + done = 0; + +#ifndef __EMX__ + fd = open(file, O_RDONLY); +#else + fd = open(file, O_RDONLY | O_BINARY); +#endif + if (fd < 0) return -1; + + gif = DGifOpenFileHandle(fd); + if (!gif) + { + if (fd) close(fd); + return -1; + } + + do + { + if (DGifGetRecordType(gif, &rec) == GIF_ERROR) + { + rec = TERMINATE_RECORD_TYPE; + } + if (rec == IMAGE_DESC_RECORD_TYPE) + { + int img_code; + GifByteType *img; + + if (DGifGetImageDesc(gif) == GIF_ERROR) + { + /* PrintGifError(); */ + rec = TERMINATE_RECORD_TYPE; + } + current_frame++; + /* we have to count frame, so use DGifGetCode and skip decoding */ + if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR) + { + rec = TERMINATE_RECORD_TYPE; + } + while (img) + { + img = NULL; + DGifGetExtensionNext(gif, &img); + } + } + else if (rec == EXTENSION_RECORD_TYPE) + { + int ext_code; + GifByteType *ext; + + ext = NULL; + DGifGetExtension(gif, &ext_code, &ext); + while (ext) + { + if (ext_code == 0xf9) /* Graphic Control Extension */ + { + if ((current_frame >= start_frame) && (current_frame <= frame_count)) + { + int frame_duration = 0; + if (remain_frames < 0) break; + frame_duration = byte2_to_int (ext[2], ext[3]); + if (frame_duration == 0) + duration += 0.1; + else + duration += (double)frame_duration/100; + remain_frames --; + } + } + ext = NULL; + DGifGetExtensionNext(gif, &ext); + } + } + } while (rec != TERMINATE_RECORD_TYPE); + + DGifCloseFile(gif); + return duration; +} + +static int +module_open(Evas_Module *em) +{ + if (!em) return 0; + em->functions = (void *)(&evas_image_load_gif_func); + return 1; +} + +static void +module_close(Evas_Module *em __UNUSED__) +{ +} + +static Evas_Module_Api evas_modapi = +{ + EVAS_MODULE_API_VERSION, + "gif", + "none", + { + module_open, + module_close + } +}; + +EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, gif); + +#ifndef EVAS_STATIC_BUILD_GIF +EVAS_EINA_MODULE_DEFINE(image_loader, gif); +#endif -- cgit v1.1