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 A8, RGB565A8, need load file to ram after https://github.com/lvgl/lvgl/pull/3337*/
364 if(cf == LV_IMG_CF_ALPHA_8BIT || cf == LV_IMG_CF_RGB565A8) {
365 if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
366 /*In case of uncompressed formats the image stored in the ROM/RAM.
367 *So simply give its pointer*/
368 dsc->img_data = ((lv_img_dsc_t *)dsc->src)->data;
369 return LV_RES_OK;
370 }
371 else {
372 /*If it's a file, read all to memory*/
373 uint32_t len = dsc->header.w * dsc->header.h;
374 len *= cf == LV_IMG_CF_RGB565A8 ? 3 : 1;
375 uint8_t * fs_buf = lv_mem_alloc(len);
376 if(fs_buf == NULL) return LV_RES_INV;
377
378 lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
379 lv_fs_seek(&user_data->f, 4, LV_FS_SEEK_SET); /*+4 to skip the header*/
380 lv_fs_res_t res = lv_fs_read(&user_data->f, fs_buf, len, NULL);
381 if(res != LV_FS_RES_OK) {
382 lv_mem_free(fs_buf);
383 return LV_RES_INV;
384 }
385 dsc->img_data = fs_buf;
386 return LV_RES_OK;
387 }
388 }
389 /*Process true color formats*/
390 else if(cf == LV_IMG_CF_TRUE_COLOR || cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
391 cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
392 if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
393 /*In case of uncompressed formats the image stored in the ROM/RAM.
394 *So simply give its pointer*/
395 dsc->img_data = ((lv_img_dsc_t *)dsc->src)->data;
396 return LV_RES_OK;
397 }
398 else {
399 /*If it's a file it need to be read line by line later*/
400 return LV_RES_OK;
401 }
402 }
403 /*Process indexed images. Build a palette*/
404 else if(cf == LV_IMG_CF_INDEXED_1BIT || cf == LV_IMG_CF_INDEXED_2BIT || cf == LV_IMG_CF_INDEXED_4BIT ||
405 cf == LV_IMG_CF_INDEXED_8BIT) {
406 uint8_t px_size = lv_img_cf_get_px_size(cf);
407 uint32_t palette_size = 1 << px_size;
408
409 /*Allocate the palette*/
410 if(dsc->user_data == NULL) {
411 dsc->user_data = lv_mem_alloc(sizeof(lv_img_decoder_built_in_data_t));
412 LV_ASSERT_MALLOC(dsc->user_data);
413 if(dsc->user_data == NULL) {
414 LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
415 return LV_RES_INV;
416 }
417 lv_memset_00(dsc->user_data, sizeof(lv_img_decoder_built_in_data_t));
418 }
419
420 lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
421 user_data->palette = lv_mem_alloc(palette_size * sizeof(lv_color_t));
422 LV_ASSERT_MALLOC(user_data->palette);
423 user_data->opa = lv_mem_alloc(palette_size * sizeof(lv_opa_t));
424 LV_ASSERT_MALLOC(user_data->opa);
425 if(user_data->palette == NULL || user_data->opa == NULL) {
426 LV_LOG_ERROR("img_decoder_built_in_open: out of memory");
427 lv_img_decoder_built_in_close(decoder, dsc);
428 return LV_RES_INV;
429 }
430
431 if(dsc->src_type == LV_IMG_SRC_FILE) {
432 /*Read the palette from file*/
433 lv_fs_seek(&user_data->f, 4, LV_FS_SEEK_SET); /*Skip the header*/
434 lv_color32_t cur_color;
435 uint32_t i;
436 for(i = 0; i < palette_size; i++) {
437 lv_fs_read(&user_data->f, &cur_color, sizeof(lv_color32_t), NULL);
438 user_data->palette[i] = lv_color_make(cur_color.ch.red, cur_color.ch.green, cur_color.ch.blue);
439 user_data->opa[i] = cur_color.ch.alpha;
440 }
441 }
442 else {
443 /*The palette begins in the beginning of the image data. Just point to it.*/
444 lv_color32_t * palette_p = (lv_color32_t *)((lv_img_dsc_t *)dsc->src)->data;
445
446 uint32_t i;
447 for(i = 0; i < palette_size; i++) {
448 user_data->palette[i] = lv_color_make(palette_p[i].ch.red, palette_p[i].ch.green, palette_p[i].ch.blue);
449 user_data->opa[i] = palette_p[i].ch.alpha;
450 }
451 }
452
453 return LV_RES_OK;
454 }
455 /*Alpha indexed images.*/
456 else if(cf == LV_IMG_CF_ALPHA_1BIT || cf == LV_IMG_CF_ALPHA_2BIT || cf == LV_IMG_CF_ALPHA_4BIT) {
457 return LV_RES_OK; /*Nothing to process*/
458 }
459 /*Unknown format. Can't decode it.*/
460 else {
461 /*Free the potentially allocated memories*/
462 lv_img_decoder_built_in_close(decoder, dsc);
463
464 LV_LOG_WARN("Image decoder open: unknown color format");
465 return LV_RES_INV;
466 }
467 }
468
469 /**
470 * Decode `len` pixels starting from the given `x`, `y` coordinates and store them in `buf`.
471 * Required only if the "open" function can't return with the whole decoded pixel array.
472 * @param decoder pointer to the decoder the function associated with
473 * @param dsc pointer to decoder descriptor
474 * @param x start x coordinate
475 * @param y start y coordinate
476 * @param len number of pixels to decode
477 * @param buf a buffer to store the decoded pixels
478 * @return LV_RES_OK: ok; LV_RES_INV: failed
479 */
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)480 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,
481 lv_coord_t y, lv_coord_t len, uint8_t * buf)
482 {
483 LV_UNUSED(decoder); /*Unused*/
484
485 lv_res_t res = LV_RES_INV;
486
487 if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
488 dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
489 /*For TRUE_COLOR images read line required only for files.
490 *For variables the image data was returned in `open`*/
491 if(dsc->src_type == LV_IMG_SRC_FILE) {
492 res = lv_img_decoder_built_in_line_true_color(dsc, x, y, len, buf);
493 }
494 }
495 else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || dsc->header.cf == LV_IMG_CF_ALPHA_2BIT ||
496 dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
497 res = lv_img_decoder_built_in_line_alpha(dsc, x, y, len, buf);
498 }
499 else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT || dsc->header.cf == LV_IMG_CF_INDEXED_2BIT ||
500 dsc->header.cf == LV_IMG_CF_INDEXED_4BIT || dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
501 res = lv_img_decoder_built_in_line_indexed(dsc, x, y, len, buf);
502 }
503 else {
504 LV_LOG_WARN("Built-in image decoder read not supports the color format");
505 return LV_RES_INV;
506 }
507
508 return res;
509 }
510
511 /**
512 * Close the pending decoding. Free resources etc.
513 * @param decoder pointer to the decoder the function associated with
514 * @param dsc pointer to decoder descriptor
515 */
lv_img_decoder_built_in_close(lv_img_decoder_t * decoder,lv_img_decoder_dsc_t * dsc)516 void lv_img_decoder_built_in_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
517 {
518 LV_UNUSED(decoder); /*Unused*/
519
520 lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
521 if(user_data) {
522 if(dsc->src_type == LV_IMG_SRC_FILE) {
523 lv_fs_close(&user_data->f);
524 }
525 if(user_data->palette) lv_mem_free(user_data->palette);
526 if(user_data->opa) lv_mem_free(user_data->opa);
527
528 lv_mem_free(user_data);
529 dsc->user_data = NULL;
530 }
531 }
532
533 /**********************
534 * STATIC FUNCTIONS
535 **********************/
536
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)537 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,
538 lv_coord_t len, uint8_t * buf)
539 {
540 lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
541 lv_fs_res_t res;
542 uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf);
543
544 uint32_t pos = ((y * dsc->header.w + x) * px_size) >> 3;
545 pos += 4; /*Skip the header*/
546 res = lv_fs_seek(&user_data->f, pos, LV_FS_SEEK_SET);
547 if(res != LV_FS_RES_OK) {
548 LV_LOG_WARN("Built-in image decoder seek failed");
549 return LV_RES_INV;
550 }
551 uint32_t btr = len * (px_size >> 3);
552 uint32_t br = 0;
553 res = lv_fs_read(&user_data->f, buf, btr, &br);
554 if(res != LV_FS_RES_OK || btr != br) {
555 LV_LOG_WARN("Built-in image decoder read failed");
556 return LV_RES_INV;
557 }
558
559 return LV_RES_OK;
560 }
561
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)562 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,
563 lv_coord_t len, uint8_t * buf)
564 {
565 const lv_opa_t alpha1_opa_table[2] = {0, 255}; /*Opacity mapping with bpp = 1 (Just for compatibility)*/
566 const lv_opa_t alpha2_opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
567 const lv_opa_t alpha4_opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
568 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255
569 };
570
571 /*Simply fill the buffer with the color. Later only the alpha value will be modified.*/
572 lv_color_t bg_color = dsc->color;
573 lv_coord_t i;
574 for(i = 0; i < len; i++) {
575 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
576 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full;
577 #elif LV_COLOR_DEPTH == 16
578 /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
579 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = bg_color.full & 0xFF;
580 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (bg_color.full >> 8) & 0xFF;
581 #elif LV_COLOR_DEPTH == 32
582 *((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = bg_color.full;
583 #else
584 #error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h"
585 #endif
586 }
587
588 const lv_opa_t * opa_table = NULL;
589 uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf);
590 uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
591
592 lv_coord_t w = 0;
593 uint32_t ofs = 0;
594 int8_t pos = 0;
595 switch(dsc->header.cf) {
596 case LV_IMG_CF_ALPHA_1BIT:
597 w = (dsc->header.w + 7) >> 3; /*E.g. w = 20 -> w = 2 + 1*/
598 ofs += w * y + (x >> 3); /*First pixel*/
599 pos = 7 - (x & 0x7);
600 opa_table = alpha1_opa_table;
601 break;
602 case LV_IMG_CF_ALPHA_2BIT:
603 w = (dsc->header.w + 3) >> 2; /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
604 ofs += w * y + (x >> 2); /*First pixel*/
605 pos = 6 - (x & 0x3) * 2;
606 opa_table = alpha2_opa_table;
607 break;
608 case LV_IMG_CF_ALPHA_4BIT:
609 w = (dsc->header.w + 1) >> 1; /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
610 ofs += w * y + (x >> 1); /*First pixel*/
611 pos = 4 - (x & 0x1) * 4;
612 opa_table = alpha4_opa_table;
613 break;
614 case LV_IMG_CF_ALPHA_8BIT:
615 w = dsc->header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
616 ofs += w * y + x; /*First pixel*/
617 pos = 0;
618 break;
619 }
620
621 lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
622 uint8_t * fs_buf = lv_mem_buf_get(w);
623 if(fs_buf == NULL) return LV_RES_INV;
624
625 const uint8_t * data_tmp = NULL;
626 if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
627 const lv_img_dsc_t * img_dsc = dsc->src;
628
629 data_tmp = img_dsc->data + ofs;
630 }
631 else {
632 lv_fs_seek(&user_data->f, ofs + 4, LV_FS_SEEK_SET); /*+4 to skip the header*/
633 lv_fs_read(&user_data->f, fs_buf, w, NULL);
634 data_tmp = fs_buf;
635 }
636
637 for(i = 0; i < len; i++) {
638 uint8_t val_act = (*data_tmp >> pos) & mask;
639
640 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] =
641 dsc->header.cf == LV_IMG_CF_ALPHA_8BIT ? val_act : opa_table[val_act];
642
643 pos -= px_size;
644 if(pos < 0) {
645 pos = 8 - px_size;
646 data_tmp++;
647 }
648 }
649 lv_mem_buf_release(fs_buf);
650 return LV_RES_OK;
651 }
652
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)653 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,
654 lv_coord_t len, uint8_t * buf)
655 {
656 uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf);
657 uint16_t mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
658
659 lv_coord_t w = 0;
660 int8_t pos = 0;
661 uint32_t ofs = 0;
662 switch(dsc->header.cf) {
663 case LV_IMG_CF_INDEXED_1BIT:
664 w = (dsc->header.w + 7) >> 3; /*E.g. w = 20 -> w = 2 + 1*/
665 ofs += w * y + (x >> 3); /*First pixel*/
666 ofs += 8; /*Skip the palette*/
667 pos = 7 - (x & 0x7);
668 break;
669 case LV_IMG_CF_INDEXED_2BIT:
670 w = (dsc->header.w + 3) >> 2; /*E.g. w = 13 -> w = 3 + 1 (bytes)*/
671 ofs += w * y + (x >> 2); /*First pixel*/
672 ofs += 16; /*Skip the palette*/
673 pos = 6 - (x & 0x3) * 2;
674 break;
675 case LV_IMG_CF_INDEXED_4BIT:
676 w = (dsc->header.w + 1) >> 1; /*E.g. w = 13 -> w = 6 + 1 (bytes)*/
677 ofs += w * y + (x >> 1); /*First pixel*/
678 ofs += 64; /*Skip the palette*/
679 pos = 4 - (x & 0x1) * 4;
680 break;
681 case LV_IMG_CF_INDEXED_8BIT:
682 w = dsc->header.w; /*E.g. x = 7 -> w = 7 (bytes)*/
683 ofs += w * y + x; /*First pixel*/
684 ofs += 1024; /*Skip the palette*/
685 pos = 0;
686 break;
687 }
688
689 lv_img_decoder_built_in_data_t * user_data = dsc->user_data;
690
691 uint8_t * fs_buf = lv_mem_buf_get(w);
692 if(fs_buf == NULL) return LV_RES_INV;
693 const uint8_t * data_tmp = NULL;
694 if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
695 const lv_img_dsc_t * img_dsc = dsc->src;
696 data_tmp = img_dsc->data + ofs;
697 }
698 else {
699 lv_fs_seek(&user_data->f, ofs + 4, LV_FS_SEEK_SET); /*+4 to skip the header*/
700 lv_fs_read(&user_data->f, fs_buf, w, NULL);
701 data_tmp = fs_buf;
702 }
703
704 lv_coord_t i;
705 for(i = 0; i < len; i++) {
706 uint8_t val_act = (*data_tmp >> pos) & mask;
707
708 lv_color_t color = user_data->palette[val_act];
709 #if LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
710 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = color.full;
711 #elif LV_COLOR_DEPTH == 16
712 /*Because of Alpha byte 16 bit color can start on odd address which can cause crash*/
713 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE] = color.full & 0xFF;
714 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + 1] = (color.full >> 8) & 0xFF;
715 #elif LV_COLOR_DEPTH == 32
716 *((uint32_t *)&buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE]) = color.full;
717 #else
718 #error "Invalid LV_COLOR_DEPTH. Check it in lv_conf.h"
719 #endif
720 buf[i * LV_IMG_PX_SIZE_ALPHA_BYTE + LV_IMG_PX_SIZE_ALPHA_BYTE - 1] = user_data->opa[val_act];
721
722 pos -= px_size;
723 if(pos < 0) {
724 pos = 8 - px_size;
725 data_tmp++;
726 }
727 }
728 lv_mem_buf_release(fs_buf);
729 return LV_RES_OK;
730 }
731