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_png.c (8729B)

      1 /**
      2  * @file lv_png.c
      3  *
      4  */
      5 
      6 /*********************
      7  *      INCLUDES
      8  *********************/
      9 #include "../../../lvgl.h"
     10 #if LV_USE_PNG
     11 
     12 #include "lv_png.h"
     13 #include "lodepng.h"
     14 #include <stdlib.h>
     15 
     16 /*********************
     17  *      DEFINES
     18  *********************/
     19 
     20 /**********************
     21  *      TYPEDEFS
     22  **********************/
     23 
     24 /**********************
     25  *  STATIC PROTOTYPES
     26  **********************/
     27 static lv_res_t decoder_info(struct _lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header);
     28 static lv_res_t decoder_open(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc);
     29 static void decoder_close(lv_img_decoder_t * dec, lv_img_decoder_dsc_t * dsc);
     30 static void convert_color_depth(uint8_t * img, uint32_t px_cnt);
     31 
     32 /**********************
     33  *  STATIC VARIABLES
     34  **********************/
     35 
     36 /**********************
     37  *      MACROS
     38  **********************/
     39 
     40 /**********************
     41  *   GLOBAL FUNCTIONS
     42  **********************/
     43 
     44 /**
     45  * Register the PNG decoder functions in LVGL
     46  */
     47 void lv_png_init(void)
     48 {
     49     lv_img_decoder_t * dec = lv_img_decoder_create();
     50     lv_img_decoder_set_info_cb(dec, decoder_info);
     51     lv_img_decoder_set_open_cb(dec, decoder_open);
     52     lv_img_decoder_set_close_cb(dec, decoder_close);
     53 }
     54 
     55 /**********************
     56  *   STATIC FUNCTIONS
     57  **********************/
     58 
     59 /**
     60  * Get info about a PNG image
     61  * @param src can be file name or pointer to a C array
     62  * @param header store the info here
     63  * @return LV_RES_OK: no error; LV_RES_INV: can't get the info
     64  */
     65 static lv_res_t decoder_info(struct _lv_img_decoder_t * decoder, const void * src, lv_img_header_t * header)
     66 {
     67     (void) decoder; /*Unused*/
     68     lv_img_src_t src_type = lv_img_src_get_type(src);          /*Get the source type*/
     69 
     70     /*If it's a PNG file...*/
     71     if(src_type == LV_IMG_SRC_FILE) {
     72         const char * fn = src;
     73         if(strcmp(lv_fs_get_ext(fn), "png") == 0) {              /*Check the extension*/
     74 
     75             /* Read the width and height from the file. They have a constant location:
     76              * [16..23]: width
     77              * [24..27]: height
     78              */
     79             uint32_t size[2];
     80             lv_fs_file_t f;
     81             lv_fs_res_t res = lv_fs_open(&f, fn, LV_FS_MODE_RD);
     82             if(res != LV_FS_RES_OK) return LV_RES_INV;
     83 
     84             lv_fs_seek(&f, 16, LV_FS_SEEK_SET);
     85 
     86             uint32_t rn;
     87             lv_fs_read(&f, &size, 8, &rn);
     88             lv_fs_close(&f);
     89 
     90             if(rn != 8) return LV_RES_INV;
     91 
     92             /*Save the data in the header*/
     93             header->always_zero = 0;
     94             header->cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
     95             /*The width and height are stored in Big endian format so convert them to little endian*/
     96             header->w = (lv_coord_t)((size[0] & 0xff000000) >> 24) + ((size[0] & 0x00ff0000) >> 8);
     97             header->h = (lv_coord_t)((size[1] & 0xff000000) >> 24) + ((size[1] & 0x00ff0000) >> 8);
     98 
     99             return LV_RES_OK;
    100         }
    101     }
    102     /*If it's a PNG file in a  C array...*/
    103     else if(src_type == LV_IMG_SRC_VARIABLE) {
    104         const lv_img_dsc_t * img_dsc = src;
    105         const uint32_t data_size = img_dsc->data_size;
    106         const uint8_t magic[] = {0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a};
    107         if(data_size < sizeof(magic)) return LV_RES_INV;
    108         if(memcmp(magic, img_dsc->data, sizeof(magic))) return LV_RES_INV;
    109         header->always_zero = 0;
    110         header->cf = img_dsc->header.cf;       /*Save the color format*/
    111         header->w = img_dsc->header.w;         /*Save the color width*/
    112         header->h = img_dsc->header.h;         /*Save the color height*/
    113         return LV_RES_OK;
    114     }
    115 
    116     return LV_RES_INV;         /*If didn't succeeded earlier then it's an error*/
    117 }
    118 
    119 
    120 /**
    121  * Open a PNG image and return the decided image
    122  * @param src can be file name or pointer to a C array
    123  * @param style style of the image object (unused now but certain formats might use it)
    124  * @return pointer to the decoded image or `LV_IMG_DECODER_OPEN_FAIL` if failed
    125  */
    126 static lv_res_t decoder_open(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
    127 {
    128 
    129     (void) decoder; /*Unused*/
    130     uint32_t error;                 /*For the return values of PNG decoder functions*/
    131 
    132     uint8_t * img_data = NULL;
    133 
    134     /*If it's a PNG file...*/
    135     if(dsc->src_type == LV_IMG_SRC_FILE) {
    136         const char * fn = dsc->src;
    137         if(strcmp(lv_fs_get_ext(fn), "png") == 0) {              /*Check the extension*/
    138 
    139             /*Load the PNG file into buffer. It's still compressed (not decoded)*/
    140             unsigned char * png_data;      /*Pointer to the loaded data. Same as the original file just loaded into the RAM*/
    141             size_t png_data_size;          /*Size of `png_data` in bytes*/
    142 
    143             error = lodepng_load_file(&png_data, &png_data_size, fn);   /*Load the file*/
    144             if(error) {
    145                 LV_LOG_WARN("error %u: %s\n", error, lodepng_error_text(error));
    146                 return LV_RES_INV;
    147             }
    148 
    149             /*Decode the PNG image*/
    150             uint32_t png_width;             /*Will be the width of the decoded image*/
    151             uint32_t png_height;            /*Will be the width of the decoded image*/
    152 
    153             /*Decode the loaded image in ARGB8888 */
    154             error = lodepng_decode32(&img_data, &png_width, &png_height, png_data, png_data_size);
    155             lv_mem_free(png_data); /*Free the loaded file*/
    156             if(error) {
    157                 if(img_data != NULL) {
    158                     lv_mem_free(img_data);
    159                 }
    160                 LV_LOG_WARN("error %u: %s\n", error, lodepng_error_text(error));
    161                 return LV_RES_INV;
    162             }
    163 
    164             /*Convert the image to the system's color depth*/
    165             convert_color_depth(img_data,  png_width * png_height);
    166             dsc->img_data = img_data;
    167             return LV_RES_OK;     /*The image is fully decoded. Return with its pointer*/
    168         }
    169     }
    170     /*If it's a PNG file in a  C array...*/
    171     else if(dsc->src_type == LV_IMG_SRC_VARIABLE) {
    172         const lv_img_dsc_t * img_dsc = dsc->src;
    173         uint32_t png_width;             /*No used, just required by he decoder*/
    174         uint32_t png_height;            /*No used, just required by he decoder*/
    175 
    176         /*Decode the image in ARGB8888 */
    177         error = lodepng_decode32(&img_data, &png_width, &png_height, img_dsc->data, img_dsc->data_size);
    178 
    179         if(error) {
    180             if(img_data != NULL) {
    181                 lv_mem_free(img_data);
    182             }
    183             return LV_RES_INV;
    184         }
    185 
    186         /*Convert the image to the system's color depth*/
    187         convert_color_depth(img_data,  png_width * png_height);
    188 
    189         dsc->img_data = img_data;
    190         return LV_RES_OK;     /*Return with its pointer*/
    191     }
    192 
    193     return LV_RES_INV;    /*If not returned earlier then it failed*/
    194 }
    195 
    196 /**
    197  * Free the allocated resources
    198  */
    199 static void decoder_close(lv_img_decoder_t * decoder, lv_img_decoder_dsc_t * dsc)
    200 {
    201     LV_UNUSED(decoder); /*Unused*/
    202     if(dsc->img_data) {
    203         lv_mem_free((uint8_t *)dsc->img_data);
    204         dsc->img_data = NULL;
    205     }
    206 }
    207 
    208 /**
    209  * If the display is not in 32 bit format (ARGB888) then covert the image to the current color depth
    210  * @param img the ARGB888 image
    211  * @param px_cnt number of pixels in `img`
    212  */
    213 static void convert_color_depth(uint8_t * img, uint32_t px_cnt)
    214 {
    215 #if LV_COLOR_DEPTH == 32
    216     lv_color32_t * img_argb = (lv_color32_t *)img;
    217     lv_color_t c;
    218     lv_color_t * img_c = (lv_color_t *) img;
    219     uint32_t i;
    220     for(i = 0; i < px_cnt; i++) {
    221         c = lv_color_make(img_argb[i].ch.red, img_argb[i].ch.green, img_argb[i].ch.blue);
    222         img_c[i].ch.red = c.ch.blue;
    223         img_c[i].ch.blue = c.ch.red;
    224     }
    225 #elif LV_COLOR_DEPTH == 16
    226     lv_color32_t * img_argb = (lv_color32_t *)img;
    227     lv_color_t c;
    228     uint32_t i;
    229     for(i = 0; i < px_cnt; i++) {
    230         c = lv_color_make(img_argb[i].ch.blue, img_argb[i].ch.green, img_argb[i].ch.red);
    231         img[i * 3 + 2] = img_argb[i].ch.alpha;
    232         img[i * 3 + 1] = c.full >> 8;
    233         img[i * 3 + 0] = c.full & 0xFF;
    234     }
    235 #elif LV_COLOR_DEPTH == 8
    236     lv_color32_t * img_argb = (lv_color32_t *)img;
    237     lv_color_t c;
    238     uint32_t i;
    239     for(i = 0; i < px_cnt; i++) {
    240         c = lv_color_make(img_argb[i].ch.red, img_argb[i].ch.green, img_argb[i].ch.blue);
    241         img[i * 2 + 1] = img_argb[i].ch.alpha;
    242         img[i * 2 + 0] = c.full;
    243     }
    244 #elif LV_COLOR_DEPTH == 1
    245     lv_color32_t * img_argb = (lv_color32_t *)img;
    246     uint8_t b;
    247     uint32_t i;
    248     for(i = 0; i < px_cnt; i++) {
    249         b = img_argb[i].ch.red | img_argb[i].ch.green | img_argb[i].ch.blue;
    250         img[i * 2 + 1] = img_argb[i].ch.alpha;
    251         img[i * 2 + 0] = b > 128 ? 1 : 0;
    252     }
    253 #endif
    254 }
    255 
    256 #endif /*LV_USE_PNG*/
    257 
    258