1 /**
2  * @file lv_gifenc.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_gif.h"
10 #if LV_USE_GIF
11 
12 #include "gifdec.h"
13 
14 /*********************
15  *      DEFINES
16  *********************/
17 #define MY_CLASS    &lv_gif_class
18 
19 /**********************
20  *      TYPEDEFS
21  **********************/
22 
23 /**********************
24  *  STATIC PROTOTYPES
25  **********************/
26 static void lv_gif_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
27 static void lv_gif_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
28 static void next_frame_task_cb(lv_timer_t * t);
29 
30 /**********************
31  *  STATIC VARIABLES
32  **********************/
33 const lv_obj_class_t lv_gif_class = {
34     .constructor_cb = lv_gif_constructor,
35     .destructor_cb = lv_gif_destructor,
36     .instance_size = sizeof(lv_gif_t),
37     .base_class = &lv_img_class
38 };
39 
40 /**********************
41  *      MACROS
42  **********************/
43 
44 /**********************
45  *   GLOBAL FUNCTIONS
46  **********************/
47 
lv_gif_create(lv_obj_t * parent)48 lv_obj_t * lv_gif_create(lv_obj_t * parent)
49 {
50 
51     LV_LOG_INFO("begin");
52     lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
53     lv_obj_class_init_obj(obj);
54     return obj;
55 }
56 
lv_gif_set_src(lv_obj_t * obj,const void * src)57 void lv_gif_set_src(lv_obj_t * obj, const void * src)
58 {
59     lv_gif_t * gifobj = (lv_gif_t *) obj;
60 
61     /*Close previous gif if any*/
62     if(gifobj->gif) {
63         lv_img_cache_invalidate_src(&gifobj->imgdsc);
64         gd_close_gif(gifobj->gif);
65         gifobj->gif = NULL;
66         gifobj->imgdsc.data = NULL;
67     }
68 
69     if(lv_img_src_get_type(src) == LV_IMG_SRC_VARIABLE) {
70         const lv_img_dsc_t * img_dsc = src;
71         gifobj->gif = gd_open_gif_data(img_dsc->data);
72     }
73     else if(lv_img_src_get_type(src) == LV_IMG_SRC_FILE) {
74         gifobj->gif = gd_open_gif_file(src);
75     }
76     if(gifobj->gif == NULL) {
77         LV_LOG_WARN("Could't load the source");
78         return;
79     }
80 
81     gifobj->imgdsc.data = gifobj->gif->canvas;
82     gifobj->imgdsc.header.always_zero = 0;
83     gifobj->imgdsc.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
84     gifobj->imgdsc.header.h = gifobj->gif->height;
85     gifobj->imgdsc.header.w = gifobj->gif->width;
86     gifobj->last_call = lv_tick_get();
87 
88     lv_img_set_src(obj, &gifobj->imgdsc);
89 
90     lv_timer_resume(gifobj->timer);
91     lv_timer_reset(gifobj->timer);
92 
93     next_frame_task_cb(gifobj->timer);
94 
95 }
96 
lv_gif_restart(lv_obj_t * obj)97 void lv_gif_restart(lv_obj_t * obj)
98 {
99     lv_gif_t * gifobj = (lv_gif_t *) obj;
100     gd_rewind(gifobj->gif);
101     lv_timer_resume(gifobj->timer);
102     lv_timer_reset(gifobj->timer);
103 }
104 
105 /**********************
106  *   STATIC FUNCTIONS
107  **********************/
108 
lv_gif_constructor(const lv_obj_class_t * class_p,lv_obj_t * obj)109 static void lv_gif_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
110 {
111     LV_UNUSED(class_p);
112 
113     lv_gif_t * gifobj = (lv_gif_t *) obj;
114 
115     gifobj->gif = NULL;
116     gifobj->timer = lv_timer_create(next_frame_task_cb, 10, obj);
117     lv_timer_pause(gifobj->timer);
118 }
119 
lv_gif_destructor(const lv_obj_class_t * class_p,lv_obj_t * obj)120 static void lv_gif_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
121 {
122     LV_UNUSED(class_p);
123     lv_gif_t * gifobj = (lv_gif_t *) obj;
124     lv_img_cache_invalidate_src(&gifobj->imgdsc);
125     if(gifobj->gif)
126         gd_close_gif(gifobj->gif);
127     lv_timer_del(gifobj->timer);
128 }
129 
next_frame_task_cb(lv_timer_t * t)130 static void next_frame_task_cb(lv_timer_t * t)
131 {
132     lv_obj_t * obj = t->user_data;
133     lv_gif_t * gifobj = (lv_gif_t *) obj;
134     uint32_t elaps = lv_tick_elaps(gifobj->last_call);
135     if(elaps < gifobj->gif->gce.delay * 10) return;
136 
137     gifobj->last_call = lv_tick_get();
138 
139     int has_next = gd_get_frame(gifobj->gif);
140     if(has_next == 0) {
141         /*It was the last repeat*/
142         lv_res_t res = lv_event_send(obj, LV_EVENT_READY, NULL);
143         lv_timer_pause(t);
144         if(res != LV_FS_RES_OK) return;
145     }
146 
147     gd_render_frame(gifobj->gif, (uint8_t *)gifobj->imgdsc.data);
148 
149     lv_img_cache_invalidate_src(lv_img_get_src(obj));
150     lv_obj_invalidate(obj);
151 }
152 
153 #endif /*LV_USE_GIF*/
154