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