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