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