1 /**
2  * @file lv_snapshot.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "../../draw/lv_draw_private.h"
10 #include "../../core/lv_obj_draw_private.h"
11 #include "lv_snapshot.h"
12 #if LV_USE_SNAPSHOT
13 
14 #include <stdbool.h>
15 #include "../../display/lv_display.h"
16 #include "../../core/lv_refr_private.h"
17 #include "../../display/lv_display_private.h"
18 #include "../../stdlib/lv_string.h"
19 
20 /*********************
21  *      DEFINES
22  *********************/
23 
24 /**********************
25  *      TYPEDEFS
26  **********************/
27 
28 /**********************
29  *  STATIC PROTOTYPES
30  **********************/
31 
32 /**********************
33  *  STATIC VARIABLES
34  **********************/
35 
36 /**********************
37  *      MACROS
38  **********************/
39 
40 /**********************
41  *   GLOBAL FUNCTIONS
42  **********************/
43 
44 /**
45  * Create a draw buffer for object to store the snapshot image.
46  */
lv_snapshot_create_draw_buf(lv_obj_t * obj,lv_color_format_t cf)47 lv_draw_buf_t * lv_snapshot_create_draw_buf(lv_obj_t * obj, lv_color_format_t cf)
48 {
49     lv_obj_update_layout(obj);
50     int32_t w = lv_obj_get_width(obj);
51     int32_t h = lv_obj_get_height(obj);
52     int32_t ext_size = lv_obj_get_ext_draw_size(obj);
53     w += ext_size * 2;
54     h += ext_size * 2;
55     if(w == 0 || h == 0) return NULL;
56 
57     return lv_draw_buf_create(w, h, cf, LV_STRIDE_AUTO);
58 }
59 
lv_snapshot_reshape_draw_buf(lv_obj_t * obj,lv_draw_buf_t * draw_buf)60 lv_result_t lv_snapshot_reshape_draw_buf(lv_obj_t * obj, lv_draw_buf_t * draw_buf)
61 {
62     lv_obj_update_layout(obj);
63     int32_t w = lv_obj_get_width(obj);
64     int32_t h = lv_obj_get_height(obj);
65     int32_t ext_size = lv_obj_get_ext_draw_size(obj);
66     w += ext_size * 2;
67     h += ext_size * 2;
68     if(w == 0 || h == 0) return LV_RESULT_INVALID;
69 
70     draw_buf = lv_draw_buf_reshape(draw_buf, LV_COLOR_FORMAT_UNKNOWN, w, h, LV_STRIDE_AUTO);
71     return draw_buf == NULL ? LV_RESULT_INVALID : LV_RESULT_OK;
72 }
73 
lv_snapshot_take_to_draw_buf(lv_obj_t * obj,lv_color_format_t cf,lv_draw_buf_t * draw_buf)74 lv_result_t lv_snapshot_take_to_draw_buf(lv_obj_t * obj, lv_color_format_t cf, lv_draw_buf_t * draw_buf)
75 {
76     LV_ASSERT_NULL(obj);
77     LV_ASSERT_NULL(draw_buf);
78     lv_result_t res;
79 
80     switch(cf) {
81         case LV_COLOR_FORMAT_RGB565:
82         case LV_COLOR_FORMAT_ARGB8565:
83         case LV_COLOR_FORMAT_RGB888:
84         case LV_COLOR_FORMAT_XRGB8888:
85         case LV_COLOR_FORMAT_ARGB8888:
86         case LV_COLOR_FORMAT_A8:
87         case LV_COLOR_FORMAT_L8:
88         case LV_COLOR_FORMAT_I1:
89         case LV_COLOR_FORMAT_ARGB2222:
90         case LV_COLOR_FORMAT_ARGB4444:
91         case LV_COLOR_FORMAT_ARGB1555:
92             break;
93         default:
94             LV_LOG_WARN("Not supported color format");
95             return LV_RESULT_INVALID;
96     }
97 
98     res = lv_snapshot_reshape_draw_buf(obj, draw_buf);
99     if(res != LV_RESULT_OK) return res;
100 
101     /* clear draw buffer*/
102     lv_draw_buf_clear(draw_buf, NULL);
103 
104     lv_area_t snapshot_area;
105     int32_t w = draw_buf->header.w;
106     int32_t h = draw_buf->header.h;
107     int32_t ext_size = lv_obj_get_ext_draw_size(obj);
108     lv_obj_get_coords(obj, &snapshot_area);
109     lv_area_increase(&snapshot_area, ext_size, ext_size);
110 
111     lv_layer_t layer;
112     lv_layer_init(&layer);
113 
114     layer.draw_buf = draw_buf;
115     layer.buf_area.x1 = snapshot_area.x1;
116     layer.buf_area.y1 = snapshot_area.y1;
117     layer.buf_area.x2 = snapshot_area.x1 + w - 1;
118     layer.buf_area.y2 = snapshot_area.y1 + h - 1;
119     layer.color_format = cf;
120     layer._clip_area = snapshot_area;
121     layer.phy_clip_area = snapshot_area;
122 
123     lv_display_t * disp_old = lv_refr_get_disp_refreshing();
124     lv_display_t * disp_new = lv_obj_get_display(obj);
125     lv_layer_t * layer_old = disp_new->layer_head;
126     disp_new->layer_head = &layer;
127 
128     lv_refr_set_disp_refreshing(disp_new);
129     lv_obj_redraw(&layer, obj);
130 
131     while(layer.draw_task_head) {
132         lv_draw_dispatch_wait_for_request();
133         lv_draw_dispatch();
134     }
135 
136     disp_new->layer_head = layer_old;
137     lv_refr_set_disp_refreshing(disp_old);
138 
139     return LV_RESULT_OK;
140 }
141 
lv_snapshot_take(lv_obj_t * obj,lv_color_format_t cf)142 lv_draw_buf_t * lv_snapshot_take(lv_obj_t * obj, lv_color_format_t cf)
143 {
144     LV_ASSERT_NULL(obj);
145     lv_draw_buf_t * draw_buf = lv_snapshot_create_draw_buf(obj, cf);
146     if(draw_buf == NULL) return NULL;
147 
148     if(lv_snapshot_take_to_draw_buf(obj, cf, draw_buf) != LV_RESULT_OK) {
149         lv_draw_buf_destroy(draw_buf);
150         return NULL;
151     }
152 
153     return draw_buf;
154 }
155 
lv_snapshot_free(lv_image_dsc_t * dsc)156 void lv_snapshot_free(lv_image_dsc_t * dsc)
157 {
158     LV_LOG_WARN("Deprecated API, use lv_draw_buf_destroy directly.");
159     lv_draw_buf_destroy((lv_draw_buf_t *)dsc);
160 }
161 
lv_snapshot_take_to_buf(lv_obj_t * obj,lv_color_format_t cf,lv_image_dsc_t * dsc,void * buf,uint32_t buf_size)162 lv_result_t lv_snapshot_take_to_buf(lv_obj_t * obj, lv_color_format_t cf, lv_image_dsc_t * dsc,
163                                     void * buf,
164                                     uint32_t buf_size)
165 {
166     lv_draw_buf_t draw_buf;
167     LV_LOG_WARN("Deprecated API, use lv_snapshot_take_to_draw_buf instead.");
168     lv_draw_buf_init(&draw_buf, 1, 1, cf, buf_size, buf, buf_size);
169     lv_result_t res = lv_snapshot_take_to_draw_buf(obj, cf, &draw_buf);
170     if(res == LV_RESULT_OK) {
171         lv_memcpy((void *)dsc, &draw_buf, sizeof(lv_image_dsc_t));
172     }
173     return res;
174 }
175 
176 /**********************
177  *   STATIC FUNCTIONS
178  **********************/
179 
180 #endif /*LV_USE_SNAPSHOT*/
181