ESPHome 2026.10.2
Loading...
Searching...
No Matches
colorconv.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <algorithm>
6
7/* Utility for converting internal \a Color RGB representation to supported IC hardware color keys
8 *
9 * Focus in driver layer is on efficiency.
10 * For optimum output quality on RGB inputs consider offline color keying/dithering.
11 * Also see e.g. Image component.
12 */
13
15
17static constexpr uint8_t COLORCONV_GRAY_THRESHOLD = 50;
18
20constexpr uint8_t rec601_luma(Color color) {
21 return (uint8_t) ((77u * color.r + 150u * color.g + 29u * color.b + 128u) >> 8);
22}
23
29constexpr uint8_t color_to_mono(Color color) { return rec601_luma(color) >= 128 ? 1 : 0; }
30
36constexpr uint8_t color_to_gray4(Color color) {
37 const uint8_t level = (uint8_t) ((rec601_luma(color) + 32u) >> 6); // quantize 0..255 to 0..3, rounded
38 return level > 3 ? 3 : level;
39}
40
51template<typename NATIVE_COLOR>
52constexpr NATIVE_COLOR color_to_bwyr(Color color, NATIVE_COLOR hw_black, NATIVE_COLOR hw_white, NATIVE_COLOR hw_yellow,
53 NATIVE_COLOR hw_red) {
54 // --- Step 1: Check for Grayscale (Black or White) ---
55 // We define "grayscale" as a color where the min and max components
56 // are close to each other.
57
58 const auto [min_rgb, max_rgb] = std::minmax({color.r, color.g, color.b});
59
60 if ((max_rgb - min_rgb) < COLORCONV_GRAY_THRESHOLD) {
61 // It's a shade of gray. Map to BLACK or WHITE.
62 return color_to_mono(color) ? hw_white : hw_black;
63 }
64
65 // --- Step 2: Check for Primary/Secondary Colors ---
66 // If it's not gray, it's a color. We check which components are
67 // "on" (over 128) vs "off". This divides the RGB cube into 8 corners.
68 const bool r_on = (color.r > 128);
69 const bool g_on = (color.g > 128);
70 const bool b_on = (color.b > 128);
71
72 if (r_on) {
73 if (!b_on) {
74 return g_on ? hw_yellow : hw_red;
75 }
76
77 // At least red+blue high (but not gray) -> White
78 return hw_white;
79 } else {
80 return (b_on && g_on) ? hw_white : hw_black;
81 }
82}
83
96template<typename NATIVE_COLOR>
97constexpr NATIVE_COLOR color_to_bwr(Color color, NATIVE_COLOR hw_black, NATIVE_COLOR hw_white, NATIVE_COLOR hw_red) {
98 return color_to_bwyr<NATIVE_COLOR>(color, hw_black, hw_white, /*hw_yellow=*/hw_white, hw_red);
99}
100
117template<typename NATIVE_COLOR>
118constexpr NATIVE_COLOR color_to_bwyrgb(Color color, NATIVE_COLOR hw_black, NATIVE_COLOR hw_white,
119 NATIVE_COLOR hw_yellow, NATIVE_COLOR hw_red, NATIVE_COLOR hw_green,
120 NATIVE_COLOR hw_blue) {
121 const auto [min_rgb, max_rgb] = std::minmax({color.r, color.g, color.b});
122
123 if ((max_rgb - min_rgb) < COLORCONV_GRAY_THRESHOLD) {
124 return color_to_mono(color) ? hw_white : hw_black;
125 }
126
127 const bool r_on = (color.r > 128);
128 const bool g_on = (color.g > 128);
129 const bool b_on = (color.b > 128);
130
131 if (r_on && g_on && !b_on) {
132 return hw_yellow;
133 }
134 if (r_on && !g_on && !b_on) {
135 return hw_red;
136 }
137 if (!r_on && g_on && !b_on) {
138 return hw_green;
139 }
140 if (!r_on && !g_on && b_on) {
141 return hw_blue;
142 }
143 // Handle "impure" colors (cyan, magenta) by folding into the closest primary.
144 if (!r_on && g_on && b_on) {
145 return hw_green; // cyan
146 }
147 if (r_on && !g_on) {
148 return hw_red; // magenta
149 }
150 if (r_on) {
151 // All high (but not gray) -> white
152 return hw_white;
153 }
154 // !r_on && !g_on && !b_on
155 // All low (but not gray) -> black
156 return hw_black;
157}
158
175template<typename NATIVE_COLOR>
176constexpr NATIVE_COLOR color_to_bwyrgbo(Color color, NATIVE_COLOR hw_black, NATIVE_COLOR hw_white,
177 NATIVE_COLOR hw_yellow, NATIVE_COLOR hw_red, NATIVE_COLOR hw_green,
178 NATIVE_COLOR hw_blue, NATIVE_COLOR hw_orange) {
179 const auto [min_rgb, max_rgb] = std::minmax({color.r, color.g, color.b});
180
181 if ((max_rgb - min_rgb) < COLORCONV_GRAY_THRESHOLD) {
182 return color_to_mono(color) ? hw_white : hw_black;
183 }
184
185 const bool r_on = (color.r > 128);
186 const bool g_on = (color.g > 128);
187 const bool b_on = (color.b > 128);
188
189 if (r_on && !b_on) {
190 // Between red and yellow: split the gradient in three instead of two, since this panel has a
191 // dedicated orange ink. Named orange (e.g. 0xFFA500) has g close to the midpoint, so the
192 // plain g_on (>128) threshold used by color_to_bwyrgb can't tell it apart from yellow.
193 if (color.g > 170) {
194 return hw_yellow;
195 }
196 if (color.g > 85) {
197 return hw_orange;
198 }
199 return hw_red;
200 }
201 if (!r_on && g_on && !b_on) {
202 return hw_green;
203 }
204 if (!r_on && !g_on && b_on) {
205 return hw_blue;
206 }
207 // Handle "impure" colors (cyan, magenta) by folding into the closest primary.
208 if (!r_on && g_on && b_on) {
209 return hw_green; // cyan
210 }
211 if (r_on && !g_on) {
212 return hw_red; // magenta
213 }
214 if (r_on) {
215 // All high (but not gray) -> white
216 return hw_white;
217 }
218 // !r_on && !g_on && !b_on
219 // All low (but not gray) -> black
220 return hw_black;
221}
222
223} // namespace esphome::epaper_spi
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:176
constexpr uint8_t rec601_luma(Color color)
Rec.601 luma (0.299/0.587/0.114 weights, scaled by 256) for optimum perceptual brightness.
Definition colorconv.h:20
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:36
constexpr uint8_t color_to_mono(Color color)
Map RGB color to a single monochrome bit.
Definition colorconv.h:29
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:97
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:118
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:52
uint8_t g
Definition color.h:34
uint8_t b
Definition color.h:38
uint8_t r
Definition color.h:30