1 /**
2  * @file lv_gifenc.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_gif_private.h"
10 #if LV_USE_GIF
11 #include "../../misc/lv_timer_private.h"
12 #include "../../misc/cache/lv_image_cache.h"
13 #include "../../core/lv_obj_class_private.h"
14 
15 #include "gifdec.h"
16 
17 /*********************
18  *      DEFINES
19  *********************/
20 #define MY_CLASS (&lv_gif_class)
21 
22 /**********************
23  *      TYPEDEFS
24  **********************/
25 
26 /**********************
27  *  STATIC PROTOTYPES
28  **********************/
29 static void lv_gif_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
30 static void lv_gif_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
31 static void next_frame_task_cb(lv_timer_t * t);
32 
33 /**********************
34  *  STATIC VARIABLES
35  **********************/
36 
37 const lv_obj_class_t lv_gif_class = {
38     .constructor_cb = lv_gif_constructor,
39     .destructor_cb = lv_gif_destructor,
40     .instance_size = sizeof(lv_gif_t),
41     .base_class = &lv_image_class,
42     .name = "gif",
43 };
44 
45 /**********************
46  *      MACROS
47  **********************/
48 
49 /**********************
50  *   GLOBAL FUNCTIONS
51  **********************/
52 
lv_gif_create(lv_obj_t * parent)53 lv_obj_t * lv_gif_create(lv_obj_t * parent)
54 {
55 
56     LV_LOG_INFO("begin");
57     lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
58     lv_obj_class_init_obj(obj);
59     return obj;
60 }
61 
lv_gif_set_src(lv_obj_t * obj,const void * src)62 void lv_gif_set_src(lv_obj_t * obj, const void * src)
63 {
64     lv_gif_t * gifobj = (lv_gif_t *) obj;
65     gd_GIF * gif = gifobj->gif;
66 
67     /*Close previous gif if any*/
68     if(gif != NULL) {
69         lv_image_cache_drop(lv_image_get_src(obj));
70 
71         gd_close_gif(gif);
72         gifobj->gif = NULL;
73         gifobj->imgdsc.data = NULL;
74     }
75 
76     if(lv_image_src_get_type(src) == LV_IMAGE_SRC_VARIABLE) {
77         const lv_image_dsc_t * img_dsc = src;
78         gif = gd_open_gif_data(img_dsc->data);
79     }
80     else if(lv_image_src_get_type(src) == LV_IMAGE_SRC_FILE) {
81         gif = gd_open_gif_file(src);
82     }
83     if(gif == NULL) {
84         LV_LOG_WARN("Couldn't load the source");
85         return;
86     }
87 
88     gifobj->gif = gif;
89     gifobj->imgdsc.data = gif->canvas;
90     gifobj->imgdsc.header.magic = LV_IMAGE_HEADER_MAGIC;
91     gifobj->imgdsc.header.flags = LV_IMAGE_FLAGS_MODIFIABLE;
92     gifobj->imgdsc.header.cf = LV_COLOR_FORMAT_ARGB8888;
93     gifobj->imgdsc.header.h = gif->height;
94     gifobj->imgdsc.header.w = gif->width;
95     gifobj->imgdsc.header.stride = gif->width * 4;
96     gifobj->imgdsc.data_size = gif->width * gif->height * 4;
97 
98     gifobj->last_call = lv_tick_get();
99 
100     lv_image_set_src(obj, &gifobj->imgdsc);
101 
102     lv_timer_resume(gifobj->timer);
103     lv_timer_reset(gifobj->timer);
104 
105     next_frame_task_cb(gifobj->timer);
106 
107 }
108 
lv_gif_restart(lv_obj_t * obj)109 void lv_gif_restart(lv_obj_t * obj)
110 {
111     lv_gif_t * gifobj = (lv_gif_t *) obj;
112 
113     if(gifobj->gif == NULL) {
114         LV_LOG_WARN("Gif resource not loaded correctly");
115         return;
116     }
117 
118     gd_rewind(gifobj->gif);
119     lv_timer_resume(gifobj->timer);
120     lv_timer_reset(gifobj->timer);
121 }
122 
lv_gif_pause(lv_obj_t * obj)123 void lv_gif_pause(lv_obj_t * obj)
124 {
125     lv_gif_t * gifobj = (lv_gif_t *) obj;
126     lv_timer_pause(gifobj->timer);
127 }
128 
lv_gif_resume(lv_obj_t * obj)129 void lv_gif_resume(lv_obj_t * obj)
130 {
131     lv_gif_t * gifobj = (lv_gif_t *) obj;
132 
133     if(gifobj->gif == NULL) {
134         LV_LOG_WARN("Gif resource not loaded correctly");
135         return;
136     }
137 
138     lv_timer_resume(gifobj->timer);
139 }
140 
lv_gif_is_loaded(lv_obj_t * obj)141 bool lv_gif_is_loaded(lv_obj_t * obj)
142 {
143     lv_gif_t * gifobj = (lv_gif_t *) obj;
144 
145     return (gifobj->gif != NULL);
146 }
147 
lv_gif_get_loop_count(lv_obj_t * obj)148 int32_t lv_gif_get_loop_count(lv_obj_t * obj)
149 {
150     lv_gif_t * gifobj = (lv_gif_t *) obj;
151 
152     if(gifobj->gif == NULL) {
153         return -1;
154     }
155 
156     return gifobj->gif->loop_count;
157 }
158 
lv_gif_set_loop_count(lv_obj_t * obj,int32_t count)159 void lv_gif_set_loop_count(lv_obj_t * obj, int32_t count)
160 {
161     lv_gif_t * gifobj = (lv_gif_t *) obj;
162 
163     if(gifobj->gif == NULL) {
164         LV_LOG_WARN("Gif resource not loaded correctly");
165         return;
166     }
167 
168     gifobj->gif->loop_count = count;
169 }
170 
171 /**********************
172  *   STATIC FUNCTIONS
173  **********************/
174 
lv_gif_constructor(const lv_obj_class_t * class_p,lv_obj_t * obj)175 static void lv_gif_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
176 {
177     LV_UNUSED(class_p);
178 
179     lv_gif_t * gifobj = (lv_gif_t *) obj;
180 
181     gifobj->gif = NULL;
182     gifobj->timer = lv_timer_create(next_frame_task_cb, 10, obj);
183     lv_timer_pause(gifobj->timer);
184 }
185 
lv_gif_destructor(const lv_obj_class_t * class_p,lv_obj_t * obj)186 static void lv_gif_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
187 {
188     LV_UNUSED(class_p);
189     lv_gif_t * gifobj = (lv_gif_t *) obj;
190 
191     lv_image_cache_drop(lv_image_get_src(obj));
192 
193     if(gifobj->gif)
194         gd_close_gif(gifobj->gif);
195     lv_timer_delete(gifobj->timer);
196 }
197 
next_frame_task_cb(lv_timer_t * t)198 static void next_frame_task_cb(lv_timer_t * t)
199 {
200     lv_obj_t * obj = t->user_data;
201     lv_gif_t * gifobj = (lv_gif_t *) obj;
202     uint32_t elaps = lv_tick_elaps(gifobj->last_call);
203     if(elaps < gifobj->gif->gce.delay * 10) return;
204 
205     gifobj->last_call = lv_tick_get();
206 
207     int has_next = gd_get_frame(gifobj->gif);
208     if(has_next == 0) {
209         /*It was the last repeat*/
210         lv_result_t res = lv_obj_send_event(obj, LV_EVENT_READY, NULL);
211         lv_timer_pause(t);
212         if(res != LV_RESULT_OK) return;
213     }
214 
215     gd_render_frame(gifobj->gif, (uint8_t *)gifobj->imgdsc.data);
216 
217     lv_image_cache_drop(lv_image_get_src(obj));
218     lv_obj_invalidate(obj);
219 }
220 
221 #endif /*LV_USE_GIF*/
222