ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
colorconv.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <algorithm>
7
8/* Utility for converting internal \a Color RGB representation to supported IC hardware color keys
9 *
10 * Focus in driver layer is on efficiency.
11 * For optimum output quality on RGB inputs consider offline color keying/dithering.
12 * Also see e.g. Image component.
13 */
14
16
17// The Rec.601 luma helpers and the RGB565 mono lookup live in the shared display utilities, so other
18// drivers (e.g. it8951 in its 1 bit per pixel mode) can use them too.
22
24static constexpr uint8_t COLORCONV_GRAY_THRESHOLD = 50;
25
31constexpr uint8_t color_to_gray4(Color color) {
32 const uint8_t level = (uint8_t) ((rec601_luma(color) + 32u) >> 6); // quantize 0..255 to 0..3, rounded
33 return level > 3 ? 3 : level;
34}
35
46template<typename NATIVE_COLOR>
47constexpr NATIVE_COLOR color_to_bwyr(Color color, NATIVE_COLOR hw_black, NATIVE_COLOR hw_white, NATIVE_COLOR hw_yellow,
48 NATIVE_COLOR hw_red) {
49 // --- Step 1: Check for Grayscale (Black or White) ---
50 // We define "grayscale" as a color where the min and max components
51 // are close to each other.
52
53 const auto [min_rgb, max_rgb] = std::minmax({color.r, color.g, color.b});
54
55 if ((max_rgb - min_rgb) < COLORCONV_GRAY_THRESHOLD) {
56 // It's a shade of gray. Map to BLACK or WHITE.
57 return color_to_mono(color) ? hw_white : hw_black;
58 }
59
60 // --- Step 2: Check for Primary/Secondary Colors ---
61 // If it's not gray, it's a color. We check which components are
62 // "on" (over 128) vs "off". This divides the RGB cube into 8 corners.
63 const bool r_on = (color.r > 128);
64 const bool g_on = (color.g > 128);
65 const bool b_on = (color.b > 128);
66
67 if (r_on) {
68 if (!b_on) {
69 return g_on ? hw_yellow : hw_red;
70 }
71
72 // At least red+blue high (but not gray) -> White
73 return hw_white;
74 } else {
75 return (b_on && g_on) ? hw_white : hw_black;
76 }
77}
78
91template<typename NATIVE_COLOR>
92constexpr NATIVE_COLOR color_to_bwr(Color color, NATIVE_COLOR hw_black, NATIVE_COLOR hw_white, NATIVE_COLOR hw_red) {
93 return color_to_bwyr<NATIVE_COLOR>(color, hw_black, hw_white, /*hw_yellow=*/hw_white, hw_red);
94}
95
112template<typename NATIVE_COLOR>
113constexpr NATIVE_COLOR color_to_bwyrgb(Color color, NATIVE_COLOR hw_black, NATIVE_COLOR hw_white,
114 NATIVE_COLOR hw_yellow, NATIVE_COLOR hw_red, NATIVE_COLOR hw_green,
115 NATIVE_COLOR hw_blue) {
116 const auto [min_rgb, max_rgb] = std::minmax({color.r, color.g, color.b});
117
118 if ((max_rgb - min_rgb) < COLORCONV_GRAY_THRESHOLD) {
119 return color_to_mono(color) ? hw_white : hw_black;
120 }
121
122 const bool r_on = (color.r > 128);
123 const bool g_on = (color.g > 128);
124 const bool b_on = (color.b > 128);
125
126 if (r_on && g_on && !b_on) {
127 return hw_yellow;
128 }
129 if (r_on && !g_on && !b_on) {
130 return hw_red;
131 }
132 if (!r_on && g_on && !b_on) {
133 return hw_green;
134 }
135 if (!r_on && !g_on && b_on) {
136 return hw_blue;
137 }
138 // Handle "impure" colors (cyan, magenta) by folding into the closest primary.
139 if (!r_on && g_on && b_on) {
140 return hw_green; // cyan
141 }
142 if (r_on && !g_on) {
143 return hw_red; // magenta
144 }
145 if (r_on) {
146 // All high (but not gray) -> white
147 return hw_white;
148 }
149 // !r_on && !g_on && !b_on
150 // All low (but not gray) -> black
151 return hw_black;
152}
153
170template<typename NATIVE_COLOR>
171constexpr NATIVE_COLOR color_to_bwyrgbo(Color color, NATIVE_COLOR hw_black, NATIVE_COLOR hw_white,
172 NATIVE_COLOR hw_yellow, NATIVE_COLOR hw_red, NATIVE_COLOR hw_green,
173 NATIVE_COLOR hw_blue, NATIVE_COLOR hw_orange) {
174 const auto [min_rgb, max_rgb] = std::minmax({color.r, color.g, color.b});
175
176 if ((max_rgb - min_rgb) < COLORCONV_GRAY_THRESHOLD) {
177 return color_to_mono(color) ? hw_white : hw_black;
178 }
179
180 const bool r_on = (color.r > 128);
181 const bool g_on = (color.g > 128);
182 const bool b_on = (color.b > 128);
183
184 if (r_on && !b_on) {
185 // Between red and yellow: split the gradient in three instead of two, since this panel has a
186 // dedicated orange ink. Named orange (e.g. 0xFFA500) has g close to the midpoint, so the
187 // plain g_on (>128) threshold used by color_to_bwyrgb can't tell it apart from yellow.
188 if (color.g > 170) {
189 return hw_yellow;
190 }
191 if (color.g > 85) {
192 return hw_orange;
193 }
194 return hw_red;
195 }
196 if (!r_on && g_on && !b_on) {
197 return hw_green;
198 }
199 if (!r_on && !g_on && b_on) {
200 return hw_blue;
201 }
202 // Handle "impure" colors (cyan, magenta) by folding into the closest primary.
203 if (!r_on && g_on && b_on) {
204 return hw_green; // cyan
205 }
206 if (r_on && !g_on) {
207 return hw_red; // magenta
208 }
209 if (r_on) {
210 // All high (but not gray) -> white
211 return hw_white;
212 }
213 // !r_on && !g_on && !b_on
214 // All low (but not gray) -> black
215 return hw_black;
216}
217
218} // namespace esphome::epaper_spi
color_to_mono() of an RGB565 value as ColorUtil::to_color() reads it, from table lookups instead of a...
constexpr uint8_t rec601_luma(Color color)
Rec.601 luma of an RGB color, for optimum perceptual brightness.
constexpr uint8_t color_to_mono(Color color)
Map an RGB color to a single monochrome bit: 1 = white, 0 = black.
constexpr NATIVE_COLOR color_to_bwyrgbo(Color color, NATIVE_COLOR hw_black, NATIVE_COLOR hw_white, NATIVE_COLOR hw_yellow, NATIVE_COLOR hw_red, NATIVE_COLOR hw_green, NATIVE_COLOR hw_blue, NATIVE_COLOR hw_orange)
Map RGB color to discrete BWYRGBO hex 7 color key.
Definition colorconv.h:171
constexpr uint8_t color_to_gray4(Color color)
Map RGB color to one of 4 discrete gray levels (2 bits per pixel)
Definition colorconv.h:31
constexpr NATIVE_COLOR color_to_bwr(Color color, NATIVE_COLOR hw_black, NATIVE_COLOR hw_white, NATIVE_COLOR hw_red)
Map RGB color to discrete BWR (black/white/red) 3 color key.
Definition colorconv.h:92
constexpr NATIVE_COLOR color_to_bwyrgb(Color color, NATIVE_COLOR hw_black, NATIVE_COLOR hw_white, NATIVE_COLOR hw_yellow, NATIVE_COLOR hw_red, NATIVE_COLOR hw_green, NATIVE_COLOR hw_blue)
Map RGB color to discrete BWYRGB hex 6 color key.
Definition colorconv.h:113
constexpr NATIVE_COLOR color_to_bwyr(Color color, NATIVE_COLOR hw_black, NATIVE_COLOR hw_white, NATIVE_COLOR hw_yellow, NATIVE_COLOR hw_red)
Map RGB color to discrete BWYR hex 4 color key.
Definition colorconv.h:47
uint8_t g
Definition color.h:34
uint8_t b
Definition color.h:38
uint8_t r
Definition color.h:30