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