/** * @file lv_gifenc.c * */ /********************* * INCLUDES *********************/ #include "lv_gif.h" #if LV_USE_GIF #include "gifdec.h" /********************* * DEFINES *********************/ #define MY_CLASS &lv_gif_class /********************** * TYPEDEFS **********************/ /********************** * STATIC PROTOTYPES **********************/ static void lv_gif_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj); static void lv_gif_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj); static void next_frame_task_cb(lv_timer_t * t); /********************** * STATIC VARIABLES **********************/ const lv_obj_class_t lv_gif_class = { .constructor_cb = lv_gif_constructor, .destructor_cb = lv_gif_destructor, .instance_size = sizeof(lv_gif_t), .base_class = &lv_img_class }; /********************** * MACROS **********************/ /********************** * GLOBAL FUNCTIONS **********************/ lv_obj_t * lv_gif_create(lv_obj_t * parent) { LV_LOG_INFO("begin"); lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent); lv_obj_class_init_obj(obj); return obj; } void lv_gif_set_src(lv_obj_t * obj, const void * src) { lv_gif_t * gifobj = (lv_gif_t *) obj; /*Close previous gif if any*/ if(gifobj->gif) { lv_img_cache_invalidate_src(&gifobj->imgdsc); gd_close_gif(gifobj->gif); gifobj->gif = NULL; gifobj->imgdsc.data = NULL; } if(lv_img_src_get_type(src) == LV_IMG_SRC_VARIABLE) { const lv_img_dsc_t * img_dsc = src; gifobj->gif = gd_open_gif_data(img_dsc->data); } else if(lv_img_src_get_type(src) == LV_IMG_SRC_FILE) { gifobj->gif = gd_open_gif_file(src); } if(gifobj->gif == NULL) { LV_LOG_WARN("Could't load the source"); return; } gifobj->imgdsc.data = gifobj->gif->canvas; gifobj->imgdsc.header.always_zero = 0; gifobj->imgdsc.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA; gifobj->imgdsc.header.h = gifobj->gif->height; gifobj->imgdsc.header.w = gifobj->gif->width; gifobj->last_call = lv_tick_get(); lv_img_set_src(obj, &gifobj->imgdsc); lv_timer_resume(gifobj->timer); lv_timer_reset(gifobj->timer); next_frame_task_cb(gifobj->timer); } void lv_gif_restart(lv_obj_t * obj) { lv_gif_t * gifobj = (lv_gif_t *) obj; gd_rewind(gifobj->gif); lv_timer_resume(gifobj->timer); lv_timer_reset(gifobj->timer); } /********************** * STATIC FUNCTIONS **********************/ static void lv_gif_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj) { LV_UNUSED(class_p); lv_gif_t * gifobj = (lv_gif_t *) obj; gifobj->gif = NULL; gifobj->timer = lv_timer_create(next_frame_task_cb, 10, obj); lv_timer_pause(gifobj->timer); } static void lv_gif_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj) { LV_UNUSED(class_p); lv_gif_t * gifobj = (lv_gif_t *) obj; lv_img_cache_invalidate_src(&gifobj->imgdsc); if(gifobj->gif) gd_close_gif(gifobj->gif); lv_timer_del(gifobj->timer); } static void next_frame_task_cb(lv_timer_t * t) { lv_obj_t * obj = t->user_data; lv_gif_t * gifobj = (lv_gif_t *) obj; uint32_t elaps = lv_tick_elaps(gifobj->last_call); if(elaps < gifobj->gif->gce.delay * 10) return; gifobj->last_call = lv_tick_get(); int has_next = gd_get_frame(gifobj->gif); if(has_next == 0) { /*It was the last repeat*/ lv_res_t res = lv_event_send(obj, LV_EVENT_READY, NULL); lv_timer_pause(t); if(res != LV_FS_RES_OK) return; } gd_render_frame(gifobj->gif, (uint8_t *)gifobj->imgdsc.data); lv_img_cache_invalidate_src(lv_img_get_src(obj)); lv_obj_invalidate(obj); } #endif /*LV_USE_GIF*/