1 /**
2 * @file lv_draw_img.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_draw_sw.h"
10 #include "../lv_img_cache.h"
11 #include "../../hal/lv_hal_disp.h"
12 #include "../../misc/lv_log.h"
13 #include "../../core/lv_refr.h"
14 #include "../../misc/lv_mem.h"
15 #include "../../misc/lv_math.h"
16
17 /*********************
18 * DEFINES
19 *********************/
20
21 /**********************
22 * TYPEDEFS
23 **********************/
24
25 /**********************
26 * STATIC PROTOTYPES
27 **********************/
28
29 /**********************
30 * STATIC VARIABLES
31 **********************/
32
33 /**********************
34 * MACROS
35 **********************/
36
37 /**********************
38 * GLOBAL FUNCTIONS
39 **********************/
40
lv_draw_sw_img_decoded(struct _lv_draw_ctx_t * draw_ctx,const lv_draw_img_dsc_t * draw_dsc,const lv_area_t * coords,const uint8_t * src_buf,lv_img_cf_t cf)41 LV_ATTRIBUTE_FAST_MEM void lv_draw_sw_img_decoded(struct _lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc,
42 const lv_area_t * coords, const uint8_t * src_buf, lv_img_cf_t cf)
43 {
44 /*Use the clip area as draw area*/
45 lv_area_t draw_area;
46 lv_area_copy(&draw_area, draw_ctx->clip_area);
47
48 bool mask_any = lv_draw_mask_is_any(&draw_area);
49
50 lv_draw_sw_blend_dsc_t blend_dsc;
51 lv_memset_00(&blend_dsc, sizeof(blend_dsc));
52 blend_dsc.opa = draw_dsc->opa;
53 blend_dsc.blend_mode = draw_dsc->blend_mode;
54
55 /*The simplest case just copy the pixels into the draw_buf*/
56 if(!mask_any && draw_dsc->angle == 0 && draw_dsc->zoom == LV_IMG_ZOOM_NONE &&
57 cf == LV_IMG_CF_TRUE_COLOR && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
58 blend_dsc.blend_area = coords;
59 blend_dsc.src_buf = (const lv_color_t *)src_buf;
60 lv_draw_sw_blend(draw_ctx, &blend_dsc);
61 }
62 /*In the other cases every pixel need to be checked one-by-one*/
63 else {
64 //#if LV_DRAW_COMPLEX
65 /*The pixel size in byte is different if an alpha byte is added too*/
66 uint8_t px_size_byte = cf == LV_IMG_CF_TRUE_COLOR_ALPHA ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t);
67
68 /*Go to the first displayed pixel of the map*/
69 int32_t src_stride = lv_area_get_width(coords);
70
71 lv_color_t c;
72 lv_color_t chroma_keyed_color = LV_COLOR_CHROMA_KEY;
73 uint32_t px_i = 0;
74
75 const uint8_t * map_px;
76
77 lv_coord_t draw_area_h = lv_area_get_height(&draw_area);
78 lv_coord_t draw_area_w = lv_area_get_width(&draw_area);
79
80 lv_area_t blend_area;
81 blend_area.x1 = draw_area.x1;
82 blend_area.x2 = draw_area.x2;
83 blend_area.y1 = draw_area.y1;
84 blend_area.y2 = blend_area.y1;
85 blend_dsc.blend_area = &blend_area;
86
87 bool transform = draw_dsc->angle != 0 || draw_dsc->zoom != LV_IMG_ZOOM_NONE ? true : false;
88 /*Simple ARGB image. Handle it as special case because it's very common*/
89 if(!mask_any && !transform && cf == LV_IMG_CF_TRUE_COLOR_ALPHA && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
90 uint32_t hor_res = (uint32_t) lv_disp_get_hor_res(_lv_refr_get_disp_refreshing());
91 uint32_t mask_buf_size = lv_area_get_size(&draw_area) > (uint32_t) hor_res ? hor_res : lv_area_get_size(&draw_area);
92 lv_color_t * src_buf_rgb = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
93 lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
94 blend_dsc.mask_buf = mask_buf;
95 blend_dsc.mask_area = &blend_area;
96 blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
97 blend_dsc.src_buf = src_buf_rgb;
98
99 const uint8_t * src_buf_tmp = src_buf;
100 src_buf_tmp += src_stride * (draw_area.y1 - coords->y1) * px_size_byte;
101 src_buf_tmp += (draw_area.x1 - coords->x1) * px_size_byte;
102
103 int32_t x;
104 int32_t y;
105 for(y = 0; y < draw_area_h; y++) {
106 map_px = src_buf_tmp;
107 for(x = 0; x < draw_area_w; x++, map_px += px_size_byte, px_i++) {
108 lv_opa_t px_opa = map_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
109 mask_buf[px_i] = px_opa;
110 if(px_opa) {
111 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
112 src_buf_rgb[px_i].full = map_px[0];
113 #elif LV_COLOR_DEPTH == 16
114 src_buf_rgb[px_i].full = map_px[0] + (map_px[1] << 8);
115 #elif LV_COLOR_DEPTH == 32
116 src_buf_rgb[px_i].full = *((uint32_t *)map_px);
117 #endif
118 }
119 #if LV_COLOR_DEPTH == 32
120 src_buf_rgb[px_i].ch.alpha = 0xFF;
121 #endif
122 }
123
124 src_buf_tmp += src_stride * px_size_byte;
125 if(px_i + draw_area_w <= mask_buf_size) {
126 blend_area.y2 ++;
127 }
128 else {
129 lv_draw_sw_blend(draw_ctx, &blend_dsc);
130
131 blend_area.y1 = blend_area.y2 + 1;
132 blend_area.y2 = blend_area.y1;
133
134 px_i = 0;
135 }
136 }
137 /*Flush the last part*/
138 if(blend_area.y1 != blend_area.y2) {
139 blend_area.y2--;
140 lv_draw_sw_blend(draw_ctx, &blend_dsc);
141 }
142
143 lv_mem_buf_release(mask_buf);
144 lv_mem_buf_release(src_buf_rgb);
145 }
146 /*Most complicated case: transform or other mask or chroma keyed*/
147 else {
148 /*Build the image and a mask line-by-line*/
149 uint32_t hor_res = (uint32_t) lv_disp_get_hor_res(_lv_refr_get_disp_refreshing());
150 uint32_t mask_buf_size = lv_area_get_size(&draw_area) > hor_res ? hor_res : lv_area_get_size(&draw_area);
151 lv_color_t * src_buf_rgb = lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
152 lv_opa_t * mask_buf = lv_mem_buf_get(mask_buf_size);
153 blend_dsc.mask_buf = mask_buf;
154 blend_dsc.mask_area = &blend_area;
155 blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
156 blend_dsc.src_buf = src_buf_rgb;
157
158 const uint8_t * src_buf_tmp = NULL;
159 #if LV_DRAW_COMPLEX
160 lv_img_transform_dsc_t trans_dsc;
161 lv_memset_00(&trans_dsc, sizeof(lv_img_transform_dsc_t));
162 if(transform) {
163 trans_dsc.cfg.angle = draw_dsc->angle;
164 trans_dsc.cfg.zoom = draw_dsc->zoom;
165 trans_dsc.cfg.src = src_buf;
166 trans_dsc.cfg.src_w = src_stride;
167 trans_dsc.cfg.src_h = lv_area_get_height(coords);
168 trans_dsc.cfg.cf = cf;
169 trans_dsc.cfg.pivot_x = draw_dsc->pivot.x;
170 trans_dsc.cfg.pivot_y = draw_dsc->pivot.y;
171 trans_dsc.cfg.color = draw_dsc->recolor;
172 trans_dsc.cfg.antialias = draw_dsc->antialias;
173
174 _lv_img_buf_transform_init(&trans_dsc);
175 }
176 else {
177 src_buf_tmp = src_buf;
178 src_buf_tmp += src_stride * (draw_area.y1 - coords->y1) * px_size_byte;
179 src_buf_tmp += (draw_area.x1 - coords->x1) * px_size_byte;
180 }
181 #endif
182 uint16_t recolor_premult[3] = {0};
183 lv_opa_t recolor_opa_inv = 255 - draw_dsc->recolor_opa;
184 if(draw_dsc->recolor_opa != 0) {
185 lv_color_premult(draw_dsc->recolor, draw_dsc->recolor_opa, recolor_premult);
186 }
187
188 blend_dsc.mask_res = (cf != LV_IMG_CF_TRUE_COLOR || draw_dsc->angle ||
189 draw_dsc->zoom != LV_IMG_ZOOM_NONE) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
190
191 /*Prepare the `mask_buf`if there are other masks*/
192 if(mask_any) {
193 lv_memset_ff(mask_buf, mask_buf_size);
194 }
195
196 int32_t x;
197 int32_t y;
198 #if LV_DRAW_COMPLEX
199 int32_t rot_y = blend_area.y1 - coords->y1;
200 #endif
201 for(y = 0; y < draw_area_h; y++) {
202 map_px = src_buf_tmp;
203 #if LV_DRAW_COMPLEX
204 uint32_t px_i_start = px_i;
205 int32_t rot_x = blend_area.x1 - coords->x1;
206 #endif
207
208 for(x = 0; x < draw_area_w; x++, px_i++, map_px += px_size_byte) {
209
210 #if LV_DRAW_COMPLEX
211 if(transform) {
212
213 /*Transform*/
214 bool ret;
215 ret = _lv_img_buf_transform(&trans_dsc, rot_x + x, rot_y + y);
216 if(ret == false) {
217 mask_buf[px_i] = LV_OPA_TRANSP;
218 continue;
219 }
220 else {
221 mask_buf[px_i] = trans_dsc.res.opa;
222 c.full = trans_dsc.res.color.full;
223 }
224 }
225 /*No transform*/
226 else
227 #endif
228 {
229 if(cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
230 lv_opa_t px_opa = map_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
231 mask_buf[px_i] = px_opa;
232 if(px_opa == 0) {
233 #if LV_COLOR_DEPTH == 32
234 src_buf_rgb[px_i].full = 0;
235 #endif
236 continue;
237 }
238 }
239 else {
240 mask_buf[px_i] = 0xFF;
241 }
242
243 #if LV_COLOR_DEPTH == 1
244 c.full = map_px[0];
245 #elif LV_COLOR_DEPTH == 8
246 c.full = map_px[0];
247 #elif LV_COLOR_DEPTH == 16
248 c.full = map_px[0] + (map_px[1] << 8);
249 #elif LV_COLOR_DEPTH == 32
250 c.full = *((uint32_t *)map_px);
251 c.ch.alpha = 0xFF;
252 #endif
253 if(cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
254 if(c.full == chroma_keyed_color.full) {
255 mask_buf[px_i] = LV_OPA_TRANSP;
256 #if LV_COLOR_DEPTH == 32
257 src_buf_rgb[px_i].full = 0;
258 #endif
259 continue;
260 }
261 }
262
263 }
264 if(draw_dsc->recolor_opa != 0) {
265 c = lv_color_mix_premult(recolor_premult, c, recolor_opa_inv);
266 }
267
268 src_buf_rgb[px_i].full = c.full;
269 }
270 #if LV_DRAW_COMPLEX
271 /*Apply the masks if any*/
272 if(mask_any) {
273 lv_draw_mask_res_t mask_res_sub;
274 mask_res_sub = lv_draw_mask_apply(mask_buf + px_i_start, blend_area.x1,
275 y + draw_area.y1, draw_area_w);
276 if(mask_res_sub == LV_DRAW_MASK_RES_TRANSP) {
277 lv_memset_00(mask_buf + px_i_start, draw_area_w);
278 blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
279 }
280 else if(mask_res_sub == LV_DRAW_MASK_RES_CHANGED) {
281 blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
282 }
283 }
284 #endif
285
286 src_buf_tmp += src_stride * px_size_byte;
287 if(px_i + draw_area_w < mask_buf_size) {
288 blend_area.y2 ++;
289 }
290 else {
291 lv_draw_sw_blend(draw_ctx, &blend_dsc);
292
293 blend_area.y1 = blend_area.y2 + 1;
294 blend_area.y2 = blend_area.y1;
295
296 px_i = 0;
297 blend_dsc.mask_res = (cf != LV_IMG_CF_TRUE_COLOR || draw_dsc->angle ||
298 draw_dsc->zoom != LV_IMG_ZOOM_NONE) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
299
300 /*Prepare the `mask_buf`if there are other masks*/
301 if(mask_any) {
302 lv_memset_ff(mask_buf, mask_buf_size);
303 }
304 }
305 }
306
307 /*Flush the last part*/
308 if(blend_area.y1 != blend_area.y2) {
309 blend_area.y2--;
310 lv_draw_sw_blend(draw_ctx, &blend_dsc);
311 }
312
313 lv_mem_buf_release(mask_buf);
314 lv_mem_buf_release(src_buf_rgb);
315 }
316 }
317 }
318
319 /**********************
320 * STATIC FUNCTIONS
321 **********************/
322