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