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