1 /**
2 * @file lv_image_decoder.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "../../draw/lv_image_decoder_private.h"
10 #include "lv_bin_decoder.h"
11 #include "../../draw/lv_draw_image.h"
12 #include "../../draw/lv_draw_buf.h"
13 #include "../../stdlib/lv_string.h"
14 #include "../../stdlib/lv_sprintf.h"
15 #include "../../libs/rle/lv_rle.h"
16 #include "../../core/lv_global.h"
17
18 #if LV_USE_LZ4_EXTERNAL
19 #include <lz4.h>
20 #endif
21
22 #if LV_USE_LZ4_INTERNAL
23 #include "../../libs/lz4/lz4.h"
24 #endif
25
26 /*********************
27 * DEFINES
28 *********************/
29
30 #define DECODER_NAME "BIN"
31
32 #define image_cache_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->image_cache_draw_buf_handlers)
33
34 /**********************
35 * TYPEDEFS
36 **********************/
37
38 /**
39 * Data format for compressed image data.
40 */
41
42 typedef struct _lv_image_compressed_t {
43 uint32_t method: 4; /*Compression method, see `lv_image_compress_t`*/
44 uint32_t reserved : 28; /*Reserved to be used later*/
45 uint32_t compressed_size; /*Compressed data size in byte*/
46 uint32_t decompressed_size; /*Decompressed data size in byte*/
47 const uint8_t * data; /*Compressed data*/
48 } lv_image_compressed_t;
49
50 typedef struct {
51 lv_fs_file_t * f;
52 lv_color32_t * palette;
53 lv_opa_t * opa;
54 lv_image_compressed_t compressed;
55 lv_draw_buf_t * decoded; /*A draw buf to store decoded image*/
56 lv_draw_buf_t * decompressed; /*Decompressed data could be used directly, thus must also be draw buf*/
57 lv_draw_buf_t c_array; /*An C-array image that need to be converted to a draw buf*/
58 lv_draw_buf_t * decoded_partial; /*A draw buf for decoded image via get_area_cb*/
59 } decoder_data_t;
60
61 /**********************
62 * STATIC PROTOTYPES
63 **********************/
64 static decoder_data_t * get_decoder_data(lv_image_decoder_dsc_t * dsc);
65 static void free_decoder_data(lv_image_decoder_dsc_t * dsc);
66 static lv_result_t decode_indexed(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
67 static lv_result_t load_indexed(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
68 #if LV_BIN_DECODER_RAM_LOAD
69 static lv_result_t decode_rgb(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
70 #endif
71 static lv_result_t decode_alpha_only(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
72 static lv_result_t decode_indexed_line(lv_color_format_t color_format, const lv_color32_t * palette, int32_t x,
73 int32_t w_px, const uint8_t * in, lv_color32_t * out);
74 static lv_result_t decode_compressed(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc);
75
76 static lv_fs_res_t fs_read_file_at(lv_fs_file_t * f, uint32_t pos, void * buff, uint32_t btr, uint32_t * br);
77
78 static lv_result_t decompress_image(lv_image_decoder_dsc_t * dsc, const lv_image_compressed_t * compressed);
79
80 /**********************
81 * STATIC VARIABLES
82 **********************/
83
84 /**********************
85 * MACROS
86 **********************/
87
88 /**********************
89 * GLOBAL FUNCTIONS
90 **********************/
91
92 /**
93 * Initialize the lvgl binary image decoder module
94 */
lv_bin_decoder_init(void)95 void lv_bin_decoder_init(void)
96 {
97 lv_image_decoder_t * decoder;
98
99 decoder = lv_image_decoder_create();
100 LV_ASSERT_MALLOC(decoder);
101 if(decoder == NULL) {
102 LV_LOG_WARN("Out of memory");
103 return;
104 }
105
106 lv_image_decoder_set_info_cb(decoder, lv_bin_decoder_info);
107 lv_image_decoder_set_open_cb(decoder, lv_bin_decoder_open);
108 lv_image_decoder_set_get_area_cb(decoder, lv_bin_decoder_get_area);
109 lv_image_decoder_set_close_cb(decoder, lv_bin_decoder_close);
110
111 decoder->name = DECODER_NAME;
112 }
113
lv_bin_decoder_info(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc,lv_image_header_t * header)114 lv_result_t lv_bin_decoder_info(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc, lv_image_header_t * header)
115 {
116 LV_UNUSED(decoder); /*Unused*/
117
118 const void * src = dsc->src;
119 lv_image_src_t src_type = dsc->src_type;
120
121 if(src_type == LV_IMAGE_SRC_VARIABLE) {
122 lv_image_dsc_t * image = (lv_image_dsc_t *)src;
123 lv_memcpy(header, &image->header, sizeof(lv_image_header_t));
124 }
125 else if(src_type == LV_IMAGE_SRC_FILE) {
126 /*Support only "*.bin" files*/
127 if(lv_strcmp(lv_fs_get_ext(src), "bin")) return LV_RESULT_INVALID;
128
129 lv_fs_res_t res;
130 uint32_t rn;
131 res = lv_fs_read(&dsc->file, header, sizeof(lv_image_header_t), &rn);
132
133 if(res != LV_FS_RES_OK || rn != sizeof(lv_image_header_t)) {
134 LV_LOG_WARN("Read file header failed: %d", res);
135 return LV_RESULT_INVALID;
136 }
137
138 /**
139 * @todo
140 * This is a temp backward compatibility solution after adding
141 * magic in image header.
142 */
143 if(header->magic != LV_IMAGE_HEADER_MAGIC) {
144 LV_LOG_WARN("Legacy bin image detected: %s", (char *)src);
145 header->cf = header->magic;
146 header->magic = LV_IMAGE_HEADER_MAGIC;
147 }
148
149 /*File is always read to buf, thus data can be modified.*/
150 header->flags |= LV_IMAGE_FLAGS_MODIFIABLE;
151 }
152 else if(src_type == LV_IMAGE_SRC_SYMBOL) {
153 /*The size depend on the font but it is unknown here. It should be handled outside of the
154 *function*/
155 header->w = 1;
156 header->h = 1;
157 /*Symbols always have transparent parts. Important because of cover check in the draw
158 *function. The actual value doesn't matter because lv_draw_label will draw it*/
159 header->cf = LV_COLOR_FORMAT_A8;
160 }
161 else {
162 LV_LOG_WARN("Image get info found unknown src type");
163 return LV_RESULT_INVALID;
164 }
165
166 /*For backward compatibility, all images are not premultiplied for now.*/
167 if(header->magic != LV_IMAGE_HEADER_MAGIC) {
168 header->flags &= ~LV_IMAGE_FLAGS_PREMULTIPLIED;
169 }
170
171 return LV_RESULT_OK;
172 }
173
174 /**
175 * Decode an image from a binary file
176 * @param decoder pointer to the decoder
177 * @param dsc pointer to the decoder descriptor
178 * @return LV_RESULT_OK: no error; LV_RESULT_INVALID: can't open the image
179 */
lv_bin_decoder_open(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)180 lv_result_t lv_bin_decoder_open(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
181 {
182 LV_UNUSED(decoder);
183
184 lv_result_t res = LV_RESULT_INVALID;
185 lv_fs_res_t fs_res = LV_FS_RES_UNKNOWN;
186 bool use_directly = false; /*If the image is already decoded and can be used directly*/
187
188 /*Open the file if it's a file*/
189 if(dsc->src_type == LV_IMAGE_SRC_FILE) {
190 /*Support only "*.bin" files*/
191 if(lv_strcmp(lv_fs_get_ext(dsc->src), "bin")) return LV_RESULT_INVALID;
192
193 /*If the file was open successfully save the file descriptor*/
194 decoder_data_t * decoder_data = get_decoder_data(dsc);
195 if(decoder_data == NULL) {
196 return LV_RESULT_INVALID;
197 }
198
199 dsc->user_data = decoder_data;
200 lv_fs_file_t * f = lv_malloc(sizeof(*f));
201 if(f == NULL) {
202 free_decoder_data(dsc);
203 return LV_RESULT_INVALID;
204 }
205
206 fs_res = lv_fs_open(f, dsc->src, LV_FS_MODE_RD);
207 if(fs_res != LV_FS_RES_OK) {
208 LV_LOG_WARN("Open file failed: %d", fs_res);
209 lv_free(f);
210 free_decoder_data(dsc);
211 return LV_RESULT_INVALID;
212 }
213
214 decoder_data->f = f; /*Now free_decoder_data will take care of the file*/
215
216 lv_color_format_t cf = dsc->header.cf;
217
218 if(dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED) {
219 res = decode_compressed(decoder, dsc);
220 }
221 else if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
222 if(dsc->args.use_indexed) {
223 /*Palette for indexed image and whole image of A8 image are always loaded to RAM for simplicity*/
224 res = load_indexed(decoder, dsc);
225 }
226 else {
227 res = decode_indexed(decoder, dsc);
228 }
229 }
230 else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) {
231 res = decode_alpha_only(decoder, dsc);
232 }
233 #if LV_BIN_DECODER_RAM_LOAD
234 else if(cf == LV_COLOR_FORMAT_ARGB8888 \
235 || cf == LV_COLOR_FORMAT_XRGB8888 \
236 || cf == LV_COLOR_FORMAT_RGB888 \
237 || cf == LV_COLOR_FORMAT_RGB565 \
238 || cf == LV_COLOR_FORMAT_RGB565A8 \
239 || cf == LV_COLOR_FORMAT_ARGB8565) {
240 res = decode_rgb(decoder, dsc);
241 }
242 #else
243 else {
244 /* decode them in get_area_cb */
245 res = LV_RESULT_OK;
246 }
247 #endif
248 }
249
250 else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) {
251 /*The variables should have valid data*/
252 lv_image_dsc_t * image = (lv_image_dsc_t *)dsc->src;
253 if(image->data == NULL) {
254 return LV_RESULT_INVALID;
255 }
256
257 lv_color_format_t cf = image->header.cf;
258 if(dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED) {
259 res = decode_compressed(decoder, dsc);
260 }
261 else if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
262 /*Need decoder data to store converted image*/
263 decoder_data_t * decoder_data = get_decoder_data(dsc);
264 if(decoder_data == NULL) {
265 return LV_RESULT_INVALID;
266 }
267
268 if(dsc->args.use_indexed) {
269 /*Palette for indexed image and whole image of A8 image are always loaded to RAM for simplicity*/
270 res = load_indexed(decoder, dsc);
271 use_directly = true; /*If draw unit supports indexed image, it can be used directly.*/
272 }
273 else {
274 res = decode_indexed(decoder, dsc);
275 }
276 }
277 else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) {
278 if(cf == LV_COLOR_FORMAT_A8) {
279 res = LV_RESULT_OK;
280 use_directly = true;
281 dsc->decoded = (lv_draw_buf_t *)image;
282 }
283 else {
284 /*Alpha only image will need decoder data to store pointer to decoded image, to free it when decoder closes*/
285 decoder_data_t * decoder_data = get_decoder_data(dsc);
286 if(decoder_data == NULL) {
287 return LV_RESULT_INVALID;
288 }
289
290 res = decode_alpha_only(decoder, dsc);
291 }
292 }
293 else {
294 /*In case of uncompressed formats the image stored in the ROM/RAM.
295 *So simply give its pointer*/
296
297 decoder_data_t * decoder_data = get_decoder_data(dsc);
298 lv_draw_buf_t * decoded;
299 if(image->header.flags & LV_IMAGE_FLAGS_ALLOCATED) {
300 decoded = (lv_draw_buf_t *)image;
301 }
302 else {
303 decoded = &decoder_data->c_array;
304 if(image->header.stride == 0) {
305 /*If image doesn't have stride, treat it as lvgl v8 legacy image format*/
306 lv_image_dsc_t tmp = *image;
307 tmp.header.stride = (tmp.header.w * lv_color_format_get_bpp(cf) + 7) >> 3;
308 lv_draw_buf_from_image(decoded, &tmp);
309 }
310 else
311 lv_draw_buf_from_image(decoded, image);
312 }
313
314 dsc->decoded = decoded;
315
316 if(decoded->header.stride == 0) {
317 /*Use the auto calculated value from decoder_info callback*/
318 decoded->header.stride = dsc->header.stride;
319 }
320
321 res = LV_RESULT_OK;
322 use_directly = true; /*A variable image that can be used directly.*/
323 }
324 }
325
326 if(res != LV_RESULT_OK) {
327 free_decoder_data(dsc);
328 return res;
329 }
330
331 if(dsc->decoded == NULL) return LV_RESULT_OK; /*Need to read via get_area_cb*/
332
333 lv_draw_buf_t * decoded = (lv_draw_buf_t *)dsc->decoded;
334 if(dsc->header.flags & LV_IMAGE_FLAGS_PREMULTIPLIED) {
335 lv_draw_buf_set_flag(decoded, LV_IMAGE_FLAGS_PREMULTIPLIED);
336 }
337
338 lv_draw_buf_t * adjusted = lv_image_decoder_post_process(dsc, decoded);
339 if(adjusted == NULL) {
340 free_decoder_data(dsc);
341 return LV_RESULT_INVALID;
342 }
343
344 /*The adjusted draw buffer is newly allocated.*/
345 if(adjusted != decoded) {
346 use_directly = false; /*Cannot use original image directly*/
347 free_decoder_data(dsc);
348 decoder_data_t * decoder_data = get_decoder_data(dsc);
349 decoder_data->decoded = adjusted; /*Now this new buffer need to be free'd on decoder close*/
350 }
351 dsc->decoded = adjusted;
352
353 if(use_directly || dsc->args.no_cache) return LV_RESULT_OK; /*Do not put image to cache if it can be used directly.*/
354
355 /*If the image cache is disabled, just return the decoded image*/
356 if(!lv_image_cache_is_enabled()) return LV_RESULT_OK;
357
358 /*Add it to cache*/
359 lv_image_cache_data_t search_key;
360 search_key.src_type = dsc->src_type;
361 search_key.src = dsc->src;
362 search_key.slot.size = dsc->decoded->data_size;
363
364 lv_cache_entry_t * cache_entry = lv_image_decoder_add_to_cache(decoder, &search_key, dsc->decoded, dsc->user_data);
365 if(cache_entry == NULL) {
366 free_decoder_data(dsc);
367 return LV_RESULT_INVALID;
368 }
369 dsc->cache_entry = cache_entry;
370 decoder_data_t * decoder_data = get_decoder_data(dsc);
371 decoder_data->decoded = NULL; /*Cache will take care of it*/
372
373 return LV_RESULT_OK;
374 }
375
lv_bin_decoder_close(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)376 void lv_bin_decoder_close(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
377 {
378 LV_UNUSED(decoder); /*Unused*/
379
380 decoder_data_t * decoder_data = dsc->user_data;
381 if(decoder_data && decoder_data->decoded_partial) {
382 lv_draw_buf_destroy(decoder_data->decoded_partial);
383 decoder_data->decoded_partial = NULL;
384 }
385
386 free_decoder_data(dsc);
387 }
388
lv_bin_decoder_get_area(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc,const lv_area_t * full_area,lv_area_t * decoded_area)389 lv_result_t lv_bin_decoder_get_area(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc,
390 const lv_area_t * full_area, lv_area_t * decoded_area)
391 {
392 LV_UNUSED(decoder); /*Unused*/
393
394 lv_color_format_t cf = dsc->header.cf;
395 /*Check if cf is supported*/
396
397 bool supported = LV_COLOR_FORMAT_IS_INDEXED(cf)
398 || cf == LV_COLOR_FORMAT_ARGB8888 \
399 || cf == LV_COLOR_FORMAT_XRGB8888 \
400 || cf == LV_COLOR_FORMAT_RGB888 \
401 || cf == LV_COLOR_FORMAT_RGB565 \
402 || cf == LV_COLOR_FORMAT_ARGB8565 \
403 || cf == LV_COLOR_FORMAT_RGB565A8;
404 if(!supported) {
405 LV_LOG_WARN("CF: %d is not supported", cf);
406 return LV_RESULT_INVALID;
407 }
408
409 lv_fs_res_t res = LV_FS_RES_UNKNOWN;
410 decoder_data_t * decoder_data = dsc->user_data;
411 if(decoder_data == NULL) {
412 LV_LOG_ERROR("Unexpected null decoder data");
413 return LV_RESULT_INVALID;
414 }
415
416 lv_fs_file_t * f = decoder_data->f;
417 uint32_t bpp = lv_color_format_get_bpp(cf);
418 int32_t w_px = lv_area_get_width(full_area);
419 uint8_t * img_data = NULL;
420 lv_draw_buf_t * decoded = NULL;
421 uint32_t offset = dsc->src_type == LV_IMAGE_SRC_FILE ? sizeof(lv_image_header_t) : 0; /*Skip the image header*/
422
423 /*We only support read line by line for now*/
424 if(decoded_area->y1 == LV_COORD_MIN) {
425 /*Indexed image is converted to ARGB888*/
426 lv_color_format_t cf_decoded = LV_COLOR_FORMAT_IS_INDEXED(cf) ? LV_COLOR_FORMAT_ARGB8888 : cf;
427
428 decoded = lv_draw_buf_reshape(decoder_data->decoded_partial, cf_decoded, w_px, 1, LV_STRIDE_AUTO);
429 if(decoded == NULL) {
430 if(decoder_data->decoded_partial != NULL) {
431 lv_draw_buf_destroy(decoder_data->decoded_partial);
432 decoder_data->decoded_partial = NULL;
433 }
434 decoded = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, w_px, 1, cf_decoded, LV_STRIDE_AUTO);
435 if(decoded == NULL) return LV_RESULT_INVALID;
436 decoder_data->decoded_partial = decoded; /*Free on decoder close*/
437 }
438 *decoded_area = *full_area;
439 decoded_area->y2 = decoded_area->y1;
440 }
441 else {
442 decoded_area->y1++;
443 decoded_area->y2++;
444 decoded = decoder_data->decoded_partial; /*Already allocated*/
445 }
446
447 img_data = decoded->data; /*Get the buffer to operate on*/
448
449 if(decoded_area->y1 > full_area->y2) {
450 return LV_RESULT_INVALID;
451 }
452
453 if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
454 int32_t x_fraction = decoded_area->x1 % (8 / bpp);
455 uint32_t len = (w_px * bpp + 7) / 8 + 1; /*10px for 1bpp may across 3bytes*/
456 uint8_t * buf = NULL;
457
458 offset += dsc->palette_size * 4; /*Skip palette*/
459 offset += decoded_area->y1 * dsc->header.stride;
460 offset += decoded_area->x1 * bpp / 8; /*Move to x1*/
461 if(dsc->src_type == LV_IMAGE_SRC_FILE) {
462 buf = lv_malloc(len);
463 LV_ASSERT_NULL(buf);
464 if(buf == NULL)
465 return LV_RESULT_INVALID;
466
467 res = fs_read_file_at(f, offset, buf, len, NULL);
468 if(res != LV_FS_RES_OK) {
469 lv_free(buf);
470 return LV_RESULT_INVALID;
471 }
472 }
473 else {
474 const lv_image_dsc_t * image = dsc->src;
475 buf = (void *)(image->data + offset);
476 }
477
478 decode_indexed_line(cf, dsc->palette, x_fraction, w_px, buf, (lv_color32_t *)img_data);
479
480 if(dsc->src_type == LV_IMAGE_SRC_FILE) lv_free((void *)buf);
481
482 dsc->decoded = decoded; /*Return decoded image*/
483 return LV_RESULT_OK;
484 }
485
486 if(cf == LV_COLOR_FORMAT_ARGB8888 || cf == LV_COLOR_FORMAT_XRGB8888 || cf == LV_COLOR_FORMAT_RGB888
487 || cf == LV_COLOR_FORMAT_RGB565 || cf == LV_COLOR_FORMAT_ARGB8565) {
488 uint32_t len = (w_px * bpp) / 8;
489 offset += decoded_area->y1 * dsc->header.stride;
490 offset += decoded_area->x1 * bpp / 8; /*Move to x1*/
491 res = fs_read_file_at(f, offset, img_data, len, NULL);
492 if(res != LV_FS_RES_OK) {
493 return LV_RESULT_INVALID;
494 }
495
496 dsc->decoded = decoded; /*Return decoded image*/
497 return LV_RESULT_OK;
498 }
499
500 if(cf == LV_COLOR_FORMAT_RGB565A8) {
501 bpp = 16; /* RGB565 + A8 mask*/
502 uint32_t len = decoded->header.stride;
503 offset += decoded_area->y1 * dsc->header.stride; /*Move to y1*/
504 offset += decoded_area->x1 * bpp / 8; /*Move to x1*/
505 res = fs_read_file_at(f, offset, img_data, len, NULL);
506 if(res != LV_FS_RES_OK) {
507 return LV_RESULT_INVALID;
508 }
509
510 /*Now the A8 mask*/
511 offset = sizeof(lv_image_header_t);
512 offset += dsc->header.h * dsc->header.stride; /*Move to A8 map*/
513 offset += decoded_area->y1 * (dsc->header.stride / 2); /*Move to y1*/
514 offset += decoded_area->x1 * 1; /*Move to x1*/
515 res = fs_read_file_at(f, offset, img_data + len, w_px * 1, NULL);
516 if(res != LV_FS_RES_OK) {
517 return LV_RESULT_INVALID;
518 }
519
520 dsc->decoded = decoded; /*Return decoded image*/
521 return LV_RESULT_OK;
522 }
523
524 return LV_RESULT_INVALID;
525 }
526
527 /**********************
528 * STATIC FUNCTIONS
529 **********************/
530
get_decoder_data(lv_image_decoder_dsc_t * dsc)531 static decoder_data_t * get_decoder_data(lv_image_decoder_dsc_t * dsc)
532 {
533 decoder_data_t * data = dsc->user_data;
534 if(data == NULL) {
535 data = lv_malloc_zeroed(sizeof(decoder_data_t));
536 LV_ASSERT_MALLOC(data);
537 if(data == NULL) {
538 LV_LOG_ERROR("Out of memory");
539 return NULL;
540 }
541
542 dsc->user_data = data;
543 }
544
545 return data;
546 }
547
free_decoder_data(lv_image_decoder_dsc_t * dsc)548 static void free_decoder_data(lv_image_decoder_dsc_t * dsc)
549 {
550 decoder_data_t * decoder_data = dsc->user_data;
551 if(decoder_data == NULL) return;
552
553 if(decoder_data->f) {
554 lv_fs_close(decoder_data->f);
555 lv_free(decoder_data->f);
556 }
557
558 if(decoder_data->decoded) lv_draw_buf_destroy(decoder_data->decoded);
559 if(decoder_data->decompressed) lv_draw_buf_destroy(decoder_data->decompressed);
560 lv_free(decoder_data->palette);
561 lv_free(decoder_data);
562 dsc->user_data = NULL;
563 }
564
decode_indexed(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)565 static lv_result_t decode_indexed(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
566 {
567 LV_UNUSED(decoder); /*Unused*/
568 lv_fs_res_t res;
569 uint32_t rn;
570 decoder_data_t * decoder_data = dsc->user_data;
571 lv_fs_file_t * f = decoder_data->f;
572 lv_color_format_t cf = dsc->header.cf;
573 uint32_t palette_len = sizeof(lv_color32_t) * LV_COLOR_INDEXED_PALETTE_SIZE(cf);
574 const lv_color32_t * palette;
575 const uint8_t * indexed_data = NULL;
576 lv_draw_buf_t * draw_buf_indexed = NULL;
577 uint32_t stride = dsc->header.stride;
578
579 bool is_compressed = dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED;
580 if(is_compressed) {
581 uint8_t * data = decoder_data->decompressed->data;
582 palette = (lv_color32_t *)data;
583 indexed_data = data + palette_len;
584 }
585 else if(dsc->src_type == LV_IMAGE_SRC_FILE) {
586 /*read palette for indexed image*/
587 palette = lv_malloc(palette_len);
588 LV_ASSERT_MALLOC(palette);
589 if(palette == NULL) {
590 LV_LOG_ERROR("Out of memory");
591 return LV_RESULT_INVALID;
592 }
593
594 res = fs_read_file_at(f, sizeof(lv_image_header_t), (uint8_t *)palette, palette_len, &rn);
595 if(res != LV_FS_RES_OK || rn != palette_len) {
596 LV_LOG_WARN("Read palette failed: %d", res);
597 lv_free((void *)palette);
598 return LV_RESULT_INVALID;
599 }
600
601 decoder_data->palette = (void *)palette; /*Need to free when decoder closes*/
602
603 #if LV_BIN_DECODER_RAM_LOAD
604 draw_buf_indexed = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, dsc->header.w, dsc->header.h, cf,
605 dsc->header.stride);
606 if(draw_buf_indexed == NULL) {
607 LV_LOG_ERROR("Draw buffer alloc failed");
608 goto exit_with_buf;
609 }
610
611 indexed_data = draw_buf_indexed->data;
612
613 uint32_t data_len = 0;
614 if(lv_fs_seek(f, 0, LV_FS_SEEK_END) != LV_FS_RES_OK ||
615 lv_fs_tell(f, &data_len) != LV_FS_RES_OK) {
616 LV_LOG_WARN("Failed to get file to size");
617 goto exit_with_buf;
618 }
619
620 uint32_t data_offset = sizeof(lv_image_header_t) + palette_len;
621 data_len -= data_offset;
622 res = fs_read_file_at(f, data_offset, (uint8_t *)indexed_data, data_len, &rn);
623 if(res != LV_FS_RES_OK || rn != data_len) {
624 LV_LOG_WARN("Read indexed image failed: %d", res);
625 goto exit_with_buf;
626 }
627 #endif
628 }
629 else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) {
630 lv_image_dsc_t * image = (lv_image_dsc_t *)dsc->src;
631 palette = (lv_color32_t *)image->data;
632 indexed_data = image->data + palette_len;
633 }
634 else {
635 return LV_RESULT_INVALID;
636 }
637
638 dsc->palette = palette;
639 dsc->palette_size = LV_COLOR_INDEXED_PALETTE_SIZE(cf);
640
641 #if LV_BIN_DECODER_RAM_LOAD
642 /*Convert to ARGB8888, since sw renderer cannot render it directly even it's in RAM*/
643 lv_draw_buf_t * decoded = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, dsc->header.w, dsc->header.h,
644 LV_COLOR_FORMAT_ARGB8888,
645 0);
646 if(decoded == NULL) {
647 LV_LOG_ERROR("No memory for indexed image");
648 goto exit_with_buf;
649 }
650
651 stride = decoded->header.stride;
652 uint8_t * img_data = decoded->data;
653
654 const uint8_t * in = indexed_data;
655 uint8_t * out = img_data;
656 for(uint32_t y = 0; y < dsc->header.h; y++) {
657 decode_indexed_line(cf, dsc->palette, 0, dsc->header.w, in, (lv_color32_t *)out);
658 in += dsc->header.stride;
659 out += stride;
660 }
661
662 dsc->decoded = decoded;
663 decoder_data->decoded = decoded; /*Free when decoder closes*/
664 if(dsc->src_type == LV_IMAGE_SRC_FILE && !is_compressed) {
665 decoder_data->palette = (void *)palette; /*Free decoder data on close*/
666 lv_draw_buf_destroy(draw_buf_indexed);
667 }
668
669 return LV_RESULT_OK;
670 exit_with_buf:
671 if(dsc->src_type == LV_IMAGE_SRC_FILE && !is_compressed) {
672 lv_free((void *)palette);
673 decoder_data->palette = NULL;
674 }
675
676 if(draw_buf_indexed) lv_draw_buf_destroy(draw_buf_indexed);
677 return LV_RESULT_INVALID;
678 #else
679 LV_UNUSED(stride);
680 LV_UNUSED(indexed_data);
681 LV_UNUSED(draw_buf_indexed);
682 /*It needs to be read by get_area_cb later*/
683 return LV_RESULT_OK;
684 #endif
685 }
686
load_indexed(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)687 static lv_result_t load_indexed(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
688 {
689 #if LV_BIN_DECODER_RAM_LOAD == 0
690 LV_UNUSED(decoder); /*Unused*/
691 LV_UNUSED(dsc); /*Unused*/
692 LV_LOG_ERROR("LV_BIN_DECODER_RAM_LOAD is disabled");
693 return LV_RESULT_INVALID;
694 #else
695
696 LV_UNUSED(decoder); /*Unused*/
697
698 lv_fs_res_t res;
699 uint32_t rn;
700 decoder_data_t * decoder_data = dsc->user_data;
701
702 if(dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED) {
703 /*The decompressed image is already loaded to RAM*/
704 dsc->decoded = decoder_data->decompressed;
705
706 /*Transfer ownership to decoded pointer because it's the final data we use.*/
707 decoder_data->decoded = decoder_data->decompressed;
708 decoder_data->decompressed = NULL;
709 return LV_RESULT_OK;
710 }
711
712 if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) {
713 lv_image_dsc_t * image = (lv_image_dsc_t *)dsc->src;
714 lv_draw_buf_t * decoded;
715 if(image->header.flags & LV_IMAGE_FLAGS_ALLOCATED) {
716 decoded = (lv_draw_buf_t *)image;
717 }
718 else {
719 decoded = &decoder_data->c_array;
720 lv_draw_buf_from_image(decoded, image);
721 }
722
723 dsc->decoded = decoded;
724
725 if(decoded->header.stride == 0) {
726 /*Use the auto calculated value from decoder_info callback*/
727 decoded->header.stride = dsc->header.stride;
728 }
729
730 return LV_RESULT_OK;
731 }
732
733 if(dsc->src_type == LV_IMAGE_SRC_FILE) {
734 lv_color_format_t cf = dsc->header.cf;
735 lv_fs_file_t * f = decoder_data->f;
736 lv_draw_buf_t * decoded = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, dsc->header.w, dsc->header.h, cf,
737 dsc->header.stride);
738 if(decoded == NULL) {
739 LV_LOG_ERROR("Draw buffer alloc failed");
740 return LV_RESULT_INVALID;
741 }
742
743 uint8_t * data = decoded->data;
744 uint32_t palette_len = sizeof(lv_color32_t) * LV_COLOR_INDEXED_PALETTE_SIZE(cf);
745 res = fs_read_file_at(f, sizeof(lv_image_header_t), data, palette_len, &rn);
746 if(res != LV_FS_RES_OK || rn != palette_len) {
747 LV_LOG_WARN("Read palette failed: %d", res);
748 lv_draw_buf_destroy(decoded);
749 return LV_RESULT_INVALID;
750 }
751
752 uint32_t data_len = 0;
753 if(lv_fs_seek(f, 0, LV_FS_SEEK_END) != LV_FS_RES_OK ||
754 lv_fs_tell(f, &data_len) != LV_FS_RES_OK) {
755 LV_LOG_WARN("Failed to get file to size");
756 lv_draw_buf_destroy(decoded);
757 return LV_RESULT_INVALID;
758 }
759
760 uint32_t data_offset = sizeof(lv_image_header_t) + palette_len;
761 data_len -= data_offset;
762 data += palette_len;
763 res = fs_read_file_at(f, data_offset, data, data_len, &rn);
764 if(res != LV_FS_RES_OK || rn != data_len) {
765 LV_LOG_WARN("Read indexed image failed: %d", res);
766 lv_draw_buf_destroy(decoded);
767 return LV_RESULT_INVALID;
768 }
769
770 decoder_data->decoded = decoded;
771 dsc->decoded = decoded;
772 return LV_RESULT_OK;
773 }
774
775 LV_LOG_ERROR("Unknown src type: %d", dsc->src_type);
776 return LV_RESULT_INVALID;
777 #endif
778 }
779
780 #if LV_BIN_DECODER_RAM_LOAD
decode_rgb(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)781 static lv_result_t decode_rgb(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
782 {
783 LV_UNUSED(decoder);
784 lv_fs_res_t res;
785 decoder_data_t * decoder_data = dsc->user_data;
786 lv_fs_file_t * f = decoder_data->f;
787 lv_color_format_t cf = dsc->header.cf;
788
789 uint32_t len = dsc->header.stride * dsc->header.h;
790 if(cf == LV_COLOR_FORMAT_RGB565A8) {
791 len += (dsc->header.stride / 2) * dsc->header.h; /*A8 mask*/
792 }
793
794 lv_draw_buf_t * decoded = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, dsc->header.w, dsc->header.h, cf,
795 dsc->header.stride);
796 if(decoded == NULL) {
797 LV_LOG_ERROR("No memory for rgb file read");
798 return LV_RESULT_INVALID;
799 }
800
801 uint8_t * img_data = decoded->data;
802
803 uint32_t rn;
804 res = fs_read_file_at(f, sizeof(lv_image_header_t), img_data, len, &rn);
805 if(res != LV_FS_RES_OK || rn != len) {
806 LV_LOG_WARN("Read rgb file failed: %d", res);
807 lv_draw_buf_destroy(decoded);
808 return LV_RESULT_INVALID;
809 }
810
811 dsc->decoded = decoded;
812 decoder_data->decoded = decoded; /*Free when decoder closes*/
813 return LV_RESULT_OK;
814 }
815 #endif
816
817 /**
818 * Extend A1/2/4 to A8 with interpolation to reduce rounding error.
819 */
bit_extend(uint8_t value,uint8_t bpp)820 static inline uint8_t bit_extend(uint8_t value, uint8_t bpp)
821 {
822 if(value == 0) return 0;
823
824 uint8_t res = value;
825 uint8_t bpp_now = bpp;
826 while(bpp_now < 8) {
827 res |= value << (8 - bpp_now);
828 bpp_now += bpp;
829 };
830
831 return res;
832 }
833
decode_alpha_only(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)834 static lv_result_t decode_alpha_only(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
835 {
836 LV_UNUSED(decoder);
837 lv_fs_res_t res;
838 uint32_t rn;
839 decoder_data_t * decoder_data = dsc->user_data;
840 uint8_t bpp = lv_color_format_get_bpp(dsc->header.cf);
841 uint32_t w = (dsc->header.stride * 8) / bpp;
842 uint32_t buf_stride = (w * 8 + 7) >> 3; /*stride for img_data*/
843 uint32_t buf_len = w * dsc->header.h; /*always decode to A8 format*/
844 lv_draw_buf_t * decoded;
845 uint32_t file_len = (uint32_t)dsc->header.stride * dsc->header.h;
846
847 decoded = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, dsc->header.w, dsc->header.h, LV_COLOR_FORMAT_A8,
848 buf_stride);
849 if(decoded == NULL) {
850 LV_LOG_ERROR("Out of memory");
851 return LV_RESULT_INVALID;
852 }
853
854 uint8_t * img_data = decoded->data;
855
856 if(dsc->header.flags & LV_IMAGE_FLAGS_COMPRESSED) {
857 /*Copy from image data*/
858 lv_memcpy(img_data, decoder_data->decompressed->data, file_len);
859 }
860 else if(dsc->src_type == LV_IMAGE_SRC_FILE) {
861 res = fs_read_file_at(decoder_data->f, sizeof(lv_image_header_t), img_data, file_len, &rn);
862 if(res != LV_FS_RES_OK || rn != file_len) {
863 LV_LOG_WARN("Read header failed: %d", res);
864 lv_draw_buf_destroy(decoded);
865 return LV_RESULT_INVALID;
866 }
867 }
868 else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) {
869 /*Copy from image data*/
870 lv_memcpy(img_data, ((lv_image_dsc_t *)dsc->src)->data, file_len);
871 }
872
873 if(dsc->header.cf != LV_COLOR_FORMAT_A8) {
874 /*Convert A1/2/4 to A8 from last pixel to first pixel*/
875 uint8_t * in = img_data + file_len - 1;
876 uint8_t * out = img_data + buf_len - 1;
877 uint8_t mask = (1 << bpp) - 1;
878 uint8_t shift = 0;
879 for(uint32_t i = 0; i < buf_len; i++) {
880 /**
881 * Rounding error:
882 * Take bpp = 4 as example, alpha value of 0x0 to 0x0F should be
883 * mapped to 0x00 to 0xFF. Using below equation will give us 0x00 to 0xF0
884 * thus causes error. We can simply interpolate the value to fix it.
885 *
886 * Equation: *out = ((*in >> shift) & mask) << (8 - bpp);
887 * Ideal: *out = ((*in >> shift) & mask) * 255 / ((1L << bpp) - 1)
888 */
889 uint8_t value = ((*in >> shift) & mask);
890 *out = bit_extend(value, bpp);
891 shift += bpp;
892 if(shift >= 8) {
893 shift = 0;
894 in--;
895 }
896 out--;
897 }
898 }
899
900 decoder_data->decoded = decoded;
901 dsc->decoded = decoded;
902 return LV_RESULT_OK;
903 }
904
decode_compressed(lv_image_decoder_t * decoder,lv_image_decoder_dsc_t * dsc)905 static lv_result_t decode_compressed(lv_image_decoder_t * decoder, lv_image_decoder_dsc_t * dsc)
906 {
907 #if LV_BIN_DECODER_RAM_LOAD
908 uint32_t rn;
909 uint32_t len;
910 uint32_t compressed_len;
911 decoder_data_t * decoder_data = get_decoder_data(dsc);
912 lv_result_t res;
913 lv_fs_res_t fs_res;
914 uint8_t * file_buf = NULL;
915 lv_image_compressed_t * compressed = &decoder_data->compressed;
916
917 lv_memzero(compressed, sizeof(lv_image_compressed_t));
918
919 if(dsc->src_type == LV_IMAGE_SRC_FILE) {
920 lv_fs_file_t * f = decoder_data->f;
921
922 if(lv_fs_seek(f, 0, LV_FS_SEEK_END) != LV_FS_RES_OK ||
923 lv_fs_tell(f, &compressed_len) != LV_FS_RES_OK) {
924 LV_LOG_WARN("Failed to get compressed file len");
925 return LV_RESULT_INVALID;
926 }
927
928 compressed_len -= sizeof(lv_image_header_t);
929 compressed_len -= 12;
930
931 /*Read compress header*/
932 len = 12;
933 fs_res = fs_read_file_at(f, sizeof(lv_image_header_t), compressed, len, &rn);
934 if(fs_res != LV_FS_RES_OK || rn != len) {
935 LV_LOG_WARN("Read compressed header failed: %d", fs_res);
936 return LV_RESULT_INVALID;
937 }
938
939 if(compressed->compressed_size != compressed_len) {
940 LV_LOG_WARN("Compressed size mismatch: %" LV_PRIu32" != %" LV_PRIu32, compressed->compressed_size, compressed_len);
941 return LV_RESULT_INVALID;
942 }
943
944 file_buf = lv_malloc(compressed_len);
945 if(file_buf == NULL) {
946 LV_LOG_WARN("No memory for compressed file");
947 return LV_RESULT_INVALID;
948
949 }
950
951 /*Continue to read the compressed data following compression header*/
952 fs_res = lv_fs_read(f, file_buf, compressed_len, &rn);
953 if(fs_res != LV_FS_RES_OK || rn != compressed_len) {
954 LV_LOG_WARN("Read compressed file failed: %d", fs_res);
955 lv_free(file_buf);
956 return LV_RESULT_INVALID;
957 }
958
959 /*Decompress the image*/
960 compressed->data = file_buf;
961 }
962 else if(dsc->src_type == LV_IMAGE_SRC_VARIABLE) {
963 lv_image_dsc_t * image = (lv_image_dsc_t *)dsc->src;
964 compressed_len = image->data_size;
965
966 /*Read compress header*/
967 len = 12;
968 compressed_len -= len;
969 lv_memcpy(compressed, image->data, len);
970 compressed->data = image->data + len;
971 if(compressed->compressed_size != compressed_len) {
972 LV_LOG_WARN("Compressed size mismatch: %" LV_PRIu32" != %" LV_PRIu32, compressed->compressed_size, compressed_len);
973 return LV_RESULT_INVALID;
974 }
975 }
976 else {
977 LV_LOG_WARN("Compressed image only support file or variable");
978 return LV_RESULT_INVALID;
979 }
980
981 res = decompress_image(dsc, compressed);
982 compressed->data = NULL; /*No need to store the data any more*/
983 lv_free(file_buf);
984 if(res != LV_RESULT_OK) {
985 LV_LOG_WARN("Decompress failed");
986 return LV_RESULT_INVALID;
987 }
988
989 /*Depends on the cf, need to further decode image like an C-array image*/
990 lv_image_dsc_t * image = (lv_image_dsc_t *)dsc->src;
991 if(image->data == NULL) {
992 return LV_RESULT_INVALID;
993 }
994
995 lv_color_format_t cf = dsc->header.cf;
996 if(LV_COLOR_FORMAT_IS_INDEXED(cf)) {
997 if(dsc->args.use_indexed) res = load_indexed(decoder, dsc);
998 else res = decode_indexed(decoder, dsc);
999 }
1000 else if(LV_COLOR_FORMAT_IS_ALPHA_ONLY(cf)) {
1001 res = decode_alpha_only(decoder, dsc);
1002 }
1003 else {
1004 /*The decompressed data is the original image data.*/
1005 dsc->decoded = decoder_data->decompressed;
1006
1007 /*Transfer ownership of decompressed to `decoded` since it can be used directly*/
1008 decoder_data->decoded = decoder_data->decompressed;
1009 decoder_data->decompressed = NULL;
1010 res = LV_RESULT_OK;
1011 }
1012
1013 return res;
1014 #else
1015 LV_UNUSED(decompress_image);
1016 LV_UNUSED(decoder);
1017 LV_UNUSED(dsc);
1018 LV_LOG_ERROR("Need LV_BIN_DECODER_RAM_LOAD to be enabled");
1019 return LV_RESULT_INVALID;
1020 #endif
1021 }
1022
decode_indexed_line(lv_color_format_t color_format,const lv_color32_t * palette,int32_t x,int32_t w_px,const uint8_t * in,lv_color32_t * out)1023 static lv_result_t decode_indexed_line(lv_color_format_t color_format, const lv_color32_t * palette, int32_t x,
1024 int32_t w_px, const uint8_t * in, lv_color32_t * out)
1025 {
1026 uint8_t px_size;
1027 uint16_t mask;
1028
1029 int8_t shift = 0;
1030 switch(color_format) {
1031 case LV_COLOR_FORMAT_I1:
1032 px_size = 1;
1033 in += x / 8; /*8pixel per byte*/
1034 shift = 7 - (x & 0x7);
1035 break;
1036 case LV_COLOR_FORMAT_I2:
1037 px_size = 2;
1038 in += x / 4; /*4pixel per byte*/
1039 shift = 6 - 2 * (x & 0x3);
1040 break;
1041 case LV_COLOR_FORMAT_I4:
1042 px_size = 4;
1043 in += x / 2; /*2pixel per byte*/
1044 shift = 4 - 4 * (x & 0x1);
1045 break;
1046 case LV_COLOR_FORMAT_I8:
1047 px_size = 8;
1048 in += x;
1049 shift = 0;
1050 break;
1051 default:
1052 return LV_RESULT_INVALID;
1053 }
1054
1055 mask = (1 << px_size) - 1; /*E.g. px_size = 2; mask = 0x03*/
1056
1057 int32_t i;
1058 for(i = 0; i < w_px; i++) {
1059 uint8_t val_act = (*in >> shift) & mask;
1060 out[i] = palette[val_act];
1061
1062 shift -= px_size;
1063 if(shift < 0) {
1064 shift = 8 - px_size;
1065 in++;
1066 }
1067 }
1068 return LV_RESULT_OK;
1069 }
1070
fs_read_file_at(lv_fs_file_t * f,uint32_t pos,void * buff,uint32_t btr,uint32_t * br)1071 static lv_fs_res_t fs_read_file_at(lv_fs_file_t * f, uint32_t pos, void * buff, uint32_t btr, uint32_t * br)
1072 {
1073 lv_fs_res_t res;
1074 if(br) *br = 0;
1075
1076 res = lv_fs_seek(f, pos, LV_FS_SEEK_SET);
1077 if(res != LV_FS_RES_OK) {
1078 return res;
1079 }
1080
1081 res |= lv_fs_read(f, buff, btr, br);
1082 if(res != LV_FS_RES_OK) {
1083 return res;
1084 }
1085
1086 return LV_FS_RES_OK;
1087 }
1088
decompress_image(lv_image_decoder_dsc_t * dsc,const lv_image_compressed_t * compressed)1089 static lv_result_t decompress_image(lv_image_decoder_dsc_t * dsc, const lv_image_compressed_t * compressed)
1090 {
1091 /*Need to store decompressed data to decoder to free on close*/
1092 decoder_data_t * decoder_data = get_decoder_data(dsc);
1093 if(decoder_data == NULL) {
1094 return LV_RESULT_INVALID;
1095 }
1096
1097 uint8_t * img_data;
1098 uint32_t out_len = compressed->decompressed_size;
1099 uint32_t input_len = compressed->compressed_size;
1100 LV_UNUSED(input_len);
1101 LV_UNUSED(out_len);
1102
1103 lv_draw_buf_t * decompressed = lv_draw_buf_create_ex(image_cache_draw_buf_handlers, dsc->header.w, dsc->header.h,
1104 dsc->header.cf,
1105 dsc->header.stride);
1106 if(decompressed == NULL) {
1107 LV_LOG_WARN("No memory for decompressed image, input: %" LV_PRIu32 ", output: %" LV_PRIu32, input_len, out_len);
1108 return LV_RESULT_INVALID;
1109 }
1110
1111 if(out_len > decompressed->data_size) {
1112 LV_LOG_ERROR("Decompressed size mismatch: %" LV_PRIu32 " > %" LV_PRIu32, out_len, decompressed->data_size);
1113 lv_draw_buf_destroy(decompressed);
1114 return LV_RESULT_INVALID;
1115 }
1116
1117 img_data = decompressed->data;
1118
1119 if(compressed->method == LV_IMAGE_COMPRESS_RLE) {
1120 #if LV_USE_RLE
1121 /*Compress always happen on byte*/
1122 uint32_t pixel_byte;
1123 if(dsc->header.cf == LV_COLOR_FORMAT_RGB565A8)
1124 pixel_byte = 2;
1125 else
1126 pixel_byte = (lv_color_format_get_bpp(dsc->header.cf) + 7) >> 3;
1127 const uint8_t * input = compressed->data;
1128 uint8_t * output = img_data;
1129 uint32_t len;
1130 len = lv_rle_decompress(input, input_len, output, out_len, pixel_byte);
1131 if(len != compressed->decompressed_size) {
1132 LV_LOG_WARN("Decompress failed: %" LV_PRIu32 ", got: %" LV_PRIu32, out_len, len);
1133 lv_draw_buf_destroy(decompressed);
1134 return LV_RESULT_INVALID;
1135 }
1136 #else
1137 LV_LOG_WARN("RLE decompress is not enabled");
1138 lv_draw_buf_destroy(decompressed);
1139 return LV_RESULT_INVALID;
1140 #endif
1141 }
1142 else if(compressed->method == LV_IMAGE_COMPRESS_LZ4) {
1143 #if LV_USE_LZ4
1144 const char * input = (const char *)compressed->data;
1145 char * output = (char *)img_data;
1146 int len;
1147 len = LZ4_decompress_safe(input, output, input_len, out_len);
1148 if(len < 0 || (uint32_t)len != compressed->decompressed_size) {
1149 LV_LOG_WARN("Decompress failed: %" LV_PRId32 ", got: %" LV_PRId32, out_len, len);
1150 lv_draw_buf_destroy(decompressed);
1151 return LV_RESULT_INVALID;
1152 }
1153 #else
1154 LV_LOG_WARN("LZ4 decompress is not enabled");
1155 lv_draw_buf_destroy(decompressed);
1156 return LV_RESULT_INVALID;
1157 #endif
1158 }
1159 else {
1160 LV_UNUSED(img_data);
1161 LV_LOG_WARN("Unknown compression method: %d", compressed->method);
1162 lv_draw_buf_destroy(decompressed);
1163 return LV_RESULT_INVALID;
1164 }
1165
1166 decoder_data->decompressed = decompressed; /*Free on decoder close*/
1167 return LV_RESULT_OK;
1168 }
1169