1 /**
2  * @file lv_draw_img.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_draw_img.h"
10 #include "lv_img_cache.h"
11 #include "../lv_hal/lv_hal_disp.h"
12 #include "../lv_misc/lv_log.h"
13 #include "../lv_core/lv_refr.h"
14 #include "../lv_misc/lv_mem.h"
15 #include "../lv_misc/lv_math.h"
16 #include "../lv_gpu/lv_gpu_stm32_dma2d.h"
17 
18 
19 /*********************
20  *      DEFINES
21  *********************/
22 
23 /**********************
24  *      TYPEDEFS
25  **********************/
26 
27 /**********************
28  *  STATIC PROTOTYPES
29  **********************/
30 LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * clip_area,
31                                                        const void * src,
32                                                        const lv_draw_img_dsc_t * draw_dsc);
33 
34 LV_ATTRIBUTE_FAST_MEM static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area,
35                                               const uint8_t * map_p,
36                                               const lv_draw_img_dsc_t * draw_dsc,
37                                               bool chroma_key, bool alpha_byte);
38 
39 static void show_error(const lv_area_t * coords, const lv_area_t * clip_area, const char * msg);
40 
41 /**********************
42  *  STATIC VARIABLES
43  **********************/
44 
45 /**********************
46  *      MACROS
47  **********************/
48 
49 /**********************
50  *   GLOBAL FUNCTIONS
51  **********************/
52 
lv_draw_img_dsc_init(lv_draw_img_dsc_t * dsc)53 void lv_draw_img_dsc_init(lv_draw_img_dsc_t * dsc)
54 {
55     _lv_memset_00(dsc, sizeof(lv_draw_img_dsc_t));
56     dsc->recolor = LV_COLOR_BLACK;
57     dsc->opa = LV_OPA_COVER;
58     dsc->zoom = LV_IMG_ZOOM_NONE;
59     dsc->antialias = LV_ANTIALIAS;
60 
61 }
62 
63 /**
64  * Draw an image
65  * @param coords the coordinates of the image
66  * @param mask the image will be drawn only in this area
67  * @param src pointer to a lv_color_t array which contains the pixels of the image
68  * @param dsc pointer to an initialized `lv_draw_img_dsc_t` variable
69  */
lv_draw_img(const lv_area_t * coords,const lv_area_t * mask,const void * src,const lv_draw_img_dsc_t * dsc)70 void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * src, const lv_draw_img_dsc_t * dsc)
71 {
72     if(src == NULL) {
73         LV_LOG_WARN("Image draw: src is NULL");
74         show_error(coords, mask, "No\ndata");
75         return;
76     }
77 
78     if(dsc->opa <= LV_OPA_MIN) return;
79 
80     lv_res_t res;
81     res = lv_img_draw_core(coords, mask, src, dsc);
82 
83     if(res == LV_RES_INV) {
84         LV_LOG_WARN("Image draw error");
85         show_error(coords, mask, "No\ndata");
86         return;
87     }
88 }
89 
90 /**
91  * Get the pixel size of a color format in bits
92  * @param cf a color format (`LV_IMG_CF_...`)
93  * @return the pixel size in bits
94  */
lv_img_cf_get_px_size(lv_img_cf_t cf)95 uint8_t lv_img_cf_get_px_size(lv_img_cf_t cf)
96 {
97     uint8_t px_size = 0;
98 
99     switch(cf) {
100         case LV_IMG_CF_UNKNOWN:
101         case LV_IMG_CF_RAW:
102             px_size = 0;
103             break;
104         case LV_IMG_CF_TRUE_COLOR:
105         case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
106             px_size = LV_COLOR_SIZE;
107             break;
108         case LV_IMG_CF_TRUE_COLOR_ALPHA:
109             px_size = LV_IMG_PX_SIZE_ALPHA_BYTE << 3;
110             break;
111         case LV_IMG_CF_INDEXED_1BIT:
112         case LV_IMG_CF_ALPHA_1BIT:
113             px_size = 1;
114             break;
115         case LV_IMG_CF_INDEXED_2BIT:
116         case LV_IMG_CF_ALPHA_2BIT:
117             px_size = 2;
118             break;
119         case LV_IMG_CF_INDEXED_4BIT:
120         case LV_IMG_CF_ALPHA_4BIT:
121             px_size = 4;
122             break;
123         case LV_IMG_CF_INDEXED_8BIT:
124         case LV_IMG_CF_ALPHA_8BIT:
125             px_size = 8;
126             break;
127         default:
128             px_size = 0;
129             break;
130     }
131 
132     return px_size;
133 }
134 
135 /**
136  * Check if a color format is chroma keyed or not
137  * @param cf a color format (`LV_IMG_CF_...`)
138  * @return true: chroma keyed; false: not chroma keyed
139  */
lv_img_cf_is_chroma_keyed(lv_img_cf_t cf)140 bool lv_img_cf_is_chroma_keyed(lv_img_cf_t cf)
141 {
142     bool is_chroma_keyed = false;
143 
144     switch(cf) {
145         case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
146         case LV_IMG_CF_RAW_CHROMA_KEYED:
147         case LV_IMG_CF_INDEXED_1BIT:
148         case LV_IMG_CF_INDEXED_2BIT:
149         case LV_IMG_CF_INDEXED_4BIT:
150         case LV_IMG_CF_INDEXED_8BIT:
151             is_chroma_keyed = true;
152             break;
153 
154         default:
155             is_chroma_keyed = false;
156             break;
157     }
158 
159     return is_chroma_keyed;
160 }
161 
162 /**
163  * Check if a color format has alpha channel or not
164  * @param cf a color format (`LV_IMG_CF_...`)
165  * @return true: has alpha channel; false: doesn't have alpha channel
166  */
lv_img_cf_has_alpha(lv_img_cf_t cf)167 bool lv_img_cf_has_alpha(lv_img_cf_t cf)
168 {
169     bool has_alpha = false;
170 
171     switch(cf) {
172         case LV_IMG_CF_TRUE_COLOR_ALPHA:
173         case LV_IMG_CF_RAW_ALPHA:
174         case LV_IMG_CF_INDEXED_1BIT:
175         case LV_IMG_CF_INDEXED_2BIT:
176         case LV_IMG_CF_INDEXED_4BIT:
177         case LV_IMG_CF_INDEXED_8BIT:
178         case LV_IMG_CF_ALPHA_1BIT:
179         case LV_IMG_CF_ALPHA_2BIT:
180         case LV_IMG_CF_ALPHA_4BIT:
181         case LV_IMG_CF_ALPHA_8BIT:
182             has_alpha = true;
183             break;
184         default:
185             has_alpha = false;
186             break;
187     }
188 
189     return has_alpha;
190 }
191 
192 /**
193  * Get the type of an image source
194  * @param src pointer to an image source:
195  *  - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code)
196  *  - a path to a file (e.g. "S:/folder/image.bin")
197  *  - or a symbol (e.g. LV_SYMBOL_CLOSE)
198  * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKNOWN
199  */
lv_img_src_get_type(const void * src)200 lv_img_src_t lv_img_src_get_type(const void * src)
201 {
202     lv_img_src_t img_src_type = LV_IMG_SRC_UNKNOWN;
203 
204     if(src == NULL) return img_src_type;
205     const uint8_t * u8_p = src;
206 
207     /*The first byte shows the type of the image source*/
208     if(u8_p[0] >= 0x20 && u8_p[0] <= 0x7F) {
209         img_src_type = LV_IMG_SRC_FILE; /*If it's an ASCII character then it's file name*/
210     }
211     else if(u8_p[0] >= 0x80) {
212         img_src_type = LV_IMG_SRC_SYMBOL; /*Symbols begins after 0x7F*/
213     }
214     else {
215         img_src_type = LV_IMG_SRC_VARIABLE; /*`lv_img_dsc_t` is design to the first byte < 0x20*/
216     }
217 
218     if(LV_IMG_SRC_UNKNOWN == img_src_type) {
219         LV_LOG_WARN("lv_img_src_get_type: unknown image type");
220     }
221 
222     return img_src_type;
223 }
224 
225 /**********************
226  *   STATIC FUNCTIONS
227  **********************/
228 
lv_img_draw_core(const lv_area_t * coords,const lv_area_t * clip_area,const void * src,const lv_draw_img_dsc_t * draw_dsc)229 LV_ATTRIBUTE_FAST_MEM static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * clip_area,
230                                                        const void * src,
231                                                        const lv_draw_img_dsc_t * draw_dsc)
232 {
233     if(draw_dsc->opa <= LV_OPA_MIN) return LV_RES_OK;
234 
235     lv_img_cache_entry_t * cdsc = _lv_img_cache_open(src, draw_dsc->recolor);
236 
237     if(cdsc == NULL) return LV_RES_INV;
238 
239     bool chroma_keyed = lv_img_cf_is_chroma_keyed(cdsc->dec_dsc.header.cf);
240     bool alpha_byte   = lv_img_cf_has_alpha(cdsc->dec_dsc.header.cf);
241 
242     if(cdsc->dec_dsc.error_msg != NULL) {
243         LV_LOG_WARN("Image draw error");
244 
245         show_error(coords, clip_area, cdsc->dec_dsc.error_msg);
246     }
247     /* The decoder could open the image and gave the entire uncompressed image.
248      * Just draw it!*/
249     else if(cdsc->dec_dsc.img_data) {
250         lv_area_t map_area_rot;
251         lv_area_copy(&map_area_rot, coords);
252         if(draw_dsc->angle || draw_dsc->zoom != LV_IMG_ZOOM_NONE) {
253             int32_t w = lv_area_get_width(coords);
254             int32_t h = lv_area_get_height(coords);
255 
256             _lv_img_buf_get_transformed_area(&map_area_rot, w, h, draw_dsc->angle, draw_dsc->zoom, &draw_dsc->pivot);
257 
258             map_area_rot.x1 += coords->x1;
259             map_area_rot.y1 += coords->y1;
260             map_area_rot.x2 += coords->x1;
261             map_area_rot.y2 += coords->y1;
262         }
263 
264         lv_area_t mask_com; /*Common area of mask and coords*/
265         bool union_ok;
266         union_ok = _lv_area_intersect(&mask_com, clip_area, &map_area_rot);
267         if(union_ok == false) {
268             return LV_RES_OK; /*Out of mask. There is nothing to draw so the image is drawn
269                                  successfully.*/
270         }
271 
272         lv_draw_map(coords, &mask_com, cdsc->dec_dsc.img_data, draw_dsc, chroma_keyed, alpha_byte);
273     }
274     /* The whole uncompressed image is not available. Try to read it line-by-line*/
275     else {
276         lv_area_t mask_com; /*Common area of mask and coords*/
277         bool union_ok;
278         union_ok = _lv_area_intersect(&mask_com, clip_area, coords);
279         if(union_ok == false) {
280             return LV_RES_OK; /*Out of mask. There is nothing to draw so the image is drawn
281                                  successfully.*/
282         }
283 
284         int32_t width = lv_area_get_width(&mask_com);
285 
286         uint8_t  * buf = _lv_mem_buf_get(lv_area_get_width(&mask_com) *
287                                          LV_IMG_PX_SIZE_ALPHA_BYTE);  /*+1 because of the possible alpha byte*/
288 
289         lv_area_t line;
290         lv_area_copy(&line, &mask_com);
291         lv_area_set_height(&line, 1);
292         int32_t x = mask_com.x1 - coords->x1;
293         int32_t y = mask_com.y1 - coords->y1;
294         int32_t row;
295         lv_res_t read_res;
296         for(row = mask_com.y1; row <= mask_com.y2; row++) {
297             lv_area_t mask_line;
298             union_ok = _lv_area_intersect(&mask_line, clip_area, &line);
299             if(union_ok == false) continue;
300 
301             read_res = lv_img_decoder_read_line(&cdsc->dec_dsc, x, y, width, buf);
302             if(read_res != LV_RES_OK) {
303                 lv_img_decoder_close(&cdsc->dec_dsc);
304                 LV_LOG_WARN("Image draw can't read the line");
305                 _lv_mem_buf_release(buf);
306                 return LV_RES_INV;
307             }
308 
309 
310             lv_draw_map(&line, &mask_line, buf, draw_dsc, chroma_keyed, alpha_byte);
311             line.y1++;
312             line.y2++;
313             y++;
314         }
315         _lv_mem_buf_release(buf);
316     }
317 
318     return LV_RES_OK;
319 }
320 
321 /**
322  * Draw a color map to the display (image)
323  * @param cords_p coordinates the color map
324  * @param mask_p the map will drawn only on this area  (truncated to VDB area)
325  * @param map_p pointer to a lv_color_t array
326  * @param draw_dsc pointer to an initialized `lv_draw_img_dsc_t` variable
327  * @param chroma_keyed true: enable transparency of LV_IMG_LV_COLOR_TRANSP color pixels
328  * @param alpha_byte true: extra alpha byte is inserted for every pixel
329  */
lv_draw_map(const lv_area_t * map_area,const lv_area_t * clip_area,const uint8_t * map_p,const lv_draw_img_dsc_t * draw_dsc,bool chroma_key,bool alpha_byte)330 LV_ATTRIBUTE_FAST_MEM static void lv_draw_map(const lv_area_t * map_area, const lv_area_t * clip_area,
331                                               const uint8_t * map_p,
332                                               const lv_draw_img_dsc_t * draw_dsc,
333                                               bool chroma_key, bool alpha_byte)
334 {
335     /* Use the clip area as draw area*/
336     lv_area_t draw_area;
337     lv_area_copy(&draw_area, clip_area);
338 
339     lv_disp_t * disp    = _lv_refr_get_disp_refreshing();
340     lv_disp_buf_t * vdb = lv_disp_get_buf(disp);
341     const lv_area_t * disp_area = &vdb->area;
342 
343     /* Now `draw_area` has absolute coordinates.
344      * Make it relative to `disp_area` to simplify draw to `disp_buf`*/
345     draw_area.x1 -= disp_area->x1;
346     draw_area.y1 -= disp_area->y1;
347     draw_area.x2 -= disp_area->x1;
348     draw_area.y2 -= disp_area->y1;
349 
350     uint8_t other_mask_cnt = lv_draw_mask_get_cnt();
351 
352     /*The simplest case just copy the pixels into the VDB*/
353     if(other_mask_cnt == 0 && draw_dsc->angle == 0 && draw_dsc->zoom == LV_IMG_ZOOM_NONE &&
354        chroma_key == false && alpha_byte == false && draw_dsc->recolor_opa == LV_OPA_TRANSP) {
355         _lv_blend_map(clip_area, map_area, (lv_color_t *)map_p, NULL, LV_DRAW_MASK_RES_FULL_COVER, draw_dsc->opa,
356                       draw_dsc->blend_mode);
357     }
358     /*In the other cases every pixel need to be checked one-by-one*/
359     else {
360         /*The pixel size in byte is different if an alpha byte is added too*/
361         uint8_t px_size_byte = alpha_byte ? LV_IMG_PX_SIZE_ALPHA_BYTE : sizeof(lv_color_t);
362 
363         /*Go to the first displayed pixel of the map*/
364         int32_t map_w = lv_area_get_width(map_area);
365         const uint8_t * map_buf_tmp = map_p;
366         map_buf_tmp += map_w * (draw_area.y1 - (map_area->y1 - disp_area->y1)) * px_size_byte;
367         map_buf_tmp += (draw_area.x1 - (map_area->x1 - disp_area->x1)) * px_size_byte;
368 
369         lv_color_t c;
370         lv_color_t chroma_keyed_color = LV_COLOR_TRANSP;
371         uint32_t px_i = 0;
372 
373         const uint8_t * map_px;
374 
375         lv_area_t blend_area;
376         blend_area.x1 = draw_area.x1 + disp_area->x1;
377         blend_area.x2 = blend_area.x1 + lv_area_get_width(&draw_area) - 1;
378         blend_area.y1 = disp_area->y1 + draw_area.y1;
379         blend_area.y2 = blend_area.y1;
380 
381         lv_coord_t draw_area_h = lv_area_get_height(&draw_area);
382         lv_coord_t draw_area_w = lv_area_get_width(&draw_area);
383 
384 #if LV_USE_IMG_TRANSFORM
385         bool transform = draw_dsc->angle != 0 || draw_dsc->zoom != LV_IMG_ZOOM_NONE ? true : false;
386 #else
387         bool transform = false;
388 #endif
389         /*Simple ARGB image. Handle it as special case because it's very common*/
390         if(other_mask_cnt == 0 && !transform && !chroma_key && draw_dsc->recolor_opa == LV_OPA_TRANSP && alpha_byte) {
391 #if LV_USE_GPU_STM32_DMA2D && LV_COLOR_DEPTH == 32
392             /*Blend ARGB images directly*/
393             if(lv_area_get_size(&draw_area) > 240) {
394                 int32_t disp_w = lv_area_get_width(disp_area);
395                 lv_color_t * disp_buf = vdb->buf_act;
396                 lv_color_t * disp_buf_first = disp_buf + disp_w * draw_area.y1 + draw_area.x1;
397                 lv_gpu_stm32_dma2d_blend(disp_buf_first, disp_w, (const lv_color_t *)map_buf_tmp, draw_dsc->opa, map_w, draw_area_w,
398                                          draw_area_h);
399                 return;
400             }
401 #endif
402             uint32_t mask_buf_size = lv_area_get_size(&draw_area) > LV_HOR_RES_MAX ? LV_HOR_RES_MAX : lv_area_get_size(&draw_area);
403             lv_color_t * map2 = _lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
404             lv_opa_t * mask_buf = _lv_mem_buf_get(mask_buf_size);
405 
406             int32_t x;
407             int32_t y;
408             for(y = 0; y < draw_area_h; y++) {
409                 map_px = map_buf_tmp;
410                 for(x = 0; x < draw_area_w; x++, map_px += px_size_byte, px_i++) {
411                     lv_opa_t px_opa = map_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
412                     mask_buf[px_i] = px_opa;
413                     if(px_opa) {
414 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
415                         map2[px_i].full =  map_px[0];
416 #elif LV_COLOR_DEPTH == 16
417                         map2[px_i].full =  map_px[0] + (map_px[1] << 8);
418 #elif LV_COLOR_DEPTH == 32
419                         map2[px_i].full =  *((uint32_t *)map_px);
420 #endif
421                     }
422 #if LV_COLOR_DEPTH == 32
423                     map2[px_i].ch.alpha = 0xFF;
424 #endif
425                 }
426 
427                 map_buf_tmp += map_w * px_size_byte;
428                 if(px_i + lv_area_get_width(&draw_area) < mask_buf_size) {
429                     blend_area.y2 ++;
430                 }
431                 else {
432                     _lv_blend_map(clip_area, &blend_area, map2, mask_buf, LV_DRAW_MASK_RES_CHANGED, draw_dsc->opa, draw_dsc->blend_mode);
433 
434                     blend_area.y1 = blend_area.y2 + 1;
435                     blend_area.y2 = blend_area.y1;
436 
437                     px_i = 0;
438                 }
439             }
440             /*Flush the last part*/
441             if(blend_area.y1 != blend_area.y2) {
442                 blend_area.y2--;
443                 _lv_blend_map(clip_area, &blend_area, map2, mask_buf, LV_DRAW_MASK_RES_CHANGED, draw_dsc->opa, draw_dsc->blend_mode);
444             }
445 
446             _lv_mem_buf_release(mask_buf);
447             _lv_mem_buf_release(map2);
448         }
449         /*Most complicated case: transform or other mask or chroma keyed*/
450         else {
451             /*Build the image and a mask line-by-line*/
452             uint32_t mask_buf_size = lv_area_get_size(&draw_area) > LV_HOR_RES_MAX ? LV_HOR_RES_MAX : lv_area_get_size(&draw_area);
453             lv_color_t * map2 = _lv_mem_buf_get(mask_buf_size * sizeof(lv_color_t));
454             lv_opa_t * mask_buf = _lv_mem_buf_get(mask_buf_size);
455 
456 #if LV_USE_IMG_TRANSFORM
457             lv_img_transform_dsc_t trans_dsc;
458             _lv_memset_00(&trans_dsc, sizeof(lv_img_transform_dsc_t));
459             if(transform) {
460                 lv_img_cf_t cf = LV_IMG_CF_TRUE_COLOR;
461                 if(alpha_byte) cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
462                 else if(chroma_key) cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED;
463 
464                 trans_dsc.cfg.angle = draw_dsc->angle;
465                 trans_dsc.cfg.zoom = draw_dsc->zoom;
466                 trans_dsc.cfg.src = map_p;
467                 trans_dsc.cfg.src_w = map_w;
468                 trans_dsc.cfg.src_h = lv_area_get_height(map_area);;
469                 trans_dsc.cfg.cf = cf;
470                 trans_dsc.cfg.pivot_x = draw_dsc->pivot.x;
471                 trans_dsc.cfg.pivot_y = draw_dsc->pivot.y;
472                 trans_dsc.cfg.color = draw_dsc->recolor;
473                 trans_dsc.cfg.antialias = draw_dsc->antialias;
474 
475                 _lv_img_buf_transform_init(&trans_dsc);
476             }
477 #endif
478             uint16_t recolor_premult[3] = {0};
479             lv_opa_t recolor_opa_inv = 255 - draw_dsc->recolor_opa;
480             if(draw_dsc->recolor_opa != 0) {
481                 lv_color_premult(draw_dsc->recolor, draw_dsc->recolor_opa, recolor_premult);
482             }
483 
484             lv_draw_mask_res_t mask_res;
485             mask_res = (alpha_byte || chroma_key || draw_dsc->angle ||
486                         draw_dsc->zoom != LV_IMG_ZOOM_NONE) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
487 
488 
489             /*Prepare the `mask_buf`if there are other masks*/
490             if(other_mask_cnt) {
491                 _lv_memset_ff(mask_buf, mask_buf_size);
492             }
493 
494             int32_t x;
495             int32_t y;
496 #if LV_USE_IMG_TRANSFORM
497             int32_t rot_y = disp_area->y1 + draw_area.y1 - map_area->y1;
498 #endif
499             for(y = 0; y < draw_area_h; y++) {
500                 map_px = map_buf_tmp;
501                 uint32_t px_i_start = px_i;
502 
503 #if LV_USE_IMG_TRANSFORM
504                 int32_t rot_x = disp_area->x1 + draw_area.x1 - map_area->x1;
505 #endif
506                 for(x = 0; x < draw_area_w; x++, map_px += px_size_byte, px_i++) {
507 
508 
509 #if LV_USE_IMG_TRANSFORM
510                     if(transform) {
511 
512                         /*Transform*/
513                         bool ret;
514                         ret = _lv_img_buf_transform(&trans_dsc, rot_x + x, rot_y + y);
515                         if(ret == false) {
516                             mask_buf[px_i] = LV_OPA_TRANSP;
517                             continue;
518                         }
519                         else {
520                             mask_buf[px_i] = trans_dsc.res.opa;
521                             c.full = trans_dsc.res.color.full;
522                         }
523                     }
524                     /*No transform*/
525                     else
526 #endif
527                     {
528                         if(alpha_byte) {
529                             lv_opa_t px_opa = map_px[LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
530                             mask_buf[px_i] = px_opa;
531                             if(px_opa == 0) {
532 #if  LV_COLOR_DEPTH == 32
533                                 map2[px_i].full = 0;
534 #endif
535                                 continue;
536                             }
537                         }
538                         else {
539                             mask_buf[px_i] = 0xFF;
540                         }
541 
542 #if LV_COLOR_DEPTH == 1
543                         c.full = map_px[0];
544 #elif LV_COLOR_DEPTH == 8
545                         c.full =  map_px[0];
546 #elif LV_COLOR_DEPTH == 16
547                         c.full =  map_px[0] + (map_px[1] << 8);
548 #elif LV_COLOR_DEPTH == 32
549                         c.full =  *((uint32_t *)map_px);
550                         c.ch.alpha = 0xFF;
551 #endif
552                         if(chroma_key) {
553                             if(c.full == chroma_keyed_color.full) {
554                                 mask_buf[px_i] = LV_OPA_TRANSP;
555 #if  LV_COLOR_DEPTH == 32
556                                 map2[px_i].full = 0;
557 #endif
558                                 continue;
559                             }
560                         }
561                     }
562 
563                     if(draw_dsc->recolor_opa != 0) {
564                         c = lv_color_mix_premult(recolor_premult, c, recolor_opa_inv);
565                     }
566 
567                     map2[px_i].full = c.full;
568                 }
569 
570                 /*Apply the masks if any*/
571                 if(other_mask_cnt) {
572                     lv_draw_mask_res_t mask_res_sub;
573                     mask_res_sub = lv_draw_mask_apply(mask_buf + px_i_start, draw_area.x1 + vdb->area.x1, y + draw_area.y1 + vdb->area.y1,
574                                                       lv_area_get_width(&draw_area));
575                     if(mask_res_sub == LV_DRAW_MASK_RES_TRANSP) {
576                         _lv_memset_00(mask_buf + px_i_start, lv_area_get_width(&draw_area));
577                         mask_res = LV_DRAW_MASK_RES_CHANGED;
578                     }
579                     else if(mask_res_sub == LV_DRAW_MASK_RES_CHANGED) {
580                         mask_res = LV_DRAW_MASK_RES_CHANGED;
581                     }
582                 }
583 
584                 map_buf_tmp += map_w * px_size_byte;
585                 if(px_i + lv_area_get_width(&draw_area) < mask_buf_size) {
586                     blend_area.y2 ++;
587                 }
588                 else {
589 
590                     _lv_blend_map(clip_area, &blend_area, map2, mask_buf, mask_res, draw_dsc->opa, draw_dsc->blend_mode);
591 
592                     blend_area.y1 = blend_area.y2 + 1;
593                     blend_area.y2 = blend_area.y1;
594 
595                     px_i = 0;
596                     mask_res = (alpha_byte || chroma_key || draw_dsc->angle ||
597                                 draw_dsc->zoom != LV_IMG_ZOOM_NONE) ? LV_DRAW_MASK_RES_CHANGED : LV_DRAW_MASK_RES_FULL_COVER;
598 
599                     /*Prepare the `mask_buf`if there are other masks*/
600                     if(other_mask_cnt) {
601                         _lv_memset_ff(mask_buf, mask_buf_size);
602                     }
603                 }
604             }
605 
606             /*Flush the last part*/
607             if(blend_area.y1 != blend_area.y2) {
608                 blend_area.y2--;
609                 _lv_blend_map(clip_area, &blend_area, map2, mask_buf, mask_res, draw_dsc->opa, draw_dsc->blend_mode);
610             }
611 
612             _lv_mem_buf_release(mask_buf);
613             _lv_mem_buf_release(map2);
614         }
615     }
616 }
617 
show_error(const lv_area_t * coords,const lv_area_t * clip_area,const char * msg)618 static void show_error(const lv_area_t * coords, const lv_area_t * clip_area, const char * msg)
619 {
620     lv_draw_rect_dsc_t rect_dsc;
621     lv_draw_rect_dsc_init(&rect_dsc);
622     rect_dsc.bg_color = LV_COLOR_WHITE;
623     lv_draw_rect(coords, clip_area, &rect_dsc);
624 
625     lv_draw_label_dsc_t label_dsc;
626     lv_draw_label_dsc_init(&label_dsc);
627     lv_draw_label(coords, clip_area, &label_dsc, msg, NULL);
628 }
629 
630