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