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
55 #define byte2_to_int(a,b) (((b)<<8)|(a))
57 #define FRAME_MAX 1024
59 /* find specific frame in image entry */
61 _find_frame(Image_Entry *ie, int frame_index, Image_Entry_Frame **frame)
64 Image_Entry_Frame *hit_frame = NULL;
66 if (!ie) return EINA_FALSE;
67 if (!ie->frames) return EINA_FALSE;
69 EINA_LIST_FOREACH(ie->frames, l, hit_frame)
71 if (hit_frame->index == frame_index)
81 _find_close_frame(Image_Entry *ie, int frame_index, Image_Entry_Frame **frame)
84 Eina_Bool hit = EINA_FALSE;
87 if (!ie) return EINA_FALSE;
88 if (!ie->frames) return EINA_FALSE;
92 hit = _find_frame(ie, i, frame);
100 _evas_image_skip_frame(GifFileType *gif, int frame)
102 int remain_frame = 0;
105 if (!gif) return EINA_FALSE;
106 if (frame == 0) return EINA_TRUE; /* no need to skip */
107 if (frame < 0 || frame > FRAME_MAX) return EINA_FALSE;
109 remain_frame = frame;
113 if (DGifGetRecordType(gif, &rec) == GIF_ERROR) return EINA_FALSE;
115 if (rec == EXTENSION_RECORD_TYPE)
121 DGifGetExtension(gif, &ext_code, &ext);
123 { /*skip extention */
125 DGifGetExtensionNext(gif, &ext);
129 if (rec == IMAGE_DESC_RECORD_TYPE)
134 if (DGifGetImageDesc(gif) == GIF_ERROR) return EINA_FALSE;
137 /* we have to count frame, so use DGifGetCode and skip decoding */
138 if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR) return EINA_FALSE;
143 DGifGetCodeNext(gif, &img);
145 if (remain_frame < 1) return EINA_TRUE;
147 if (rec == TERMINATE_RECORD_TYPE) return EINA_FALSE; /* end of file */
149 } while ((rec != TERMINATE_RECORD_TYPE) && (remain_frame > 0));
154 _evas_image_load_frame_graphic_info(Image_Entry_Frame *frame, GifByteType *ext)
156 Gif_Frame *gif_frame = NULL;
157 if ((!frame) || (!ext)) return EINA_FALSE;
159 gif_frame = (Gif_Frame *) frame->info;
162 if ((ext[1] & 0x1) != 0)
163 gif_frame->frame_info.transparent = ext[4];
165 gif_frame->frame_info.transparent = -1;
167 gif_frame->frame_info.input = (ext[1] >>1) & 0x1;
168 gif_frame->frame_info.disposal = (ext[1] >>2) & 0x7;
169 gif_frame->frame_info.delay = byte2_to_int(ext[2], ext[3]);
174 _evas_image_load_frame_image_des_info(GifFileType *gif, Image_Entry_Frame *frame)
176 Gif_Frame *gif_frame = NULL;
177 if ((!gif) || (!frame)) return EINA_FALSE;
179 gif_frame = (Gif_Frame *) frame->info;
180 gif_frame->image_des.x = gif->Image.Left;
181 gif_frame->image_des.y = gif->Image.Top;
182 gif_frame->image_des.w = gif->Image.Width;
183 gif_frame->image_des.h = gif->Image.Height;
184 gif_frame->image_des.interlace = gif->Image.Interlace;
189 _evas_image_load_frame_image_data(Image_Entry *ie, GifFileType *gif, Image_Entry_Frame *frame, int *error)
197 ColorMapObject *cmap;
199 GifRowType *tmp; /*for skip gif line */
200 int intoffset[] = { 0, 4, 2, 1 };
201 int intjump[] = { 8, 8, 4, 2 };
203 int cache_w, cache_h, cur_w, cur_h;
207 Gif_Frame *gif_frame = NULL;
208 /* for scale down decoding */
210 int scale_w, scale_h, scale_x, scale_y;
212 if ((!gif) || (!frame)) return EINA_FALSE;
214 gif_frame = (Gif_Frame *) frame->info;
215 w = gif->Image.Width;
216 h = gif->Image.Height;
222 /* if user don't set scale down, default scale_ratio is 1 */
223 if (ie->load_opts.scale_down_by > 1) scale_ratio = ie->load_opts.scale_down_by;
224 scale_w = w / scale_ratio;
225 scale_h = h / scale_ratio;
226 scale_x = x / scale_ratio;
227 scale_y = y / scale_ratio;
231 tmp = malloc(w * sizeof(GifPixelType));
234 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
239 rows = malloc(scale_h * sizeof(GifRowType *));
243 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
247 for (i = 0; i < scale_h; i++)
251 /* alloc memory according to scaled size */
252 for (i = 0; i < scale_h; i++)
254 rows[i] = malloc(w * sizeof(GifPixelType));
257 for (i = 0; i < scale_h; i++)
265 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
269 if (gif->Image.Interlace)
271 for (i = 0; i < 4; i++)
273 for (j = intoffset[i]; j < h; j += intjump[i])
275 if ((j % scale_ratio) == 0)
276 DGifGetLine(gif, rows[(j / scale_ratio)], w);
278 DGifGetLine(gif, tmp, w);
284 for (i = 0; i < scale_h; i++)
286 if (DGifGetLine(gif, rows[i], w) != GIF_OK)
288 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
293 /* we use down sample method for scale down, so skip other line */
294 for (j = 0; j < (scale_ratio - 1); j++)
296 if (DGifGetLine(gif, tmp, w) != GIF_OK)
298 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
305 alpha = gif_frame->frame_info.transparent;
306 siz = cache_w *cache_h * sizeof(DATA32);
307 frame->data = malloc(siz);
310 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
314 bg = gif->SBackGroundColor;
315 cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap);
320 for (i = 0; i < scale_h; i++)
325 if (frame->data) free(frame->data);
326 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
330 /* get the background value */
331 r = cmap->Colors[bg].Red;
332 g = cmap->Colors[bg].Green;
333 b = cmap->Colors[bg].Blue;
334 bg_val = ARGB_JOIN(0xff, r, g, b);
336 per_inc = 100.0 / (((double)w) * h);
340 if (cur_h > cache_h) cur_h = cache_h;
341 if (cur_w > cache_w) cur_w = cache_w;
343 if (frame->index > 1)
345 /* get previous frame only frame index is bigger than 1 */
347 Image_Entry_Frame *new_frame = NULL;
348 int cur_frame = frame->index;
352 if (_find_close_frame(ie, cur_frame, &new_frame))
353 start_frame = new_frame->index + 1;
355 if ((start_frame < 1) || (start_frame > cur_frame))
357 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
360 /* load previous frame of cur_frame */
361 for (j = start_frame; j < cur_frame ; j++)
363 if (!evas_image_load_specific_frame(ie, ie->file, j, error))
365 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
369 if (!_find_frame(ie, cur_frame - 1, &new_frame))
371 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
376 Gif_Frame *gif_frame = NULL;
377 ptr_src = new_frame->data;
380 gif_frame = (Gif_Frame *)(new_frame->info);
381 disposal = gif_frame->frame_info.disposal;
383 switch(disposal) /* we only support disposal flag 0,1,2 */
385 case 1: /* Do not dispose. need previous frame*/
386 memcpy(ptr, ptr_src, siz);
387 /* only decoding image descriptor's region */
388 ptr = ptr + cache_w * scale_y;
390 for (i = 0; i < cur_h; i++)
393 for (j = 0; j < cur_w; j++)
395 if (rows[i][j * scale_ratio] == alpha)
401 r = cmap->Colors[rows[i][j * scale_ratio]].Red;
402 g = cmap->Colors[rows[i][j * scale_ratio]].Green;
403 b = cmap->Colors[rows[i][j * scale_ratio]].Blue;
404 *ptr++ = ARGB_JOIN(0xff, r, g, b);
408 ptr = ptr + (cache_w - (scale_x + cur_w));
411 case 2: /* Restore to background color */
412 memcpy(ptr, ptr_src, siz);
413 /* composite frames */
414 for (i = 0; i < cache_h; i++)
416 if ((i < scale_y) || (i >= (scale_y + cur_h)))
418 for (j = 0; j < cache_w; j++)
429 for (j = 0; j < cache_w; j++)
432 if ((j < scale_x) || (j >= (scale_x + cur_w)))
439 r = cmap->Colors[rows[i1][j1 * scale_ratio]].Red;
440 g = cmap->Colors[rows[i1][j1 * scale_ratio]].Green;
441 b = cmap->Colors[rows[i1][j1 * scale_ratio]].Blue;
442 *ptr++ = ARGB_JOIN(0xff, r, g, b);
448 case 0: /* No disposal specified */
451 for (i = 0; i < cache_h; i++)
453 if ((i < scale_y) || (i >= (scale_y + cur_h)))
455 for (j = 0; j < cache_w; j++)
466 for (j = 0; j < cache_w; j++)
469 if ((j < scale_x) || (j >= (scale_x + cur_w)))
476 r = cmap->Colors[rows[i1][j1 * scale_ratio]].Red;
477 g = cmap->Colors[rows[i1][j1 * scale_ratio]].Green;
478 b = cmap->Colors[rows[i1][j1 * scale_ratio]].Blue;
479 *ptr++ = ARGB_JOIN(0xff, r, g, b);
488 else /* first frame decoding */
490 /* fill background color */
491 for (i = 0; i < cache_h; i++)
493 /* the row's of logical screen not overap with frame */
494 if ((i < scale_y) || (i >= (scale_y + cur_h)))
496 for (j = 0; j < cache_w; j++)
507 for (j = 0; j < cache_w; j++)
510 if ((j < scale_x) || (j >= (scale_x + cur_w)))
517 r = cmap->Colors[rows[i1][j1 * scale_ratio]].Red;
518 g = cmap->Colors[rows[i1][j1 * scale_ratio]].Green;
519 b = cmap->Colors[rows[i1][j1 * scale_ratio]].Blue;
520 *ptr++ = ARGB_JOIN(0xff, r, g, b);
527 for (i = 0; i < scale_h; i++)
529 if (rows[i]) free(rows[i]);
531 if (rows) free(rows);
532 frame->loaded = EINA_TRUE;
535 for (i = 0; i < scale_h; i++)
537 if (rows[i]) free(rows[i]);
539 if (rows) free(rows);
544 _evas_image_load_frame(Image_Entry *ie, GifFileType *gif, Image_Entry_Frame *frame, Frame_Load_Type type, int *error)
547 int gra_res = 0, img_res = 0;
548 Eina_Bool res = EINA_FALSE;
549 Gif_Frame *gif_frame = NULL;
551 if ((!gif) || (!frame)) return EINA_FALSE;
552 gif_frame = (Gif_Frame *) frame->info;
554 if (type > LOAD_FRAME_DATA_INFO) return EINA_FALSE;
558 if (DGifGetRecordType(gif, &rec) == GIF_ERROR) return EINA_FALSE;
559 if (rec == IMAGE_DESC_RECORD_TYPE)
564 else if (rec == EXTENSION_RECORD_TYPE)
570 DGifGetExtension(gif, &ext_code, &ext);
573 if (ext_code == 0xf9) /* Graphic Control Extension */
576 /* fill frame info */
577 if ((type == LOAD_FRAME_INFO) || (type == LOAD_FRAME_DATA_INFO))
578 _evas_image_load_frame_graphic_info(frame,ext);
581 DGifGetExtensionNext(gif, &ext);
584 } while ((rec != TERMINATE_RECORD_TYPE) && (img_res == 0));
585 if (img_res != 1) return EINA_FALSE;
586 if (DGifGetImageDesc(gif) == GIF_ERROR) return EINA_FALSE;
587 if ((type == LOAD_FRAME_INFO) || (type == LOAD_FRAME_DATA_INFO))
588 _evas_image_load_frame_image_des_info(gif, frame);
590 if ((type == LOAD_FRAME_DATA) || (type == LOAD_FRAME_DATA_INFO))
592 res = _evas_image_load_frame_image_data(ie, gif,frame, error);
593 if (!res) return EINA_FALSE;
599 /* set frame data to cache entry's data */
601 evas_image_load_file_data_gif_internal(Image_Entry *ie, Image_Entry_Frame *frame, int *error)
609 int cache_w, cache_h;
611 Gif_Frame *gif_frame = NULL;
613 gif_frame = (Gif_Frame *) frame->info;
616 w = gif_frame->image_des.w;
617 h = gif_frame->image_des.h;
618 dst_x = gif_frame->image_des.x;
619 dst_y = gif_frame->image_des.y;
623 if (!evas_cache_image_pixels(ie))
625 evas_cache_image_surface_alloc(ie, cache_w, cache_h);
628 if (!evas_cache_image_pixels(ie))
630 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
634 /* only copy real frame part */
635 siz = cache_w * cache_h * sizeof(DATA32);
636 dst = evas_cache_image_pixels(ie);
638 memcpy(dst, src, siz);
640 evas_common_image_premul(ie);
642 *error = EVAS_LOAD_ERROR_NONE;
647 evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
662 fd = open(file, O_RDONLY);
664 fd = open(file, O_RDONLY | O_BINARY);
668 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
672 gif = DGifOpenFileHandle(fd);
676 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
680 /* check logical screen size */
683 /* support scale down feture in gif*/
684 if (ie->load_opts.scale_down_by > 1)
686 w /= ie->load_opts.scale_down_by;
687 h /= ie->load_opts.scale_down_by;
690 if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
694 if (IMG_TOO_BIG(w, h))
695 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
697 *error = EVAS_LOAD_ERROR_GENERIC;
705 if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
707 /* PrintGifError(); */
709 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
713 /* image descript info */
714 if (rec == IMAGE_DESC_RECORD_TYPE)
719 if (DGifGetImageDesc(gif) == GIF_ERROR)
721 /* PrintGifError(); */
723 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
726 /* we have to count frame, so use DGifGetCode and skip decoding */
727 if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
729 /* PrintGifError(); */
731 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
737 DGifGetCodeNext(gif, &img);
740 else if (rec == EXTENSION_RECORD_TYPE)
746 DGifGetExtension(gif, &ext_code, &ext);
749 if (ext_code == 0xf9) /* Graphic Control Extension */
751 if ((ext[1] & 1) && (alpha < 0)) alpha = (int)ext[4];
753 else if (ext_code == 0xff) /* application extension */
755 if (!strncmp ((char*)(&ext[1]), "NETSCAPE2.0", 11) ||
756 !strncmp ((char*)(&ext[1]), "ANIMEXTS1.0", 11))
759 DGifGetExtensionNext(gif, &ext);
763 loop_count = ext[2] + (ext[3] << 8);
764 if (loop_count > 0) loop_count++;
770 DGifGetExtensionNext(gif, &ext);
773 } while (rec != TERMINATE_RECORD_TYPE);
775 if (alpha >= 0) ie->flags.alpha = 1;
777 if (gif->ImageCount > 1)
779 ie->flags.animated = 1;
780 ie->loop_count = loop_count;
781 ie->loop_hint = EVAS_IMAGE_ANIMATED_HINT_LOOP;
782 ie->frame_count = gif->ImageCount;
787 *error = EVAS_LOAD_ERROR_NONE;
792 evas_image_load_specific_frame(Image_Entry *ie, const char *file, int frame_index, int *error)
796 Image_Entry_Frame *frame = NULL;
797 Gif_Frame *gif_frame = NULL;
800 fd = open(file, O_RDONLY);
802 fd = open(file, O_RDONLY | O_BINARY);
806 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
810 gif = DGifOpenFileHandle(fd);
814 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
817 if (!_evas_image_skip_frame(gif, frame_index-1))
820 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
824 frame = malloc(sizeof (Image_Entry_Frame));
828 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
832 gif_frame = malloc(sizeof (Gif_Frame));
836 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
839 frame->info = gif_frame;
840 frame->index = frame_index;
841 if (!_evas_image_load_frame(ie,gif, frame, LOAD_FRAME_DATA_INFO,error))
844 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
848 ie->frames = eina_list_append(ie->frames, frame);
854 evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
857 Image_Entry_Frame *frame = NULL;
860 if(!ie->flags.animated)
863 cur_frame_index = ie->cur_frame;
865 if ((ie->flags.animated) &&
866 ((cur_frame_index <0) || (cur_frame_index > FRAME_MAX) || (cur_frame_index > ie->frame_count)))
868 *error = EVAS_LOAD_ERROR_GENERIC;
872 /* first time frame is set to be 0. so default is 1 */
873 if (cur_frame_index == 0) cur_frame_index++;
875 /* Check current frame exists in hash table */
876 hit = _find_frame(ie, cur_frame_index, &frame);
878 /* if current frame exist in has table, check load flag */
882 evas_image_load_file_data_gif_internal(ie,frame,error);
889 fd = open(file, O_RDONLY);
891 fd = open(file, O_RDONLY | O_BINARY);
895 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
899 gif = DGifOpenFileHandle(fd);
903 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
906 _evas_image_skip_frame(gif, cur_frame_index-1);
907 if (!_evas_image_load_frame(ie, gif, frame, LOAD_FRAME_DATA,error))
910 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
913 if (!evas_image_load_file_data_gif_internal(ie, frame, error))
916 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
920 *error = EVAS_LOAD_ERROR_NONE;
924 /* current frame does is not exist */
927 if (!evas_image_load_specific_frame(ie, file, cur_frame_index, error))
933 hit = _find_frame(ie, cur_frame_index, &frame);
934 if (!hit) return EINA_FALSE;
935 if (!evas_image_load_file_data_gif_internal(ie, frame, error))
937 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
946 evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, const int start_frame, const int frame_num)
952 int current_frame = 1;
953 int remain_frames = frame_num;
957 frame_count = ie->frame_count;
959 if (!ie->flags.animated) return -1;
960 if ((start_frame + frame_num) > frame_count) return -1;
961 if (frame_num < 0) return -1;
966 fd = open(file, O_RDONLY);
968 fd = open(file, O_RDONLY | O_BINARY);
970 if (fd < 0) return -1;
972 gif = DGifOpenFileHandle(fd);
981 if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
983 rec = TERMINATE_RECORD_TYPE;
985 if (rec == IMAGE_DESC_RECORD_TYPE)
990 if (DGifGetImageDesc(gif) == GIF_ERROR)
992 /* PrintGifError(); */
993 rec = TERMINATE_RECORD_TYPE;
996 /* we have to count frame, so use DGifGetCode and skip decoding */
997 if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
999 rec = TERMINATE_RECORD_TYPE;
1004 DGifGetExtensionNext(gif, &img);
1007 else if (rec == EXTENSION_RECORD_TYPE)
1013 DGifGetExtension(gif, &ext_code, &ext);
1016 if (ext_code == 0xf9) /* Graphic Control Extension */
1018 if ((current_frame >= start_frame) && (current_frame <= frame_count))
1020 int frame_duration = 0;
1021 if (remain_frames < 0) break;
1022 frame_duration = byte2_to_int (ext[2], ext[3]);
1023 if (frame_duration == 0)
1026 duration += (double)frame_duration/100;
1031 DGifGetExtensionNext(gif, &ext);
1034 } while (rec != TERMINATE_RECORD_TYPE);
1041 module_open(Evas_Module *em)
1044 em->functions = (void *)(&evas_image_load_gif_func);
1049 module_close(Evas_Module *em __UNUSED__)
1053 static Evas_Module_Api evas_modapi =
1055 EVAS_MODULE_API_VERSION,
1064 EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, gif);
1066 #ifndef EVAS_STATIC_BUILD_GIF
1067 EVAS_EINA_MODULE_DEFINE(image_loader, gif);