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_misc/lv_log.h"
12
13 /*********************
14 * DEFINES
15 *********************/
16
17 /**********************
18 * TYPEDEFS
19 **********************/
20
21 /**********************
22 * STATIC PROTOTYPES
23 **********************/
24 static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, const void * src,
25 const lv_style_t * style, lv_opa_t opa_scale);
26
27 /**********************
28 * STATIC VARIABLES
29 **********************/
30
31 /**********************
32 * MACROS
33 **********************/
34
35 /**********************
36 * GLOBAL FUNCTIONS
37 **********************/
38
39 /**
40 * Draw an image
41 * @param coords the coordinates of the image
42 * @param mask the image will be drawn only in this area
43 * @param src pointer to a lv_color_t array which contains the pixels of the image
44 * @param style style of the image
45 * @param opa_scale scale down all opacities by the factor
46 */
lv_draw_img(const lv_area_t * coords,const lv_area_t * mask,const void * src,const lv_style_t * style,lv_opa_t opa_scale)47 void lv_draw_img(const lv_area_t * coords, const lv_area_t * mask, const void * src, const lv_style_t * style,
48 lv_opa_t opa_scale)
49 {
50 if(src == NULL) {
51 LV_LOG_WARN("Image draw: src is NULL");
52 lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER);
53 lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, "No\ndata", LV_TXT_FLAG_NONE, NULL, -1, -1, NULL);
54 return;
55 }
56
57 lv_res_t res;
58 res = lv_img_draw_core(coords, mask, src, style, opa_scale);
59
60 if(res == LV_RES_INV) {
61 LV_LOG_WARN("Image draw error");
62 lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER);
63 lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, "No\ndata", LV_TXT_FLAG_NONE, NULL, -1, -1, NULL);
64 return;
65 }
66 }
67
68 /**
69 * Get the color of an image's pixel
70 * @param dsc an image descriptor
71 * @param x x coordinate of the point to get
72 * @param y x coordinate of the point to get
73 * @param style style of the image. In case of `LV_IMG_CF_ALPHA_1/2/4/8` `style->image.color` shows
74 * the color. Can be `NULL` but for `ALPHA` images black will be returned. In other cases it is not
75 * used.
76 * @return color of the point
77 */
lv_img_buf_get_px_color(lv_img_dsc_t * dsc,lv_coord_t x,lv_coord_t y,const lv_style_t * style)78 lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, const lv_style_t * style)
79 {
80 lv_color_t p_color = LV_COLOR_BLACK;
81 if(x >= dsc->header.w) {
82 x = dsc->header.w - 1;
83 LV_LOG_WARN("lv_canvas_get_px: x is too large (out of canvas)");
84 } else if(x < 0) {
85 x = 0;
86 LV_LOG_WARN("lv_canvas_get_px: x is < 0 (out of canvas)");
87 }
88
89 if(y >= dsc->header.h) {
90 y = dsc->header.h - 1;
91 LV_LOG_WARN("lv_canvas_get_px: y is too large (out of canvas)");
92 } else if(y < 0) {
93 y = 0;
94 LV_LOG_WARN("lv_canvas_get_px: y is < 0 (out of canvas)");
95 }
96
97 uint8_t * buf_u8 = (uint8_t *)dsc->data;
98
99 if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED ||
100 dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
101 uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf) >> 3;
102 uint32_t px = dsc->header.w * y * px_size + x * px_size;
103 memcpy(&p_color, &buf_u8[px], sizeof(lv_color_t));
104 #if LV_COLOR_SIZE == 32
105 p_color.ch.alpha = 0xFF; /*Only the color should be get so use a deafult alpha value*/
106 #endif
107 } else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT) {
108 buf_u8 += 4 * 2;
109 uint8_t bit = x & 0x7;
110 x = x >> 3;
111
112 /* Get the current pixel.
113 * dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
114 * so the possible real width are 8, 16, 24 ...*/
115 uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
116 p_color.full = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit);
117 } else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) {
118 buf_u8 += 4 * 4;
119 uint8_t bit = (x & 0x3) * 2;
120 x = x >> 2;
121
122 /* Get the current pixel.
123 * dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned
124 * so the possible real width are 4, 8, 12 ...*/
125 uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
126 p_color.full = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit);
127 } else if(dsc->header.cf == LV_IMG_CF_INDEXED_4BIT) {
128 buf_u8 += 4 * 16;
129 uint8_t bit = (x & 0x1) * 4;
130 x = x >> 1;
131
132 /* Get the current pixel.
133 * dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned
134 * so the possible real width are 2, 4, 6 ...*/
135 uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
136 p_color.full = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit);
137 } else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
138 buf_u8 += 4 * 256;
139 uint32_t px = dsc->header.w * y + x;
140 p_color.full = buf_u8[px];
141 } else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || dsc->header.cf == LV_IMG_CF_ALPHA_2BIT ||
142 dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
143 if(style)
144 p_color = style->image.color;
145 else
146 p_color = LV_COLOR_BLACK;
147 }
148 return p_color;
149 }
150
151 /**
152 * Get the alpha value of an image's pixel
153 * @param dsc pointer to an image descriptor
154 * @param x x coordinate of the point to set
155 * @param y x coordinate of the point to set
156 * @return alpha value of the point
157 */
lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc,lv_coord_t x,lv_coord_t y)158 lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y)
159 {
160 if(x >= dsc->header.w) {
161 x = dsc->header.w - 1;
162 LV_LOG_WARN("lv_canvas_get_px: x is too large (out of canvas)");
163 } else if(x < 0) {
164 x = 0;
165 LV_LOG_WARN("lv_canvas_get_px: x is < 0 (out of canvas)");
166 }
167
168 if(y >= dsc->header.h) {
169 y = dsc->header.h - 1;
170 LV_LOG_WARN("lv_canvas_get_px: y is too large (out of canvas)");
171 } else if(y < 0) {
172 y = 0;
173 LV_LOG_WARN("lv_canvas_get_px: y is < 0 (out of canvas)");
174 }
175
176 uint8_t * buf_u8 = (uint8_t *)dsc->data;
177
178 if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
179 uint32_t px = dsc->header.w * y * LV_IMG_PX_SIZE_ALPHA_BYTE + x * LV_IMG_PX_SIZE_ALPHA_BYTE;
180 return buf_u8[px + LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
181 } else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT) {
182 uint8_t bit = x & 0x7;
183 x = x >> 3;
184
185 /* Get the current pixel.
186 * dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
187 * so the possible real width are 8 ,16, 24 ...*/
188 uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
189 uint8_t px_opa = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit);
190 return px_opa ? LV_OPA_TRANSP : LV_OPA_COVER;
191 } else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) {
192 const uint8_t opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
193
194 uint8_t bit = (x & 0x3) * 2;
195 x = x >> 2;
196
197 /* Get the current pixel.
198 * dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned
199 * so the possible real width are 4 ,8, 12 ...*/
200 uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
201 uint8_t px_opa = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit);
202 return opa_table[px_opa];
203 } else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) {
204 const uint8_t opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
205 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255};
206
207 uint8_t bit = (x & 0x1) * 4;
208 x = x >> 1;
209
210 /* Get the current pixel.
211 * dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned
212 * so the possible real width are 2 ,4, 6 ...*/
213 uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
214 uint8_t px_opa = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit);
215 return opa_table[px_opa];
216 } else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
217 uint32_t px = dsc->header.w * y + x;
218 return buf_u8[px];
219 }
220
221 return LV_OPA_COVER;
222 }
223
224 /**
225 * Set the color of a pixel of an image. The alpha channel won't be affected.
226 * @param dsc pointer to an image descriptor
227 * @param x x coordinate of the point to set
228 * @param y x coordinate of the point to set
229 * @param c color of the point
230 */
lv_img_buf_set_px_color(lv_img_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_color_t c)231 void lv_img_buf_set_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t c)
232 {
233 uint8_t * buf_u8 = (uint8_t *)dsc->data;
234
235 if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
236 uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf) >> 3;
237 uint32_t px = dsc->header.w * y * px_size + x * px_size;
238 memcpy(&buf_u8[px], &c, px_size);
239 } else if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
240 uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf) >> 3;
241 uint32_t px = dsc->header.w * y * px_size + x * px_size;
242 memcpy(&buf_u8[px], &c, px_size - 1); /*-1 to not overwrite the alpha value*/
243 } else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT) {
244 buf_u8 += sizeof(lv_color32_t) * 2; /*Skip the palette*/
245
246 uint8_t bit = x & 0x7;
247 x = x >> 3;
248
249 /* Get the current pixel.
250 * dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
251 * so the possible real width are 8 ,16, 24 ...*/
252 uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
253 buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit));
254 buf_u8[px] = buf_u8[px] | ((c.full & 0x1) << (7 - bit));
255 } else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) {
256 buf_u8 += sizeof(lv_color32_t) * 4; /*Skip the palette*/
257 uint8_t bit = (x & 0x3) * 2;
258 x = x >> 2;
259
260 /* Get the current pixel.
261 * dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned
262 * so the possible real width are 4, 8 ,12 ...*/
263 uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
264
265 buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit));
266 buf_u8[px] = buf_u8[px] | ((c.full & 0x3) << (6 - bit));
267 } else if(dsc->header.cf == LV_IMG_CF_INDEXED_4BIT) {
268 buf_u8 += sizeof(lv_color32_t) * 16; /*Skip the palette*/
269 uint8_t bit = (x & 0x1) * 4;
270 x = x >> 1;
271
272 /* Get the current pixel.
273 * dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned
274 * so the possible real width are 2 ,4, 6 ...*/
275 uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
276 buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit));
277 buf_u8[px] = buf_u8[px] | ((c.full & 0xF) << (4 - bit));
278 } else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
279 buf_u8 += sizeof(lv_color32_t) * 256; /*Skip the palette*/
280 uint32_t px = dsc->header.w * y + x;
281 buf_u8[px] = c.full;
282 }
283 }
284
285 /**
286 * Set the alpha value of a pixel of an image. The color won't be affected
287 * @param dsc pointer to an image descriptor
288 * @param x x coordinate of the point to set
289 * @param y x coordinate of the point to set
290 * @param opa the desired opacity
291 */
lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_opa_t opa)292 void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_opa_t opa)
293 {
294 uint8_t * buf_u8 = (uint8_t *)dsc->data;
295
296 if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
297 uint8_t px_size = lv_img_color_format_get_px_size(dsc->header.cf) >> 3;
298 uint32_t px = dsc->header.w * y * px_size + x * px_size;
299 buf_u8[px + px_size - 1] = opa;
300 } else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT) {
301 opa = opa >> 7; /*opa -> [0,1]*/
302 uint8_t bit = x & 0x7;
303 x = x >> 3;
304
305 /* Get the current pixel.
306 * dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
307 * so the possible real width are 8 ,16, 24 ...*/
308 uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
309 buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit));
310 buf_u8[px] = buf_u8[px] | ((opa & 0x1) << (7 - bit));
311 } else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) {
312 opa = opa >> 6; /*opa -> [0,3]*/
313 uint8_t bit = (x & 0x3) * 2;
314 x = x >> 2;
315
316 /* Get the current pixel.
317 * dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned
318 * so the possible real width are 4 ,8, 12 ...*/
319 uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
320 buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit));
321 buf_u8[px] = buf_u8[px] | ((opa & 0x3) << (6 - bit));
322 } else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) {
323 opa = opa >> 4; /*opa -> [0,15]*/
324 uint8_t bit = (x & 0x1) * 4;
325 x = x >> 1;
326
327 /* Get the current pixel.
328 * dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned
329 * so the possible real width are 2 ,4, 6 ...*/
330 uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
331 buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit));
332 buf_u8[px] = buf_u8[px] | ((opa & 0xF) << (4 - bit));
333 } else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
334 uint32_t px = dsc->header.w * y + x;
335 buf_u8[px] = opa;
336 }
337 }
338
339 /**
340 * Set the palette color of an indexed image. Valid only for `LV_IMG_CF_INDEXED1/2/4/8`
341 * @param dsc pointer to an image descriptor
342 * @param id the palette color to set:
343 * - for `LV_IMG_CF_INDEXED1`: 0..1
344 * - for `LV_IMG_CF_INDEXED2`: 0..3
345 * - for `LV_IMG_CF_INDEXED4`: 0..15
346 * - for `LV_IMG_CF_INDEXED8`: 0..255
347 * @param c the color to set
348 */
lv_img_buf_set_palette(lv_img_dsc_t * dsc,uint8_t id,lv_color_t c)349 void lv_img_buf_set_palette(lv_img_dsc_t * dsc, uint8_t id, lv_color_t c)
350 {
351 if((dsc->header.cf == LV_IMG_CF_ALPHA_1BIT && id > 1) || (dsc->header.cf == LV_IMG_CF_ALPHA_2BIT && id > 3) ||
352 (dsc->header.cf == LV_IMG_CF_ALPHA_4BIT && id > 15) || (dsc->header.cf == LV_IMG_CF_ALPHA_8BIT)) {
353 LV_LOG_WARN("lv_img_buf_set_px_alpha: invalid 'id'");
354 return;
355 }
356
357 lv_color32_t c32;
358 c32.full = lv_color_to32(c);
359 uint8_t * buf = (uint8_t *)dsc->data;
360 memcpy(&buf[id * sizeof(c32)], &c32, sizeof(c32));
361 }
362
363 /**
364 * Get the pixel size of a color format in bits
365 * @param cf a color format (`LV_IMG_CF_...`)
366 * @return the pixel size in bits
367 */
lv_img_color_format_get_px_size(lv_img_cf_t cf)368 uint8_t lv_img_color_format_get_px_size(lv_img_cf_t cf)
369 {
370 uint8_t px_size = 0;
371
372 switch(cf) {
373 case LV_IMG_CF_UNKNOWN:
374 case LV_IMG_CF_RAW: px_size = 0; break;
375 case LV_IMG_CF_TRUE_COLOR:
376 case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED: px_size = LV_COLOR_SIZE; break;
377 case LV_IMG_CF_TRUE_COLOR_ALPHA: px_size = LV_IMG_PX_SIZE_ALPHA_BYTE << 3; break;
378 case LV_IMG_CF_INDEXED_1BIT:
379 case LV_IMG_CF_ALPHA_1BIT: px_size = 1; break;
380 case LV_IMG_CF_INDEXED_2BIT:
381 case LV_IMG_CF_ALPHA_2BIT: px_size = 2; break;
382 case LV_IMG_CF_INDEXED_4BIT:
383 case LV_IMG_CF_ALPHA_4BIT: px_size = 4; break;
384 case LV_IMG_CF_INDEXED_8BIT:
385 case LV_IMG_CF_ALPHA_8BIT: px_size = 8; break;
386 default: px_size = 0; break;
387 }
388
389 return px_size;
390 }
391
392 /**
393 * Check if a color format is chroma keyed or not
394 * @param cf a color format (`LV_IMG_CF_...`)
395 * @return true: chroma keyed; false: not chroma keyed
396 */
lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf)397 bool lv_img_color_format_is_chroma_keyed(lv_img_cf_t cf)
398 {
399 bool is_chroma_keyed = false;
400
401 switch(cf) {
402 case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
403 case LV_IMG_CF_RAW_CHROMA_KEYED:
404 case LV_IMG_CF_INDEXED_1BIT:
405 case LV_IMG_CF_INDEXED_2BIT:
406 case LV_IMG_CF_INDEXED_4BIT:
407 case LV_IMG_CF_INDEXED_8BIT: is_chroma_keyed = true; break;
408 default: is_chroma_keyed = false; break;
409 }
410
411 return is_chroma_keyed;
412 }
413
414 /**
415 * Check if a color format has alpha channel or not
416 * @param cf a color format (`LV_IMG_CF_...`)
417 * @return true: has alpha channel; false: doesn't have alpha channel
418 */
lv_img_color_format_has_alpha(lv_img_cf_t cf)419 bool lv_img_color_format_has_alpha(lv_img_cf_t cf)
420 {
421 bool has_alpha = false;
422
423 switch(cf) {
424 case LV_IMG_CF_TRUE_COLOR_ALPHA:
425 case LV_IMG_CF_RAW_ALPHA:
426 case LV_IMG_CF_ALPHA_1BIT:
427 case LV_IMG_CF_ALPHA_2BIT:
428 case LV_IMG_CF_ALPHA_4BIT:
429 case LV_IMG_CF_ALPHA_8BIT: has_alpha = true; break;
430 default: has_alpha = false; break;
431 }
432
433 return has_alpha;
434 }
435
436 /**
437 * Get the type of an image source
438 * @param src pointer to an image source:
439 * - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code)
440 * - a path to a file (e.g. "S:/folder/image.bin")
441 * - or a symbol (e.g. LV_SYMBOL_CLOSE)
442 * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKNOWN
443 */
lv_img_src_get_type(const void * src)444 lv_img_src_t lv_img_src_get_type(const void * src)
445 {
446 lv_img_src_t img_src_type = LV_IMG_SRC_UNKNOWN;
447
448 if(src == NULL) return img_src_type;
449 const uint8_t * u8_p = src;
450
451 /*The first byte shows the type of the image source*/
452 if(u8_p[0] >= 0x20 && u8_p[0] <= 0x7F) {
453 img_src_type = LV_IMG_SRC_FILE; /*If it's an ASCII character then it's file name*/
454 } else if(u8_p[0] >= 0x80) {
455 img_src_type = LV_IMG_SRC_SYMBOL; /*Symbols begins after 0x7F*/
456 } else {
457 img_src_type = LV_IMG_SRC_VARIABLE; /*`lv_img_dsc_t` is design to the first byte < 0x20*/
458 }
459
460 if(LV_IMG_SRC_UNKNOWN == img_src_type) {
461 LV_LOG_WARN("lv_img_src_get_type: unknown image type");
462 }
463
464 return img_src_type;
465 }
466
467 /**********************
468 * STATIC FUNCTIONS
469 **********************/
470
lv_img_draw_core(const lv_area_t * coords,const lv_area_t * mask,const void * src,const lv_style_t * style,lv_opa_t opa_scale)471 static lv_res_t lv_img_draw_core(const lv_area_t * coords, const lv_area_t * mask, const void * src,
472 const lv_style_t * style, lv_opa_t opa_scale)
473 {
474
475 lv_area_t mask_com; /*Common area of mask and coords*/
476 bool union_ok;
477 union_ok = lv_area_intersect(&mask_com, mask, coords);
478 if(union_ok == false) {
479 return LV_RES_OK; /*Out of mask. There is nothing to draw so the image is drawn
480 successfully.*/
481 }
482
483 lv_opa_t opa =
484 opa_scale == LV_OPA_COVER ? style->image.opa : (uint16_t)((uint16_t)style->image.opa * opa_scale) >> 8;
485
486 lv_img_cache_entry_t * cdsc = lv_img_cache_open(src, style);
487
488 if(cdsc == NULL) return LV_RES_INV;
489
490 bool chroma_keyed = lv_img_color_format_is_chroma_keyed(cdsc->dec_dsc.header.cf);
491 bool alpha_byte = lv_img_color_format_has_alpha(cdsc->dec_dsc.header.cf);
492
493 if(cdsc->dec_dsc.error_msg != NULL) {
494 LV_LOG_WARN("Image draw error");
495 lv_draw_rect(coords, mask, &lv_style_plain, LV_OPA_COVER);
496 lv_draw_label(coords, mask, &lv_style_plain, LV_OPA_COVER, cdsc->dec_dsc.error_msg, LV_TXT_FLAG_NONE, NULL, -1,
497 -1, NULL);
498 }
499 /* The decoder open could open the image and gave the entire uncompressed image.
500 * Just draw it!*/
501 else if(cdsc->dec_dsc.img_data) {
502 lv_draw_map(coords, mask, cdsc->dec_dsc.img_data, opa, chroma_keyed, alpha_byte, style->image.color,
503 style->image.intense);
504 }
505 /* The whole uncompressed image is not available. Try to read it line-by-line*/
506 else {
507 lv_coord_t width = lv_area_get_width(&mask_com);
508
509 uint8_t * buf = lv_draw_get_buf(lv_area_get_width(&mask_com) * ((LV_COLOR_DEPTH >> 3) + 1)); /*+1 because of the possible alpha byte*/
510
511 lv_area_t line;
512 lv_area_copy(&line, &mask_com);
513 lv_area_set_height(&line, 1);
514 lv_coord_t x = mask_com.x1 - coords->x1;
515 lv_coord_t y = mask_com.y1 - coords->y1;
516 lv_coord_t row;
517 lv_res_t read_res;
518 for(row = mask_com.y1; row <= mask_com.y2; row++) {
519 read_res = lv_img_decoder_read_line(&cdsc->dec_dsc, x, y, width, buf);
520 if(read_res != LV_RES_OK) {
521 lv_img_decoder_close(&cdsc->dec_dsc);
522 LV_LOG_WARN("Image draw can't read the line");
523 return LV_RES_INV;
524 }
525 lv_draw_map(&line, mask, buf, opa, chroma_keyed, alpha_byte, style->image.color, style->image.intense);
526 line.y1++;
527 line.y2++;
528 y++;
529 }
530 }
531
532 return LV_RES_OK;
533 }
534