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