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_buf.c (27211B)

      1 /**
      2  * @file lv_img_buf.c
      3  *
      4  */
      5 
      6 /*********************
      7  *      INCLUDES
      8  *********************/
      9 #include <stddef.h>
     10 #include <string.h>
     11 #include "lv_img_buf.h"
     12 #include "lv_draw_img.h"
     13 #include "../misc/lv_math.h"
     14 #include "../misc/lv_log.h"
     15 #include "../misc/lv_mem.h"
     16 
     17 /*********************
     18  *      DEFINES
     19  *********************/
     20 
     21 /**********************
     22  *      TYPEDEFS
     23  **********************/
     24 
     25 /**********************
     26  *  STATIC PROTOTYPES
     27  **********************/
     28 
     29 /**********************
     30  *  STATIC VARIABLES
     31  **********************/
     32 
     33 /**********************
     34  *      MACROS
     35  **********************/
     36 
     37 /**********************
     38  *   GLOBAL FUNCTIONS
     39  **********************/
     40 
     41 /**
     42  * Get the color of an image's pixel
     43  * @param dsc an image descriptor
     44  * @param x x coordinate of the point to get
     45  * @param y x coordinate of the point to get
     46  * @param color the color of the image. In case of `LV_IMG_CF_ALPHA_1/2/4/8` this color is used.
     47  * Not used in other cases.
     48  * @param safe true: check out of bounds
     49  * @return color of the point
     50  */
     51 lv_color_t lv_img_buf_get_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t color)
     52 {
     53     lv_color_t p_color = lv_color_black();
     54     uint8_t * buf_u8 = (uint8_t *)dsc->data;
     55 
     56     if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED ||
     57        dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
     58         uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3;
     59         uint32_t px     = dsc->header.w * y * px_size + x * px_size;
     60         lv_memcpy_small(&p_color, &buf_u8[px], sizeof(lv_color_t));
     61 #if LV_COLOR_SIZE == 32
     62         p_color.ch.alpha = 0xFF; /*Only the color should be get so use a default alpha value*/
     63 #endif
     64     }
     65     else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT) {
     66         buf_u8 += 4 * 2;
     67         uint8_t bit = x & 0x7;
     68         x           = x >> 3;
     69 
     70         /*Get the current pixel.
     71          *dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
     72          *so the possible real width are 8, 16, 24 ...*/
     73         uint32_t px  = ((dsc->header.w + 7) >> 3) * y + x;
     74         p_color.full = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit);
     75     }
     76     else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) {
     77         buf_u8 += 4 * 4;
     78         uint8_t bit = (x & 0x3) * 2;
     79         x           = x >> 2;
     80 
     81         /*Get the current pixel.
     82          *dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned
     83          *so the possible real width are 4, 8, 12 ...*/
     84         uint32_t px  = ((dsc->header.w + 3) >> 2) * y + x;
     85         p_color.full = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit);
     86     }
     87     else if(dsc->header.cf == LV_IMG_CF_INDEXED_4BIT) {
     88         buf_u8 += 4 * 16;
     89         uint8_t bit = (x & 0x1) * 4;
     90         x           = x >> 1;
     91 
     92         /*Get the current pixel.
     93          *dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned
     94          *so the possible real width are 2, 4, 6 ...*/
     95         uint32_t px  = ((dsc->header.w + 1) >> 1) * y + x;
     96         p_color.full = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit);
     97     }
     98     else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
     99         buf_u8 += 4 * 256;
    100         uint32_t px  = dsc->header.w * y + x;
    101         p_color.full = buf_u8[px];
    102     }
    103     else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || dsc->header.cf == LV_IMG_CF_ALPHA_2BIT ||
    104             dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
    105         p_color = color;
    106     }
    107     return p_color;
    108 }
    109 
    110 /**
    111  * Get the alpha value of an image's pixel
    112  * @param dsc pointer to an image descriptor
    113  * @param x x coordinate of the point to set
    114  * @param y x coordinate of the point to set
    115  * @param safe true: check out of bounds
    116  * @return alpha value of the point
    117  */
    118 lv_opa_t lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y)
    119 {
    120     uint8_t * buf_u8 = (uint8_t *)dsc->data;
    121 
    122     if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
    123         uint32_t px = dsc->header.w * y * LV_IMG_PX_SIZE_ALPHA_BYTE + x * LV_IMG_PX_SIZE_ALPHA_BYTE;
    124         return buf_u8[px + LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
    125     }
    126     else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT) {
    127         uint8_t bit = x & 0x7;
    128         x           = x >> 3;
    129 
    130         /*Get the current pixel.
    131          *dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
    132          *so the possible real width are 8 ,16, 24 ...*/
    133         uint32_t px    = ((dsc->header.w + 7) >> 3) * y + x;
    134         uint8_t px_opa = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit);
    135         return px_opa ? LV_OPA_TRANSP : LV_OPA_COVER;
    136     }
    137     else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) {
    138         const uint8_t opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
    139 
    140         uint8_t bit = (x & 0x3) * 2;
    141         x           = x >> 2;
    142 
    143         /*Get the current pixel.
    144          *dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned
    145          *so the possible real width are 4 ,8, 12 ...*/
    146         uint32_t px    = ((dsc->header.w + 3) >> 2) * y + x;
    147         uint8_t px_opa = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit);
    148         return opa_table[px_opa];
    149     }
    150     else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) {
    151         const uint8_t opa_table[16] = {0,  17, 34,  51, /*Opacity mapping with bpp = 4*/
    152                                        68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255
    153                                       };
    154 
    155         uint8_t bit = (x & 0x1) * 4;
    156         x           = x >> 1;
    157 
    158         /*Get the current pixel.
    159          *dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned
    160          *so the possible real width are 2 ,4, 6 ...*/
    161         uint32_t px    = ((dsc->header.w + 1) >> 1) * y + x;
    162         uint8_t px_opa = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit);
    163         return opa_table[px_opa];
    164     }
    165     else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
    166         uint32_t px = dsc->header.w * y + x;
    167         return buf_u8[px];
    168     }
    169 
    170     return LV_OPA_COVER;
    171 }
    172 
    173 /**
    174  * Set the alpha value of a pixel of an image. The color won't be affected
    175  * @param dsc pointer to an image descriptor
    176  * @param x x coordinate of the point to set
    177  * @param y x coordinate of the point to set
    178  * @param opa the desired opacity
    179  * @param safe true: check out of bounds
    180  */
    181 void lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_opa_t opa)
    182 {
    183     uint8_t * buf_u8 = (uint8_t *)dsc->data;
    184 
    185     if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
    186         uint8_t px_size          = lv_img_cf_get_px_size(dsc->header.cf) >> 3;
    187         uint32_t px              = dsc->header.w * y * px_size + x * px_size;
    188         buf_u8[px + px_size - 1] = opa;
    189     }
    190     else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT) {
    191         opa         = opa >> 7; /*opa -> [0,1]*/
    192         uint8_t bit = x & 0x7;
    193         x           = x >> 3;
    194 
    195         /*Get the current pixel.
    196          *dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
    197          *so the possible real width are 8 ,16, 24 ...*/
    198         uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
    199         buf_u8[px]  = buf_u8[px] & ~(1 << (7 - bit));
    200         buf_u8[px]  = buf_u8[px] | ((opa & 0x1) << (7 - bit));
    201     }
    202     else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) {
    203         opa         = opa >> 6; /*opa -> [0,3]*/
    204         uint8_t bit = (x & 0x3) * 2;
    205         x           = x >> 2;
    206 
    207         /*Get the current pixel.
    208          *dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned
    209          *so the possible real width are 4 ,8, 12 ...*/
    210         uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
    211         buf_u8[px]  = buf_u8[px] & ~(3 << (6 - bit));
    212         buf_u8[px]  = buf_u8[px] | ((opa & 0x3) << (6 - bit));
    213     }
    214     else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) {
    215         opa         = opa >> 4; /*opa -> [0,15]*/
    216         uint8_t bit = (x & 0x1) * 4;
    217         x           = x >> 1;
    218 
    219         /*Get the current pixel.
    220          *dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned
    221          *so the possible real width are 2 ,4, 6 ...*/
    222         uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
    223         buf_u8[px]  = buf_u8[px] & ~(0xF << (4 - bit));
    224         buf_u8[px]  = buf_u8[px] | ((opa & 0xF) << (4 - bit));
    225     }
    226     else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
    227         uint32_t px = dsc->header.w * y + x;
    228         buf_u8[px]  = opa;
    229     }
    230 }
    231 
    232 /**
    233  * Set the color of a pixel of an image. The alpha channel won't be affected.
    234  * @param dsc pointer to an image descriptor
    235  * @param x x coordinate of the point to set
    236  * @param y x coordinate of the point to set
    237  * @param c color of the point
    238  * @param safe true: check out of bounds
    239  */
    240 void lv_img_buf_set_px_color(lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t c)
    241 {
    242     uint8_t * buf_u8 = (uint8_t *)dsc->data;
    243 
    244     if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
    245         uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3;
    246         uint32_t px     = dsc->header.w * y * px_size + x * px_size;
    247         lv_memcpy_small(&buf_u8[px], &c, px_size);
    248     }
    249     else if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
    250         uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3;
    251         uint32_t px     = dsc->header.w * y * px_size + x * px_size;
    252         lv_memcpy_small(&buf_u8[px], &c, px_size - 1); /*-1 to not overwrite the alpha value*/
    253     }
    254     else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT) {
    255         buf_u8 += sizeof(lv_color32_t) * 2; /*Skip the palette*/
    256 
    257         uint8_t bit = x & 0x7;
    258         x           = x >> 3;
    259 
    260         /*Get the current pixel.
    261          *dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
    262          *so the possible real width are 8 ,16, 24 ...*/
    263         uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
    264         buf_u8[px]  = buf_u8[px] & ~(1 << (7 - bit));
    265         buf_u8[px]  = buf_u8[px] | ((c.full & 0x1) << (7 - bit));
    266     }
    267     else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) {
    268         buf_u8 += sizeof(lv_color32_t) * 4; /*Skip the palette*/
    269         uint8_t bit = (x & 0x3) * 2;
    270         x           = x >> 2;
    271 
    272         /*Get the current pixel.
    273          *dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned
    274          *so the possible real width are 4, 8 ,12 ...*/
    275         uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
    276 
    277         buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit));
    278         buf_u8[px] = buf_u8[px] | ((c.full & 0x3) << (6 - bit));
    279     }
    280     else if(dsc->header.cf == LV_IMG_CF_INDEXED_4BIT) {
    281         buf_u8 += sizeof(lv_color32_t) * 16; /*Skip the palette*/
    282         uint8_t bit = (x & 0x1) * 4;
    283         x           = x >> 1;
    284 
    285         /*Get the current pixel.
    286          *dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned
    287          *so the possible real width are 2 ,4, 6 ...*/
    288         uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
    289         buf_u8[px]  = buf_u8[px] & ~(0xF << (4 - bit));
    290         buf_u8[px]  = buf_u8[px] | ((c.full & 0xF) << (4 - bit));
    291     }
    292     else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
    293         buf_u8 += sizeof(lv_color32_t) * 256; /*Skip the palette*/
    294         uint32_t px = dsc->header.w * y + x;
    295         buf_u8[px]  = c.full;
    296     }
    297 }
    298 
    299 /**
    300  * Set the palette color of an indexed image. Valid only for `LV_IMG_CF_INDEXED1/2/4/8`
    301  * @param dsc pointer to an image descriptor
    302  * @param id the palette color to set:
    303  *   - for `LV_IMG_CF_INDEXED1`: 0..1
    304  *   - for `LV_IMG_CF_INDEXED2`: 0..3
    305  *   - for `LV_IMG_CF_INDEXED4`: 0..15
    306  *   - for `LV_IMG_CF_INDEXED8`: 0..255
    307  * @param c the color to set
    308  */
    309 void lv_img_buf_set_palette(lv_img_dsc_t * dsc, uint8_t id, lv_color_t c)
    310 {
    311     if((dsc->header.cf == LV_IMG_CF_ALPHA_1BIT && id > 1) || (dsc->header.cf == LV_IMG_CF_ALPHA_2BIT && id > 3) ||
    312        (dsc->header.cf == LV_IMG_CF_ALPHA_4BIT && id > 15) || (dsc->header.cf == LV_IMG_CF_ALPHA_8BIT)) {
    313         LV_LOG_WARN("lv_img_buf_set_px_alpha: invalid 'id'");
    314         return;
    315     }
    316 
    317     lv_color32_t c32;
    318     c32.full      = lv_color_to32(c);
    319     uint8_t * buf = (uint8_t *)dsc->data;
    320     lv_memcpy_small(&buf[id * sizeof(c32)], &c32, sizeof(c32));
    321 }
    322 
    323 /**
    324  * Allocate an image buffer in RAM
    325  * @param w width of image
    326  * @param h height of image
    327  * @param cf a color format (`LV_IMG_CF_...`)
    328  * @return an allocated image, or NULL on failure
    329  */
    330 lv_img_dsc_t * lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)
    331 {
    332     /*Allocate image descriptor*/
    333     lv_img_dsc_t * dsc = lv_mem_alloc(sizeof(lv_img_dsc_t));
    334     if(dsc == NULL)
    335         return NULL;
    336 
    337     lv_memset_00(dsc, sizeof(lv_img_dsc_t));
    338 
    339     /*Get image data size*/
    340     dsc->data_size = lv_img_buf_get_img_size(w, h, cf);
    341     if(dsc->data_size == 0) {
    342         lv_mem_free(dsc);
    343         return NULL;
    344     }
    345 
    346     /*Allocate raw buffer*/
    347     dsc->data = lv_mem_alloc(dsc->data_size);
    348     if(dsc->data == NULL) {
    349         lv_mem_free(dsc);
    350         return NULL;
    351     }
    352     lv_memset_00((uint8_t *)dsc->data, dsc->data_size);
    353 
    354     /*Fill in header*/
    355     dsc->header.always_zero = 0;
    356     dsc->header.w = w;
    357     dsc->header.h = h;
    358     dsc->header.cf = cf;
    359     return dsc;
    360 }
    361 
    362 /**
    363  * Free an allocated image buffer
    364  * @param dsc image buffer to free
    365  */
    366 void lv_img_buf_free(lv_img_dsc_t * dsc)
    367 {
    368     if(dsc != NULL) {
    369         if(dsc->data != NULL)
    370             lv_mem_free((void *)dsc->data);
    371 
    372         lv_mem_free(dsc);
    373     }
    374 }
    375 
    376 /**
    377  * Get the memory consumption of a raw bitmap, given color format and dimensions.
    378  * @param w width
    379  * @param h height
    380  * @param cf color format
    381  * @return size in bytes
    382  */
    383 uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)
    384 {
    385     switch(cf) {
    386         case LV_IMG_CF_TRUE_COLOR:
    387             return LV_IMG_BUF_SIZE_TRUE_COLOR(w, h);
    388         case LV_IMG_CF_TRUE_COLOR_ALPHA:
    389             return LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h);
    390         case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
    391             return LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h);
    392         case LV_IMG_CF_ALPHA_1BIT:
    393             return LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h);
    394         case LV_IMG_CF_ALPHA_2BIT:
    395             return LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h);
    396         case LV_IMG_CF_ALPHA_4BIT:
    397             return LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h);
    398         case LV_IMG_CF_ALPHA_8BIT:
    399             return LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h);
    400         case LV_IMG_CF_INDEXED_1BIT:
    401             return LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h);
    402         case LV_IMG_CF_INDEXED_2BIT:
    403             return LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h);
    404         case LV_IMG_CF_INDEXED_4BIT:
    405             return LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h);
    406         case LV_IMG_CF_INDEXED_8BIT:
    407             return LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h);
    408         default:
    409             return 0;
    410     }
    411 }
    412 
    413 #if LV_DRAW_COMPLEX
    414 /**
    415  * Initialize a descriptor to transform an image
    416  * @param dsc pointer to an `lv_img_transform_dsc_t` variable whose `cfg` field is initialized
    417  */
    418 void _lv_img_buf_transform_init(lv_img_transform_dsc_t * dsc)
    419 {
    420     dsc->tmp.pivot_x_256 = dsc->cfg.pivot_x * 256;
    421     dsc->tmp.pivot_y_256 = dsc->cfg.pivot_y * 256;
    422 
    423     int32_t angle_low = dsc->cfg.angle / 10;
    424     int32_t angle_high = angle_low + 1;
    425     int32_t angle_rem = dsc->cfg.angle  - (angle_low * 10);
    426 
    427     int32_t s1 = lv_trigo_sin(-angle_low);
    428     int32_t s2 = lv_trigo_sin(-angle_high);
    429 
    430     int32_t c1 = lv_trigo_sin(-angle_low + 90);
    431     int32_t c2 = lv_trigo_sin(-angle_high + 90);
    432 
    433     dsc->tmp.sinma = (s1 * (10 - angle_rem) + s2 * angle_rem) / 10;
    434     dsc->tmp.cosma = (c1 * (10 - angle_rem) + c2 * angle_rem) / 10;
    435 
    436     /*Use smaller value to avoid overflow*/
    437     dsc->tmp.sinma = dsc->tmp.sinma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
    438     dsc->tmp.cosma = dsc->tmp.cosma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
    439 
    440     dsc->tmp.chroma_keyed = lv_img_cf_is_chroma_keyed(dsc->cfg.cf) ? 1 : 0;
    441     dsc->tmp.has_alpha = lv_img_cf_has_alpha(dsc->cfg.cf) ? 1 : 0;
    442     if(dsc->cfg.cf == LV_IMG_CF_TRUE_COLOR || dsc->cfg.cf == LV_IMG_CF_TRUE_COLOR_ALPHA ||
    443        dsc->cfg.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
    444         dsc->tmp.native_color = 1;
    445     }
    446     else {
    447         dsc->tmp.native_color = 0;
    448     }
    449 
    450     dsc->tmp.img_dsc.data = dsc->cfg.src;
    451     dsc->tmp.img_dsc.header.always_zero = 0;
    452     dsc->tmp.img_dsc.header.cf = dsc->cfg.cf;
    453     dsc->tmp.img_dsc.header.w = dsc->cfg.src_w;
    454     dsc->tmp.img_dsc.header.h = dsc->cfg.src_h;
    455 
    456     /*The inverse of the zoom will be sued during the transformation
    457      * + dsc->cfg.zoom / 2 for rounding*/
    458     dsc->tmp.zoom_inv = (((256 * 256) << _LV_ZOOM_INV_UPSCALE) + dsc->cfg.zoom / 2) / dsc->cfg.zoom;
    459 
    460     dsc->res.opa = LV_OPA_COVER;
    461     dsc->res.color = dsc->cfg.color;
    462 }
    463 #endif
    464 
    465 /**
    466  * Get the area of a rectangle if its rotated and scaled
    467  * @param res store the coordinates here
    468  * @param w width of the rectangle to transform
    469  * @param h height of the rectangle to transform
    470  * @param angle angle of rotation
    471  * @param zoom zoom, (256 no zoom)
    472  * @param pivot x,y pivot coordinates of rotation
    473  */
    474 void _lv_img_buf_get_transformed_area(lv_area_t * res, lv_coord_t w, lv_coord_t h, int16_t angle, uint16_t zoom,
    475                                       const lv_point_t * pivot)
    476 {
    477 #if LV_DRAW_COMPLEX
    478     if(angle == 0 && zoom == LV_IMG_ZOOM_NONE) {
    479         res->x1 = 0;
    480         res->y1 = 0;
    481         res->x2 = w - 1;
    482         res->y2 = h - 1;
    483         return;
    484     }
    485 
    486     res->x1 = (((int32_t)(-pivot->x) * zoom) >> 8) - 1;
    487     res->y1 = (((int32_t)(-pivot->y) * zoom) >> 8) - 1;
    488     res->x2 = (((int32_t)(w - pivot->x) * zoom) >> 8) + 2;
    489     res->y2 = (((int32_t)(h - pivot->y) * zoom) >> 8) + 2;
    490 
    491     if(angle == 0) {
    492         res->x1 += pivot->x;
    493         res->y1 += pivot->y;
    494         res->x2 += pivot->x;
    495         res->y2 += pivot->y;
    496         return;
    497     }
    498 
    499     int32_t angle_low = angle / 10;
    500     int32_t angle_high = angle_low + 1;
    501     int32_t angle_rem = angle  - (angle_low * 10);
    502 
    503     int32_t s1 = lv_trigo_sin(angle_low);
    504     int32_t s2 = lv_trigo_sin(angle_high);
    505 
    506     int32_t c1 = lv_trigo_sin(angle_low + 90);
    507     int32_t c2 = lv_trigo_sin(angle_high + 90);
    508 
    509     int32_t sinma = (s1 * (10 - angle_rem) + s2 * angle_rem) / 10;
    510     int32_t cosma = (c1 * (10 - angle_rem) + c2 * angle_rem) / 10;
    511 
    512     /*Use smaller value to avoid overflow*/
    513     sinma = sinma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
    514     cosma = cosma >> (LV_TRIGO_SHIFT - _LV_TRANSFORM_TRIGO_SHIFT);
    515 
    516     lv_point_t lt;
    517     lv_point_t rt;
    518     lv_point_t lb;
    519     lv_point_t rb;
    520 
    521     lv_coord_t xt;
    522     lv_coord_t yt;
    523 
    524     xt = res->x1;
    525     yt = res->y1;
    526     lt.x = ((cosma * xt - sinma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
    527     lt.y = ((sinma * xt + cosma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
    528 
    529     xt = res->x2;
    530     yt = res->y1;
    531     rt.x = ((cosma * xt - sinma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
    532     rt.y = ((sinma * xt + cosma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
    533 
    534     xt = res->x1;
    535     yt = res->y2;
    536     lb.x = ((cosma * xt - sinma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
    537     lb.y = ((sinma * xt + cosma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
    538 
    539     xt = res->x2;
    540     yt = res->y2;
    541     rb.x = ((cosma * xt - sinma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->x;
    542     rb.y = ((sinma * xt + cosma * yt) >> _LV_TRANSFORM_TRIGO_SHIFT) + pivot->y;
    543 
    544     res->x1 = LV_MIN4(lb.x, lt.x, rb.x, rt.x);
    545     res->x2 = LV_MAX4(lb.x, lt.x, rb.x, rt.x);
    546     res->y1 = LV_MIN4(lb.y, lt.y, rb.y, rt.y);
    547     res->y2 = LV_MAX4(lb.y, lt.y, rb.y, rt.y);
    548 #else
    549     LV_UNUSED(angle);
    550     LV_UNUSED(zoom);
    551     LV_UNUSED(pivot);
    552     res->x1 = 0;
    553     res->y1 = 0;
    554     res->x2 = w - 1;
    555     res->y2 = h - 1;
    556 #endif
    557 }
    558 
    559 
    560 #if LV_DRAW_COMPLEX
    561 /**
    562  * Get which color and opa would come to a pixel if it were rotated
    563  * @param dsc a descriptor initialized by `lv_img_buf_rotate_init`
    564  * @param x the coordinate which color and opa should be get
    565  * @param y the coordinate which color and opa should be get
    566  * @return true: there is valid pixel on these x/y coordinates; false: the rotated pixel was out of the image
    567  * @note the result is written back to `dsc->res_color` and `dsc->res_opa`
    568  */
    569 bool _lv_img_buf_transform(lv_img_transform_dsc_t * dsc, lv_coord_t x, lv_coord_t y)
    570 {
    571     const uint8_t * src_u8 = (const uint8_t *)dsc->cfg.src;
    572 
    573     /*Get the target point relative coordinates to the pivot*/
    574     int32_t xt = x - dsc->cfg.pivot_x;
    575     int32_t yt = y - dsc->cfg.pivot_y;
    576 
    577     int32_t xs;
    578     int32_t ys;
    579     if(dsc->cfg.zoom == LV_IMG_ZOOM_NONE) {
    580         /*Get the source pixel from the upscaled image*/
    581         xs = ((dsc->tmp.cosma * xt - dsc->tmp.sinma * yt) >> (_LV_TRANSFORM_TRIGO_SHIFT - 8)) + dsc->tmp.pivot_x_256;
    582         ys = ((dsc->tmp.sinma * xt + dsc->tmp.cosma * yt) >> (_LV_TRANSFORM_TRIGO_SHIFT - 8)) + dsc->tmp.pivot_y_256;
    583     }
    584     else if(dsc->cfg.angle == 0) {
    585         xt = (int32_t)((int32_t)xt * dsc->tmp.zoom_inv) >> _LV_ZOOM_INV_UPSCALE;
    586         yt = (int32_t)((int32_t)yt * dsc->tmp.zoom_inv) >> _LV_ZOOM_INV_UPSCALE;
    587         xs = xt + dsc->tmp.pivot_x_256;
    588         ys = yt + dsc->tmp.pivot_y_256;
    589     }
    590     else {
    591         xt = (int32_t)((int32_t)xt * dsc->tmp.zoom_inv) >> _LV_ZOOM_INV_UPSCALE;
    592         yt = (int32_t)((int32_t)yt * dsc->tmp.zoom_inv) >> _LV_ZOOM_INV_UPSCALE;
    593         xs = ((dsc->tmp.cosma * xt - dsc->tmp.sinma * yt) >> (_LV_TRANSFORM_TRIGO_SHIFT)) + dsc->tmp.pivot_x_256;
    594         ys = ((dsc->tmp.sinma * xt + dsc->tmp.cosma * yt) >> (_LV_TRANSFORM_TRIGO_SHIFT)) + dsc->tmp.pivot_y_256;
    595     }
    596 
    597     /*Get the integer part of the source pixel*/
    598     int32_t xs_int = xs >> 8;
    599     int32_t ys_int = ys >> 8;
    600 
    601     if(xs_int >= dsc->cfg.src_w) return false;
    602     else if(xs_int < 0) return false;
    603 
    604     if(ys_int >= dsc->cfg.src_h) return false;
    605     else if(ys_int < 0) return false;
    606 
    607     uint8_t px_size;
    608     uint32_t pxi;
    609     if(dsc->tmp.native_color) {
    610         if(dsc->tmp.has_alpha == 0) {
    611             px_size = LV_COLOR_SIZE >> 3;
    612 
    613             pxi     = dsc->cfg.src_w * ys_int * px_size + xs_int * px_size;
    614             lv_memcpy_small(&dsc->res.color, &src_u8[pxi], px_size);
    615         }
    616         else {
    617             px_size = LV_IMG_PX_SIZE_ALPHA_BYTE;
    618             pxi     = dsc->cfg.src_w * ys_int * px_size + xs_int * px_size;
    619             lv_memcpy_small(&dsc->res.color, &src_u8[pxi], px_size - 1);
    620             dsc->res.opa = src_u8[pxi + px_size - 1];
    621         }
    622     }
    623     else {
    624         pxi = 0; /*unused*/
    625         px_size = 0;    /*unused*/
    626         dsc->res.color = lv_img_buf_get_px_color(&dsc->tmp.img_dsc, xs_int, ys_int, dsc->cfg.color);
    627         dsc->res.opa = lv_img_buf_get_px_alpha(&dsc->tmp.img_dsc, xs_int, ys_int);
    628     }
    629 
    630     if(dsc->tmp.chroma_keyed) {
    631         lv_color_t ct = LV_COLOR_CHROMA_KEY;
    632         if(dsc->res.color.full == ct.full) return false;
    633     }
    634 
    635     if(dsc->cfg.antialias == false) return true;
    636 
    637     dsc->tmp.xs = xs;
    638     dsc->tmp.ys = ys;
    639     dsc->tmp.xs_int = xs_int;
    640     dsc->tmp.ys_int = ys_int;
    641     dsc->tmp.pxi = pxi;
    642     dsc->tmp.px_size = px_size;
    643 
    644     bool ret;
    645     ret = _lv_img_buf_transform_anti_alias(dsc);
    646 
    647     return ret;
    648 }
    649 
    650 /**
    651  * Continue transformation by taking the neighbors into account
    652  * @param dsc pointer to the transformation descriptor
    653  */
    654 bool _lv_img_buf_transform_anti_alias(lv_img_transform_dsc_t * dsc)
    655 {
    656     const uint8_t * src_u8 = dsc->cfg.src;
    657 
    658     /*Get the fractional part of the source pixel*/
    659     int xs_fract = dsc->tmp.xs & 0xff;
    660     int ys_fract = dsc->tmp.ys & 0xff;
    661     int32_t xn;      /*x neighbor*/
    662     lv_opa_t xr; /*x mix ratio*/
    663 
    664     if(xs_fract < 0x70) {
    665         xn = - 1;
    666         if(dsc->tmp.xs_int + xn < 0) xn = 0;
    667         xr = xs_fract + 0x80;
    668     }
    669     else if(xs_fract > 0x90) {
    670         xn = 1;
    671         if(dsc->tmp.xs_int + xn >= dsc->cfg.src_w) xn = 0;
    672         xr = (0xFF - xs_fract) + 0x80;
    673     }
    674     else {
    675         xn = 0;
    676         xr = 0xFF;
    677     }
    678 
    679     int32_t yn;      /*x neighbor*/
    680     lv_opa_t yr; /*x mix ratio*/
    681 
    682     if(ys_fract < 0x70) {
    683         yn = - 1;
    684         if(dsc->tmp.ys_int + yn < 0) yn = 0;
    685 
    686         yr = ys_fract + 0x80;
    687     }
    688     else if(ys_fract > 0x90) {
    689         yn = 1;
    690         if(dsc->tmp.ys_int + yn >= dsc->cfg.src_h) yn = 0;
    691 
    692         yr = (0xFF - ys_fract) + 0x80;
    693     }
    694     else {
    695         yn = 0;
    696         yr = 0xFF;
    697     }
    698 
    699     lv_color_t c00 = dsc->res.color;
    700     lv_color_t c01;
    701     lv_color_t c10;
    702     lv_color_t c11;
    703 
    704     lv_opa_t a00 = dsc->res.opa;
    705     lv_opa_t a10 = 0;
    706     lv_opa_t a01 = 0;
    707     lv_opa_t a11 = 0;
    708 
    709     if(dsc->tmp.native_color) {
    710         lv_memcpy_small(&c01, &src_u8[dsc->tmp.pxi + dsc->tmp.px_size * xn], sizeof(lv_color_t));
    711         lv_memcpy_small(&c10, &src_u8[dsc->tmp.pxi + dsc->cfg.src_w * dsc->tmp.px_size * yn], sizeof(lv_color_t));
    712         lv_memcpy_small(&c11, &src_u8[dsc->tmp.pxi + dsc->cfg.src_w * dsc->tmp.px_size * yn + dsc->tmp.px_size * xn],
    713                         sizeof(lv_color_t));
    714         if(dsc->tmp.has_alpha) {
    715             a10 = src_u8[dsc->tmp.pxi + dsc->tmp.px_size * xn + dsc->tmp.px_size - 1];
    716             a01 = src_u8[dsc->tmp.pxi + dsc->cfg.src_w * dsc->tmp.px_size * yn + dsc->tmp.px_size - 1];
    717             a11 = src_u8[dsc->tmp.pxi + dsc->cfg.src_w * dsc->tmp.px_size * yn + dsc->tmp.px_size * xn + dsc->tmp.px_size - 1];
    718         }
    719     }
    720     else {
    721         c01 = lv_img_buf_get_px_color(&dsc->tmp.img_dsc, dsc->tmp.xs_int + xn, dsc->tmp.ys_int, dsc->cfg.color);
    722         c10 = lv_img_buf_get_px_color(&dsc->tmp.img_dsc, dsc->tmp.xs_int, dsc->tmp.ys_int + yn, dsc->cfg.color);
    723         c11 = lv_img_buf_get_px_color(&dsc->tmp.img_dsc, dsc->tmp.xs_int + xn, dsc->tmp.ys_int + yn, dsc->cfg.color);
    724 
    725         if(dsc->tmp.has_alpha) {
    726             a10 = lv_img_buf_get_px_alpha(&dsc->tmp.img_dsc, dsc->tmp.xs_int + xn, dsc->tmp.ys_int);
    727             a01 = lv_img_buf_get_px_alpha(&dsc->tmp.img_dsc, dsc->tmp.xs_int, dsc->tmp.ys_int + yn);
    728             a11 = lv_img_buf_get_px_alpha(&dsc->tmp.img_dsc, dsc->tmp.xs_int + xn, dsc->tmp.ys_int + yn);
    729         }
    730     }
    731 
    732     lv_opa_t xr0 = xr;
    733     lv_opa_t xr1 = xr;
    734     if(dsc->tmp.has_alpha) {
    735         lv_opa_t a0 = (a00 * xr + (a10 * (255 - xr))) >> 8;
    736         lv_opa_t a1 = (a01 * xr + (a11 * (255 - xr))) >> 8;
    737         dsc->res.opa = (a0 * yr + (a1 * (255 - yr))) >> 8;
    738 
    739         if(a0 <= LV_OPA_MIN && a1 <= LV_OPA_MIN) return false;
    740         if(a0 <= LV_OPA_MIN) yr = LV_OPA_TRANSP;
    741         if(a1 <= LV_OPA_MIN) yr = LV_OPA_COVER;
    742         if(a00 <= LV_OPA_MIN) xr0 = LV_OPA_TRANSP;
    743         if(a10 <= LV_OPA_MIN) xr0 = LV_OPA_COVER;
    744         if(a01 <= LV_OPA_MIN) xr1 = LV_OPA_TRANSP;
    745         if(a11 <= LV_OPA_MIN) xr1 = LV_OPA_COVER;
    746     }
    747     else {
    748         xr0 = xr;
    749         xr1 = xr;
    750         dsc->res.opa = LV_OPA_COVER;
    751     }
    752 
    753     lv_color_t c0;
    754     if(xr0 == LV_OPA_TRANSP) c0 = c01;
    755     else if(xr0 == LV_OPA_COVER) c0 = c00;
    756     else c0 = lv_color_mix(c00, c01, xr0);
    757 
    758     lv_color_t c1;
    759     if(xr1 == LV_OPA_TRANSP) c1 = c11;
    760     else if(xr1 == LV_OPA_COVER) c1 = c10;
    761     else c1 = lv_color_mix(c10, c11, xr1);
    762 
    763     if(yr == LV_OPA_TRANSP) dsc->res.color = c1;
    764     else if(yr == LV_OPA_COVER) dsc->res.color = c0;
    765     else dsc->res.color = lv_color_mix(c0, c1, yr);
    766 
    767     return true;
    768 }
    769 #endif
    770 /**********************
    771  *   STATIC FUNCTIONS
    772  **********************/