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_draw_img.c (10832B)

      1 /**
      2  * @file lv_draw_img.c
      3  *
      4  */
      5 
      6 /*********************
      7  *      INCLUDES
      8  *********************/
      9 #include "lv_draw_img.h"
     10 #include "lv_img_cache.h"
     11 #include "../hal/lv_hal_disp.h"
     12 #include "../misc/lv_log.h"
     13 #include "../core/lv_refr.h"
     14 #include "../misc/lv_mem.h"
     15 #include "../misc/lv_math.h"
     16 
     17 /*********************
     18  *      DEFINES
     19  *********************/
     20 
     21 /**********************
     22  *      TYPEDEFS
     23  **********************/
     24 
     25 /**********************
     26  *  STATIC PROTOTYPES
     27  **********************/
     28 LV_ATTRIBUTE_FAST_MEM static lv_res_t decode_and_draw(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc,
     29                                                       const lv_area_t * coords, const void * src);
     30 
     31 static void show_error(lv_draw_ctx_t * draw_ctx, const lv_area_t * coords, const char * msg);
     32 static void draw_cleanup(_lv_img_cache_entry_t * cache);
     33 
     34 /**********************
     35  *  STATIC VARIABLES
     36  **********************/
     37 
     38 /**********************
     39  *      MACROS
     40  **********************/
     41 
     42 /**********************
     43  *   GLOBAL FUNCTIONS
     44  **********************/
     45 
     46 void lv_draw_img_dsc_init(lv_draw_img_dsc_t * dsc)
     47 {
     48     lv_memset_00(dsc, sizeof(lv_draw_img_dsc_t));
     49     dsc->recolor = lv_color_black();
     50     dsc->opa = LV_OPA_COVER;
     51     dsc->zoom = LV_IMG_ZOOM_NONE;
     52     dsc->antialias = LV_COLOR_DEPTH > 8 ? 1 : 0;
     53 }
     54 
     55 /**
     56  * Draw an image
     57  * @param coords the coordinates of the image
     58  * @param mask the image will be drawn only in this area
     59  * @param src pointer to a lv_color_t array which contains the pixels of the image
     60  * @param dsc pointer to an initialized `lv_draw_img_dsc_t` variable
     61  */
     62 void lv_draw_img(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc, const lv_area_t * coords, const void * src)
     63 {
     64     if(src == NULL) {
     65         LV_LOG_WARN("Image draw: src is NULL");
     66         show_error(draw_ctx, coords, "No\ndata");
     67         return;
     68     }
     69 
     70     if(dsc->opa <= LV_OPA_MIN) return;
     71 
     72     lv_res_t res;
     73     if(draw_ctx->draw_img) {
     74         res = draw_ctx->draw_img(draw_ctx, dsc, coords, src);
     75     }
     76     else {
     77         res = decode_and_draw(draw_ctx, dsc, coords, src);
     78     }
     79 
     80     if(res == LV_RES_INV) {
     81         LV_LOG_WARN("Image draw error");
     82         show_error(draw_ctx, coords, "No\ndata");
     83         return;
     84     }
     85 }
     86 
     87 /**
     88  * Get the pixel size of a color format in bits
     89  * @param cf a color format (`LV_IMG_CF_...`)
     90  * @return the pixel size in bits
     91  */
     92 uint8_t lv_img_cf_get_px_size(lv_img_cf_t cf)
     93 {
     94     uint8_t px_size = 0;
     95 
     96     switch(cf) {
     97         case LV_IMG_CF_UNKNOWN:
     98         case LV_IMG_CF_RAW:
     99             px_size = 0;
    100             break;
    101         case LV_IMG_CF_TRUE_COLOR:
    102         case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
    103             px_size = LV_COLOR_SIZE;
    104             break;
    105         case LV_IMG_CF_TRUE_COLOR_ALPHA:
    106             px_size = LV_IMG_PX_SIZE_ALPHA_BYTE << 3;
    107             break;
    108         case LV_IMG_CF_INDEXED_1BIT:
    109         case LV_IMG_CF_ALPHA_1BIT:
    110             px_size = 1;
    111             break;
    112         case LV_IMG_CF_INDEXED_2BIT:
    113         case LV_IMG_CF_ALPHA_2BIT:
    114             px_size = 2;
    115             break;
    116         case LV_IMG_CF_INDEXED_4BIT:
    117         case LV_IMG_CF_ALPHA_4BIT:
    118             px_size = 4;
    119             break;
    120         case LV_IMG_CF_INDEXED_8BIT:
    121         case LV_IMG_CF_ALPHA_8BIT:
    122             px_size = 8;
    123             break;
    124         default:
    125             px_size = 0;
    126             break;
    127     }
    128 
    129     return px_size;
    130 }
    131 
    132 /**
    133  * Check if a color format is chroma keyed or not
    134  * @param cf a color format (`LV_IMG_CF_...`)
    135  * @return true: chroma keyed; false: not chroma keyed
    136  */
    137 bool lv_img_cf_is_chroma_keyed(lv_img_cf_t cf)
    138 {
    139     bool is_chroma_keyed = false;
    140 
    141     switch(cf) {
    142         case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
    143         case LV_IMG_CF_RAW_CHROMA_KEYED:
    144             is_chroma_keyed = true;
    145             break;
    146 
    147         default:
    148             is_chroma_keyed = false;
    149             break;
    150     }
    151 
    152     return is_chroma_keyed;
    153 }
    154 
    155 /**
    156  * Check if a color format has alpha channel or not
    157  * @param cf a color format (`LV_IMG_CF_...`)
    158  * @return true: has alpha channel; false: doesn't have alpha channel
    159  */
    160 bool lv_img_cf_has_alpha(lv_img_cf_t cf)
    161 {
    162     bool has_alpha = false;
    163 
    164     switch(cf) {
    165         case LV_IMG_CF_TRUE_COLOR_ALPHA:
    166         case LV_IMG_CF_RAW_ALPHA:
    167         case LV_IMG_CF_INDEXED_1BIT:
    168         case LV_IMG_CF_INDEXED_2BIT:
    169         case LV_IMG_CF_INDEXED_4BIT:
    170         case LV_IMG_CF_INDEXED_8BIT:
    171         case LV_IMG_CF_ALPHA_1BIT:
    172         case LV_IMG_CF_ALPHA_2BIT:
    173         case LV_IMG_CF_ALPHA_4BIT:
    174         case LV_IMG_CF_ALPHA_8BIT:
    175             has_alpha = true;
    176             break;
    177         default:
    178             has_alpha = false;
    179             break;
    180     }
    181 
    182     return has_alpha;
    183 }
    184 
    185 /**
    186  * Get the type of an image source
    187  * @param src pointer to an image source:
    188  *  - pointer to an 'lv_img_t' variable (image stored internally and compiled into the code)
    189  *  - a path to a file (e.g. "S:/folder/image.bin")
    190  *  - or a symbol (e.g. LV_SYMBOL_CLOSE)
    191  * @return type of the image source LV_IMG_SRC_VARIABLE/FILE/SYMBOL/UNKNOWN
    192  */
    193 lv_img_src_t lv_img_src_get_type(const void * src)
    194 {
    195     lv_img_src_t img_src_type = LV_IMG_SRC_UNKNOWN;
    196 
    197     if(src == NULL) return img_src_type;
    198     const uint8_t * u8_p = src;
    199 
    200     /*The first byte shows the type of the image source*/
    201     if(u8_p[0] >= 0x20 && u8_p[0] <= 0x7F) {
    202         img_src_type = LV_IMG_SRC_FILE; /*If it's an ASCII character then it's file name*/
    203     }
    204     else if(u8_p[0] >= 0x80) {
    205         img_src_type = LV_IMG_SRC_SYMBOL; /*Symbols begins after 0x7F*/
    206     }
    207     else {
    208         img_src_type = LV_IMG_SRC_VARIABLE; /*`lv_img_dsc_t` is draw to the first byte < 0x20*/
    209     }
    210 
    211     if(LV_IMG_SRC_UNKNOWN == img_src_type) {
    212         LV_LOG_WARN("lv_img_src_get_type: unknown image type");
    213     }
    214 
    215     return img_src_type;
    216 }
    217 
    218 void lv_draw_img_decoded(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * dsc,
    219                          const lv_area_t * coords, const uint8_t * map_p, lv_img_cf_t color_format)
    220 {
    221     if(draw_ctx->draw_img_decoded == NULL) return;
    222 
    223     draw_ctx->draw_img_decoded(draw_ctx, dsc, coords, map_p, color_format);
    224 }
    225 
    226 /**********************
    227  *   STATIC FUNCTIONS
    228  **********************/
    229 
    230 LV_ATTRIBUTE_FAST_MEM static lv_res_t decode_and_draw(lv_draw_ctx_t * draw_ctx, const lv_draw_img_dsc_t * draw_dsc,
    231                                                       const lv_area_t * coords, const void * src)
    232 {
    233     if(draw_dsc->opa <= LV_OPA_MIN) return LV_RES_OK;
    234 
    235     _lv_img_cache_entry_t * cdsc = _lv_img_cache_open(src, draw_dsc->recolor, draw_dsc->frame_id);
    236 
    237     if(cdsc == NULL) return LV_RES_INV;
    238 
    239 
    240     lv_img_cf_t cf;
    241     if(lv_img_cf_is_chroma_keyed(cdsc->dec_dsc.header.cf)) cf = LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED;
    242     else if(lv_img_cf_has_alpha(cdsc->dec_dsc.header.cf)) cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
    243     else cf = LV_IMG_CF_TRUE_COLOR;
    244 
    245     if(cdsc->dec_dsc.error_msg != NULL) {
    246         LV_LOG_WARN("Image draw error");
    247 
    248         show_error(draw_ctx, coords, cdsc->dec_dsc.error_msg);
    249     }
    250     /*The decoder could open the image and gave the entire uncompressed image.
    251      *Just draw it!*/
    252     else if(cdsc->dec_dsc.img_data) {
    253         lv_area_t map_area_rot;
    254         lv_area_copy(&map_area_rot, coords);
    255         if(draw_dsc->angle || draw_dsc->zoom != LV_IMG_ZOOM_NONE) {
    256             int32_t w = lv_area_get_width(coords);
    257             int32_t h = lv_area_get_height(coords);
    258 
    259             _lv_img_buf_get_transformed_area(&map_area_rot, w, h, draw_dsc->angle, draw_dsc->zoom, &draw_dsc->pivot);
    260 
    261             map_area_rot.x1 += coords->x1;
    262             map_area_rot.y1 += coords->y1;
    263             map_area_rot.x2 += coords->x1;
    264             map_area_rot.y2 += coords->y1;
    265         }
    266 
    267         lv_area_t clip_com; /*Common area of mask and coords*/
    268         bool union_ok;
    269         union_ok = _lv_area_intersect(&clip_com, draw_ctx->clip_area, &map_area_rot);
    270         /*Out of mask. There is nothing to draw so the image is drawn successfully.*/
    271         if(union_ok == false) {
    272             draw_cleanup(cdsc);
    273             return LV_RES_OK;
    274         }
    275 
    276         const lv_area_t * clip_area_ori = draw_ctx->clip_area;
    277         draw_ctx->clip_area = &clip_com;
    278         lv_draw_img_decoded(draw_ctx, draw_dsc, coords, cdsc->dec_dsc.img_data, cf);
    279         draw_ctx->clip_area = clip_area_ori;
    280     }
    281     /*The whole uncompressed image is not available. Try to read it line-by-line*/
    282     else {
    283         lv_area_t mask_com; /*Common area of mask and coords*/
    284         bool union_ok;
    285         union_ok = _lv_area_intersect(&mask_com, draw_ctx->clip_area, coords);
    286         /*Out of mask. There is nothing to draw so the image is drawn successfully.*/
    287         if(union_ok == false) {
    288             draw_cleanup(cdsc);
    289             return LV_RES_OK;
    290         }
    291 
    292         int32_t width = lv_area_get_width(&mask_com);
    293 
    294         uint8_t  * buf = lv_mem_buf_get(lv_area_get_width(&mask_com) *
    295                                         LV_IMG_PX_SIZE_ALPHA_BYTE);  /*+1 because of the possible alpha byte*/
    296 
    297         const lv_area_t * clip_area_ori = draw_ctx->clip_area;
    298         lv_area_t line;
    299         lv_area_copy(&line, &mask_com);
    300         lv_area_set_height(&line, 1);
    301         int32_t x = mask_com.x1 - coords->x1;
    302         int32_t y = mask_com.y1 - coords->y1;
    303         int32_t row;
    304         lv_res_t read_res;
    305         for(row = mask_com.y1; row <= mask_com.y2; row++) {
    306             lv_area_t mask_line;
    307             union_ok = _lv_area_intersect(&mask_line, clip_area_ori, &line);
    308             if(union_ok == false) continue;
    309 
    310             read_res = lv_img_decoder_read_line(&cdsc->dec_dsc, x, y, width, buf);
    311             if(read_res != LV_RES_OK) {
    312                 lv_img_decoder_close(&cdsc->dec_dsc);
    313                 LV_LOG_WARN("Image draw can't read the line");
    314                 lv_mem_buf_release(buf);
    315                 draw_cleanup(cdsc);
    316                 draw_ctx->clip_area = clip_area_ori;
    317                 return LV_RES_INV;
    318             }
    319 
    320             draw_ctx->clip_area = &mask_line;
    321             lv_draw_img_decoded(draw_ctx, draw_dsc, &line, buf, cf);
    322             line.y1++;
    323             line.y2++;
    324             y++;
    325         }
    326         draw_ctx->clip_area = clip_area_ori;
    327         lv_mem_buf_release(buf);
    328     }
    329 
    330     draw_cleanup(cdsc);
    331     return LV_RES_OK;
    332 }
    333 
    334 
    335 static void show_error(lv_draw_ctx_t * draw_ctx, const lv_area_t * coords, const char * msg)
    336 {
    337     lv_draw_rect_dsc_t rect_dsc;
    338     lv_draw_rect_dsc_init(&rect_dsc);
    339     rect_dsc.bg_color = lv_color_white();
    340     lv_draw_rect(draw_ctx, &rect_dsc, coords);
    341 
    342     lv_draw_label_dsc_t label_dsc;
    343     lv_draw_label_dsc_init(&label_dsc);
    344     lv_draw_label(draw_ctx, &label_dsc, coords, msg, NULL);
    345 }
    346 
    347 static void draw_cleanup(_lv_img_cache_entry_t * cache)
    348 {
    349     /*Automatically close images with no caching*/
    350 #if LV_IMG_CACHE_DEF_SIZE == 0
    351     lv_img_decoder_close(&cache->dec_dsc);
    352 #else
    353     LV_UNUSED(cache);
    354 #endif
    355 }