1 #include "evas_common.h"
2 #include "evas_private.h"
11 typedef struct _Gif_Frame Gif_Frame;
13 typedef enum _Frame_Load_Type
18 LOAD_FRAME_DATA_INFO = 3
24 /* Image descriptor */
41 static Eina_Bool evas_image_load_file_data_gif_internal(Image_Entry *ie, Image_Entry_Frame *frame, int *error);
43 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);
44 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);
45 static double evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, int start_frame, int frame_num) ;
46 static Eina_Bool evas_image_load_specific_frame(Image_Entry *ie, const char *file, int frame_index, int *error);
48 static Evas_Image_Load_Func evas_image_load_gif_func =
51 evas_image_load_file_head_gif,
52 evas_image_load_file_data_gif,
53 evas_image_load_frame_duration_gif,
56 #define byte2_to_int(a,b) (((b)<<8)|(a))
58 #define FRAME_MAX 1024
60 /* find specific frame in image entry */
62 _find_frame(Image_Entry *ie, int frame_index, Image_Entry_Frame **frame)
65 Image_Entry_Frame *hit_frame = NULL;
67 if (!ie) return EINA_FALSE;
68 if (!ie->frames) return EINA_FALSE;
70 EINA_LIST_FOREACH(ie->frames, l, hit_frame)
72 if (hit_frame->index == frame_index)
82 _find_close_frame(Image_Entry *ie, int frame_index, Image_Entry_Frame **frame)
85 Eina_Bool hit = EINA_FALSE;
88 if (!ie) return EINA_FALSE;
89 if (!ie->frames) return EINA_FALSE;
93 hit = _find_frame(ie, i, frame);
101 _evas_image_skip_frame(GifFileType *gif, int frame)
103 int remain_frame = 0;
106 if (!gif) return EINA_FALSE;
107 if (frame == 0) return EINA_TRUE; /* no need to skip */
108 if (frame < 0 || frame > FRAME_MAX) return EINA_FALSE;
110 remain_frame = frame;
114 if (DGifGetRecordType(gif, &rec) == GIF_ERROR) return EINA_FALSE;
116 if (rec == EXTENSION_RECORD_TYPE)
122 DGifGetExtension(gif, &ext_code, &ext);
124 { /*skip extention */
126 DGifGetExtensionNext(gif, &ext);
130 if (rec == IMAGE_DESC_RECORD_TYPE)
135 if (DGifGetImageDesc(gif) == GIF_ERROR) return EINA_FALSE;
138 /* we have to count frame, so use DGifGetCode and skip decoding */
139 if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR) return EINA_FALSE;
144 DGifGetCodeNext(gif, &img);
146 if (remain_frame < 1) return EINA_TRUE;
148 if (rec == TERMINATE_RECORD_TYPE) return EINA_FALSE; /* end of file */
150 } while ((rec != TERMINATE_RECORD_TYPE) && (remain_frame > 0));
155 _evas_image_load_frame_graphic_info(Image_Entry_Frame *frame, GifByteType *ext)
157 Gif_Frame *gif_frame = NULL;
158 if ((!frame) || (!ext)) return EINA_FALSE;
160 gif_frame = (Gif_Frame *) frame->info;
163 if ((ext[1] & 0x1) != 0)
164 gif_frame->frame_info.transparent = ext[4];
166 gif_frame->frame_info.transparent = -1;
168 gif_frame->frame_info.input = (ext[1] >>1) & 0x1;
169 gif_frame->frame_info.disposal = (ext[1] >>2) & 0x7;
170 gif_frame->frame_info.delay = byte2_to_int(ext[2], ext[3]);
175 _evas_image_load_frame_image_des_info(GifFileType *gif, Image_Entry_Frame *frame)
177 Gif_Frame *gif_frame = NULL;
178 if ((!gif) || (!frame)) return EINA_FALSE;
180 gif_frame = (Gif_Frame *) frame->info;
181 gif_frame->image_des.x = gif->Image.Left;
182 gif_frame->image_des.y = gif->Image.Top;
183 gif_frame->image_des.w = gif->Image.Width;
184 gif_frame->image_des.h = gif->Image.Height;
185 gif_frame->image_des.interlace = gif->Image.Interlace;
190 _evas_image_load_frame_image_data(Image_Entry *ie, GifFileType *gif, Image_Entry_Frame *frame, int *error)
204 ColorMapObject *cmap;
206 GifPixelType *tmp = NULL; /*for skip gif line */
207 int intoffset[] = { 0, 4, 2, 1 };
208 int intjump[] = { 8, 8, 4, 2 };
217 Gif_Frame *gif_frame = NULL;
218 /* for scale down decoding */
220 int scale_w, scale_h, scale_x, scale_y;
222 if ((!gif) || (!frame)) return EINA_FALSE;
224 gif_frame = (Gif_Frame *) frame->info;
225 w = gif->Image.Width;
226 h = gif->Image.Height;
232 /* if user don't set scale down, default scale_ratio is 1 */
233 if (ie->load_opts.scale_down_by > 1) scale_ratio = ie->load_opts.scale_down_by;
234 scale_w = w / scale_ratio;
235 scale_h = h / scale_ratio;
236 scale_x = x / scale_ratio;
237 scale_y = y / scale_ratio;
239 rows = malloc(scale_h * sizeof(GifRowType *));
243 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
246 for (i = 0; i < scale_h; i++)
250 /* alloc memory according to scaled size */
251 for (i = 0; i < scale_h; i++)
253 rows[i] = malloc(w * sizeof(GifPixelType));
256 for (i = 0; i < scale_h; i++)
264 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
271 tmp = malloc(w * sizeof(GifPixelType));
274 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
279 if (gif->Image.Interlace)
283 for (i = 0; i < 4; i++)
285 for (j = intoffset[i]; j < h; j += intjump[i])
287 scale_j = j / scale_ratio;
288 multiple = ((j % scale_ratio) ? EINA_FALSE : EINA_TRUE);
290 if (multiple && (scale_j < scale_h))
291 DGifGetLine(gif, rows[scale_j], w);
293 DGifGetLine(gif, tmp, w);
299 for (i = 0; i < scale_h; i++)
301 if (DGifGetLine(gif, rows[i], w) != GIF_OK)
303 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
308 /* we use down sample method for scale down, so skip other line */
309 for (j = 0; j < (scale_ratio - 1); j++)
311 if (DGifGetLine(gif, tmp, w) != GIF_OK)
313 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
327 alpha = gif_frame->frame_info.transparent;
328 siz = cache_w *cache_h * sizeof(DATA32);
329 frame->data = malloc(siz);
332 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
336 bg = gif->SBackGroundColor;
337 cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap);
342 for (i = 0; i < scale_h; i++)
347 if (frame->data) free(frame->data);
348 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
352 /* get the background value */
353 r = cmap->Colors[bg].Red;
354 g = cmap->Colors[bg].Green;
355 b = cmap->Colors[bg].Blue;
356 bg_val = ARGB_JOIN(0xff, r, g, b);
358 per_inc = 100.0 / (((double)w) * h);
362 if (cur_h > cache_h) cur_h = cache_h;
363 if (cur_w > cache_w) cur_w = cache_w;
365 if (frame->index > 1)
367 /* get previous frame only frame index is bigger than 1 */
369 Image_Entry_Frame *new_frame = NULL;
370 int cur_frame = frame->index;
373 if (_find_close_frame(ie, cur_frame, &new_frame))
374 start_frame = new_frame->index + 1;
376 if ((start_frame < 1) || (start_frame > cur_frame))
378 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
381 /* load previous frame of cur_frame */
382 for (j = start_frame; j < cur_frame ; j++)
384 if (!evas_image_load_specific_frame(ie, ie->file, j, error))
386 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
390 if (!_find_frame(ie, cur_frame - 1, &new_frame))
392 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
397 Gif_Frame *gif_frame2 = NULL;
398 ptr_src = new_frame->data;
401 gif_frame2 = (Gif_Frame *)(new_frame->info);
402 disposal = gif_frame2->frame_info.disposal;
404 switch(disposal) /* we only support disposal flag 0,1,2 */
406 case 1: /* Do not dispose. need previous frame*/
407 memcpy(ptr, ptr_src, siz);
408 /* only decoding image descriptor's region */
409 ptr = ptr + cache_w * scale_y;
411 for (i = 0; i < cur_h; i++)
414 for (j = 0; j < cur_w; j++)
416 if (rows[i][j * scale_ratio] == alpha)
422 r = cmap->Colors[rows[i][j * scale_ratio]].Red;
423 g = cmap->Colors[rows[i][j * scale_ratio]].Green;
424 b = cmap->Colors[rows[i][j * scale_ratio]].Blue;
425 *ptr++ = ARGB_JOIN(0xff, r, g, b);
429 ptr = ptr + (cache_w - (scale_x + cur_w));
432 case 2: /* Restore to background color */
433 memcpy(ptr, ptr_src, siz);
434 /* composite frames */
435 for (i = 0; i < cache_h; i++)
437 if ((i < scale_y) || (i >= (scale_y + cur_h)))
439 for (j = 0; j < cache_w; j++)
450 for (j = 0; j < cache_w; j++)
453 if ((j < scale_x) || (j >= (scale_x + cur_w)))
460 r = cmap->Colors[rows[i1][j1 * scale_ratio]].Red;
461 g = cmap->Colors[rows[i1][j1 * scale_ratio]].Green;
462 b = cmap->Colors[rows[i1][j1 * scale_ratio]].Blue;
463 *ptr++ = ARGB_JOIN(0xff, r, g, b);
469 case 0: /* No disposal specified */
472 for (i = 0; i < cache_h; i++)
474 if ((i < scale_y) || (i >= (scale_y + cur_h)))
476 for (j = 0; j < cache_w; j++)
487 for (j = 0; j < cache_w; j++)
490 if ((j < scale_x) || (j >= (scale_x + cur_w)))
497 r = cmap->Colors[rows[i1][j1 * scale_ratio]].Red;
498 g = cmap->Colors[rows[i1][j1 * scale_ratio]].Green;
499 b = cmap->Colors[rows[i1][j1 * scale_ratio]].Blue;
500 *ptr++ = ARGB_JOIN(0xff, r, g, b);
509 else /* first frame decoding */
513 /* fill background color */
514 for (i = 0; i < cache_h; i++)
516 /* the row's of logical screen not overap with frame */
517 if ((i < scale_y) || (i >= (scale_y + cur_h)))
519 for (j = 0; j < cache_w; j++)
530 for (j = 0; j < cache_w; j++)
533 if ((j < scale_x) || (j >= (scale_x + cur_w)))
540 if (rows[i1][j1] == alpha)
546 r = cmap->Colors[rows[i1][j1]].Red;
547 g = cmap->Colors[rows[i1][j1]].Green;
548 b = cmap->Colors[rows[i1][j1]].Blue;
549 *ptr++ = ARGB_JOIN(0xff, r, g, b);
557 for (i = 0; i < scale_h; i++)
559 if (rows[i]) free(rows[i]);
561 if (rows) free(rows);
562 frame->loaded = EINA_TRUE;
565 for (i = 0; i < scale_h; i++)
567 if (rows[i]) free(rows[i]);
569 if (rows) free(rows);
575 _evas_image_load_frame(Image_Entry *ie, GifFileType *gif, Image_Entry_Frame *frame, Frame_Load_Type type, int *error)
578 int gra_res = 0, img_res = 0;
579 Eina_Bool res = EINA_FALSE;
580 Gif_Frame *gif_frame = NULL;
582 if ((!gif) || (!frame)) return EINA_FALSE;
583 gif_frame = (Gif_Frame *) frame->info;
585 if (type > LOAD_FRAME_DATA_INFO) return EINA_FALSE;
589 if (DGifGetRecordType(gif, &rec) == GIF_ERROR) return EINA_FALSE;
590 if (rec == IMAGE_DESC_RECORD_TYPE)
595 else if (rec == EXTENSION_RECORD_TYPE)
601 DGifGetExtension(gif, &ext_code, &ext);
604 if (ext_code == 0xf9) /* Graphic Control Extension */
607 /* fill frame info */
608 if ((type == LOAD_FRAME_INFO) || (type == LOAD_FRAME_DATA_INFO))
609 _evas_image_load_frame_graphic_info(frame,ext);
612 DGifGetExtensionNext(gif, &ext);
615 } while ((rec != TERMINATE_RECORD_TYPE) && (img_res == 0));
616 if (img_res != 1) return EINA_FALSE;
617 if (DGifGetImageDesc(gif) == GIF_ERROR) return EINA_FALSE;
618 if ((type == LOAD_FRAME_INFO) || (type == LOAD_FRAME_DATA_INFO))
619 _evas_image_load_frame_image_des_info(gif, frame);
621 if ((type == LOAD_FRAME_DATA) || (type == LOAD_FRAME_DATA_INFO))
623 res = _evas_image_load_frame_image_data(ie, gif,frame, error);
624 if (!res) return EINA_FALSE;
630 /* set frame data to cache entry's data */
632 evas_image_load_file_data_gif_internal(Image_Entry *ie, Image_Entry_Frame *frame, int *error)
640 int cache_w, cache_h;
642 Gif_Frame *gif_frame = NULL;
644 gif_frame = (Gif_Frame *) frame->info;
647 w = gif_frame->image_des.w;
648 h = gif_frame->image_des.h;
649 dst_x = gif_frame->image_des.x;
650 dst_y = gif_frame->image_des.y;
654 if (!evas_cache_image_pixels(ie))
656 evas_cache_image_surface_alloc(ie, cache_w, cache_h);
659 if (!evas_cache_image_pixels(ie))
661 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
665 /* only copy real frame part */
666 siz = cache_w * cache_h * sizeof(DATA32);
667 dst = evas_cache_image_pixels(ie);
669 memcpy(dst, src, siz);
671 evas_common_image_premul(ie);
673 *error = EVAS_LOAD_ERROR_NONE;
678 evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
693 fd = open(file, O_RDONLY);
695 fd = open(file, O_RDONLY | O_BINARY);
699 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
703 gif = DGifOpenFileHandle(fd);
707 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
711 /* check logical screen size */
714 /* support scale down feture in gif*/
715 if (ie->load_opts.scale_down_by > 1)
717 w /= ie->load_opts.scale_down_by;
718 h /= ie->load_opts.scale_down_by;
721 if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
725 if (IMG_TOO_BIG(w, h))
726 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
728 *error = EVAS_LOAD_ERROR_GENERIC;
736 if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
738 /* PrintGifError(); */
740 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
744 /* image descript info */
745 if (rec == IMAGE_DESC_RECORD_TYPE)
750 if (DGifGetImageDesc(gif) == GIF_ERROR)
752 /* PrintGifError(); */
754 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
757 /* we have to count frame, so use DGifGetCode and skip decoding */
758 if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
760 /* PrintGifError(); */
762 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
768 DGifGetCodeNext(gif, &img);
771 else if (rec == EXTENSION_RECORD_TYPE)
777 DGifGetExtension(gif, &ext_code, &ext);
780 if (ext_code == 0xf9) /* Graphic Control Extension */
782 if ((ext[1] & 1) && (alpha < 0)) alpha = (int)ext[4];
784 else if (ext_code == 0xff) /* application extension */
786 if (!strncmp ((char*)(&ext[1]), "NETSCAPE2.0", 11) ||
787 !strncmp ((char*)(&ext[1]), "ANIMEXTS1.0", 11))
790 DGifGetExtensionNext(gif, &ext);
794 loop_count = ext[2] + (ext[3] << 8);
795 if (loop_count > 0) loop_count++;
801 DGifGetExtensionNext(gif, &ext);
804 } while (rec != TERMINATE_RECORD_TYPE);
806 if (alpha >= 0) ie->flags.alpha = 1;
808 if (gif->ImageCount > 1)
810 ie->flags.animated = 1;
811 ie->loop_count = loop_count;
812 ie->loop_hint = EVAS_IMAGE_ANIMATED_HINT_LOOP;
813 ie->frame_count = gif->ImageCount;
818 *error = EVAS_LOAD_ERROR_NONE;
823 evas_image_load_specific_frame(Image_Entry *ie, const char *file, int frame_index, int *error)
827 Image_Entry_Frame *frame = NULL;
828 Gif_Frame *gif_frame = NULL;
831 fd = open(file, O_RDONLY);
833 fd = open(file, O_RDONLY | O_BINARY);
837 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
841 gif = DGifOpenFileHandle(fd);
845 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
848 if (!_evas_image_skip_frame(gif, frame_index-1))
851 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
855 frame = malloc(sizeof (Image_Entry_Frame));
859 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
863 gif_frame = malloc(sizeof (Gif_Frame));
867 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
870 frame->info = gif_frame;
871 frame->index = frame_index;
872 if (!_evas_image_load_frame(ie,gif, frame, LOAD_FRAME_DATA_INFO,error))
875 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
879 ie->frames = eina_list_append(ie->frames, frame);
885 evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
888 Image_Entry_Frame *frame = NULL;
891 if(!ie->flags.animated)
894 cur_frame_index = ie->cur_frame;
896 if ((ie->flags.animated) &&
897 ((cur_frame_index <0) || (cur_frame_index > FRAME_MAX) || (cur_frame_index > ie->frame_count)))
899 *error = EVAS_LOAD_ERROR_GENERIC;
903 /* first time frame is set to be 0. so default is 1 */
904 if (cur_frame_index == 0) cur_frame_index++;
906 /* Check current frame exists in hash table */
907 hit = _find_frame(ie, cur_frame_index, &frame);
909 /* if current frame exist in has table, check load flag */
913 evas_image_load_file_data_gif_internal(ie,frame,error);
920 fd = open(file, O_RDONLY);
922 fd = open(file, O_RDONLY | O_BINARY);
926 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
930 gif = DGifOpenFileHandle(fd);
934 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
937 _evas_image_skip_frame(gif, cur_frame_index-1);
938 if (!_evas_image_load_frame(ie, gif, frame, LOAD_FRAME_DATA,error))
941 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
944 if (!evas_image_load_file_data_gif_internal(ie, frame, error))
947 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
951 *error = EVAS_LOAD_ERROR_NONE;
955 /* current frame does is not exist */
958 if (!evas_image_load_specific_frame(ie, file, cur_frame_index, error))
964 hit = _find_frame(ie, cur_frame_index, &frame);
965 if (!hit) return EINA_FALSE;
966 if (!evas_image_load_file_data_gif_internal(ie, frame, error))
968 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
977 evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, const int start_frame, const int frame_num)
983 int current_frame = 1;
984 int remain_frames = frame_num;
988 frame_count = ie->frame_count;
990 if (!ie->flags.animated) return -1;
991 if ((start_frame + frame_num) > frame_count) return -1;
992 if (frame_num < 0) return -1;
997 fd = open(file, O_RDONLY);
999 fd = open(file, O_RDONLY | O_BINARY);
1001 if (fd < 0) return -1;
1003 gif = DGifOpenFileHandle(fd);
1012 if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
1014 rec = TERMINATE_RECORD_TYPE;
1016 if (rec == IMAGE_DESC_RECORD_TYPE)
1021 if (DGifGetImageDesc(gif) == GIF_ERROR)
1023 /* PrintGifError(); */
1024 rec = TERMINATE_RECORD_TYPE;
1027 /* we have to count frame, so use DGifGetCode and skip decoding */
1028 if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
1030 rec = TERMINATE_RECORD_TYPE;
1035 DGifGetExtensionNext(gif, &img);
1038 else if (rec == EXTENSION_RECORD_TYPE)
1044 DGifGetExtension(gif, &ext_code, &ext);
1047 if (ext_code == 0xf9) /* Graphic Control Extension */
1049 if ((current_frame >= start_frame) && (current_frame <= frame_count))
1051 int frame_duration = 0;
1052 if (remain_frames < 0) break;
1053 frame_duration = byte2_to_int (ext[2], ext[3]);
1054 if (frame_duration == 0)
1057 duration += (double)frame_duration/100;
1062 DGifGetExtensionNext(gif, &ext);
1065 } while (rec != TERMINATE_RECORD_TYPE);
1072 module_open(Evas_Module *em)
1075 em->functions = (void *)(&evas_image_load_gif_func);
1080 module_close(Evas_Module *em __UNUSED__)
1084 static Evas_Module_Api evas_modapi =
1086 EVAS_MODULE_API_VERSION,
1095 EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, gif);
1097 #ifndef EVAS_STATIC_BUILD_GIF
1098 EVAS_EINA_MODULE_DEFINE(image_loader, gif);