Evas_Map *defmap;
const char *file;
const char *key;
+ int frame;
int cspace;
unsigned char smooth_scale : 1;
}
+#define FRAME_MAX 1024
EAPI Evas_Image_Content_Hint
evas_object_image_content_hint_get(const Evas_Object *obj)
{
return o->content_hint;
}
+/* animated feature */
+EAPI Eina_Bool
+evas_object_image_animated_get(const Evas_Object *obj)
+{
+ Evas_Object_Image *o;
+
+ MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
+ return EINA_FALSE;
+ MAGIC_CHECK_END();
+ o = (Evas_Object_Image *)(obj->object_data);
+ MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
+ return EINA_FALSE;
+ MAGIC_CHECK_END();
+
+ if (obj->layer->evas->engine.func->image_animated_get)
+ return obj->layer->evas->engine.func->image_animated_get(obj->layer->evas->engine.data.output, o->engine_data);
+ return EINA_FALSE;
+}
+
+EAPI int
+evas_object_image_animated_frame_count_get(const Evas_Object *obj)
+{
+ Evas_Object_Image *o;
+
+ MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
+ return -1;
+ MAGIC_CHECK_END();
+ o = (Evas_Object_Image *)(obj->object_data);
+ MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
+ return -1;
+ MAGIC_CHECK_END();
+
+ if (!evas_object_image_animated_get(obj)) return -1;
+ if (obj->layer->evas->engine.func->image_animated_frame_count_get)
+ return obj->layer->evas->engine.func->image_animated_frame_count_get(obj->layer->evas->engine.data.output, o->engine_data);
+ return -1;
+}
+
+EAPI Evas_Image_Animated_Loop_Hint
+evas_object_image_animated_loop_type_get(const Evas_Object *obj)
+{
+ Evas_Object_Image *o;
+
+ MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
+ return EVAS_IMAGE_ANIMATED_HINT_NONE;
+ MAGIC_CHECK_END();
+ o = (Evas_Object_Image *)(obj->object_data);
+ MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
+ return EVAS_IMAGE_ANIMATED_HINT_NONE;
+ MAGIC_CHECK_END();
+
+ if (!evas_object_image_animated_get(obj)) return EVAS_IMAGE_ANIMATED_HINT_NONE;
+
+ if (obj->layer->evas->engine.func->image_animated_loop_type_get)
+ return obj->layer->evas->engine.func->image_animated_loop_type_get(obj->layer->evas->engine.data.output, o->engine_data);
+ return EVAS_IMAGE_ANIMATED_HINT_NONE;
+}
+
+EAPI int
+evas_object_image_animated_loop_count_get(const Evas_Object *obj)
+{
+ Evas_Object_Image *o;
+
+ MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
+ return -1;
+ MAGIC_CHECK_END();
+ o = (Evas_Object_Image *)(obj->object_data);
+ MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
+ return -1;
+ MAGIC_CHECK_END();
+
+ if (!evas_object_image_animated_get(obj)) return -1;
+
+ if (obj->layer->evas->engine.func->image_animated_loop_count_get)
+ return obj->layer->evas->engine.func->image_animated_loop_count_get(obj->layer->evas->engine.data.output, o->engine_data);
+ return -1;
+}
+
+EAPI double
+evas_object_image_animated_frame_duration_get(const Evas_Object *obj, int start_frame, int frame_num)
+{
+ Evas_Object_Image *o;
+ int frame_count = 0;
+
+ if (start_frame < 1) return -1;
+ if (frame_num < 0) return -1;
+
+ MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
+ return -1;
+ MAGIC_CHECK_END();
+ o = (Evas_Object_Image *)(obj->object_data);
+ MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
+ return -1;
+ MAGIC_CHECK_END();
+
+ if (!evas_object_image_animated_get(obj)) return -1;
+
+ if (!obj->layer->evas->engine.func->image_animated_frame_count_get) return -1;
+
+ frame_count = obj->layer->evas->engine.func->image_animated_frame_count_get(obj->layer->evas->engine.data.output, o->engine_data);
+
+ if ((start_frame + frame_num) > frame_count) return -1;
+ if (obj->layer->evas->engine.func->image_animated_frame_duration_get)
+ return obj->layer->evas->engine.func->image_animated_frame_duration_get(obj->layer->evas->engine.data.output, o->engine_data, start_frame, frame_num);
+ return -1;
+}
+
+EAPI void
+evas_object_image_animated_frame_set(Evas_Object *obj, int frame_index)
+{
+ Evas_Object_Image *o;
+ int frame_count = 0;
+ Eina_Bool animated = EINA_FALSE;
+ char frame_index_char[4];
+
+ MAGIC_CHECK(obj, Evas_Object, MAGIC_OBJ);
+ return;
+ MAGIC_CHECK_END();
+ o = (Evas_Object_Image *)(obj->object_data);
+ MAGIC_CHECK(o, Evas_Object_Image, MAGIC_OBJ_IMAGE);
+ return;
+ MAGIC_CHECK_END();
+
+ if (!o->cur.file) return;
+ if (o->cur.frame == frame_index) return;
+
+ if (!evas_object_image_animated_get(obj)) return;
+
+ frame_count = evas_object_image_animated_frame_count_get(obj);
+
+ /* limit the size of frame to FRAME_MAX */
+ if ((frame_count > FRAME_MAX) || (frame_count < 0) || (frame_index > frame_count))
+ return;
+
+ if (!obj->layer->evas->engine.func->image_animated_frame_set) return;
+ if (!obj->layer->evas->engine.func->image_animated_frame_set(obj->layer->evas->engine.data.output, o->engine_data, frame_index))
+ return;
+
+ o->prev.frame = o->cur.frame;
+ o->cur.frame = frame_index;
+
+ o->changed = 1;
+ evas_object_change(obj);
+
+}
+
EAPI void
evas_image_cache_flush(Evas *e)
{
evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
if (!o->pixel_updates) goto done;
}
+ if (o->cur.frame != o->prev.frame)
+ {
+ evas_object_render_pre_prev_cur_add(&e->clip_changes, obj);
+ if (!o->pixel_updates) goto done;
+ }
+
}
/* if it changed geometry - and obviously not visibility or color */
/* calculate differences since we have a constant color fill */
#include <gif_lib.h>
+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
+{
+ int index;
+ Eina_Bool loaded : 1;
+
+ 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;
+ DATA32 *data;
+};
+
+static Eina_Bool evas_image_load_file_data_gif_internal(Image_Entry *ie, Gif_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_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, Gif_Frame **frame)
+{
+ Eina_List *l;
+ Gif_Frame *hit_frame;
+
+ 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, Gif_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));
+}
+
+static Eina_Bool _evas_image_load_frame_graphic_info(Gif_Frame *frame, GifByteType *ext)
+{
+ if (!frame || !ext) return EINA_FALSE;
+
+ /* transparent */
+ if ((ext[1] & 0x1) != 0)
+ frame->frame_info.transparent = ext[4];
+ else
+ frame->frame_info.transparent = -1;
+
+ frame->frame_info.input = (ext[1] >>1) & 0x1;
+ frame->frame_info.disposal = (ext[1] >>2) & 0x7;
+ frame->frame_info.delay = byte2_to_int(ext[2], ext[3]);
+}
+
+static Eina_Bool _evas_image_load_frame_image_des_info(GifFileType *gif, Gif_Frame *frame)
+{
+ if (!gif || !frame) return EINA_FALSE;
+ frame->image_des.x = gif->Image.Left;
+ frame->image_des.y = gif->Image.Top;
+ frame->image_des.w = gif->Image.Width;
+ frame->image_des.h = gif->Image.Height;
+ frame->image_des.interlace = gif->Image.Interlace;
+}
+
+static Eina_Bool _evas_image_load_frame_image_data(Image_Entry *ie, GifFileType *gif, Gif_Frame *frame, int *error)
+{
+ int w;
+ int h;
+ int i,j;
+ int img_code;
+ int bg;
+ int r;
+ int g;
+ int b;
+ int alpha;
+ double per;
+ double per_inc;
+ ColorMapObject *cmap;
+ GifByteType *img;
+ GifRowType *rows;
+ int intoffset[] = { 0, 4, 2, 1 };
+ int intjump[] = { 8, 8, 4, 2 };
+ size_t siz;
+ int cache_w;
+ int cache_h;
+ DATA32 *ptr;
+
+ if (!gif || !frame) return EINA_FALSE;
+
+ w = gif->Image.Width;
+ h = gif->Image.Height;
+ 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 = frame->frame_info.transparent;
+ siz = cache_w *cache_h * sizeof(DATA32);
+ frame->data = malloc(siz);
+ ptr = frame->data;
+ bg = gif->SBackGroundColor;
+ cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap);
+
+ per_inc = 100.0 / (((double)w) * h);
+ if (frame->index > 1)
+ {
+ /* get previous frame only frame index is bigger than 1 */
+ DATA32 *ptr_src;
+ Gif_Frame *new_frame = NULL;
+ int cur_x, cur_y;
+ int cur_frame = frame->index;
+
+ if (!_find_close_frame(ie, cur_frame, &new_frame))
+ {
+ if (!evas_image_load_specific_frame(ie, ie->file, cur_frame-1, error))
+ {
+ *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
+ goto error;
+ }
+ }
+ else
+ {
+ ptr_src = new_frame->data;
+ memcpy(ptr, ptr_src, siz);
+ }
+
+ /* composite frames */
+ cur_x = frame->image_des.x;
+ cur_y = frame->image_des.y;
+ ptr = ptr + cache_w * cur_y;
+
+ for (i = 0; i < h; i++)
+ {
+ ptr = ptr + cur_x;
+ for (j = 0; j < 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 - (cur_x + w));
+ }
+ }
+ else
+ {
+ int cur_x = frame->image_des.x;
+ int cur_y = frame->image_des.y;
+ ptr = ptr + cache_w * cur_y;
+
+ for (i = 0; i < h; i++)
+ {
+ ptr = ptr + cur_x;
+ for (j = 0; j < w; j++)
+ {
+ 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 - (cur_x + w));
+ }
+ }
+
+ for (i = 0; i < h; i++)
+ {
+ free(rows[i]);
+ }
+ free(rows);
+ frame->loaded = EINA_TRUE;
+ return EINA_TRUE;
+error:
+ for (i = 0; i < h; i++)
+ {
+ free(rows[i]);
+ }
+ free(rows);
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_evas_image_load_frame(Image_Entry *ie, GifFileType *gif, Gif_Frame *frame, Frame_Load_Type type, int *error)
+{
+ GifRecordType rec;
+ int gra_res = 0, img_res = 0;
+ Eina_Bool res = EINA_FALSE;
+
+ if (!gif || !frame) return EINA_FALSE;
+ if (LOAD_FRAME_NONE > type || LOAD_FRAME_DATA_INFO < type) 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, Gif_Frame *frame, int *error)
+{
+ int w;
+ int h;
+ int dst_x;
+ int dst_y;
+ int i;
+ int j;
+ DATA32 *dst;
+ DATA32 *src;
+ int cache_w, cache_h;
+ size_t siz;
+
+ cache_w = ie->w;
+ cache_h = ie->h;
+ w = frame->image_des.w;
+ h = frame->image_des.h;
+ dst_x = frame->image_des.x;
+ dst_y = 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 done;
int w;
int h;
int alpha;
+ int loop_count = -1;
- done = 0;
w = 0;
h = 0;
alpha = -1;
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(); */
- rec = TERMINATE_RECORD_TYPE;
+ DGifCloseFile(gif);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
}
- if ((rec == IMAGE_DESC_RECORD_TYPE) && (!done))
+
+ /* image descript info */
+ if (rec == IMAGE_DESC_RECORD_TYPE)
{
+ int img_code;
+ GifByteType *img;
+
if (DGifGetImageDesc(gif) == GIF_ERROR)
{
/* PrintGifError(); */
- rec = TERMINATE_RECORD_TYPE;
+ DGifCloseFile(gif);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
}
- w = gif->Image.Width;
- h = gif->Image.Height;
- if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
- IMG_TOO_BIG(w, h))
+ /* we have to count frame, so use DGifGetCode and skip decoding */
+ if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
{
+ /* PrintGifError(); */
DGifCloseFile(gif);
- if (IMG_TOO_BIG(w, h))
- *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
- else
- *error = EVAS_LOAD_ERROR_GENERIC;
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
- done = 1;
+ while (img)
+ {
+ img = NULL;
+ DGifGetExtensionNext(gif, &img);
+ }
}
else if (rec == EXTENSION_RECORD_TYPE)
{
DGifGetExtension(gif, &ext_code, &ext);
while (ext)
{
- if ((ext_code == 0xf9) && (ext[1] & 1) && (alpha < 0))
+ if (ext_code == 0xf9) /* Graphic Control Extension */
{
- alpha = (int)ext[4];
+ 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;
- ie->w = w;
- ie->h = h;
+
+ 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;
}
static Eina_Bool
-evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
+evas_image_load_specific_frame(Image_Entry *ie, const char *file, int frame_index, int *error)
{
- int intoffset[] = { 0, 4, 2, 1 };
- int intjump[] = { 8, 8, 4, 2 };
- double per;
- double per_inc;
int fd;
GifFileType *gif;
- GifRecordType rec;
- GifRowType *rows;
- ColorMapObject *cmap;
- DATA32 *ptr;
- int done;
- int last_y;
- int last_per;
- int w;
- int h;
- int alpha;
- int i;
- int j;
- int bg;
- int r;
- int g;
- int b;
-
- rows = NULL;
- per = 0.0;
- done = 0;
- last_y = 0;
- last_per = 0;
- w = 0;
- h = 0;
- alpha = -1;
+ Gif_Frame *frame = NULL;
#ifndef __EMX__
fd = open(file, O_RDONLY);
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
- do
+ if (!_evas_image_skip_frame(gif, frame_index-1))
{
- if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
+ close(fd);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ frame = malloc(sizeof (Gif_Frame));
+ if (!frame)
{
- /* PrintGifError(); */
- rec = TERMINATE_RECORD_TYPE;
+ if (fd)
+ close(fd);
+ *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ return EINA_FALSE;
}
- if ((rec == IMAGE_DESC_RECORD_TYPE) && (!done))
+
+ frame->index = frame_index;
+ if (!_evas_image_load_frame(ie,gif, frame, LOAD_FRAME_DATA_INFO,error))
{
- if (DGifGetImageDesc(gif) == GIF_ERROR)
- {
- /* PrintGifError(); */
- rec = TERMINATE_RECORD_TYPE;
+ if (fd)
+ close(fd);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
+ }
+
+ ie->frames = eina_list_append(ie->frames, frame);
+ if (fd)
+ close(fd);
+ return EINA_TRUE;
}
- w = gif->Image.Width;
- h = gif->Image.Height;
- rows = malloc(h * sizeof(GifRowType *));
- if (!rows)
+
+static Eina_Bool
+evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
{
- DGifCloseFile(gif);
- return 0;
- }
- for (i = 0; i < h; i++)
+ int cur_frame_index;
+ Gif_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)))
{
- rows[i] = NULL;
+ *error = EVAS_LOAD_ERROR_GENERIC;
+ return EINA_FALSE;
}
- for (i = 0; i < h; i++)
+
+ /* 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)
{
- rows[i] = malloc(w * sizeof(GifPixelType));
- if (!rows[i])
+ if (frame->loaded)
+ evas_image_load_file_data_gif_internal(ie,frame,error);
+ else
{
- DGifCloseFile(gif);
- for (i = 0; i < h; i++)
+ int fd;
+ GifFileType *gif;
+
+#ifndef __EMX__
+ fd = open(file, O_RDONLY);
+#else
+ fd = open(file, O_RDONLY | O_BINARY);
+#endif
+ if (fd < 0)
{
- if (rows[i])
+ *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
+ return EINA_FALSE;
+ }
+
+ gif = DGifOpenFileHandle(fd);
+ if (!gif)
{
- free(rows[i]);
+ close(fd);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
}
- }
- free(rows);
- *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+ _evas_image_skip_frame(gif, cur_frame_index-1);
+ if (!_evas_image_load_frame(ie, gif, frame, LOAD_FRAME_DATA,error))
+ {
+ close(fd);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
return EINA_FALSE;
}
- }
- if (gif->Image.Interlace)
+ if (!evas_image_load_file_data_gif_internal(ie, frame, error))
{
- for (i = 0; i < 4; i++)
- {
- for (j = intoffset[i]; j < h; j += intjump[i])
- {
- DGifGetLine(gif, rows[j], w);
+ close(fd);
+ *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
+ return EINA_FALSE;
}
+ return EINA_TRUE;
}
}
+ /* current frame does is not exist */
else
{
- for (i = 0; i < h; i++)
+ if (!evas_image_load_specific_frame(ie, file, cur_frame_index, error))
{
- DGifGetLine(gif, rows[i], w);
+ 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;
}
- done = 1;
+ return EINA_TRUE;
+ }
}
- else if (rec == EXTENSION_RECORD_TYPE)
+
+static double
+evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, const int start_frame, const int frame_num)
{
- int ext_code;
- GifByteType *ext;
+ int fd;
+ GifFileType *gif;
+ GifRecordType rec;
+ int done;
+ int current_frame = 1;
+ int remain_frames = frame_num;
+ double duration = 0;
+ int frame_count = 0;
- ext = NULL;
- DGifGetExtension(gif, &ext_code, &ext);
- while (ext)
+ 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 ((ext_code == 0xf9) && (ext[1] & 1) && (alpha < 0))
- {
- alpha = (int)ext[4];
- }
- ext = NULL;
- DGifGetExtensionNext(gif, &ext);
+ close(fd);
+ return -1;
}
+
+ do
+ {
+ if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
+ {
+ rec = TERMINATE_RECORD_TYPE;
}
- } while (rec != TERMINATE_RECORD_TYPE);
+ if (rec == IMAGE_DESC_RECORD_TYPE)
+ {
+ int img_code;
+ GifByteType *img;
- if (alpha >= 0) ie->flags.alpha = 1;
- evas_cache_image_surface_alloc(ie, w, h);
- if (!evas_cache_image_pixels(ie))
+ 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)
{
- DGifCloseFile(gif);
- for (i = 0; i < h; i++)
+ rec = TERMINATE_RECORD_TYPE;
+ }
+ while (img)
{
- free(rows[i]);
+ img = NULL;
+ DGifGetExtensionNext(gif, &img);
}
- free(rows);
- *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
- return EINA_FALSE;
}
+ else if (rec == EXTENSION_RECORD_TYPE)
+ {
+ int ext_code;
+ GifByteType *ext;
- bg = gif->SBackGroundColor;
- cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap);
-
- ptr = evas_cache_image_pixels(ie);
- per_inc = 100.0 / (((double)w) * h);
-
- for (i = 0; i < h; i++)
+ ext = NULL;
+ DGifGetExtension(gif, &ext_code, &ext);
+ while (ext)
{
- for (j = 0; j < w; j++)
+ if (ext_code == 0xf9) /* Graphic Control Extension */
{
- if (rows[i][j] == alpha)
+ int *test = NULL;
+
+ if ((current_frame >= start_frame) && (current_frame <= frame_count))
{
- r = cmap->Colors[bg].Red;
- g = cmap->Colors[bg].Green;
- b = cmap->Colors[bg].Blue;
- *ptr++ = 0x00ffffff & RGB_JOIN(r, g, b);
- }
+ 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
- {
- 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);
+ duration += (double)frame_duration/100;
+ remain_frames --;
}
- per += per_inc;
}
+ ext = NULL;
+ DGifGetExtensionNext(gif, &ext);
}
- evas_common_image_premul(ie);
- DGifCloseFile(gif);
- for (i = 0; i < h; i++)
- {
- free(rows[i]);
}
- free(rows);
+ } while (rec != TERMINATE_RECORD_TYPE);
- *error = EVAS_LOAD_ERROR_NONE;
- return EINA_TRUE;
+ DGifCloseFile(gif);
+ return duration;
}
static int