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 */
lv_img_buf_get_px_color(lv_img_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_color_t color)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 */
lv_img_buf_get_px_alpha(lv_img_dsc_t * dsc,lv_coord_t x,lv_coord_t y)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 */
lv_img_buf_set_px_alpha(lv_img_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_opa_t opa)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 */
lv_img_buf_set_px_color(lv_img_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_color_t c)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 */
lv_img_buf_set_palette(lv_img_dsc_t * dsc,uint8_t id,lv_color_t c)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 */
lv_img_buf_alloc(lv_coord_t w,lv_coord_t h,lv_img_cf_t cf)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 */
lv_img_buf_free(lv_img_dsc_t * dsc)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 */
lv_img_buf_get_img_size(lv_coord_t w,lv_coord_t h,lv_img_cf_t cf)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 */
_lv_img_buf_transform_init(lv_img_transform_dsc_t * dsc)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 */
_lv_img_buf_get_transformed_area(lv_area_t * res,lv_coord_t w,lv_coord_t h,int16_t angle,uint16_t zoom,const lv_point_t * pivot)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 */
_lv_img_buf_transform(lv_img_transform_dsc_t * dsc,lv_coord_t x,lv_coord_t y)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 */
_lv_img_buf_transform_anti_alias(lv_img_transform_dsc_t * dsc)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 **********************/
773