2006-10-27 20:02:23 -07:00
|
|
|
#include "evas_common.h"
|
|
|
|
#include "evas_private.h"
|
|
|
|
|
2006-04-08 05:22:18 -07:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2011-01-16 00:08:13 -08:00
|
|
|
#include <unistd.h>
|
2006-04-08 05:22:18 -07:00
|
|
|
|
|
|
|
#include <gif_lib.h>
|
|
|
|
|
2011-08-10 23:04:08 -07:00
|
|
|
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);
|
|
|
|
|
2009-12-22 15:11:57 -08:00
|
|
|
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);
|
2011-08-10 23:04:08 -07:00
|
|
|
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);
|
2006-04-08 05:22:18 -07:00
|
|
|
|
2009-06-16 06:01:36 -07:00
|
|
|
static Evas_Image_Load_Func evas_image_load_gif_func =
|
2006-04-08 05:22:18 -07:00
|
|
|
{
|
2009-12-24 05:15:34 -08:00
|
|
|
EINA_TRUE,
|
2006-04-08 05:22:18 -07:00
|
|
|
evas_image_load_file_head_gif,
|
2011-08-10 23:04:08 -07:00
|
|
|
evas_image_load_file_data_gif,
|
|
|
|
evas_image_load_frame_duration_gif
|
2006-04-08 05:22:18 -07:00
|
|
|
};
|
2011-08-10 23:04:08 -07:00
|
|
|
#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;
|
|
|
|
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);
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
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 */
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ptr = ptr + cache_w * y;
|
|
|
|
|
|
|
|
for (i = 0; i < cur_h; i++)
|
|
|
|
{
|
|
|
|
ptr = ptr + x;
|
|
|
|
for (j = 0; j < cur_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 - (x + cur_w));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2011-08-11 16:18:34 -07:00
|
|
|
if (LOAD_FRAME_NONE < type) return EINA_FALSE;
|
2011-08-10 23:04:08 -07:00
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (DGifGetRecordType(gif, &rec) == GIF_ERROR) return EINA_FALSE;
|
|
|
|
if (rec == IMAGE_DESC_RECORD_TYPE)
|
|
|
|
{
|
|
|
|
img_res++;
|
|
|
|
break;
|
|
|
|
}
|
2011-08-11 14:35:17 -07:00
|
|
|
else if (rec == EXTENSION_RECORD_TYPE)
|
2011-08-10 23:04:08 -07:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2006-04-08 05:22:18 -07:00
|
|
|
|
2009-12-22 15:11:57 -08:00
|
|
|
static Eina_Bool
|
|
|
|
evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
|
2006-04-08 05:22:18 -07:00
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
GifFileType *gif;
|
|
|
|
GifRecordType rec;
|
|
|
|
int w;
|
|
|
|
int h;
|
|
|
|
int alpha;
|
2011-08-10 23:04:08 -07:00
|
|
|
int loop_count = -1;
|
2006-04-08 05:22:18 -07:00
|
|
|
|
|
|
|
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)
|
2009-12-22 15:11:57 -08:00
|
|
|
{
|
2011-08-10 23:04:08 -07:00
|
|
|
*error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
|
|
|
|
return EINA_FALSE;
|
2009-12-22 15:11:57 -08:00
|
|
|
}
|
2006-04-08 05:22:18 -07:00
|
|
|
|
|
|
|
gif = DGifOpenFileHandle(fd);
|
|
|
|
if (!gif)
|
|
|
|
{
|
2011-08-10 23:04:08 -07:00
|
|
|
if (fd) close(fd);
|
|
|
|
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
|
|
|
|
return EINA_FALSE;
|
2006-04-08 05:22:18 -07:00
|
|
|
}
|
|
|
|
|
2011-08-10 23:04:08 -07:00
|
|
|
/* 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;
|
|
|
|
|
2006-04-08 05:22:18 -07:00
|
|
|
do
|
|
|
|
{
|
|
|
|
if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
|
|
|
|
{
|
|
|
|
/* PrintGifError(); */
|
2011-08-10 23:04:08 -07:00
|
|
|
DGifCloseFile(gif);
|
|
|
|
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
|
|
|
|
return EINA_FALSE;
|
2006-04-08 05:22:18 -07:00
|
|
|
}
|
2011-08-10 23:04:08 -07:00
|
|
|
|
|
|
|
/* image descript info */
|
|
|
|
if (rec == IMAGE_DESC_RECORD_TYPE)
|
2006-04-08 05:22:18 -07:00
|
|
|
{
|
2011-08-10 23:04:08 -07:00
|
|
|
int img_code;
|
|
|
|
GifByteType *img;
|
|
|
|
|
2006-04-08 05:22:18 -07:00
|
|
|
if (DGifGetImageDesc(gif) == GIF_ERROR)
|
|
|
|
{
|
|
|
|
/* PrintGifError(); */
|
2011-08-10 23:04:08 -07:00
|
|
|
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);
|
2006-04-08 05:22:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (rec == EXTENSION_RECORD_TYPE)
|
|
|
|
{
|
|
|
|
int ext_code;
|
|
|
|
GifByteType *ext;
|
2009-12-22 15:11:57 -08:00
|
|
|
|
2006-04-08 05:22:18 -07:00
|
|
|
ext = NULL;
|
|
|
|
DGifGetExtension(gif, &ext_code, &ext);
|
|
|
|
while (ext)
|
|
|
|
{
|
2011-08-10 23:04:08 -07:00
|
|
|
if (ext_code == 0xf9) /* Graphic Control Extension */
|
2006-04-08 05:22:18 -07:00
|
|
|
{
|
2011-08-10 23:04:08 -07:00
|
|
|
if ((ext[1] & 1) && (alpha < 0)) alpha = (int)ext[4];
|
2006-04-08 05:22:18 -07:00
|
|
|
}
|
2011-08-10 23:04:08 -07:00
|
|
|
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++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-08 05:22:18 -07:00
|
|
|
ext = NULL;
|
|
|
|
DGifGetExtensionNext(gif, &ext);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while (rec != TERMINATE_RECORD_TYPE);
|
|
|
|
|
2008-06-03 02:09:39 -07:00
|
|
|
if (alpha >= 0) ie->flags.alpha = 1;
|
2011-08-10 23:04:08 -07:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2006-04-08 05:22:18 -07:00
|
|
|
|
|
|
|
DGifCloseFile(gif);
|
2009-12-22 15:11:57 -08:00
|
|
|
*error = EVAS_LOAD_ERROR_NONE;
|
|
|
|
return EINA_TRUE;
|
2006-04-08 05:22:18 -07:00
|
|
|
}
|
|
|
|
|
2011-08-10 23:04:08 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-12-22 15:11:57 -08:00
|
|
|
static Eina_Bool
|
|
|
|
evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
|
2006-04-08 05:22:18 -07:00
|
|
|
{
|
2011-08-10 23:04:08 -07:00
|
|
|
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)
|
|
|
|
{
|
2006-04-08 05:22:18 -07:00
|
|
|
int fd;
|
|
|
|
GifFileType *gif;
|
|
|
|
GifRecordType rec;
|
|
|
|
int done;
|
2011-08-10 23:04:08 -07:00
|
|
|
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;
|
2006-04-08 05:22:18 -07:00
|
|
|
|
|
|
|
done = 0;
|
|
|
|
|
|
|
|
#ifndef __EMX__
|
|
|
|
fd = open(file, O_RDONLY);
|
|
|
|
#else
|
|
|
|
fd = open(file, O_RDONLY | O_BINARY);
|
|
|
|
#endif
|
2011-08-10 23:04:08 -07:00
|
|
|
if (fd < 0) return -1;
|
2006-04-08 05:22:18 -07:00
|
|
|
|
|
|
|
gif = DGifOpenFileHandle(fd);
|
|
|
|
if (!gif)
|
2011-08-10 23:04:08 -07:00
|
|
|
{
|
|
|
|
if (fd) close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-04-08 05:22:18 -07:00
|
|
|
do
|
|
|
|
{
|
|
|
|
if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
|
|
|
|
{
|
|
|
|
rec = TERMINATE_RECORD_TYPE;
|
|
|
|
}
|
2011-08-10 23:04:08 -07:00
|
|
|
if (rec == IMAGE_DESC_RECORD_TYPE)
|
2006-04-08 05:22:18 -07:00
|
|
|
{
|
2011-08-10 23:04:08 -07:00
|
|
|
int img_code;
|
|
|
|
GifByteType *img;
|
|
|
|
|
2006-04-08 05:22:18 -07:00
|
|
|
if (DGifGetImageDesc(gif) == GIF_ERROR)
|
|
|
|
{
|
|
|
|
/* PrintGifError(); */
|
|
|
|
rec = TERMINATE_RECORD_TYPE;
|
|
|
|
}
|
2011-08-10 23:04:08 -07:00
|
|
|
current_frame++;
|
|
|
|
/* we have to count frame, so use DGifGetCode and skip decoding */
|
|
|
|
if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
|
2006-04-08 05:22:18 -07:00
|
|
|
{
|
2011-08-10 23:04:08 -07:00
|
|
|
rec = TERMINATE_RECORD_TYPE;
|
2006-04-08 05:22:18 -07:00
|
|
|
}
|
2011-08-10 23:04:08 -07:00
|
|
|
while (img)
|
2006-04-08 05:22:18 -07:00
|
|
|
{
|
2011-08-10 23:04:08 -07:00
|
|
|
img = NULL;
|
|
|
|
DGifGetExtensionNext(gif, &img);
|
2006-04-08 05:22:18 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (rec == EXTENSION_RECORD_TYPE)
|
|
|
|
{
|
|
|
|
int ext_code;
|
|
|
|
GifByteType *ext;
|
|
|
|
|
|
|
|
ext = NULL;
|
|
|
|
DGifGetExtension(gif, &ext_code, &ext);
|
|
|
|
while (ext)
|
|
|
|
{
|
2011-08-10 23:04:08 -07:00
|
|
|
if (ext_code == 0xf9) /* Graphic Control Extension */
|
2006-04-08 05:22:18 -07:00
|
|
|
{
|
2011-08-10 23:04:08 -07:00
|
|
|
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 --;
|
|
|
|
}
|
2006-04-08 05:22:18 -07:00
|
|
|
}
|
|
|
|
ext = NULL;
|
|
|
|
DGifGetExtensionNext(gif, &ext);
|
|
|
|
}
|
|
|
|
}
|
2011-08-10 23:04:08 -07:00
|
|
|
} while (rec != TERMINATE_RECORD_TYPE);
|
2006-04-08 05:22:18 -07:00
|
|
|
|
2011-08-10 23:04:08 -07:00
|
|
|
DGifCloseFile(gif);
|
|
|
|
return duration;
|
2006-04-08 05:22:18 -07:00
|
|
|
}
|
|
|
|
|
2009-06-16 06:01:36 -07:00
|
|
|
static int
|
2006-09-06 00:28:46 -07:00
|
|
|
module_open(Evas_Module *em)
|
2006-04-08 05:22:18 -07:00
|
|
|
{
|
|
|
|
if (!em) return 0;
|
|
|
|
em->functions = (void *)(&evas_image_load_gif_func);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-06-16 06:01:36 -07:00
|
|
|
static void
|
cleanup: fix some "unused" errors from -Wextra.
As we're heading for a release we better remove as much errors as
possible and as the first step I'm removing warnings due unused
parameters, variables and functions. These tend to pollute real errors
spotted by -Wall and clang/llvm.
This does not fixes all, just the clear that could be set to
__UNUSED__, particularly to do (and I'd like some help from the
authors):
* src/lib/engines/common/evas_font_{draw,query}.c (tasn):
intl_props is just used while doing BIDI, but also used in other
#ifdef blocks :-/
* evas_map_* (raster):
huge amount of warnings, code is quite confusing and thus I'm not
touching it. I have no idea whenever the commented blocks or extra
parameters are intended to be used or no.
* src/modules/engines/fbevas_fb_main.c (raster?):
is fb_setvt() to be used? If not do you mind removing it?
* src/modules/engines/gl_{common,x11} (raster):
huge amount of warnings, code is quite nested and full of #ifdefs
that does not help to give a clear picture of what's going on.
* src/bin/evas_cserve_main.c (raster):
I could have ignored most of the errors, but is the code correct? I
mean, there is no unload of images being applied. If you confirm
none of those warnings are harmful I can flag them as unused.
* src/lib/engines/common_8 (dottedmag):
lots of unused functions that were acquired from common_16, they
are unused and if they will not, then they should be removed.
SVN revision: 52421
2010-09-18 12:17:41 -07:00
|
|
|
module_close(Evas_Module *em __UNUSED__)
|
2006-04-08 05:22:18 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-06-16 06:01:36 -07:00
|
|
|
static Evas_Module_Api evas_modapi =
|
2006-04-08 05:22:18 -07:00
|
|
|
{
|
2009-06-16 06:01:36 -07:00
|
|
|
EVAS_MODULE_API_VERSION,
|
|
|
|
"gif",
|
|
|
|
"none",
|
|
|
|
{
|
|
|
|
module_open,
|
|
|
|
module_close
|
|
|
|
}
|
2006-04-08 05:22:18 -07:00
|
|
|
};
|
2009-06-16 06:01:36 -07:00
|
|
|
|
|
|
|
EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, gif);
|
|
|
|
|
|
|
|
#ifndef EVAS_STATIC_BUILD_GIF
|
|
|
|
EVAS_EINA_MODULE_DEFINE(image_loader, gif);
|
|
|
|
#endif
|