1 /**
2 * @file lv_img_decoder.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_img_decoder.h"
10 #include "../misc/lv_assert.h"
11 #include "../draw/lv_draw_img.h"
12 #include "../misc/lv_ll.h"
13 #include "../misc/lv_gc.h"
14
15 /*********************
16 * DEFINES
17 *********************/
18 #define CF_BUILT_IN_FIRST LV_IMG_CF_TRUE_COLOR
19 #define CF_BUILT_IN_LAST LV_IMG_CF_RGB565A8
20
21 /**********************
22 * TYPEDEFS
23 **********************/
24
25 typedef struct {
26 lv_fs_file_t f;
27 lv_color_t * palette;
28 lv_opa_t * opa;
29 } lv_img_decoder_built_in_data_t;
30
31 /**********************
32 * STATIC PROTOTYPES
33 **********************/
34 static lv_res_t lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
35 lv_coord_t len, uint8_t * buf);
36 static lv_res_t lv_img_decoder_built_in_line_alpha(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
37 lv_coord_t len, uint8_t * buf);
38 static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
39 lv_coord_t len, uint8_t * buf);
40
41 /**********************
42 * STATIC VARIABLES
43 **********************/
44
45 /**********************
46 * MACROS
47 **********************/
48
49 /**********************
50 * GLOBAL FUNCTIONS
51 **********************/
52
53 /**
54 * Initialize the image decoder module
55 */
_lv_img_decoder_init(void)56 void _lv_img_decoder_init(void)
57 {
58 _lv_ll_init(&LV_GC_ROOT(_lv_img_decoder_ll), sizeof(lv_img_decoder_t));
59
60 lv_img_decoder_t * decoder;
61
62 /*Create a decoder for the built in color format*/
63 decoder = lv_img_decoder_create();
64 LV_ASSERT_MALLOC(decoder);
65 if(decoder == NULL) {
66 LV_LOG_WARN("lv_img_decoder_init: out of memory");
67 return;
68 }
69
70 lv_img_decoder_set_info_cb(decoder, lv_img_decoder_built_in_info);
71 lv_img_decoder_set_open_cb(decoder, lv_img_decoder_built_in_open);
72 lv_img_decoder_set_read_line_cb(decoder, lv_img_decoder_built_in_read_line);
73 lv_img_decoder_set_close_cb(decoder, lv_img_decoder_built_in_close);
74 }
75
76 /**
77 * Get information about an image.
78 * Try the created image decoder one by one. Once one is able to get info that info will be used.
79 * @param src the image source. E.g. file name or variable.
80 * @param header the image info will be stored here
81 * @return LV_RES_OK: success; LV_RES_INV: wasn't able to get info about the image
82 */
lv_img_decoder_get_info(const void * src,lv_img_header_t * header)83 lv_res_t lv_img_decoder_get_info(const void * src, lv_img_header_t * header)
84 {
85 lv_memset_00(header, sizeof(lv_img_header_t));
86
87 if(src == NULL) return LV_RES_INV;
88
89 lv_img_src_t src_type = lv_img_src_get_type(src);
90 if(src_type == LV_IMG_SRC_VARIABLE) {
91 const lv_img_dsc_t * img_dsc = src;
92 if(img_dsc->data == NULL) return LV_RES_INV;
93 }
94
95 lv_res_t res = LV_RES_INV;
96 lv_img_decoder_t * d;
97 _LV_LL_READ(&LV_GC_ROOT(_lv_img_decoder_ll), d) {
98 if(d->info_cb) {
99 res = d->info_cb(d, src, header);
100 if(res == LV_RES_OK) break;
101 }
102 }
103
104 return res;
105 }
106
lv_img_decoder_open(lv_img_decoder_dsc_t * dsc,const void * src,lv_color_t color,int32_t frame_id)107 lv_res_t lv_img_decoder_open(lv_img_decoder_dsc_t * dsc, const void * src, lv_color_t color, int32_t frame_id)
108 {
109 lv_memset_00(dsc, sizeof(lv_img_decoder_dsc_t));
110
111 if(src == NULL) return LV_RES_INV;
112 lv_img_src_t src_type = lv_img_src_get_type(src);
113 if(src_type == LV_IMG_SRC_VARIABLE) {
114 const lv_img_dsc_t * img_dsc = src;
115 if(img_dsc->data == NULL) return LV_RES_INV;
116 }
117
118 dsc->color = color;
119 dsc->src_type = src_type;
120 dsc->frame_id = frame_id;
121
122 if(dsc->src_type == LV_IMG_SRC_FILE) {
123 size_t fnlen = strlen(src);
124 dsc->src = lv_mem_alloc(fnlen + 1);
125 LV_ASSERT_MALLOC(dsc->src);
126 if(dsc->src == NULL) {
127 LV_LOG_WARN("lv_img_decoder_open: out of memory");
128 return LV_RES_INV;
129 }
130 strcpy((char *)dsc->src, src);
131 }
132 else {
133 dsc->src = src;
134 }
135
136 lv_res_t res = LV_RES_INV;
137
138 lv_img_decoder_t * decoder;
139 _LV_LL_READ(&LV_GC_ROOT(_lv_img_decoder_ll), decoder) {
140 /*Info and Open callbacks are required*/
141 if(decoder->info_cb == NULL || decoder->open_cb == NULL) continue;
142
143 res = decoder->info_cb(decoder, src, &dsc->header);
144 if(res != LV_RES_OK) continue;
145
146 dsc->decoder = decoder;
147 res = decoder->open_cb(decoder, dsc);
148
149 /*Opened successfully. It is a good decoder for this image source*/
150 if(res == LV_RES_OK) return res;
151
152 /*Prepare for the next loop*/
153 lv_memset_00(&dsc->header, sizeof(lv_img_header_t));
154
155 dsc->error_msg = NULL;
156 dsc->img_data = NULL;
157 dsc->user_data = NULL;
158 dsc->time_to_open = 0;
159 }
160
161 if(dsc->src_type == LV_IMG_SRC_FILE)
162 lv_mem_free((void *)dsc->src);
163
164 return res;
165 }
166
167 /**
168 * Read a line from an opened image
169 * @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open`
170 * @param x start X coordinate (from left)
171 * @param y start Y coordinate (from top)
172 * @param len number of pixels to read
173 * @param buf store the data here
174 * @return LV_RES_OK: success; LV_RES_INV: an error occurred
175 */
lv_img_decoder_read_line(lv_img_decoder_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_coord_t len,uint8_t * buf)176 lv_res_t lv_img_decoder_read_line(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_coord_t len, uint8_t * buf)
177 {
178 lv_res_t res = LV_RES_INV;
179 if(dsc->decoder->read_line_cb) res = dsc->decoder->read_line_cb(dsc->decoder, dsc, x, y, len, buf);
180
181 return res;
182 }
183
184 /**
185 * Close a decoding session
186 * @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open`
187 */
lv_img_decoder_close(lv_img_decoder_dsc_t * dsc)188 void lv_img_decoder_close(lv_img_decoder_dsc_t * dsc)
189 {
190 if(dsc->decoder) {
191 if(dsc->decoder->close_cb) dsc->decoder->close_cb(dsc->decoder, dsc);
192
193 if(dsc->src_type == LV_IMG_SRC_FILE) {
194 lv_mem_free((void *)dsc->src);
195 dsc->src = NULL;
196 }
197 }
198 }
199
200 /**
201 * Create a new image decoder
202 * @return pointer to the new image decoder
203 */
lv_img_decoder_create(void)204 lv_img_decoder_t * lv_img_decoder_create(void)
205 {
206 lv_img_decoder_t * decoder;
207 decoder = _lv_ll_ins_head(&LV_GC_ROOT(_lv_img_decoder_ll));
208 LV_ASSERT_MALLOC(decoder);
209 if(decoder == NULL) return NULL;
210
211 lv_memset_00(decoder, sizeof(lv_img_decoder_t));
212
213 return decoder;
214 }
215
216 /**
217 * Delete an image decoder
218 * @param decoder pointer to an image decoder
219 */
lv_img_decoder_delete(lv_img_decoder_t * decoder)220 void lv_img_decoder_delete(lv_img_decoder_t * decoder)
221 {
222 _lv_ll_remove(&LV_GC_ROOT(_lv_img_decoder_ll), decoder);
223 lv_mem_free(decoder);
224 }
225
226 /**
227 * Set a callback to get information about the image
228 * @param decoder pointer to an image decoder
229 * @param info_cb a function to collect info about an image (fill an `lv_img_header_t` struct)
230 */
lv_img_decoder_set_info_cb(lv_img_decoder_t * decoder,lv_img_decoder_info_f_t info_cb)231 void lv_img_decoder_set_info_cb(lv_img_decoder_t * decoder, lv_img_decoder_info_f_t info_cb)
232 {
233 decoder->info_cb = info_cb;
234 }
235
236 /**
237 * Set a callback to open an image
238 * @param decoder pointer to an image decoder
239 * @param open_cb a function to open an image
240 */
lv_img_decoder_set_open_cb(lv_img_decoder_t * decoder,lv_img_decoder_open_f_t open_cb)241 void lv_img_decoder_set_open_cb(lv_img_decoder_t * decoder, lv_img_decoder_open_f_t open_cb)
242 {
243 decoder->open_cb = open_cb;
244 }
245
246 /**
247 * Set a callback to a decoded line of an image
248 * @param decoder pointer to an image decoder
249 * @param read_line_cb a function to read a line of an image
250 */
lv_img_decoder_set_read_line_cb(lv_img_decoder_t * decoder,lv_img_decoder_read_line_f_t read_line_cb)251 void lv_img_decoder_set_read_line_cb(lv_img_decoder_t * decoder, lv_img_decoder_read_line_f_t read_line_cb)
252 {
253 decoder->read_line_cb = read_line_cb;
254 }
255
256 /**
257 * Set a callback to close a decoding session. E.g. close files and free other resources.
258 * @param decoder pointer to an image decoder
259 * @param close_cb a function to close a decoding session
260 */
lv_img_decoder_set_close_cb(lv_img_decoder_t * decoder,lv_img_decoder_close_f_t close_cb)261 void lv_img_decoder_set_close_cb(lv_img_decoder_t * decoder, lv_img_decoder_close_f_t close_cb)
262 {
263 decoder->close_cb = close_cb;
264 }
265
266 /**
267 * Get info about a built-in image
268 * @param decoder the decoder where this function belongs
269 * @param src the image source: pointer to an `lv_img_dsc_t` variable, a file path or a symbol
270 * @param header store the image data here
271 * @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error.
272 */
lv_img_decoder_built_in_info(lv_img_decoder_t * decoder,const void * src,lv_img_header_t * header)273 lv_res_t lv_img_decoder_built_in_info(lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
274 {
275 LV_UNUSED(decoder); /*Unused*/
276
277 lv_img_src_t src_type = lv_img_src_get_type(src);
278 if(src_type == LV_IMG_SRC_VARIABLE) {
279 lv_img_cf_t cf = ((lv_img_dsc_t *)src)->header.cf;
280 if(cf < CF_BUILT_IN_FIRST || cf > CF_BUILT_IN_LAST) return LV_RES_INV;
281
282 header->w = ((lv_img_dsc_t *)src)->header.w;
283 header->h = ((lv_img_dsc_t *)src)->header.h;
284 header->cf = ((lv_img_dsc_t *)src)->header.cf;
285 }
286 else if(src_type == LV_IMG_SRC_FILE) {
287 /*Support only "*.bin" files*/
288 if(strcmp(lv_fs_get_ext(src), "bin")) return LV_RES_INV;
289
290 lv_fs_file_t f;
291 lv_fs_res_t res = lv_fs_open(&f, src, LV_FS_MODE_RD);
292 if(res == LV_FS_RES_OK) {
293 uint32_t rn;
294 res = lv_fs_read(&f, header, sizeof(lv_img_header_t), &rn);
295 lv_fs_close(&f);
296 if(res != LV_FS_RES_OK || rn != sizeof(lv_img_header_t)) {
297 LV_LOG_WARN("Image get info get read file header");
298 return LV_RES_INV;
299 }
300 }
301
302 if(header->cf < CF_BUILT_IN_FIRST || header->cf > CF_BUILT_IN_LAST) return LV_RES_INV;
303 }
304 else if(src_type == LV_IMG_SRC_SYMBOL) {
305 /*The size depend on the font but it is unknown here. It should be handled outside of the
306 *function*/
307 header->w = 1;
308 header->h = 1;
309 /*Symbols always have transparent parts. Important because of cover check in the draw
310 *function. The actual value doesn't matter because lv_draw_label will draw it*/
311 header->cf = LV_IMG_CF_ALPHA_1BIT;
312 }
313 else {
314 LV_LOG_WARN("Image get info found unknown src type");
315 return LV_RES_INV;
316 }
317 return LV_RES_OK;
318 }
319
320 /**
321 * Open a built in image
322 * @param decoder the decoder where this function belongs
323 * @param dsc pointer to decoder descriptor. `src`, `color` are already initialized in it.
324 * @return LV_RES_OK: the info is successfully stored in `header`; LV_RES_INV: unknown format or other error.
325 */
lv_img_decoder_built_in_open(lv_img_decoder_t * decoder,lv_img_decoder_dsc_t * dsc)326 lv_res_t lv_img_decoder_built_in_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
327 {
328 /*Open the file if it's a file*/
329 if(dsc->src_type == LV_IMG_SRC_FILE) {
330 /*Support only "*.bin" files*/
331 if(strcmp(lv_fs_get_ext(dsc->src), "bin")) return LV_RES_INV;
332
333 lv_fs_file_t f;
334 lv_fs_res_t res = lv_fs_open(&f, dsc->src, LV_FS_MODE_RD);
335 if(res != LV_FS_RES_OK) {
336 LV_LOG_WARN("Built-in image decoder can't open the file");
337 return LV_RES_INV;
338 }
339
340 /*If the file was open successfully save the file descriptor*/
341 if(dsc->user_data == NULL) {
342 dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t));
343 LV_ASSERT_MALLOC(dsc->user_data);
344 if(dsc->user_data == NULL) {
345 LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
346 lv_fs_close(&f);
347 return LV_RES_INV;
348 }
349 lv_memset_00(dsc->user_data, sizeof(lv_img_decoder_built_in_data_t));
350 }
351
352 lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
353 lv_memcpy_small(&user_data->f, &f, sizeof(f));
354 }
355 else if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
356 /*The variables should have valid data*/
357 if(((lv_img_dsc_t *)dsc->src)->data == NULL) {
358 return LV_RES_INV;
359 }
360 }
361
362 lv_img_cf_t cf = dsc->header.cf;
363 /*Process true color formats*/
364 if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
365 cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED || cf == LV_IMG_CF_RGB565A8 ||
366 cf == LV_IMG_CF_ALPHA_8BIT) {
367 if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
368 /*In case of uncompressed formats the image stored in the ROM/RAM.
369 *So simply give its pointer*/
370 dsc->img_data = ((lv_img_dsc_t *)dsc->src)->data;
371 return LV_RES_OK;
372 }
373 else {
374 /*If it's a file it need to be read line by line later*/
375 return LV_RES_OK;
376 }
377 }
378 /*Process indexed images. Build a palette*/
379 else if(cf == LV_IMG_CF_INDEXED_1BIT || cf == LV_IMG_CF_INDEXED_2BIT || cf == LV_IMG_CF_INDEXED_4BIT ||
380 cf == LV_IMG_CF_INDEXED_8BIT) {
381 uint8_t px_size = lv_img_cf_get_px_size(cf);
382 uint32_t palette_size = 1 << px_size;
383
384 /*Allocate the palette*/
385 if(dsc->user_data == NULL) {
386 dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t));
387 LV_ASSERT_MALLOC(dsc->user_data);
388 if(dsc->user_data == NULL) {
389 LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
390 return LV_RES_INV;
391 }
392 lv_memset_00(dsc->user_data, sizeof(lv_img_decoder_built_in_data_t));
393 }
394
395 lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
396 user_data->palette = lv_mem_alloc(palette_size * sizeof(lv_color_t));
397 LV_ASSERT_MALLOC(user_data->palette);
398 user_data->opa = lv_mem_alloc(palette_size * sizeof(lv_opa_t));
399 LV_ASSERT_MALLOC(user_data->opa);
400 if(user_data->palette == NULL || user_data->opa == NULL) {
401 LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
402 lv_img_decoder_built_in_close(decoder, dsc);
403 return LV_RES_INV;
404 }
405
406 if(dsc->src_type == LV_IMG_SRC_FILE) {
407 /*Read the palette from file*/
408 lv_fs_seek(&user_data->f, 4, LV_FS_SEEK_SET); /*Skip the header*/
409 lv_color32_t cur_color;
410 uint32_t i;
411 for(i = 0; i < palette_size; i++) {
412 lv_fs_read(&user_data->f, &cur_color, sizeof(lv_color32_t), NULL);
413 user_data->palette[i] = lv_color_make(cur_color.ch.red, cur_color.ch.green, cur_color.ch.blue);
414 user_data->opa[i] = cur_color.ch.alpha;
415 }
416 }
417 else {
418 /*The palette begins in the beginning of the image data. Just point to it.*/
419 lv_color32_t * palette_p = (lv_color32_t *)((lv_img_dsc_t *)dsc->src)->data;
420
421 uint32_t i;
422 for(i = 0; i < palette_size; i++) {
423 user_data->palette[i] = lv_color_make(palette_p[i].ch.red, palette_p[i].ch.green, palette_p[i].ch.blue);
424 user_data->opa[i] = palette_p[i].ch.alpha;
425 }
426 }
427
428 return LV_RES_OK;
429 }
430 /*Alpha indexed images.*/
431 else if(cf == LV_IMG_CF_ALPHA_1BIT || cf == LV_IMG_CF_ALPHA_2BIT || cf == LV_IMG_CF_ALPHA_4BIT) {
432 return LV_RES_OK; /*Nothing to process*/
433 }
434 /*Unknown format. Can't decode it.*/
435 else {
436 /*Free the potentially allocated memories*/
437 lv_img_decoder_built_in_close(decoder, dsc);
438
439 LV_LOG_WARN("Image decoder open: unknown color format");
440 return LV_RES_INV;
441 }
442 }
443
444 /**
445 * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
446 * Required only if the "open" function can't return with the whole decoded pixel array.
447 * @param decoder pointer to the decoder the function associated with
448 * @param dsc pointer to decoder descriptor
449 * @param x start x coordinate
450 * @param y start y coordinate
451 * @param len number of pixels to decode
452 * @param buf a buffer to store the decoded pixels
453 * @return LV_RES_OK: ok; LV_RES_INV: failed
454 */
lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder,lv_img_decoder_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_coord_t len,uint8_t * buf)455 lv_res_t lv_img_decoder_built_in_read_line(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc, lv_coord_t x,
456 lv_coord_t y, lv_coord_t len, uint8_t * buf)
457 {
458 LV_UNUSED(decoder); /*Unused*/
459
460 lv_res_t res = LV_RES_INV;
461
462 if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
463 dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
464 /*For TRUE_COLOR images read line required only for files.
465 *For variables the image data was returned in `open`*/
466 if(dsc->src_type == LV_IMG_SRC_FILE) {
467 res = lv_img_decoder_built_in_line_true_color(dsc, x, y, len, buf);
468 }
469 }
470 else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || dsc->header.cf == LV_IMG_CF_ALPHA_2BIT ||
471 dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
472 res = lv_img_decoder_built_in_line_alpha(dsc, x, y, len, buf);
473 }
474 else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT || dsc->header.cf == LV_IMG_CF_INDEXED_2BIT ||
475 dsc->header.cf == LV_IMG_CF_INDEXED_4BIT || dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
476 res = lv_img_decoder_built_in_line_indexed(dsc, x, y, len, buf);
477 }
478 else {
479 LV_LOG_WARN("Built-in image decoder read not supports the color format");
480 return LV_RES_INV;
481 }
482
483 return res;
484 }
485
486 /**
487 * Close the pending decoding. Free resources etc.
488 * @param decoder pointer to the decoder the function associated with
489 * @param dsc pointer to decoder descriptor
490 */
lv_img_decoder_built_in_close(lv_img_decoder_t * decoder,lv_img_decoder_dsc_t * dsc)491 void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
492 {
493 LV_UNUSED(decoder); /*Unused*/
494
495 lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
496 if(user_data) {
497 if(dsc->src_type == LV_IMG_SRC_FILE) {
498 lv_fs_close(&user_data->f);
499 }
500 if(user_data->palette) lv_mem_free(user_data->palette);
501 if(user_data->opa) lv_mem_free(user_data->opa);
502
503 lv_mem_free(user_data);
504 dsc->user_data = NULL;
505 }
506 }
507
508 /**********************
509 * STATIC FUNCTIONS
510 **********************/
511
lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_coord_t len,uint8_t * buf)512 static lv_res_t lv_img_decoder_built_in_line_true_color(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
513 lv_coord_t len, uint8_t * buf)
514 {
515 lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
516 lv_fs_res_t res;
517 uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf);
518
519 uint32_t pos = ((y * dsc->header.w + x) * px_size) >> 3;
520 pos += 4; /*Skip the header*/
521 res = lv_fs_seek(&user_data->f, pos, LV_FS_SEEK_SET);
522 if(res != LV_FS_RES_OK) {
523 LV_LOG_WARN("Built-in image decoder seek failed");
524 return LV_RES_INV;
525 }
526 uint32_t btr = len * (px_size >> 3);
527 uint32_t br = 0;
528 res = lv_fs_read(&user_data->f, buf, btr, &br);
529 if(res != LV_FS_RES_OK || btr != br) {
530 LV_LOG_WARN("Built-in image decoder read failed");
531 return LV_RES_INV;
532 }
533
534 return LV_RES_OK;
535 }
536
lv_img_decoder_built_in_line_alpha(lv_img_decoder_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_coord_t len,uint8_t * buf)537 static lv_res_t lv_img_decoder_built_in_line_alpha(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
538 lv_coord_t len, uint8_t * buf)
539 {
540 const lv_opa_t alpha1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
541 const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
542 const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
543 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255
544 };
545
546 /*Simply fill the buffer with the color. Later only the alpha value will be modified.*/
547 lv_color_t bg_color = dsc->color;
548 lv_coord_t i;
549 for(i = 0; i < len; i++) {
550 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
551 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full;
552 #elif LV_COLOR_DEPTH == 16
553 /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
554 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF;
555 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF;
556 #elif LV_COLOR_DEPTH == 32
557 *((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full;
558 #else
559 #error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h"
560 #endif
561 }
562
563 const lv_opa_t * opa_table = NULL;
564 uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf);
565 uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
566
567 lv_coord_t w = 0;
568 uint32_t ofs = 0;
569 int8_t pos = 0;
570 switch(dsc->header.cf) {
571 case LV_IMG_CF_ALPHA_1BIT:
572 w = (dsc->header.w + 7) >> 3; /*E.g. w = 20 -> w = 2 + 1*/
573 ofs += w * y + (x >> 3); /*First pixel*/
574 pos = 7 - (x & 0x7);
575 opa_table = alpha1_opa_table;
576 break;
577 case LV_IMG_CF_ALPHA_2BIT:
578 w = (dsc->header.w + 3) >> 2; /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
579 ofs += w * y + (x >> 2); /*First pixel*/
580 pos = 6 - (x & 0x3) * 2;
581 opa_table = alpha2_opa_table;
582 break;
583 case LV_IMG_CF_ALPHA_4BIT:
584 w = (dsc->header.w + 1) >> 1; /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
585 ofs += w * y + (x >> 1); /*First pixel*/
586 pos = 4 - (x & 0x1) * 4;
587 opa_table = alpha4_opa_table;
588 break;
589 case LV_IMG_CF_ALPHA_8BIT:
590 w = dsc->header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
591 ofs += w * y + x; /*First pixel*/
592 pos = 0;
593 break;
594 }
595
596 lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
597 uint8_t * fs_buf = lv_mem_buf_get(w);
598 if(fs_buf == NULL) return LV_RES_INV;
599
600 const uint8_t * data_tmp = NULL;
601 if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
602 const lv_img_dsc_t * img_dsc = dsc->src;
603
604 data_tmp = img_dsc->data + ofs;
605 }
606 else {
607 lv_fs_seek(&user_data->f, ofs + 4, LV_FS_SEEK_SET); /*+4 to skip the header*/
608 lv_fs_read(&user_data->f, fs_buf, w, NULL);
609 data_tmp = fs_buf;
610 }
611
612 for(i = 0; i < len; i++) {
613 uint8_t val_act = (*data_tmp >> pos) & mask;
614
615 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] =
616 dsc->header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act];
617
618 pos -= px_size;
619 if(pos < 0) {
620 pos = 8 - px_size;
621 data_tmp++;
622 }
623 }
624 lv_mem_buf_release(fs_buf);
625 return LV_RES_OK;
626 }
627
lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_coord_t len,uint8_t * buf)628 static lv_res_t lv_img_decoder_built_in_line_indexed(lv_img_decoder_dsc_t * dsc, lv_coord_t x, lv_coord_t y,
629 lv_coord_t len, uint8_t * buf)
630 {
631 uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf);
632 uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
633
634 lv_coord_t w = 0;
635 int8_t pos = 0;
636 uint32_t ofs = 0;
637 switch(dsc->header.cf) {
638 case LV_IMG_CF_INDEXED_1BIT:
639 w = (dsc->header.w + 7) >> 3; /*E.g. w = 20 -> w = 2 + 1*/
640 ofs += w * y + (x >> 3); /*First pixel*/
641 ofs += 8; /*Skip the palette*/
642 pos = 7 - (x & 0x7);
643 break;
644 case LV_IMG_CF_INDEXED_2BIT:
645 w = (dsc->header.w + 3) >> 2; /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
646 ofs += w * y + (x >> 2); /*First pixel*/
647 ofs += 16; /*Skip the palette*/
648 pos = 6 - (x & 0x3) * 2;
649 break;
650 case LV_IMG_CF_INDEXED_4BIT:
651 w = (dsc->header.w + 1) >> 1; /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
652 ofs += w * y + (x >> 1); /*First pixel*/
653 ofs += 64; /*Skip the palette*/
654 pos = 4 - (x & 0x1) * 4;
655 break;
656 case LV_IMG_CF_INDEXED_8BIT:
657 w = dsc->header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
658 ofs += w * y + x; /*First pixel*/
659 ofs += 1024; /*Skip the palette*/
660 pos = 0;
661 break;
662 }
663
664 lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
665
666 uint8_t * fs_buf = lv_mem_buf_get(w);
667 if(fs_buf == NULL) return LV_RES_INV;
668 const uint8_t * data_tmp = NULL;
669 if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
670 const lv_img_dsc_t * img_dsc = dsc->src;
671 data_tmp = img_dsc->data + ofs;
672 }
673 else {
674 lv_fs_seek(&user_data->f, ofs + 4, LV_FS_SEEK_SET); /*+4 to skip the header*/
675 lv_fs_read(&user_data->f, fs_buf, w, NULL);
676 data_tmp = fs_buf;
677 }
678
679 lv_coord_t i;
680 for(i = 0; i < len; i++) {
681 uint8_t val_act = (*data_tmp >> pos) & mask;
682
683 lv_color_t color = user_data->palette[val_act];
684 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
685 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = color.full;
686 #elif LV_COLOR_DEPTH == 16
687 /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
688 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = color.full & 0xFF;
689 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (color.full >> 8) & 0xFF;
690 #elif LV_COLOR_DEPTH == 32
691 *((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = color.full;
692 #else
693 #error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h"
694 #endif
695 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = user_data->opa[val_act];
696
697 pos -= px_size;
698 if(pos < 0) {
699 pos = 8 - px_size;
700 data_tmp++;
701 }
702 }
703 lv_mem_buf_release(fs_buf);
704 return LV_RES_OK;
705 }
706