1 /**
2  * @file lv_snapshot.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_snapshot.h"
10 #if LV_USE_SNAPSHOT
11 
12 #include <stdbool.h>
13 #include "../../../core/lv_disp.h"
14 #include "../../../core/lv_refr.h"
15 /*********************
16  *      DEFINES
17  *********************/
18 
19 /**********************
20  *      TYPEDEFS
21  **********************/
22 
23 /**********************
24  *  STATIC PROTOTYPES
25  **********************/
26 
27 /**********************
28  *  STATIC VARIABLES
29  **********************/
30 
31 /**********************
32  *      MACROS
33  **********************/
34 
35 /**********************
36  *   GLOBAL FUNCTIONS
37  **********************/
38 
39 /** Get the buffer needed for object snapshot image.
40  *
41  * @param obj    The object to generate snapshot.
42  * @param cf     color format for generated image.
43  *
44  * @return the buffer size needed in bytes
45  */
lv_snapshot_buf_size_needed(lv_obj_t * obj,lv_img_cf_t cf)46 uint32_t lv_snapshot_buf_size_needed(lv_obj_t * obj, lv_img_cf_t cf)
47 {
48     LV_ASSERT_NULL(obj);
49     switch(cf) {
50         case LV_IMG_CF_TRUE_COLOR:
51         case LV_IMG_CF_TRUE_COLOR_ALPHA:
52         case LV_IMG_CF_ALPHA_1BIT:
53         case LV_IMG_CF_ALPHA_2BIT:
54         case LV_IMG_CF_ALPHA_4BIT:
55         case LV_IMG_CF_ALPHA_8BIT:
56             break;
57         default:
58             return 0;
59     }
60 
61     lv_obj_update_layout(obj);
62 
63     /*Width and height determine snapshot image size.*/
64     lv_coord_t w = lv_obj_get_width(obj);
65     lv_coord_t h = lv_obj_get_height(obj);
66     lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj);
67     w += ext_size * 2;
68     h += ext_size * 2;
69 
70     uint8_t px_size = lv_img_cf_get_px_size(cf);
71     return w * h * ((px_size + 7) >> 3);
72 }
73 
74 /** Take snapshot for object with its children, save image info to provided buffer.
75  *
76  * @param obj      The object to generate snapshot.
77  * @param cf       color format for generated image.
78  * @param dsc      image descriptor to store the image result.
79  * @param buf      the buffer to store image data.
80  * @param buf_size provided buffer size in bytes.
81  *
82  * @return LV_RES_OK on success, LV_RES_INV on error.
83  */
lv_snapshot_take_to_buf(lv_obj_t * obj,lv_img_cf_t cf,lv_img_dsc_t * dsc,void * buf,uint32_t buf_size)84 lv_res_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_img_cf_t cf, lv_img_dsc_t * dsc, void * buf, uint32_t buf_size)
85 {
86     LV_ASSERT_NULL(obj);
87     LV_ASSERT_NULL(dsc);
88     LV_ASSERT_NULL(buf);
89 
90     switch(cf) {
91         case LV_IMG_CF_TRUE_COLOR:
92         case LV_IMG_CF_TRUE_COLOR_ALPHA:
93         case LV_IMG_CF_ALPHA_1BIT:
94         case LV_IMG_CF_ALPHA_2BIT:
95         case LV_IMG_CF_ALPHA_4BIT:
96         case LV_IMG_CF_ALPHA_8BIT:
97             break;
98         default:
99             return LV_RES_INV;
100     }
101 
102     uint32_t buf_size_needed = lv_snapshot_buf_size_needed(obj, cf);
103     if(buf_size_needed == 0 || buf_size < buf_size_needed) return LV_RES_INV;
104 
105     /*Width and height determine snapshot image size.*/
106     lv_coord_t w = lv_obj_get_width(obj);
107     lv_coord_t h = lv_obj_get_height(obj);
108     lv_coord_t ext_size = _lv_obj_get_ext_draw_size(obj);
109     w += ext_size * 2;
110     h += ext_size * 2;
111 
112     lv_area_t snapshot_area;
113     lv_obj_get_coords(obj, &snapshot_area);
114     lv_area_increase(&snapshot_area, ext_size, ext_size);
115 
116     lv_memset(buf, 0x00, buf_size);
117     lv_memset_00(dsc, sizeof(lv_img_dsc_t));
118 
119     lv_disp_t * obj_disp = lv_obj_get_disp(obj);
120     lv_disp_drv_t driver;
121     lv_disp_drv_init(&driver);
122     /*In lack of a better idea use the resolution of the object's display*/
123     driver.hor_res = lv_disp_get_hor_res(obj_disp);
124     driver.ver_res = lv_disp_get_hor_res(obj_disp);
125     lv_disp_drv_use_generic_set_px_cb(&driver, cf);
126 
127     lv_disp_t fake_disp;
128     lv_memset_00(&fake_disp, sizeof(lv_disp_t));
129     fake_disp.driver = &driver;
130 
131     lv_draw_ctx_t * draw_ctx = lv_mem_alloc(obj_disp->driver->draw_ctx_size);
132     LV_ASSERT_MALLOC(draw_ctx);
133     if(draw_ctx == NULL) return LV_RES_INV;
134     obj_disp->driver->draw_ctx_init(fake_disp.driver, draw_ctx);
135     fake_disp.driver->draw_ctx = draw_ctx;
136     draw_ctx->clip_area = &snapshot_area;
137     draw_ctx->buf_area = &snapshot_area;
138     draw_ctx->buf = (void *)buf;
139     driver.draw_ctx = draw_ctx;
140 
141     lv_disp_t * refr_ori = _lv_refr_get_disp_refreshing();
142     _lv_refr_set_disp_refreshing(&fake_disp);
143 
144     lv_obj_redraw(draw_ctx, obj);
145 
146     _lv_refr_set_disp_refreshing(refr_ori);
147     obj_disp->driver->draw_ctx_deinit(fake_disp.driver, draw_ctx);
148     lv_mem_free(draw_ctx);
149 
150     dsc->data = buf;
151     dsc->data_size = buf_size_needed;
152     dsc->header.w = w;
153     dsc->header.h = h;
154     dsc->header.cf = cf;
155     return LV_RES_OK;
156 }
157 
158 /** Take snapshot for object with its children, alloc the memory needed.
159  *
160  * @param obj    The object to generate snapshot.
161  * @param cf     color format for generated image.
162  *
163  * @return a pointer to an image descriptor, or NULL if failed.
164  */
lv_snapshot_take(lv_obj_t * obj,lv_img_cf_t cf)165 lv_img_dsc_t * lv_snapshot_take(lv_obj_t * obj, lv_img_cf_t cf)
166 {
167     LV_ASSERT_NULL(obj);
168     uint32_t buf_size = lv_snapshot_buf_size_needed(obj, cf);
169 
170     void * buf = lv_mem_alloc(buf_size);
171     LV_ASSERT_MALLOC(buf);
172     if(buf == NULL) {
173         return NULL;
174     }
175 
176     lv_img_dsc_t * dsc = lv_mem_alloc(sizeof(lv_img_dsc_t));
177     LV_ASSERT_MALLOC(buf);
178     if(dsc == NULL) {
179         lv_mem_free(buf);
180         return NULL;
181     }
182 
183     if(lv_snapshot_take_to_buf(obj, cf, dsc, buf, buf_size) == LV_RES_INV) {
184         lv_mem_free(buf);
185         lv_mem_free(dsc);
186         return NULL;
187     }
188 
189     return dsc;
190 }
191 
192 /** Free the snapshot image returned by @ref lv_snapshot_take
193  *
194  * It will firstly free the data image takes, then the image descriptor.
195  *
196  * @param dsc    The image descriptor generated by lv_snapshot_take.
197  *
198  */
lv_snapshot_free(lv_img_dsc_t * dsc)199 void lv_snapshot_free(lv_img_dsc_t * dsc)
200 {
201     if(!dsc)
202         return;
203 
204     if(dsc->data)
205         lv_mem_free((void *)dsc->data);
206 
207     lv_mem_free(dsc);
208 }
209 
210 /**********************
211  *   STATIC FUNCTIONS
212  **********************/
213 
214 #endif /*LV_USE_SNAPSHOT*/
215