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