1 /**
2 * @file lv_color.h
3 *
4 */
5
6 #ifndef LV_COLOR_H
7 #define LV_COLOR_H
8
9 #ifdef __cplusplus
10 extern "C" {
11 #endif
12
13 /*********************
14 * INCLUDES
15 *********************/
16 #include "../lv_conf_internal.h"
17 #include "lv_assert.h"
18 #include "lv_math.h"
19 #include "lv_types.h"
20
21 /*Error checking*/
22 #if LV_COLOR_DEPTH == 24
23 #error "LV_COLOR_DEPTH 24 is deprecated. Use LV_COLOR_DEPTH 32 instead (lv_conf.h)"
24 #endif
25
26 #if LV_COLOR_DEPTH != 32 && LV_COLOR_SCREEN_TRANSP != 0
27 #error "LV_COLOR_SCREEN_TRANSP requires LV_COLOR_DEPTH == 32. Set it in lv_conf.h"
28 #endif
29
30 #if LV_COLOR_DEPTH != 16 && LV_COLOR_16_SWAP != 0
31 #error "LV_COLOR_16_SWAP requires LV_COLOR_DEPTH == 16. Set it in lv_conf.h"
32 #endif
33
34 #include <stdint.h>
35
36 /*********************
37 * DEFINES
38 *********************/
39 LV_EXPORT_CONST_INT(LV_COLOR_DEPTH);
40 LV_EXPORT_CONST_INT(LV_COLOR_16_SWAP);
41
42 /**
43 * Opacity percentages.
44 */
45 enum {
46 LV_OPA_TRANSP = 0,
47 LV_OPA_0 = 0,
48 LV_OPA_10 = 25,
49 LV_OPA_20 = 51,
50 LV_OPA_30 = 76,
51 LV_OPA_40 = 102,
52 LV_OPA_50 = 127,
53 LV_OPA_60 = 153,
54 LV_OPA_70 = 178,
55 LV_OPA_80 = 204,
56 LV_OPA_90 = 229,
57 LV_OPA_100 = 255,
58 LV_OPA_COVER = 255,
59 };
60
61 #define LV_OPA_MIN 2 /*Opacities below this will be transparent*/
62 #define LV_OPA_MAX 253 /*Opacities above this will fully cover*/
63
64 #if LV_COLOR_DEPTH == 1
65 #define LV_COLOR_SIZE 8
66 #elif LV_COLOR_DEPTH == 8
67 #define LV_COLOR_SIZE 8
68 #elif LV_COLOR_DEPTH == 16
69 #define LV_COLOR_SIZE 16
70 #elif LV_COLOR_DEPTH == 32
71 #define LV_COLOR_SIZE 32
72 #else
73 #error "Invalid LV_COLOR_DEPTH in lv_conf.h! Set it to 1, 8, 16 or 32!"
74 #endif
75
76 #if defined(__cplusplus) && !defined(_LV_COLOR_HAS_MODERN_CPP)
77 /**
78 * MSVC compiler's definition of the __cplusplus indicating 199711L regardless to C++ standard version
79 * see https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-cplusplus
80 * so we use _MSC_VER macro instead of __cplusplus
81 */
82 #ifdef _MSC_VER
83 #if _MSC_VER >= 1900 /*Visual Studio 2015*/
84 #define _LV_COLOR_HAS_MODERN_CPP 1
85 #endif
86 #else
87 #if __cplusplus >= 201103L
88 #define _LV_COLOR_HAS_MODERN_CPP 1
89 #endif
90 #endif
91 #endif /*__cplusplus*/
92
93 #ifndef _LV_COLOR_HAS_MODERN_CPP
94 #define _LV_COLOR_HAS_MODERN_CPP 0
95 #endif
96
97 #if _LV_COLOR_HAS_MODERN_CPP
98 /*Fix msvc compiler error C4576 inside C++ code*/
99 #define _LV_COLOR_MAKE_TYPE_HELPER lv_color_t
100 #else
101 #define _LV_COLOR_MAKE_TYPE_HELPER (lv_color_t)
102 #endif
103
104 /*---------------------------------------
105 * Macros for all existing color depths
106 * to set/get values of the color channels
107 *------------------------------------------*/
108 # define LV_COLOR_SET_R1(c, v) (c).ch.red = (uint8_t)((v) & 0x1)
109 # define LV_COLOR_SET_G1(c, v) (c).ch.green = (uint8_t)((v) & 0x1)
110 # define LV_COLOR_SET_B1(c, v) (c).ch.blue = (uint8_t)((v) & 0x1)
111 # define LV_COLOR_SET_A1(c, v) do {} while(0)
112
113 # define LV_COLOR_GET_R1(c) (c).ch.red
114 # define LV_COLOR_GET_G1(c) (c).ch.green
115 # define LV_COLOR_GET_B1(c) (c).ch.blue
116 # define LV_COLOR_GET_A1(c) 0xFF
117
118 # define _LV_COLOR_ZERO_INITIALIZER1 {0x00}
119 # define LV_COLOR_MAKE1(r8, g8, b8) {(uint8_t)((b8 >> 7) | (g8 >> 7) | (r8 >> 7))}
120
121 # define LV_COLOR_SET_R8(c, v) (c).ch.red = (uint8_t)((v) & 0x7U)
122 # define LV_COLOR_SET_G8(c, v) (c).ch.green = (uint8_t)((v) & 0x7U)
123 # define LV_COLOR_SET_B8(c, v) (c).ch.blue = (uint8_t)((v) & 0x3U)
124 # define LV_COLOR_SET_A8(c, v) do {} while(0)
125
126 # define LV_COLOR_GET_R8(c) (c).ch.red
127 # define LV_COLOR_GET_G8(c) (c).ch.green
128 # define LV_COLOR_GET_B8(c) (c).ch.blue
129 # define LV_COLOR_GET_A8(c) 0xFF
130
131 # define _LV_COLOR_ZERO_INITIALIZER8 {{0x00, 0x00, 0x00}}
132 # define LV_COLOR_MAKE8(r8, g8, b8) {{(uint8_t)((b8 >> 6) & 0x3U), (uint8_t)((g8 >> 5) & 0x7U), (uint8_t)((r8 >> 5) & 0x7U)}}
133
134 # define LV_COLOR_SET_R16(c, v) (c).ch.red = (uint8_t)((v) & 0x1FU)
135 #if LV_COLOR_16_SWAP == 0
136 # define LV_COLOR_SET_G16(c, v) (c).ch.green = (uint8_t)((v) & 0x3FU)
137 #else
138 # define LV_COLOR_SET_G16(c, v) {(c).ch.green_h = (uint8_t)(((v) >> 3) & 0x7); (c).ch.green_l = (uint8_t)((v) & 0x7);}
139 #endif
140 # define LV_COLOR_SET_B16(c, v) (c).ch.blue = (uint8_t)((v) & 0x1FU)
141 # define LV_COLOR_SET_A16(c, v) do {} while(0)
142
143 # define LV_COLOR_GET_R16(c) (c).ch.red
144 #if LV_COLOR_16_SWAP == 0
145 # define LV_COLOR_GET_G16(c) (c).ch.green
146 #else
147 # define LV_COLOR_GET_G16(c) (((c).ch.green_h << 3) + (c).ch.green_l)
148 #endif
149 # define LV_COLOR_GET_B16(c) (c).ch.blue
150 # define LV_COLOR_GET_A16(c) 0xFF
151
152 #if LV_COLOR_16_SWAP == 0
153 # define _LV_COLOR_ZERO_INITIALIZER16 {{0x00, 0x00, 0x00}}
154 # define LV_COLOR_MAKE16(r8, g8, b8) {{(uint8_t)((b8 >> 3) & 0x1FU), (uint8_t)((g8 >> 2) & 0x3FU), (uint8_t)((r8 >> 3) & 0x1FU)}}
155 #else
156 # define _LV_COLOR_ZERO_INITIALIZER16 {{0x00, 0x00, 0x00, 0x00}}
157 # define LV_COLOR_MAKE16(r8, g8, b8) {{(uint8_t)((g8 >> 5) & 0x7U), (uint8_t)((r8 >> 3) & 0x1FU), (uint8_t)((b8 >> 3) & 0x1FU), (uint8_t)((g8 >> 2) & 0x7U)}}
158 #endif
159
160 # define LV_COLOR_SET_R32(c, v) (c).ch.red = (uint8_t)((v) & 0xFF)
161 # define LV_COLOR_SET_G32(c, v) (c).ch.green = (uint8_t)((v) & 0xFF)
162 # define LV_COLOR_SET_B32(c, v) (c).ch.blue = (uint8_t)((v) & 0xFF)
163 # define LV_COLOR_SET_A32(c, v) (c).ch.alpha = (uint8_t)((v) & 0xFF)
164
165 # define LV_COLOR_GET_R32(c) (c).ch.red
166 # define LV_COLOR_GET_G32(c) (c).ch.green
167 # define LV_COLOR_GET_B32(c) (c).ch.blue
168 # define LV_COLOR_GET_A32(c) (c).ch.alpha
169
170 # define _LV_COLOR_ZERO_INITIALIZER32 {{0x00, 0x00, 0x00, 0x00}}
171 # define LV_COLOR_MAKE32(r8, g8, b8) {{b8, g8, r8, 0xff}} /*Fix 0xff alpha*/
172
173 /*---------------------------------------
174 * Macros for the current color depth
175 * to set/get values of the color channels
176 *------------------------------------------*/
177 #define LV_COLOR_SET_R(c, v) LV_CONCAT(LV_COLOR_SET_R, LV_COLOR_DEPTH)(c, v)
178 #define LV_COLOR_SET_G(c, v) LV_CONCAT(LV_COLOR_SET_G, LV_COLOR_DEPTH)(c, v)
179 #define LV_COLOR_SET_B(c, v) LV_CONCAT(LV_COLOR_SET_B, LV_COLOR_DEPTH)(c, v)
180 #define LV_COLOR_SET_A(c, v) LV_CONCAT(LV_COLOR_SET_A, LV_COLOR_DEPTH)(c, v)
181
182 #define LV_COLOR_GET_R(c) LV_CONCAT(LV_COLOR_GET_R, LV_COLOR_DEPTH)(c)
183 #define LV_COLOR_GET_G(c) LV_CONCAT(LV_COLOR_GET_G, LV_COLOR_DEPTH)(c)
184 #define LV_COLOR_GET_B(c) LV_CONCAT(LV_COLOR_GET_B, LV_COLOR_DEPTH)(c)
185 #define LV_COLOR_GET_A(c) LV_CONCAT(LV_COLOR_GET_A, LV_COLOR_DEPTH)(c)
186
187 #define _LV_COLOR_ZERO_INITIALIZER LV_CONCAT(_LV_COLOR_ZERO_INITIALIZER, LV_COLOR_DEPTH)
188 #define LV_COLOR_MAKE(r8, g8, b8) LV_CONCAT(LV_COLOR_MAKE, LV_COLOR_DEPTH)(r8, g8, b8)
189
190 /**********************
191 * TYPEDEFS
192 **********************/
193
194 typedef union {
195 uint8_t full; /*must be declared first to set all bits of byte via initializer list*/
196 union {
197 uint8_t blue : 1;
198 uint8_t green : 1;
199 uint8_t red : 1;
200 } ch;
201 } lv_color1_t;
202
203 typedef union {
204 struct {
205 uint8_t blue : 2;
206 uint8_t green : 3;
207 uint8_t red : 3;
208 } ch;
209 uint8_t full;
210 } lv_color8_t;
211
212 typedef union {
213 struct {
214 #if LV_COLOR_16_SWAP == 0
215 uint16_t blue : 5;
216 uint16_t green : 6;
217 uint16_t red : 5;
218 #else
219 uint16_t green_h : 3;
220 uint16_t red : 5;
221 uint16_t blue : 5;
222 uint16_t green_l : 3;
223 #endif
224 } ch;
225 uint16_t full;
226 } lv_color16_t;
227
228 typedef union {
229 struct {
230 uint8_t blue;
231 uint8_t green;
232 uint8_t red;
233 uint8_t alpha;
234 } ch;
235 uint32_t full;
236 } lv_color32_t;
237
238 typedef LV_CONCAT3(uint, LV_COLOR_SIZE, _t) lv_color_int_t;
239 typedef LV_CONCAT3(lv_color, LV_COLOR_DEPTH, _t) lv_color_t;
240
241 typedef struct {
242 uint16_t h;
243 uint8_t s;
244 uint8_t v;
245 } lv_color_hsv_t;
246
247 //! @cond Doxygen_Suppress
248 /*No idea where the guard is required but else throws warnings in the docs*/
249 typedef uint8_t lv_opa_t;
250 //! @endcond
251
252 struct _lv_color_filter_dsc_t;
253
254 typedef lv_color_t (*lv_color_filter_cb_t)(const struct _lv_color_filter_dsc_t *, lv_color_t, lv_opa_t);
255
256 typedef struct _lv_color_filter_dsc_t {
257 lv_color_filter_cb_t filter_cb;
258 void * user_data;
259 } lv_color_filter_dsc_t;
260
261
262 typedef enum {
263 LV_PALETTE_RED,
264 LV_PALETTE_PINK,
265 LV_PALETTE_PURPLE,
266 LV_PALETTE_DEEP_PURPLE,
267 LV_PALETTE_INDIGO,
268 LV_PALETTE_BLUE,
269 LV_PALETTE_LIGHT_BLUE,
270 LV_PALETTE_CYAN,
271 LV_PALETTE_TEAL,
272 LV_PALETTE_GREEN,
273 LV_PALETTE_LIGHT_GREEN,
274 LV_PALETTE_LIME,
275 LV_PALETTE_YELLOW,
276 LV_PALETTE_AMBER,
277 LV_PALETTE_ORANGE,
278 LV_PALETTE_DEEP_ORANGE,
279 LV_PALETTE_BROWN,
280 LV_PALETTE_BLUE_GREY,
281 LV_PALETTE_GREY,
282 _LV_PALETTE_LAST,
283 LV_PALETTE_NONE = 0xff,
284 } lv_palette_t;
285
286 /**********************
287 * GLOBAL PROTOTYPES
288 **********************/
289
290 /*In color conversations:
291 * - When converting to bigger color type the LSB weight of 1 LSB is calculated
292 * E.g. 16 bit Red has 5 bits
293 * 8 bit Red has 3 bits
294 * ----------------------
295 * 8 bit red LSB = (2^5 - 1) / (2^3 - 1) = 31 / 7 = 4
296 *
297 * - When calculating to smaller color type simply shift out the LSBs
298 * E.g. 8 bit Red has 3 bits
299 * 16 bit Red has 5 bits
300 * ----------------------
301 * Shift right with 5 - 3 = 2
302 */
lv_color_to1(lv_color_t color)303 static inline uint8_t lv_color_to1(lv_color_t color)
304 {
305 #if LV_COLOR_DEPTH == 1
306 return color.full;
307 #elif LV_COLOR_DEPTH == 8
308 if((LV_COLOR_GET_R(color) & 0x4) || (LV_COLOR_GET_G(color) & 0x4) || (LV_COLOR_GET_B(color) & 0x2)) {
309 return 1;
310 }
311 else {
312 return 0;
313 }
314 #elif LV_COLOR_DEPTH == 16
315 if((LV_COLOR_GET_R(color) & 0x10) || (LV_COLOR_GET_G(color) & 0x20) || (LV_COLOR_GET_B(color) & 0x10)) {
316 return 1;
317 }
318 else {
319 return 0;
320 }
321 #elif LV_COLOR_DEPTH == 32
322 if((LV_COLOR_GET_R(color) & 0x80) || (LV_COLOR_GET_G(color) & 0x80) || (LV_COLOR_GET_B(color) & 0x80)) {
323 return 1;
324 }
325 else {
326 return 0;
327 }
328 #endif
329 }
330
lv_color_to8(lv_color_t color)331 static inline uint8_t lv_color_to8(lv_color_t color)
332 {
333 #if LV_COLOR_DEPTH == 1
334 if(color.full == 0)
335 return 0;
336 else
337 return 0xFF;
338 #elif LV_COLOR_DEPTH == 8
339 return color.full;
340 #elif LV_COLOR_DEPTH == 16
341 lv_color8_t ret;
342 LV_COLOR_SET_R8(ret, LV_COLOR_GET_R(color) >> 2); /*5 - 3 = 2*/
343 LV_COLOR_SET_G8(ret, LV_COLOR_GET_G(color) >> 3); /*6 - 3 = 3*/
344 LV_COLOR_SET_B8(ret, LV_COLOR_GET_B(color) >> 3); /*5 - 2 = 3*/
345 return ret.full;
346 #elif LV_COLOR_DEPTH == 32
347 lv_color8_t ret;
348 LV_COLOR_SET_R8(ret, LV_COLOR_GET_R(color) >> 5); /*8 - 3 = 5*/
349 LV_COLOR_SET_G8(ret, LV_COLOR_GET_G(color) >> 5); /*8 - 3 = 5*/
350 LV_COLOR_SET_B8(ret, LV_COLOR_GET_B(color) >> 6); /*8 - 2 = 6*/
351 return ret.full;
352 #endif
353 }
354
lv_color_to16(lv_color_t color)355 static inline uint16_t lv_color_to16(lv_color_t color)
356 {
357 #if LV_COLOR_DEPTH == 1
358 if(color.full == 0)
359 return 0;
360 else
361 return 0xFFFF;
362 #elif LV_COLOR_DEPTH == 8
363 lv_color16_t ret;
364 LV_COLOR_SET_R16(ret, LV_COLOR_GET_R(color) * 4); /*(2^5 - 1)/(2^3 - 1) = 31/7 = 4*/
365 LV_COLOR_SET_G16(ret, LV_COLOR_GET_G(color) * 9); /*(2^6 - 1)/(2^3 - 1) = 63/7 = 9*/
366 LV_COLOR_SET_B16(ret, LV_COLOR_GET_B(color) * 10); /*(2^5 - 1)/(2^2 - 1) = 31/3 = 10*/
367 return ret.full;
368 #elif LV_COLOR_DEPTH == 16
369 return color.full;
370 #elif LV_COLOR_DEPTH == 32
371 lv_color16_t ret;
372 LV_COLOR_SET_R16(ret, LV_COLOR_GET_R(color) >> 3); /*8 - 5 = 3*/
373 LV_COLOR_SET_G16(ret, LV_COLOR_GET_G(color) >> 2); /*8 - 6 = 2*/
374 LV_COLOR_SET_B16(ret, LV_COLOR_GET_B(color) >> 3); /*8 - 5 = 3*/
375 return ret.full;
376 #endif
377 }
378
lv_color_to32(lv_color_t color)379 static inline uint32_t lv_color_to32(lv_color_t color)
380 {
381 #if LV_COLOR_DEPTH == 1
382 if(color.full == 0)
383 return 0xFF000000;
384 else
385 return 0xFFFFFFFF;
386 #elif LV_COLOR_DEPTH == 8
387 lv_color32_t ret;
388 LV_COLOR_SET_R32(ret, LV_COLOR_GET_R(color) * 36); /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/
389 LV_COLOR_SET_G32(ret, LV_COLOR_GET_G(color) * 36); /*(2^8 - 1)/(2^3 - 1) = 255/7 = 36*/
390 LV_COLOR_SET_B32(ret, LV_COLOR_GET_B(color) * 85); /*(2^8 - 1)/(2^2 - 1) = 255/3 = 85*/
391 LV_COLOR_SET_A32(ret, 0xFF);
392 return ret.full;
393 #elif LV_COLOR_DEPTH == 16
394 /**
395 * The floating point math for conversion is:
396 * valueto = valuefrom * ( (2^bitsto - 1) / (float)(2^bitsfrom - 1) )
397 * The faster integer math for conversion is:
398 * valueto = ( valuefrom * multiplier + adder ) >> divisor
399 * multiplier = FLOOR( ( (2^bitsto - 1) << divisor ) / (float)(2^bitsfrom - 1) )
400 *
401 * Find the first divisor where ( adder >> divisor ) <= 0
402 *
403 * 5-bit to 8-bit: ( 31 * multiplier + adder ) >> divisor = 255
404 * divisor multiplier adder min (0) max (31)
405 * 0 8 7 7 255
406 * 1 16 14 7 255
407 * 2 32 28 7 255
408 * 3 65 25 3 255
409 * 4 131 19 1 255
410 * 5 263 7 0 255
411 *
412 * 6-bit to 8-bit: 255 = ( 63 * multiplier + adder ) >> divisor
413 * divisor multiplier adder min (0) max (63)
414 * 0 4 3 3 255
415 * 1 8 6 3 255
416 * 2 16 12 3 255
417 * 3 32 24 3 255
418 * 4 64 48 3 255
419 * 5 129 33 1 255
420 * 6 259 3 0 255
421 */
422
423 lv_color32_t ret;
424 LV_COLOR_SET_R32(ret, (LV_COLOR_GET_R(color) * 263 + 7) >> 5);
425 LV_COLOR_SET_G32(ret, (LV_COLOR_GET_G(color) * 259 + 3) >> 6);
426 LV_COLOR_SET_B32(ret, (LV_COLOR_GET_B(color) * 263 + 7) >> 5);
427 LV_COLOR_SET_A32(ret, 0xFF);
428 return ret.full;
429 #elif LV_COLOR_DEPTH == 32
430 return color.full;
431 #endif
432 }
433
434 //! @cond Doxygen_Suppress
435
436 /**
437 * Mix two colors with a given ratio.
438 * @param c1 the first color to mix (usually the foreground)
439 * @param c2 the second color to mix (usually the background)
440 * @param mix The ratio of the colors. 0: full `c2`, 255: full `c1`, 127: half `c1` and half`c2`
441 * @return the mixed color
442 */
lv_color_mix(lv_color_t c1,lv_color_t c2,uint8_t mix)443 LV_ATTRIBUTE_FAST_MEM static inline lv_color_t lv_color_mix(lv_color_t c1, lv_color_t c2, uint8_t mix)
444 {
445 lv_color_t ret;
446
447 #if LV_COLOR_DEPTH == 16 && LV_COLOR_16_SWAP == 0
448 /*Source: https://stackoverflow.com/a/50012418/1999969*/
449 mix = (mix + 4) >> 3;
450 uint32_t bg = (uint32_t)((uint32_t)c2.full | ((uint32_t)c2.full << 16)) &
451 0x7E0F81F; /*0b00000111111000001111100000011111*/
452 uint32_t fg = (uint32_t)((uint32_t)c1.full | ((uint32_t)c1.full << 16)) & 0x7E0F81F;
453 uint32_t result = ((((fg - bg) * mix) >> 5) + bg) & 0x7E0F81F;
454 ret.full = (uint16_t)((result >> 16) | result);
455 #elif LV_COLOR_DEPTH != 1
456 /*LV_COLOR_DEPTH == 8, 16 or 32*/
457 LV_COLOR_SET_R(ret, LV_UDIV255((uint16_t)LV_COLOR_GET_R(c1) * mix + LV_COLOR_GET_R(c2) *
458 (255 - mix) + LV_COLOR_MIX_ROUND_OFS));
459 LV_COLOR_SET_G(ret, LV_UDIV255((uint16_t)LV_COLOR_GET_G(c1) * mix + LV_COLOR_GET_G(c2) *
460 (255 - mix) + LV_COLOR_MIX_ROUND_OFS));
461 LV_COLOR_SET_B(ret, LV_UDIV255((uint16_t)LV_COLOR_GET_B(c1) * mix + LV_COLOR_GET_B(c2) *
462 (255 - mix) + LV_COLOR_MIX_ROUND_OFS));
463 LV_COLOR_SET_A(ret, 0xFF);
464 #else
465 /*LV_COLOR_DEPTH == 1*/
466 ret.full = mix > LV_OPA_50 ? c1.full : c2.full;
467 #endif
468
469 return ret;
470 }
471
lv_color_premult(lv_color_t c,uint8_t mix,uint16_t * out)472 LV_ATTRIBUTE_FAST_MEM static inline void lv_color_premult(lv_color_t c, uint8_t mix, uint16_t * out)
473 {
474 #if LV_COLOR_DEPTH != 1
475 out[0] = (uint16_t)LV_COLOR_GET_R(c) * mix;
476 out[1] = (uint16_t)LV_COLOR_GET_G(c) * mix;
477 out[2] = (uint16_t)LV_COLOR_GET_B(c) * mix;
478 #else
479 (void) mix;
480 /*Pre-multiplication can't be used with 1 bpp*/
481 out[0] = LV_COLOR_GET_R(c);
482 out[1] = LV_COLOR_GET_G(c);
483 out[2] = LV_COLOR_GET_B(c);
484 #endif
485
486 }
487
488 /**
489 * Mix two colors with a given ratio. It runs faster then `lv_color_mix` but requires some pre computation.
490 * @param premult_c1 The first color. Should be preprocessed with `lv_color_premult(c1)`
491 * @param c2 The second color. As it is no pre computation required on it
492 * @param mix The ratio of the colors. 0: full `c1`, 255: full `c2`, 127: half `c1` and half `c2`.
493 * Should be modified like mix = `255 - mix`
494 * @return the mixed color
495 * @note 255 won't give clearly `c1`.
496 */
lv_color_mix_premult(uint16_t * premult_c1,lv_color_t c2,uint8_t mix)497 LV_ATTRIBUTE_FAST_MEM static inline lv_color_t lv_color_mix_premult(uint16_t * premult_c1, lv_color_t c2, uint8_t mix)
498 {
499 lv_color_t ret;
500 #if LV_COLOR_DEPTH != 1
501 /*LV_COLOR_DEPTH == 8 or 32*/
502 LV_COLOR_SET_R(ret, LV_UDIV255(premult_c1[0] + LV_COLOR_GET_R(c2) * mix + LV_COLOR_MIX_ROUND_OFS));
503 LV_COLOR_SET_G(ret, LV_UDIV255(premult_c1[1] + LV_COLOR_GET_G(c2) * mix + LV_COLOR_MIX_ROUND_OFS));
504 LV_COLOR_SET_B(ret, LV_UDIV255(premult_c1[2] + LV_COLOR_GET_B(c2) * mix + LV_COLOR_MIX_ROUND_OFS));
505 LV_COLOR_SET_A(ret, 0xFF);
506 #else
507 /*LV_COLOR_DEPTH == 1*/
508 /*Restore color1*/
509 lv_color_t c1;
510 LV_COLOR_SET_R(c1, premult_c1[0]);
511 LV_COLOR_SET_G(c1, premult_c1[1]);
512 LV_COLOR_SET_B(c1, premult_c1[2]);
513 ret.full = mix > LV_OPA_50 ? c2.full : c1.full;
514 #endif
515
516 return ret;
517 }
518
519 /**
520 * Mix two colors. Both color can have alpha value.
521 * @param bg_color background color
522 * @param bg_opa alpha of the background color
523 * @param fg_color foreground color
524 * @param fg_opa alpha of the foreground color
525 * @param res_color the result color
526 * @param res_opa the result opacity
527 */
lv_color_mix_with_alpha(lv_color_t bg_color,lv_opa_t bg_opa,lv_color_t fg_color,lv_opa_t fg_opa,lv_color_t * res_color,lv_opa_t * res_opa)528 LV_ATTRIBUTE_FAST_MEM static inline void lv_color_mix_with_alpha(lv_color_t bg_color, lv_opa_t bg_opa,
529 lv_color_t fg_color, lv_opa_t fg_opa,
530 lv_color_t * res_color, lv_opa_t * res_opa)
531 {
532 /*Pick the foreground if it's fully opaque or the Background is fully transparent*/
533 if(fg_opa >= LV_OPA_MAX || bg_opa <= LV_OPA_MIN) {
534 res_color->full = fg_color.full;
535 *res_opa = fg_opa;
536 }
537 /*Transparent foreground: use the Background*/
538 else if(fg_opa <= LV_OPA_MIN) {
539 res_color->full = bg_color.full;
540 *res_opa = bg_opa;
541 }
542 /*Opaque background: use simple mix*/
543 else if(bg_opa >= LV_OPA_MAX) {
544 *res_color = lv_color_mix(fg_color, bg_color, fg_opa);
545 *res_opa = LV_OPA_COVER;
546 }
547 /*Both colors have alpha. Expensive calculation need to be applied*/
548 else {
549 /*Save the parameters and the result. If they will be asked again don't compute again*/
550 static lv_opa_t fg_opa_save = 0;
551 static lv_opa_t bg_opa_save = 0;
552 static lv_color_t fg_color_save = _LV_COLOR_ZERO_INITIALIZER;
553 static lv_color_t bg_color_save = _LV_COLOR_ZERO_INITIALIZER;
554 static lv_color_t res_color_saved = _LV_COLOR_ZERO_INITIALIZER;
555 static lv_opa_t res_opa_saved = 0;
556
557 if(fg_opa != fg_opa_save || bg_opa != bg_opa_save || fg_color.full != fg_color_save.full ||
558 bg_color.full != bg_color_save.full) {
559 fg_opa_save = fg_opa;
560 bg_opa_save = bg_opa;
561 fg_color_save.full = fg_color.full;
562 bg_color_save.full = bg_color.full;
563 /*Info:
564 * https://en.wikipedia.org/wiki/Alpha_compositing#Analytical_derivation_of_the_over_operator*/
565 res_opa_saved = 255 - ((uint16_t)((uint16_t)(255 - fg_opa) * (255 - bg_opa)) >> 8);
566 LV_ASSERT(res_opa_saved != 0);
567 lv_opa_t ratio = (uint16_t)((uint16_t)fg_opa * 255) / res_opa_saved;
568 res_color_saved = lv_color_mix(fg_color, bg_color, ratio);
569
570 }
571
572 res_color->full = res_color_saved.full;
573 *res_opa = res_opa_saved;
574 }
575 }
576
577 //! @endcond
578
579 /**
580 * Get the brightness of a color
581 * @param color a color
582 * @return the brightness [0..255]
583 */
lv_color_brightness(lv_color_t color)584 static inline uint8_t lv_color_brightness(lv_color_t color)
585 {
586 lv_color32_t c32;
587 c32.full = lv_color_to32(color);
588 uint16_t bright = (uint16_t)(3u * LV_COLOR_GET_R32(c32) + LV_COLOR_GET_B32(c32) + 4u * LV_COLOR_GET_G32(c32));
589 return (uint8_t)(bright >> 3);
590 }
591
lv_color_make(uint8_t r,uint8_t g,uint8_t b)592 static inline lv_color_t lv_color_make(uint8_t r, uint8_t g, uint8_t b)
593 {
594 return _LV_COLOR_MAKE_TYPE_HELPER LV_COLOR_MAKE(r, g, b);
595 }
596
lv_color_hex(uint32_t c)597 static inline lv_color_t lv_color_hex(uint32_t c)
598 {
599 #if LV_COLOR_DEPTH == 16
600 lv_color_t r;
601 #if LV_COLOR_16_SWAP == 0
602 /* Convert a 4 bytes per pixel in format ARGB32 to R5G6B5 format
603 naive way (by calling lv_color_make with components):
604 r = ((c & 0xFF0000) >> 19)
605 g = ((c & 0xFF00) >> 10)
606 b = ((c & 0xFF) >> 3)
607 rgb565 = (r << 11) | (g << 5) | b
608 That's 3 mask, 5 bitshift and 2 or operations
609
610 A bit better:
611 r = ((c & 0xF80000) >> 8)
612 g = ((c & 0xFC00) >> 5)
613 b = ((c & 0xFF) >> 3)
614 rgb565 = r | g | b
615 That's 3 mask, 3 bitshifts and 2 or operations */
616 r.full = (uint16_t)(((c & 0xF80000) >> 8) | ((c & 0xFC00) >> 5) | ((c & 0xFF) >> 3));
617 #else
618 /* We want: rrrr rrrr GGGg gggg bbbb bbbb => gggb bbbb rrrr rGGG */
619 r.full = (uint16_t)(((c & 0xF80000) >> 16) | ((c & 0xFC00) >> 13) | ((c & 0x1C00) << 3) | ((c & 0xF8) << 5));
620 #endif
621 return r;
622 #elif LV_COLOR_DEPTH == 32
623 lv_color_t r;
624 r.full = c | 0xFF000000;
625 return r;
626 #else /*LV_COLOR_DEPTH == 8*/
627 return lv_color_make((uint8_t)((c >> 16) & 0xFF), (uint8_t)((c >> 8) & 0xFF), (uint8_t)(c & 0xFF));
628 #endif
629 }
630
lv_color_hex3(uint32_t c)631 static inline lv_color_t lv_color_hex3(uint32_t c)
632 {
633 return lv_color_make((uint8_t)(((c >> 4) & 0xF0) | ((c >> 8) & 0xF)), (uint8_t)((c & 0xF0) | ((c & 0xF0) >> 4)),
634 (uint8_t)((c & 0xF) | ((c & 0xF) << 4)));
635 }
636
lv_color_filter_dsc_init(lv_color_filter_dsc_t * dsc,lv_color_filter_cb_t cb)637 static inline void lv_color_filter_dsc_init(lv_color_filter_dsc_t * dsc, lv_color_filter_cb_t cb)
638 {
639 dsc->filter_cb = cb;
640 }
641
642 //! @cond Doxygen_Suppress
643 //!
644 LV_ATTRIBUTE_FAST_MEM void lv_color_fill(lv_color_t * buf, lv_color_t color, uint32_t px_num);
645
646 //! @endcond
647 lv_color_t lv_color_lighten(lv_color_t c, lv_opa_t lvl);
648
649 lv_color_t lv_color_darken(lv_color_t c, lv_opa_t lvl);
650
651 lv_color_t lv_color_change_lightness(lv_color_t c, lv_opa_t lvl);
652
653 /**
654 * Convert a HSV color to RGB
655 * @param h hue [0..359]
656 * @param s saturation [0..100]
657 * @param v value [0..100]
658 * @return the given RGB color in RGB (with LV_COLOR_DEPTH depth)
659 */
660 lv_color_t lv_color_hsv_to_rgb(uint16_t h, uint8_t s, uint8_t v);
661
662 /**
663 * Convert a 32-bit RGB color to HSV
664 * @param r8 8-bit red
665 * @param g8 8-bit green
666 * @param b8 8-bit blue
667 * @return the given RGB color in HSV
668 */
669 lv_color_hsv_t lv_color_rgb_to_hsv(uint8_t r8, uint8_t g8, uint8_t b8);
670
671 /**
672 * Convert a color to HSV
673 * @param color color
674 * @return the given color in HSV
675 */
676 lv_color_hsv_t lv_color_to_hsv(lv_color_t color);
677
678 /**
679 * Just a wrapper around LV_COLOR_CHROMA_KEY because it might be more convenient to use a function is some cases
680 * @return LV_COLOR_CHROMA_KEY
681 */
lv_color_chroma_key(void)682 static inline lv_color_t lv_color_chroma_key(void)
683 {
684 return LV_COLOR_CHROMA_KEY;
685 }
686
687 /**********************
688 * PREDEFINED COLORS
689 **********************/
690 /*Source: https://vuetifyjs.com/en/styles/colors/#material-colors*/
691
692 lv_color_t lv_palette_main(lv_palette_t p);
lv_color_white(void)693 static inline lv_color_t lv_color_white(void)
694 {
695 return lv_color_make(0xff, 0xff, 0xff);
696 }
lv_color_black(void)697 static inline lv_color_t lv_color_black(void)
698 {
699 return lv_color_make(0x00, 0x0, 0x00);
700 }
701 lv_color_t lv_palette_lighten(lv_palette_t p, uint8_t lvl);
702 lv_color_t lv_palette_darken(lv_palette_t p, uint8_t lvl);
703
704 /**********************
705 * MACROS
706 **********************/
707
708 #ifdef __cplusplus
709 } /*extern "C"*/
710 #endif
711
712 #endif /*LV_COLOR_H*/
713