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
lv_img_buf_get_px_color(const lv_img_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_color_t color)41 lv_color_t lv_img_buf_get_px_color(const lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t color)
42 {
43 lv_color_t p_color = lv_color_black();
44 uint8_t * buf_u8 = (uint8_t *)dsc->data;
45
46 if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED ||
47 dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA || dsc->header.cf == LV_IMG_CF_RGB565A8) {
48 uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3;
49 uint32_t px = dsc->header.w * y * px_size + x * px_size;
50 lv_memcpy_small(&p_color, &buf_u8[px], sizeof(lv_color_t));
51 #if LV_COLOR_SIZE == 32
52 p_color.ch.alpha = 0xFF; /*Only the color should be get so use a default alpha value*/
53 #endif
54 }
55 else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT) {
56 buf_u8 += 4 * 2;
57 uint8_t bit = x & 0x7;
58 x = x >> 3;
59
60 /*Get the current pixel.
61 *dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
62 *so the possible real width are 8, 16, 24 ...*/
63 uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
64 p_color.full = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit);
65 }
66 else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) {
67 buf_u8 += 4 * 4;
68 uint8_t bit = (x & 0x3) * 2;
69 x = x >> 2;
70
71 /*Get the current pixel.
72 *dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned
73 *so the possible real width are 4, 8, 12 ...*/
74 uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
75 p_color.full = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit);
76 }
77 else if(dsc->header.cf == LV_IMG_CF_INDEXED_4BIT) {
78 buf_u8 += 4 * 16;
79 uint8_t bit = (x & 0x1) * 4;
80 x = x >> 1;
81
82 /*Get the current pixel.
83 *dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned
84 *so the possible real width are 2, 4, 6 ...*/
85 uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
86 p_color.full = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit);
87 }
88 else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
89 buf_u8 += 4 * 256;
90 uint32_t px = dsc->header.w * y + x;
91 p_color.full = buf_u8[px];
92 }
93 else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT || dsc->header.cf == LV_IMG_CF_ALPHA_2BIT ||
94 dsc->header.cf == LV_IMG_CF_ALPHA_4BIT || dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
95 p_color = color;
96 }
97 return p_color;
98 }
99
lv_img_buf_get_px_alpha(const lv_img_dsc_t * dsc,lv_coord_t x,lv_coord_t y)100 lv_opa_t lv_img_buf_get_px_alpha(const lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y)
101 {
102 uint8_t * buf_u8 = (uint8_t *)dsc->data;
103
104 if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
105 uint32_t px = dsc->header.w * y * LV_IMG_PX_SIZE_ALPHA_BYTE + x * LV_IMG_PX_SIZE_ALPHA_BYTE;
106 return buf_u8[px + LV_IMG_PX_SIZE_ALPHA_BYTE - 1];
107 }
108 else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT) {
109 uint8_t bit = x & 0x7;
110 x = x >> 3;
111
112 /*Get the current pixel.
113 *dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
114 *so the possible real width are 8 ,16, 24 ...*/
115 uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
116 uint8_t px_opa = (buf_u8[px] & (1 << (7 - bit))) >> (7 - bit);
117 return px_opa ? LV_OPA_TRANSP : LV_OPA_COVER;
118 }
119 else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) {
120 const uint8_t opa_table[4] = {0, 85, 170, 255}; /*Opacity mapping with bpp = 2*/
121
122 uint8_t bit = (x & 0x3) * 2;
123 x = x >> 2;
124
125 /*Get the current pixel.
126 *dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned
127 *so the possible real width are 4 ,8, 12 ...*/
128 uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
129 uint8_t px_opa = (buf_u8[px] & (3 << (6 - bit))) >> (6 - bit);
130 return opa_table[px_opa];
131 }
132 else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) {
133 const uint8_t opa_table[16] = {0, 17, 34, 51, /*Opacity mapping with bpp = 4*/
134 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255
135 };
136
137 uint8_t bit = (x & 0x1) * 4;
138 x = x >> 1;
139
140 /*Get the current pixel.
141 *dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned
142 *so the possible real width are 2 ,4, 6 ...*/
143 uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
144 uint8_t px_opa = (buf_u8[px] & (0xF << (4 - bit))) >> (4 - bit);
145 return opa_table[px_opa];
146 }
147 else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
148 uint32_t px = dsc->header.w * y + x;
149 return buf_u8[px];
150 }
151
152 return LV_OPA_COVER;
153 }
154
lv_img_buf_set_px_alpha(const lv_img_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_opa_t opa)155 void lv_img_buf_set_px_alpha(const lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_opa_t opa)
156 {
157 uint8_t * buf_u8 = (uint8_t *)dsc->data;
158
159 if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
160 uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3;
161 uint32_t px = dsc->header.w * y * px_size + x * px_size;
162 buf_u8[px + px_size - 1] = opa;
163 }
164 else if(dsc->header.cf == LV_IMG_CF_ALPHA_1BIT) {
165 opa = opa >> 7; /*opa -> [0,1]*/
166 uint8_t bit = x & 0x7;
167 x = x >> 3;
168
169 /*Get the current pixel.
170 *dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
171 *so the possible real width are 8 ,16, 24 ...*/
172 uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
173 buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit));
174 buf_u8[px] = buf_u8[px] | ((opa & 0x1) << (7 - bit));
175 }
176 else if(dsc->header.cf == LV_IMG_CF_ALPHA_2BIT) {
177 opa = opa >> 6; /*opa -> [0,3]*/
178 uint8_t bit = (x & 0x3) * 2;
179 x = x >> 2;
180
181 /*Get the current pixel.
182 *dsc->header.w + 4 means rounding up to 8 because the lines are byte aligned
183 *so the possible real width are 4 ,8, 12 ...*/
184 uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
185 buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit));
186 buf_u8[px] = buf_u8[px] | ((opa & 0x3) << (6 - bit));
187 }
188 else if(dsc->header.cf == LV_IMG_CF_ALPHA_4BIT) {
189 opa = opa >> 4; /*opa -> [0,15]*/
190 uint8_t bit = (x & 0x1) * 4;
191 x = x >> 1;
192
193 /*Get the current pixel.
194 *dsc->header.w + 1 means rounding up to 8 because the lines are byte aligned
195 *so the possible real width are 2 ,4, 6 ...*/
196 uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
197 buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit));
198 buf_u8[px] = buf_u8[px] | ((opa & 0xF) << (4 - bit));
199 }
200 else if(dsc->header.cf == LV_IMG_CF_ALPHA_8BIT) {
201 uint32_t px = dsc->header.w * y + x;
202 buf_u8[px] = opa;
203 }
204 }
205
lv_img_buf_set_px_color(const lv_img_dsc_t * dsc,lv_coord_t x,lv_coord_t y,lv_color_t c)206 void lv_img_buf_set_px_color(const lv_img_dsc_t * dsc, lv_coord_t x, lv_coord_t y, lv_color_t c)
207 {
208 uint8_t * buf_u8 = (uint8_t *)dsc->data;
209
210 if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR || dsc->header.cf == LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED) {
211 uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3;
212 uint32_t px = dsc->header.w * y * px_size + x * px_size;
213 lv_memcpy_small(&buf_u8[px], &c, px_size);
214 }
215 else if(dsc->header.cf == LV_IMG_CF_TRUE_COLOR_ALPHA) {
216 uint8_t px_size = lv_img_cf_get_px_size(dsc->header.cf) >> 3;
217 uint32_t px = dsc->header.w * y * px_size + x * px_size;
218 lv_memcpy_small(&buf_u8[px], &c, px_size - 1); /*-1 to not overwrite the alpha value*/
219 }
220 else if(dsc->header.cf == LV_IMG_CF_INDEXED_1BIT) {
221 buf_u8 += sizeof(lv_color32_t) * 2; /*Skip the palette*/
222
223 uint8_t bit = x & 0x7;
224 x = x >> 3;
225
226 /*Get the current pixel.
227 *dsc->header.w + 7 means rounding up to 8 because the lines are byte aligned
228 *so the possible real width are 8 ,16, 24 ...*/
229 uint32_t px = ((dsc->header.w + 7) >> 3) * y + x;
230 buf_u8[px] = buf_u8[px] & ~(1 << (7 - bit));
231 buf_u8[px] = buf_u8[px] | ((c.full & 0x1) << (7 - bit));
232 }
233 else if(dsc->header.cf == LV_IMG_CF_INDEXED_2BIT) {
234 buf_u8 += sizeof(lv_color32_t) * 4; /*Skip the palette*/
235 uint8_t bit = (x & 0x3) * 2;
236 x = x >> 2;
237
238 /*Get the current pixel.
239 *dsc->header.w + 3 means rounding up to 4 because the lines are byte aligned
240 *so the possible real width are 4, 8 ,12 ...*/
241 uint32_t px = ((dsc->header.w + 3) >> 2) * y + x;
242
243 buf_u8[px] = buf_u8[px] & ~(3 << (6 - bit));
244 buf_u8[px] = buf_u8[px] | ((c.full & 0x3) << (6 - bit));
245 }
246 else if(dsc->header.cf == LV_IMG_CF_INDEXED_4BIT) {
247 buf_u8 += sizeof(lv_color32_t) * 16; /*Skip the palette*/
248 uint8_t bit = (x & 0x1) * 4;
249 x = x >> 1;
250
251 /*Get the current pixel.
252 *dsc->header.w + 1 means rounding up to 2 because the lines are byte aligned
253 *so the possible real width are 2 ,4, 6 ...*/
254 uint32_t px = ((dsc->header.w + 1) >> 1) * y + x;
255 buf_u8[px] = buf_u8[px] & ~(0xF << (4 - bit));
256 buf_u8[px] = buf_u8[px] | ((c.full & 0xF) << (4 - bit));
257 }
258 else if(dsc->header.cf == LV_IMG_CF_INDEXED_8BIT) {
259 buf_u8 += sizeof(lv_color32_t) * 256; /*Skip the palette*/
260 uint32_t px = dsc->header.w * y + x;
261 buf_u8[px] = c.full;
262 }
263 }
264
lv_img_buf_set_palette(const lv_img_dsc_t * dsc,uint8_t id,lv_color_t c)265 void lv_img_buf_set_palette(const lv_img_dsc_t * dsc, uint8_t id, lv_color_t c)
266 {
267 if((dsc->header.cf == LV_IMG_CF_ALPHA_1BIT && id > 1) || (dsc->header.cf == LV_IMG_CF_ALPHA_2BIT && id > 3) ||
268 (dsc->header.cf == LV_IMG_CF_ALPHA_4BIT && id > 15) || (dsc->header.cf == LV_IMG_CF_ALPHA_8BIT)) {
269 LV_LOG_WARN("lv_img_buf_set_px_alpha: invalid 'id'");
270 return;
271 }
272
273 lv_color32_t c32;
274 c32.full = lv_color_to32(c);
275 uint8_t * buf = (uint8_t *)dsc->data;
276 lv_memcpy_small(&buf[id * sizeof(c32)], &c32, sizeof(c32));
277 }
278
lv_img_buf_alloc(lv_coord_t w,lv_coord_t h,lv_img_cf_t cf)279 lv_img_dsc_t * lv_img_buf_alloc(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)
280 {
281 /*Allocate image descriptor*/
282 lv_img_dsc_t * dsc = lv_mem_alloc(sizeof(lv_img_dsc_t));
283 if(dsc == NULL)
284 return NULL;
285
286 lv_memset_00(dsc, sizeof(lv_img_dsc_t));
287
288 /*Get image data size*/
289 dsc->data_size = lv_img_buf_get_img_size(w, h, cf);
290 if(dsc->data_size == 0) {
291 lv_mem_free(dsc);
292 return NULL;
293 }
294
295 /*Allocate raw buffer*/
296 dsc->data = lv_mem_alloc(dsc->data_size);
297 if(dsc->data == NULL) {
298 lv_mem_free(dsc);
299 return NULL;
300 }
301 lv_memset_00((uint8_t *)dsc->data, dsc->data_size);
302
303 /*Fill in header*/
304 dsc->header.always_zero = 0;
305 dsc->header.w = w;
306 dsc->header.h = h;
307 dsc->header.cf = cf;
308 return dsc;
309 }
310
lv_img_buf_free(lv_img_dsc_t * dsc)311 void lv_img_buf_free(lv_img_dsc_t * dsc)
312 {
313 if(dsc != NULL) {
314 if(dsc->data != NULL)
315 lv_mem_free((void *)dsc->data);
316
317 lv_mem_free(dsc);
318 }
319 }
320
lv_img_buf_get_img_size(lv_coord_t w,lv_coord_t h,lv_img_cf_t cf)321 uint32_t lv_img_buf_get_img_size(lv_coord_t w, lv_coord_t h, lv_img_cf_t cf)
322 {
323 switch(cf) {
324 case LV_IMG_CF_TRUE_COLOR:
325 return LV_IMG_BUF_SIZE_TRUE_COLOR(w, h);
326 case LV_IMG_CF_TRUE_COLOR_ALPHA:
327 case LV_IMG_CF_RGB565A8:
328 return LV_IMG_BUF_SIZE_TRUE_COLOR_ALPHA(w, h);
329 case LV_IMG_CF_TRUE_COLOR_CHROMA_KEYED:
330 return LV_IMG_BUF_SIZE_TRUE_COLOR_CHROMA_KEYED(w, h);
331 case LV_IMG_CF_ALPHA_1BIT:
332 return LV_IMG_BUF_SIZE_ALPHA_1BIT(w, h);
333 case LV_IMG_CF_ALPHA_2BIT:
334 return LV_IMG_BUF_SIZE_ALPHA_2BIT(w, h);
335 case LV_IMG_CF_ALPHA_4BIT:
336 return LV_IMG_BUF_SIZE_ALPHA_4BIT(w, h);
337 case LV_IMG_CF_ALPHA_8BIT:
338 return LV_IMG_BUF_SIZE_ALPHA_8BIT(w, h);
339 case LV_IMG_CF_INDEXED_1BIT:
340 return LV_IMG_BUF_SIZE_INDEXED_1BIT(w, h);
341 case LV_IMG_CF_INDEXED_2BIT:
342 return LV_IMG_BUF_SIZE_INDEXED_2BIT(w, h);
343 case LV_IMG_CF_INDEXED_4BIT:
344 return LV_IMG_BUF_SIZE_INDEXED_4BIT(w, h);
345 case LV_IMG_CF_INDEXED_8BIT:
346 return LV_IMG_BUF_SIZE_INDEXED_8BIT(w, h);
347 default:
348 return 0;
349 }
350 }
351
_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)352 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,
353 const lv_point_t * pivot)
354 {
355 #if LV_DRAW_COMPLEX
356 if(angle == 0 && zoom == LV_IMG_ZOOM_NONE) {
357 res->x1 = 0;
358 res->y1 = 0;
359 res->x2 = w - 1;
360 res->y2 = h - 1;
361 return;
362 }
363
364 lv_point_t p[4] = {
365 {0, 0},
366 {w, 0},
367 {0, h},
368 {w, h},
369 };
370 lv_point_transform(&p[0], angle, zoom, pivot);
371 lv_point_transform(&p[1], angle, zoom, pivot);
372 lv_point_transform(&p[2], angle, zoom, pivot);
373 lv_point_transform(&p[3], angle, zoom, pivot);
374 res->x1 = LV_MIN4(p[0].x, p[1].x, p[2].x, p[3].x) - 2;
375 res->x2 = LV_MAX4(p[0].x, p[1].x, p[2].x, p[3].x) + 2;
376 res->y1 = LV_MIN4(p[0].y, p[1].y, p[2].y, p[3].y) - 2;
377 res->y2 = LV_MAX4(p[0].y, p[1].y, p[2].y, p[3].y) + 2;
378
379 #else
380 LV_UNUSED(angle);
381 LV_UNUSED(zoom);
382 LV_UNUSED(pivot);
383 res->x1 = 0;
384 res->y1 = 0;
385 res->x2 = w - 1;
386 res->y2 = h - 1;
387 #endif
388 }
389
390 /**********************
391 * STATIC FUNCTIONS
392 **********************/
393