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 **********************/