aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/modules/loaders/gif/evas_image_load_gif.c
diff options
context:
space:
mode:
authorDavid Walter Seikel2012-01-04 18:41:13 +1000
committerDavid Walter Seikel2012-01-04 18:41:13 +1000
commitdd7595a3475407a7fa96a97393bae8c5220e8762 (patch)
treee341e911d7eb911a51684a7412ef7f7c7605d28e /libraries/evas/src/modules/loaders/gif/evas_image_load_gif.c
parentAdd the skeleton. (diff)
downloadSledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.zip
SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.gz
SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.bz2
SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.xz
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.
Diffstat (limited to '')
-rw-r--r--libraries/evas/src/modules/loaders/gif/evas_image_load_gif.c1030
1 files changed, 1030 insertions, 0 deletions
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 @@
1#include "evas_common.h"
2#include "evas_private.h"
3
4#include <sys/types.h>
5#include <sys/stat.h>
6#include <fcntl.h>
7#include <unistd.h>
8
9#include <gif_lib.h>
10
11typedef struct _Gif_Frame Gif_Frame;
12
13typedef enum _Frame_Load_Type
14{
15 LOAD_FRAME_NONE = 0,
16 LOAD_FRAME_INFO = 1,
17 LOAD_FRAME_DATA = 2,
18 LOAD_FRAME_DATA_INFO = 3
19} Frame_Load_Type;
20
21struct _Gif_Frame
22{
23 struct {
24 /* Image descriptor */
25 int x;
26 int y;
27 int w;
28 int h;
29 int interlace;
30 } image_des;
31
32 struct {
33 /* Graphic Control*/
34 int disposal;
35 int transparent;
36 int delay;
37 int input;
38 } frame_info;
39};
40
41static Eina_Bool evas_image_load_file_data_gif_internal(Image_Entry *ie, Image_Entry_Frame *frame, int *error);
42
43static 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);
44static 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);
45static double evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, int start_frame, int frame_num) ;
46static Eina_Bool evas_image_load_specific_frame(Image_Entry *ie, const char *file, int frame_index, int *error);
47
48static Evas_Image_Load_Func evas_image_load_gif_func =
49{
50 EINA_TRUE,
51 evas_image_load_file_head_gif,
52 evas_image_load_file_data_gif,
53 evas_image_load_frame_duration_gif
54};
55#define byte2_to_int(a,b) (((b)<<8)|(a))
56
57#define FRAME_MAX 1024
58
59/* find specific frame in image entry */
60static Eina_Bool
61_find_frame(Image_Entry *ie, int frame_index, Image_Entry_Frame **frame)
62{
63 Eina_List *l;
64 Image_Entry_Frame *hit_frame = NULL;
65
66 if (!ie) return EINA_FALSE;
67 if (!ie->frames) return EINA_FALSE;
68
69 EINA_LIST_FOREACH(ie->frames, l, hit_frame)
70 {
71 if (hit_frame->index == frame_index)
72 {
73 *frame = hit_frame;
74 return EINA_TRUE;
75 }
76 }
77 return EINA_FALSE;
78}
79
80static Eina_Bool
81_find_close_frame(Image_Entry *ie, int frame_index, Image_Entry_Frame **frame)
82{
83 int i;
84 Eina_Bool hit = EINA_FALSE;
85 i = frame_index -1;
86
87 if (!ie) return EINA_FALSE;
88 if (!ie->frames) return EINA_FALSE;
89
90 for (; i > 0; i--)
91 {
92 hit = _find_frame(ie, i, frame);
93 if (hit)
94 return EINA_TRUE;
95 }
96 return EINA_FALSE;
97}
98
99static Eina_Bool
100_evas_image_skip_frame(GifFileType *gif, int frame)
101{
102 int remain_frame = 0;
103 GifRecordType rec;
104
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;
108
109 remain_frame = frame;
110
111 do
112 {
113 if (DGifGetRecordType(gif, &rec) == GIF_ERROR) return EINA_FALSE;
114
115 if (rec == EXTENSION_RECORD_TYPE)
116 {
117 int ext_code;
118 GifByteType *ext;
119
120 ext = NULL;
121 DGifGetExtension(gif, &ext_code, &ext);
122 while (ext)
123 { /*skip extention */
124 ext = NULL;
125 DGifGetExtensionNext(gif, &ext);
126 }
127 }
128
129 if (rec == IMAGE_DESC_RECORD_TYPE)
130 {
131 int img_code;
132 GifByteType *img;
133
134 if (DGifGetImageDesc(gif) == GIF_ERROR) return EINA_FALSE;
135
136 remain_frame --;
137 /* we have to count frame, so use DGifGetCode and skip decoding */
138 if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR) return EINA_FALSE;
139
140 while (img)
141 {
142 img = NULL;
143 DGifGetCodeNext(gif, &img);
144 }
145 if (remain_frame < 1) return EINA_TRUE;
146 }
147 if (rec == TERMINATE_RECORD_TYPE) return EINA_FALSE; /* end of file */
148
149 } while ((rec != TERMINATE_RECORD_TYPE) && (remain_frame > 0));
150 return EINA_FALSE;
151}
152
153static Eina_Bool
154_evas_image_load_frame_graphic_info(Image_Entry_Frame *frame, GifByteType *ext)
155{
156 Gif_Frame *gif_frame = NULL;
157 if ((!frame) || (!ext)) return EINA_FALSE;
158
159 gif_frame = (Gif_Frame *) frame->info;
160
161 /* transparent */
162 if ((ext[1] & 0x1) != 0)
163 gif_frame->frame_info.transparent = ext[4];
164 else
165 gif_frame->frame_info.transparent = -1;
166
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]);
170 return EINA_TRUE;
171}
172
173static Eina_Bool
174_evas_image_load_frame_image_des_info(GifFileType *gif, Image_Entry_Frame *frame)
175{
176 Gif_Frame *gif_frame = NULL;
177 if ((!gif) || (!frame)) return EINA_FALSE;
178
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;
185 return EINA_TRUE;
186}
187
188static Eina_Bool
189_evas_image_load_frame_image_data(Image_Entry *ie, GifFileType *gif, Image_Entry_Frame *frame, int *error)
190{
191 int w;
192 int h;
193 int x;
194 int y;
195 int i,j;
196 int bg;
197 int r;
198 int g;
199 int b;
200 int alpha;
201 double per;
202 double per_inc;
203 ColorMapObject *cmap;
204 GifRowType *rows;
205 int intoffset[] = { 0, 4, 2, 1 };
206 int intjump[] = { 8, 8, 4, 2 };
207 size_t siz;
208 int cache_w;
209 int cache_h;
210 int cur_h;
211 int cur_w;
212 int disposal = 0;
213 int bg_val = 0;
214 DATA32 *ptr;
215 Gif_Frame *gif_frame = NULL;
216
217 if ((!gif) || (!frame)) return EINA_FALSE;
218
219 gif_frame = (Gif_Frame *) frame->info;
220 w = gif->Image.Width;
221 h = gif->Image.Height;
222 x = gif->Image.Left;
223 y = gif->Image.Top;
224 cache_w = ie->w;
225 cache_h = ie->h;
226
227 rows = malloc(h * sizeof(GifRowType *));
228 if (!rows)
229 {
230 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
231 return EINA_FALSE;
232 }
233 for (i = 0; i < h; i++)
234 {
235 rows[i] = NULL;
236 }
237 for (i = 0; i < h; i++)
238 {
239 rows[i] = malloc(w * sizeof(GifPixelType));
240 if (!rows[i])
241 {
242 for (i = 0; i < h; i++)
243 {
244 if (rows[i])
245 {
246 free(rows[i]);
247 }
248 }
249 free(rows);
250 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
251 return EINA_FALSE;
252 }
253 }
254 if (gif->Image.Interlace)
255 {
256 for (i = 0; i < 4; i++)
257 {
258 for (j = intoffset[i]; j < h; j += intjump[i])
259 {
260 DGifGetLine(gif, rows[j], w);
261 }
262 }
263 }
264 else
265 {
266 for (i = 0; i < h; i++)
267 {
268 if (DGifGetLine(gif, rows[i], w) != GIF_OK)
269 {
270 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
271 goto error;
272 }
273 }
274 }
275 alpha = gif_frame->frame_info.transparent;
276 siz = cache_w *cache_h * sizeof(DATA32);
277 frame->data = malloc(siz);
278 if (!frame->data)
279 {
280 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
281 goto error;
282 }
283 ptr = frame->data;
284 bg = gif->SBackGroundColor;
285 cmap = (gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap);
286
287 if (!cmap)
288 {
289 DGifCloseFile(gif);
290 for (i = 0; i < h; i++)
291 {
292 free(rows[i]);
293 }
294 free(rows);
295 if (frame->data) free(frame->data);
296 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
297 return EINA_FALSE;
298 }
299
300 /* get the background value */
301 r = cmap->Colors[bg].Red;
302 g = cmap->Colors[bg].Green;
303 b = cmap->Colors[bg].Blue;
304 bg_val = ARGB_JOIN(0xff, r, g, b);
305
306 per_inc = 100.0 / (((double)w) * h);
307 cur_h = h;
308 cur_w = w;
309 if (cur_h > cache_h) cur_h = cache_h;
310 if (cur_w > cache_w) cur_w = cache_w;
311
312 if (frame->index > 1)
313 {
314 /* get previous frame only frame index is bigger than 1 */
315 DATA32 *ptr_src;
316 Image_Entry_Frame *new_frame = NULL;
317 int cur_frame = frame->index;
318 int start_frame = 1;
319 int j = 0;
320
321 if (_find_close_frame(ie, cur_frame, &new_frame))
322 start_frame = new_frame->index + 1;
323
324 if ((start_frame < 1) || (start_frame > cur_frame))
325 {
326 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
327 goto error;
328 }
329 /* load previous frame of cur_frame */
330 for (j = start_frame; j < cur_frame ; j++)
331 {
332 if (!evas_image_load_specific_frame(ie, ie->file, j, error))
333 {
334 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
335 goto error;
336 }
337 }
338 if (!_find_frame(ie, cur_frame - 1, &new_frame))
339 {
340 *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
341 goto error;
342 }
343 else
344 {
345 Gif_Frame *gif_frame = NULL;
346 ptr_src = new_frame->data;
347 if (new_frame->info)
348 {
349 gif_frame = (Gif_Frame *)(new_frame->info);
350 disposal = gif_frame->frame_info.disposal;
351 }
352 switch(disposal) /* we only support disposal flag 0,1,2 */
353 {
354 case 1: /* Do not dispose. need previous frame*/
355 memcpy(ptr, ptr_src, siz);
356 /* composite frames */
357 ptr = ptr + cache_w * y;
358
359 for (i = 0; i < cur_h; i++)
360 {
361 ptr = ptr + x;
362 for (j = 0; j < cur_w; j++)
363 {
364 if (rows[i][j] == alpha)
365 {
366 ptr++ ;
367 }
368 else
369 {
370 r = cmap->Colors[rows[i][j]].Red;
371 g = cmap->Colors[rows[i][j]].Green;
372 b = cmap->Colors[rows[i][j]].Blue;
373 *ptr++ = ARGB_JOIN(0xff, r, g, b);
374 }
375 per += per_inc;
376 }
377 ptr = ptr + (cache_w - (x + cur_w));
378 }
379 break;
380 case 2: /* Restore to background color */
381 memcpy(ptr, ptr_src, siz);
382 /* composite frames */
383 for (i = 0; i < cache_h; i++)
384 {
385 if ((i < y) || (i >= (y + cur_h)))
386 {
387 for (j = 0; j < cache_w; j++)
388 {
389 *ptr = bg_val;
390 ptr++;
391 }
392 }
393 else
394 {
395 int i1, j1;
396 i1 = i -y;
397
398 for (j = 0; j < cache_w; j++)
399 {
400 j1 = j - x;
401 if ((j < x) || (j >= (x + cur_w)))
402 {
403 *ptr = bg_val;
404 ptr++;
405 }
406 else
407 {
408 r = cmap->Colors[rows[i1][j1]].Red;
409 g = cmap->Colors[rows[i1][j1]].Green;
410 b = cmap->Colors[rows[i1][j1]].Blue;
411 *ptr++ = ARGB_JOIN(0xff, r, g, b);
412 }
413 }
414 }
415 }
416 break;
417 case 0: /* No disposal specified */
418 default:
419 memset(ptr, 0, siz);
420 for (i = 0; i < cache_h; i++)
421 {
422 if ((i < y) || (i >= (y + cur_h)))
423 {
424 for (j = 0; j < cache_w; j++)
425 {
426 *ptr = bg_val;
427 ptr++;
428 }
429 }
430 else
431 {
432 int i1, j1;
433 i1 = i -y;
434
435 for (j = 0; j < cache_w; j++)
436 {
437 j1 = j - x;
438 if ((j < x) || (j >= (x + cur_w)))
439 {
440 *ptr = bg_val;
441 ptr++;
442 }
443 else
444 {
445 r = cmap->Colors[rows[i1][j1]].Red;
446 g = cmap->Colors[rows[i1][j1]].Green;
447 b = cmap->Colors[rows[i1][j1]].Blue;
448 *ptr++ = ARGB_JOIN(0xff, r, g, b);
449 }
450 }
451 }
452 }
453 break;
454 }
455 }
456 }
457 else /* first frame decoding */
458 {
459 /* fill background color */
460 for (i = 0; i < cache_h; i++)
461 {
462 if ((i < y) || (i >= (y + cur_h)))
463 {
464 for (j = 0; j < cache_w; j++)
465 {
466 *ptr = bg_val;
467 ptr++;
468 }
469 }
470 else
471 {
472 int i1, j1;
473 i1 = i -y;
474
475 for (j = 0; j < cache_w; j++)
476 {
477 j1 = j - x;
478 if ((j < x) || (j >= (x + cur_w)))
479 {
480 *ptr = bg_val;
481 ptr++;
482 }
483 else
484 {
485 r = cmap->Colors[rows[i1][j1]].Red;
486 g = cmap->Colors[rows[i1][j1]].Green;
487 b = cmap->Colors[rows[i1][j1]].Blue;
488 *ptr++ = ARGB_JOIN(0xff, r, g, b);
489 }
490 }
491 }
492 }
493 }
494
495 for (i = 0; i < h; i++)
496 {
497 if (rows[i]) free(rows[i]);
498 }
499 if (rows) free(rows);
500 frame->loaded = EINA_TRUE;
501 return EINA_TRUE;
502error:
503 for (i = 0; i < h; i++)
504 {
505 if (rows[i]) free(rows[i]);
506 }
507 if (rows) free(rows);
508 return EINA_FALSE;
509}
510
511static Eina_Bool
512_evas_image_load_frame(Image_Entry *ie, GifFileType *gif, Image_Entry_Frame *frame, Frame_Load_Type type, int *error)
513{
514 GifRecordType rec;
515 int gra_res = 0, img_res = 0;
516 Eina_Bool res = EINA_FALSE;
517 Gif_Frame *gif_frame = NULL;
518
519 if ((!gif) || (!frame)) return EINA_FALSE;
520 gif_frame = (Gif_Frame *) frame->info;
521
522 if (type > LOAD_FRAME_DATA_INFO) return EINA_FALSE;
523
524 do
525 {
526 if (DGifGetRecordType(gif, &rec) == GIF_ERROR) return EINA_FALSE;
527 if (rec == IMAGE_DESC_RECORD_TYPE)
528 {
529 img_res++;
530 break;
531 }
532 else if (rec == EXTENSION_RECORD_TYPE)
533 {
534 int ext_code;
535 GifByteType *ext;
536
537 ext = NULL;
538 DGifGetExtension(gif, &ext_code, &ext);
539 while (ext)
540 {
541 if (ext_code == 0xf9) /* Graphic Control Extension */
542 {
543 gra_res++;
544 /* fill frame info */
545 if ((type == LOAD_FRAME_INFO) || (type == LOAD_FRAME_DATA_INFO))
546 _evas_image_load_frame_graphic_info(frame,ext);
547 }
548 ext = NULL;
549 DGifGetExtensionNext(gif, &ext);
550 }
551 }
552 } while ((rec != TERMINATE_RECORD_TYPE) && (img_res == 0));
553 if (img_res != 1) return EINA_FALSE;
554 if (DGifGetImageDesc(gif) == GIF_ERROR) return EINA_FALSE;
555 if ((type == LOAD_FRAME_INFO) || (type == LOAD_FRAME_DATA_INFO))
556 _evas_image_load_frame_image_des_info(gif, frame);
557
558 if ((type == LOAD_FRAME_DATA) || (type == LOAD_FRAME_DATA_INFO))
559 {
560 res = _evas_image_load_frame_image_data(ie, gif,frame, error);
561 if (!res) return EINA_FALSE;
562 }
563 return EINA_TRUE;
564}
565
566
567/* set frame data to cache entry's data */
568static Eina_Bool
569evas_image_load_file_data_gif_internal(Image_Entry *ie, Image_Entry_Frame *frame, int *error)
570{
571 int w;
572 int h;
573 int dst_x;
574 int dst_y;
575 DATA32 *dst;
576 DATA32 *src;
577 int cache_w, cache_h;
578 size_t siz;
579 Gif_Frame *gif_frame = NULL;
580
581 gif_frame = (Gif_Frame *) frame->info;
582 cache_w = ie->w;
583 cache_h = ie->h;
584 w = gif_frame->image_des.w;
585 h = gif_frame->image_des.h;
586 dst_x = gif_frame->image_des.x;
587 dst_y = gif_frame->image_des.y;
588
589 src = frame->data;
590
591 if (!evas_cache_image_pixels(ie))
592 {
593 evas_cache_image_surface_alloc(ie, cache_w, cache_h);
594 }
595
596 if (!evas_cache_image_pixels(ie))
597 {
598 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
599 return EINA_FALSE;
600 }
601
602 /* only copy real frame part */
603 siz = cache_w * cache_h * sizeof(DATA32);
604 dst = evas_cache_image_pixels(ie);
605
606 memcpy(dst, src, siz);
607
608 evas_common_image_premul(ie);
609
610 *error = EVAS_LOAD_ERROR_NONE;
611 return EINA_TRUE;
612}
613
614static Eina_Bool
615evas_image_load_file_head_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
616{
617 int fd;
618 GifFileType *gif;
619 GifRecordType rec;
620 int w;
621 int h;
622 int alpha;
623 int loop_count = -1;
624
625 w = 0;
626 h = 0;
627 alpha = -1;
628
629#ifndef __EMX__
630 fd = open(file, O_RDONLY);
631#else
632 fd = open(file, O_RDONLY | O_BINARY);
633#endif
634 if (fd < 0)
635 {
636 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
637 return EINA_FALSE;
638 }
639
640 gif = DGifOpenFileHandle(fd);
641 if (!gif)
642 {
643 if (fd) close(fd);
644 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
645 return EINA_FALSE;
646 }
647
648 /* check logical screen size */
649 w = gif->SWidth;
650 h = gif->SHeight;
651
652 if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
653 IMG_TOO_BIG(w, h))
654 {
655 DGifCloseFile(gif);
656 if (IMG_TOO_BIG(w, h))
657 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
658 else
659 *error = EVAS_LOAD_ERROR_GENERIC;
660 return EINA_FALSE;
661 }
662 ie->w = w;
663 ie->h = h;
664
665 do
666 {
667 if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
668 {
669 /* PrintGifError(); */
670 DGifCloseFile(gif);
671 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
672 return EINA_FALSE;
673 }
674
675 /* image descript info */
676 if (rec == IMAGE_DESC_RECORD_TYPE)
677 {
678 int img_code;
679 GifByteType *img;
680
681 if (DGifGetImageDesc(gif) == GIF_ERROR)
682 {
683 /* PrintGifError(); */
684 DGifCloseFile(gif);
685 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
686 return EINA_FALSE;
687 }
688 /* we have to count frame, so use DGifGetCode and skip decoding */
689 if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
690 {
691 /* PrintGifError(); */
692 DGifCloseFile(gif);
693 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
694 return EINA_FALSE;
695 }
696 while (img)
697 {
698 img = NULL;
699 DGifGetCodeNext(gif, &img);
700 }
701 }
702 else if (rec == EXTENSION_RECORD_TYPE)
703 {
704 int ext_code;
705 GifByteType *ext;
706
707 ext = NULL;
708 DGifGetExtension(gif, &ext_code, &ext);
709 while (ext)
710 {
711 if (ext_code == 0xf9) /* Graphic Control Extension */
712 {
713 if ((ext[1] & 1) && (alpha < 0)) alpha = (int)ext[4];
714 }
715 else if (ext_code == 0xff) /* application extension */
716 {
717 if (!strncmp ((char*)(&ext[1]), "NETSCAPE2.0", 11) ||
718 !strncmp ((char*)(&ext[1]), "ANIMEXTS1.0", 11))
719 {
720 ext=NULL;
721 DGifGetExtensionNext(gif, &ext);
722
723 if (ext[1] == 0x01)
724 {
725 loop_count = ext[2] + (ext[3] << 8);
726 if (loop_count > 0) loop_count++;
727 }
728 }
729 }
730
731 ext = NULL;
732 DGifGetExtensionNext(gif, &ext);
733 }
734 }
735 } while (rec != TERMINATE_RECORD_TYPE);
736
737 if (alpha >= 0) ie->flags.alpha = 1;
738
739 if (gif->ImageCount > 1)
740 {
741 ie->flags.animated = 1;
742 ie->loop_count = loop_count;
743 ie->loop_hint = EVAS_IMAGE_ANIMATED_HINT_LOOP;
744 ie->frame_count = gif->ImageCount;
745 ie->frames = NULL;
746 }
747
748 DGifCloseFile(gif);
749 *error = EVAS_LOAD_ERROR_NONE;
750 return EINA_TRUE;
751}
752
753static Eina_Bool
754evas_image_load_specific_frame(Image_Entry *ie, const char *file, int frame_index, int *error)
755{
756 int fd;
757 GifFileType *gif;
758 Image_Entry_Frame *frame = NULL;
759 Gif_Frame *gif_frame = NULL;
760
761#ifndef __EMX__
762 fd = open(file, O_RDONLY);
763#else
764 fd = open(file, O_RDONLY | O_BINARY);
765#endif
766 if (fd < 0)
767 {
768 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
769 return EINA_FALSE;
770 }
771
772 gif = DGifOpenFileHandle(fd);
773 if (!gif)
774 {
775 if (fd) close(fd);
776 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
777 return EINA_FALSE;
778 }
779 if (!_evas_image_skip_frame(gif, frame_index-1))
780 {
781 if (fd) close(fd);
782 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
783 return EINA_FALSE;
784 }
785
786 frame = malloc(sizeof (Image_Entry_Frame));
787 if (!frame)
788 {
789 if (fd) close(fd);
790 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
791 return EINA_FALSE;
792 }
793
794 gif_frame = malloc(sizeof (Gif_Frame));
795 if (!gif_frame)
796 {
797 if (fd) close(fd);
798 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
799 return EINA_FALSE;
800 }
801 frame->info = gif_frame;
802 frame->index = frame_index;
803 if (!_evas_image_load_frame(ie,gif, frame, LOAD_FRAME_DATA_INFO,error))
804 {
805 if (fd) close(fd);
806 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
807 return EINA_FALSE;
808 }
809
810 ie->frames = eina_list_append(ie->frames, frame);
811 DGifCloseFile(gif);
812 return EINA_TRUE;
813}
814
815static Eina_Bool
816evas_image_load_file_data_gif(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error)
817{
818 int cur_frame_index;
819 Image_Entry_Frame *frame = NULL;
820 Eina_Bool hit;
821
822 if(!ie->flags.animated)
823 cur_frame_index = 1;
824 else
825 cur_frame_index = ie->cur_frame;
826
827 if ((ie->flags.animated) &&
828 ((cur_frame_index <0) || (cur_frame_index > FRAME_MAX) || (cur_frame_index > ie->frame_count)))
829 {
830 *error = EVAS_LOAD_ERROR_GENERIC;
831 return EINA_FALSE;
832 }
833
834 /* first time frame is set to be 0. so default is 1 */
835 if (cur_frame_index == 0) cur_frame_index++;
836
837 /* Check current frame exists in hash table */
838 hit = _find_frame(ie, cur_frame_index, &frame);
839
840 /* if current frame exist in has table, check load flag */
841 if (hit)
842 {
843 if (frame->loaded)
844 evas_image_load_file_data_gif_internal(ie,frame,error);
845 else
846 {
847 int fd;
848 GifFileType *gif;
849
850#ifndef __EMX__
851 fd = open(file, O_RDONLY);
852#else
853 fd = open(file, O_RDONLY | O_BINARY);
854#endif
855 if (fd < 0)
856 {
857 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
858 return EINA_FALSE;
859 }
860
861 gif = DGifOpenFileHandle(fd);
862 if (!gif)
863 {
864 if (fd) close(fd);
865 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
866 return EINA_FALSE;
867 }
868 _evas_image_skip_frame(gif, cur_frame_index-1);
869 if (!_evas_image_load_frame(ie, gif, frame, LOAD_FRAME_DATA,error))
870 {
871 if (fd) close(fd);
872 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
873 return EINA_FALSE;
874 }
875 if (!evas_image_load_file_data_gif_internal(ie, frame, error))
876 {
877 if (fd) close(fd);
878 *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
879 return EINA_FALSE;
880 }
881 DGifCloseFile(gif);
882 *error = EVAS_LOAD_ERROR_NONE;
883 return EINA_TRUE;
884 }
885 }
886 /* current frame does is not exist */
887 else
888 {
889 if (!evas_image_load_specific_frame(ie, file, cur_frame_index, error))
890 {
891 return EINA_FALSE;
892 }
893 hit = EINA_FALSE;
894 frame = NULL;
895 hit = _find_frame(ie, cur_frame_index, &frame);
896 if (!hit) return EINA_FALSE;
897 if (!evas_image_load_file_data_gif_internal(ie, frame, error))
898 {
899 *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
900 return EINA_FALSE;
901 }
902 return EINA_TRUE;
903 }
904 return EINA_FALSE;
905}
906
907static double
908evas_image_load_frame_duration_gif(Image_Entry *ie, const char *file, const int start_frame, const int frame_num)
909{
910 int fd;
911 GifFileType *gif;
912 GifRecordType rec;
913 int done;
914 int current_frame = 1;
915 int remain_frames = frame_num;
916 double duration = 0;
917 int frame_count = 0;
918
919 frame_count = ie->frame_count;
920
921 if (!ie->flags.animated) return -1;
922 if ((start_frame + frame_num) > frame_count) return -1;
923 if (frame_num < 0) return -1;
924
925 done = 0;
926
927#ifndef __EMX__
928 fd = open(file, O_RDONLY);
929#else
930 fd = open(file, O_RDONLY | O_BINARY);
931#endif
932 if (fd < 0) return -1;
933
934 gif = DGifOpenFileHandle(fd);
935 if (!gif)
936 {
937 if (fd) close(fd);
938 return -1;
939 }
940
941 do
942 {
943 if (DGifGetRecordType(gif, &rec) == GIF_ERROR)
944 {
945 rec = TERMINATE_RECORD_TYPE;
946 }
947 if (rec == IMAGE_DESC_RECORD_TYPE)
948 {
949 int img_code;
950 GifByteType *img;
951
952 if (DGifGetImageDesc(gif) == GIF_ERROR)
953 {
954 /* PrintGifError(); */
955 rec = TERMINATE_RECORD_TYPE;
956 }
957 current_frame++;
958 /* we have to count frame, so use DGifGetCode and skip decoding */
959 if (DGifGetCode(gif, &img_code, &img) == GIF_ERROR)
960 {
961 rec = TERMINATE_RECORD_TYPE;
962 }
963 while (img)
964 {
965 img = NULL;
966 DGifGetExtensionNext(gif, &img);
967 }
968 }
969 else if (rec == EXTENSION_RECORD_TYPE)
970 {
971 int ext_code;
972 GifByteType *ext;
973
974 ext = NULL;
975 DGifGetExtension(gif, &ext_code, &ext);
976 while (ext)
977 {
978 if (ext_code == 0xf9) /* Graphic Control Extension */
979 {
980 if ((current_frame >= start_frame) && (current_frame <= frame_count))
981 {
982 int frame_duration = 0;
983 if (remain_frames < 0) break;
984 frame_duration = byte2_to_int (ext[2], ext[3]);
985 if (frame_duration == 0)
986 duration += 0.1;
987 else
988 duration += (double)frame_duration/100;
989 remain_frames --;
990 }
991 }
992 ext = NULL;
993 DGifGetExtensionNext(gif, &ext);
994 }
995 }
996 } while (rec != TERMINATE_RECORD_TYPE);
997
998 DGifCloseFile(gif);
999 return duration;
1000}
1001
1002static int
1003module_open(Evas_Module *em)
1004{
1005 if (!em) return 0;
1006 em->functions = (void *)(&evas_image_load_gif_func);
1007 return 1;
1008}
1009
1010static void
1011module_close(Evas_Module *em __UNUSED__)
1012{
1013}
1014
1015static Evas_Module_Api evas_modapi =
1016{
1017 EVAS_MODULE_API_VERSION,
1018 "gif",
1019 "none",
1020 {
1021 module_open,
1022 module_close
1023 }
1024};
1025
1026EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, gif);
1027
1028#ifndef EVAS_STATIC_BUILD_GIF
1029EVAS_EINA_MODULE_DEFINE(image_loader, gif);
1030#endif