acid-drop

- Hacking the planet from a LilyGo T-Deck using custom firmware
git clone git://git.acid.vegas/acid-drop.git
Log | Files | Refs | Archive | README | LICENSE

lv_img_decoder.c (25258B)

      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  */
     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  */
     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 
    107 lv_res_t lv_img_decoder_open(lv_img_decoder_dsc_t * dsc, const void * src, lv_color_t color, int32_t frame_id)
    108 {
    109     lv_memset_00(dsc, sizeof(lv_img_decoder_dsc_t));
    110 
    111     if(src == NULL) return LV_RES_INV;
    112     lv_img_src_t src_type = lv_img_src_get_type(src);
    113     if(src_type == LV_IMG_SRC_VARIABLE) {
    114         const lv_img_dsc_t * img_dsc = src;
    115         if(img_dsc->data == NULL) return LV_RES_INV;
    116     }
    117 
    118     dsc->color    = color;
    119     dsc->src_type = src_type;
    120     dsc->frame_id = frame_id;
    121 
    122     if(dsc->src_type == LV_IMG_SRC_FILE) {
    123         size_t fnlen = strlen(src);
    124         dsc->src = lv_mem_alloc(fnlen + 1);
    125         LV_ASSERT_MALLOC(dsc->src);
    126         if(dsc->src == NULL) {
    127             LV_LOG_WARN("lv_img_decoder_open: out of memory");
    128             return LV_RES_INV;
    129         }
    130         strcpy((char *)dsc->src, src);
    131     }
    132     else {
    133         dsc->src = src;
    134     }
    135 
    136     lv_res_t res = LV_RES_INV;
    137 
    138     lv_img_decoder_t * decoder;
    139     _LV_LL_READ(&LV_GC_ROOT(_lv_img_decoder_ll), decoder) {
    140         /*Info and Open callbacks are required*/
    141         if(decoder->info_cb == NULL || decoder->open_cb == NULL) continue;
    142 
    143         res = decoder->info_cb(decoder, src, &dsc->header);
    144         if(res != LV_RES_OK) continue;
    145 
    146         dsc->decoder = decoder;
    147         res = decoder->open_cb(decoder, dsc);
    148 
    149         /*Opened successfully. It is a good decoder for this image source*/
    150         if(res == LV_RES_OK) return res;
    151 
    152         /*Prepare for the next loop*/
    153         lv_memset_00(&dsc->header, sizeof(lv_img_header_t));
    154 
    155         dsc->error_msg = NULL;
    156         dsc->img_data  = NULL;
    157         dsc->user_data = NULL;
    158         dsc->time_to_open = 0;
    159     }
    160 
    161     if(dsc->src_type == LV_IMG_SRC_FILE)
    162         lv_mem_free((void *)dsc->src);
    163 
    164     return res;
    165 }
    166 
    167 /**
    168  * Read a line from an opened image
    169  * @param dsc pointer to `lv_img_decoder_dsc_t` used in `lv_img_decoder_open`
    170  * @param x start X coordinate (from left)
    171  * @param y start Y coordinate (from top)
    172  * @param len number of pixels to read
    173  * @param buf store the data here
    174  * @return LV_RES_OK: success; LV_RES_INV: an error occurred
    175  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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 
    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 
    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 
    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 }