1 /**
2 * @file lv_color.c
3 *
4 */
5
6 /*********************
7 * INCLUDES
8 *********************/
9 #include "lv_color.h"
10 #include "lv_log.h"
11
12 /*********************
13 * DEFINES
14 *********************/
15
16 /**********************
17 * TYPEDEFS
18 **********************/
19
20 /**********************
21 * STATIC PROTOTYPES
22 **********************/
23 static lv_color_t lv_color_filter_shade_cb(const lv_color_filter_dsc_t * dsc, lv_color_t c, lv_opa_t opa);
24
25 /**********************
26 * GLOBAL VARIABLES
27 **********************/
28
29 const lv_color_filter_dsc_t lv_color_filter_shade = {.filter_cb = lv_color_filter_shade_cb};
30
31 /**********************
32 * STATIC VARIABLES
33 **********************/
34
35 /**********************
36 * MACROS
37 **********************/
38
39 /**********************
40 * GLOBAL FUNCTIONS
41 **********************/
42
lv_color_format_get_bpp(lv_color_format_t cf)43 uint8_t lv_color_format_get_bpp(lv_color_format_t cf)
44 {
45 switch(cf) {
46 case LV_COLOR_FORMAT_I1:
47 case LV_COLOR_FORMAT_A1:
48 return 1;
49 case LV_COLOR_FORMAT_I2:
50 case LV_COLOR_FORMAT_A2:
51 return 2;
52 case LV_COLOR_FORMAT_I4:
53 case LV_COLOR_FORMAT_A4:
54 return 4;
55 case LV_COLOR_FORMAT_L8:
56 case LV_COLOR_FORMAT_A8:
57 case LV_COLOR_FORMAT_I8:
58 case LV_COLOR_FORMAT_ARGB2222:
59 return 8;
60
61 case LV_COLOR_FORMAT_RGB565A8:
62 case LV_COLOR_FORMAT_RGB565:
63 case LV_COLOR_FORMAT_YUY2:
64 case LV_COLOR_FORMAT_AL88:
65 case LV_COLOR_FORMAT_ARGB1555:
66 case LV_COLOR_FORMAT_ARGB4444:
67 return 16;
68
69 case LV_COLOR_FORMAT_ARGB8565:
70 case LV_COLOR_FORMAT_RGB888:
71 return 24;
72 case LV_COLOR_FORMAT_ARGB8888:
73 case LV_COLOR_FORMAT_XRGB8888:
74 return 32;
75
76 case LV_COLOR_FORMAT_UNKNOWN:
77 default:
78 return 0;
79 }
80 }
81
lv_color_format_has_alpha(lv_color_format_t cf)82 bool lv_color_format_has_alpha(lv_color_format_t cf)
83 {
84 switch(cf) {
85 case LV_COLOR_FORMAT_A1:
86 case LV_COLOR_FORMAT_A2:
87 case LV_COLOR_FORMAT_A4:
88 case LV_COLOR_FORMAT_A8:
89 case LV_COLOR_FORMAT_I1:
90 case LV_COLOR_FORMAT_I2:
91 case LV_COLOR_FORMAT_I4:
92 case LV_COLOR_FORMAT_I8:
93 case LV_COLOR_FORMAT_RGB565A8:
94 case LV_COLOR_FORMAT_ARGB8565:
95 case LV_COLOR_FORMAT_ARGB8888:
96 case LV_COLOR_FORMAT_AL88:
97 case LV_COLOR_FORMAT_ARGB2222:
98 case LV_COLOR_FORMAT_ARGB1555:
99 case LV_COLOR_FORMAT_ARGB4444:
100 return true;
101 default:
102 return false;
103 }
104 }
105
lv_color_to_32(lv_color_t color,lv_opa_t opa)106 lv_color32_t lv_color_to_32(lv_color_t color, lv_opa_t opa)
107 {
108 lv_color32_t c32;
109 c32.red = color.red;
110 c32.green = color.green;
111 c32.blue = color.blue;
112 c32.alpha = opa;
113 return c32;
114 }
115
lv_color_to_u16(lv_color_t color)116 uint16_t lv_color_to_u16(lv_color_t color)
117 {
118 return ((color.red & 0xF8) << 8) + ((color.green & 0xFC) << 3) + ((color.blue & 0xF8) >> 3);
119 }
120
lv_color_to_u32(lv_color_t color)121 uint32_t lv_color_to_u32(lv_color_t color)
122 {
123 return (uint32_t)((uint32_t)0xff << 24) + (color.red << 16) + (color.green << 8) + (color.blue);
124 }
125
lv_color_lighten(lv_color_t c,lv_opa_t lvl)126 lv_color_t lv_color_lighten(lv_color_t c, lv_opa_t lvl)
127 {
128
129 return lv_color_mix(lv_color_white(), c, lvl);
130 }
131
lv_color_darken(lv_color_t c,lv_opa_t lvl)132 lv_color_t lv_color_darken(lv_color_t c, lv_opa_t lvl)
133 {
134 return lv_color_mix(lv_color_black(), c, lvl);
135 }
136
lv_color_hsv_to_rgb(uint16_t h,uint8_t s,uint8_t v)137 lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v)
138 {
139 h = (uint32_t)((uint32_t)h * 255) / 360;
140 s = (uint16_t)((uint16_t)s * 255) / 100;
141 v = (uint16_t)((uint16_t)v * 255) / 100;
142
143 uint8_t r, g, b;
144
145 uint8_t region, remainder, p, q, t;
146
147 if(s == 0) {
148 return lv_color_make(v, v, v);
149 }
150
151 region = h / 43;
152 remainder = (h - (region * 43)) * 6;
153
154 p = (v * (255 - s)) >> 8;
155 q = (v * (255 - ((s * remainder) >> 8))) >> 8;
156 t = (v * (255 - ((s * (255 - remainder)) >> 8))) >> 8;
157
158 switch(region) {
159 case 0:
160 r = v;
161 g = t;
162 b = p;
163 break;
164 case 1:
165 r = q;
166 g = v;
167 b = p;
168 break;
169 case 2:
170 r = p;
171 g = v;
172 b = t;
173 break;
174 case 3:
175 r = p;
176 g = q;
177 b = v;
178 break;
179 case 4:
180 r = t;
181 g = p;
182 b = v;
183 break;
184 default:
185 r = v;
186 g = p;
187 b = q;
188 break;
189 }
190
191 lv_color_t result = lv_color_make(r, g, b);
192 return result;
193 }
194
lv_color_rgb_to_hsv(uint8_t r8,uint8_t g8,uint8_t b8)195 lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r8, uint8_t g8, uint8_t b8)
196 {
197 uint16_t r = ((uint32_t)r8 << 10) / 255;
198 uint16_t g = ((uint32_t)g8 << 10) / 255;
199 uint16_t b = ((uint32_t)b8 << 10) / 255;
200
201 uint16_t rgbMin = r < g ? (r < b ? r : b) : (g < b ? g : b);
202 uint16_t rgbMax = r > g ? (r > b ? r : b) : (g > b ? g : b);
203
204 lv_color_hsv_t hsv;
205
206 // https://en.wikipedia.org/wiki/HSL_and_HSV#Lightness
207 hsv.v = (100 * rgbMax) >> 10;
208
209 int32_t delta = rgbMax - rgbMin;
210 if(delta < 3) {
211 hsv.h = 0;
212 hsv.s = 0;
213 return hsv;
214 }
215
216 // https://en.wikipedia.org/wiki/HSL_and_HSV#Saturation
217 hsv.s = 100 * delta / rgbMax;
218 if(hsv.s < 3) {
219 hsv.h = 0;
220 return hsv;
221 }
222
223 // https://en.wikipedia.org/wiki/HSL_and_HSV#Hue_and_chroma
224 int32_t h;
225 if(rgbMax == r)
226 h = (((g - b) << 10) / delta) + (g < b ? (6 << 10) : 0); // between yellow & magenta
227 else if(rgbMax == g)
228 h = (((b - r) << 10) / delta) + (2 << 10); // between cyan & yellow
229 else if(rgbMax == b)
230 h = (((r - g) << 10) / delta) + (4 << 10); // between magenta & cyan
231 else
232 h = 0;
233 h *= 60;
234 h >>= 10;
235 if(h < 0) h += 360;
236
237 hsv.h = h;
238 return hsv;
239 }
240
241 /**
242 * Convert a color to HSV
243 * @param color color
244 * @return the given color in HSV
245 */
lv_color_to_hsv(lv_color_t c)246 lv_color_hsv_t lv_color_to_hsv(lv_color_t c)
247 {
248 return lv_color_rgb_to_hsv(c.red, c.green, c.blue);
249 }
250
lv_color_format_get_size(lv_color_format_t cf)251 uint8_t lv_color_format_get_size(lv_color_format_t cf)
252 {
253 return (lv_color_format_get_bpp(cf) + 7) >> 3;
254 }
255
lv_color_to_int(lv_color_t c)256 uint32_t lv_color_to_int(lv_color_t c)
257 {
258 uint8_t * tmp = (uint8_t *) &c;
259 return tmp[0] + (tmp[1] << 8) + (tmp[2] << 16);
260 }
261
lv_color_eq(lv_color_t c1,lv_color_t c2)262 bool lv_color_eq(lv_color_t c1, lv_color_t c2)
263 {
264 return lv_color_to_int(c1) == lv_color_to_int(c2);
265 }
266
lv_color32_eq(lv_color32_t c1,lv_color32_t c2)267 bool lv_color32_eq(lv_color32_t c1, lv_color32_t c2)
268 {
269 return *((uint32_t *)&c1) == *((uint32_t *)&c2);
270 }
271
lv_color_hex(uint32_t c)272 lv_color_t lv_color_hex(uint32_t c)
273 {
274 lv_color_t ret;
275 ret.red = (c >> 16) & 0xff;
276 ret.green = (c >> 8) & 0xff;
277 ret.blue = (c >> 0) & 0xff;
278 return ret;
279 }
280
lv_color_make(uint8_t r,uint8_t g,uint8_t b)281 lv_color_t lv_color_make(uint8_t r, uint8_t g, uint8_t b)
282 {
283 lv_color_t ret;
284 ret.red = r;
285 ret.green = g;
286 ret.blue = b;
287 return ret;
288 }
289
lv_color32_make(uint8_t r,uint8_t g,uint8_t b,uint8_t a)290 lv_color32_t lv_color32_make(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
291 {
292 lv_color32_t ret;
293 ret.red = r;
294 ret.green = g;
295 ret.blue = b;
296 ret.alpha = a;
297 return ret;
298 }
299
lv_color_hex3(uint32_t c)300 lv_color_t lv_color_hex3(uint32_t c)
301 {
302 return lv_color_make((uint8_t)(((c >> 4) & 0xF0) | ((c >> 8) & 0xF)), (uint8_t)((c & 0xF0) | ((c & 0xF0) >> 4)),
303 (uint8_t)((c & 0xF) | ((c & 0xF) << 4)));
304 }
305
lv_color_16_16_mix(uint16_t c1,uint16_t c2,uint8_t mix)306 uint16_t LV_ATTRIBUTE_FAST_MEM lv_color_16_16_mix(uint16_t c1, uint16_t c2, uint8_t mix)
307 {
308 if(mix == 255) return c1;
309 if(mix == 0) return c2;
310 if(c1 == c2) return c1;
311
312 uint16_t ret;
313
314 /* Source: https://stackoverflow.com/a/50012418/1999969*/
315 mix = (uint32_t)((uint32_t)mix + 4) >> 3;
316
317 /*0x7E0F81F = 0b00000111111000001111100000011111*/
318 uint32_t bg = (uint32_t)(c2 | ((uint32_t)c2 << 16)) & 0x7E0F81F;
319 uint32_t fg = (uint32_t)(c1 | ((uint32_t)c1 << 16)) & 0x7E0F81F;
320 uint32_t result = ((((fg - bg) * mix) >> 5) + bg) & 0x7E0F81F;
321 ret = (uint16_t)(result >> 16) | result;
322
323 return ret;
324 }
325
lv_color_white(void)326 lv_color_t lv_color_white(void)
327 {
328 return lv_color_make(0xff, 0xff, 0xff);
329 }
330
lv_color_black(void)331 lv_color_t lv_color_black(void)
332 {
333 return lv_color_make(0x00, 0x00, 0x00);
334 }
335
lv_color_premultiply(lv_color32_t * c)336 void lv_color_premultiply(lv_color32_t * c)
337 {
338 if(c->alpha == LV_OPA_COVER) {
339 return;
340 }
341
342 if(c->alpha == LV_OPA_TRANSP) {
343 lv_memzero(c, sizeof(lv_color32_t));
344 return;
345 }
346
347 c->red = LV_OPA_MIX2(c->red, c->alpha);
348 c->green = LV_OPA_MIX2(c->green, c->alpha);
349 c->blue = LV_OPA_MIX2(c->blue, c->alpha);
350 }
351
lv_color16_premultiply(lv_color16_t * c,lv_opa_t a)352 void lv_color16_premultiply(lv_color16_t * c, lv_opa_t a)
353 {
354 if(a == LV_OPA_COVER) {
355 return;
356 }
357
358 if(a == LV_OPA_TRANSP) {
359 lv_memzero(c, sizeof(lv_color16_t));
360 return;
361 }
362
363 c->red = LV_OPA_MIX2(c->red, a);
364 c->green = LV_OPA_MIX2(c->green, a);
365 c->blue = LV_OPA_MIX2(c->blue, a);
366 }
367
lv_color_luminance(lv_color_t c)368 uint8_t lv_color_luminance(lv_color_t c)
369 {
370 return (uint8_t)((uint16_t)(77u * c.red + 151u * c.green + 28u * c.blue) >> 8);
371 }
372
lv_color16_luminance(const lv_color16_t c)373 uint8_t lv_color16_luminance(const lv_color16_t c)
374 {
375 return (uint8_t)((uint16_t)(635u * c.red + 613u * c.green + 231u * c.blue) >> 8);
376 }
377
lv_color24_luminance(const uint8_t * c)378 uint8_t lv_color24_luminance(const uint8_t * c)
379 {
380 return (uint8_t)((uint16_t)(77u * c[2] + 151u * c[1] + 28u * c[0]) >> 8);
381 }
382
lv_color32_luminance(lv_color32_t c)383 uint8_t lv_color32_luminance(lv_color32_t c)
384 {
385 return (uint8_t)((uint16_t)(77u * c.red + 151u * c.green + 28u * c.blue) >> 8);
386 }
387
388 /**********************
389 * STATIC FUNCTIONS
390 **********************/
391
392 /**
393 * Helper function to easily create color filters
394 * @param dsc pointer to a color filter descriptor
395 * @param c the color to modify
396 * @param opa the intensity of the modification
397 * - LV_OPA_50: do nothing
398 * - < LV_OPA_50: darken
399 * - LV_OPA_0: fully black
400 * - > LV_OPA_50: lighten
401 * - LV_OPA_100: fully white
402 * @return the modified color
403 */
lv_color_filter_shade_cb(const lv_color_filter_dsc_t * dsc,lv_color_t c,lv_opa_t opa)404 static lv_color_t lv_color_filter_shade_cb(const lv_color_filter_dsc_t * dsc, lv_color_t c, lv_opa_t opa)
405 {
406 LV_UNUSED(dsc);
407 if(opa == LV_OPA_50) return c;
408 if(opa < LV_OPA_50) return lv_color_lighten(c, (LV_OPA_50 - opa) * 2);
409 else return lv_color_darken(c, (opa - LV_OPA_50 * LV_OPA_50) * 2);
410 }
411