ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
color_helpers.cpp
Go to the documentation of this file.
1#include "color_helpers.h"
2
3#include <algorithm>
4#include <cmath>
5
6namespace esphome::as734x {
7
8namespace {
9
10// Range McCamy's approximation is meaningful over.
11constexpr float CCT_MIN_K = 1000.0f;
12constexpr float CCT_MAX_K = 25000.0f;
13
14#ifdef USE_AS734X_RGB
15// sRGB transfer function.
16float gamma_correct(float channel) {
17 if (channel <= 0.0031308f) {
18 return 12.92f * channel;
19 }
20 return 1.055f * std::pow(channel, 1.0f / 2.4f) - 0.055f;
21}
22
23uint8_t to_byte(float channel) { return static_cast<uint8_t>(std::clamp(channel, 0.0f, 1.0f) * 255.0f); }
24#endif
25
26} // namespace
27
28float tristimulus_to_cct(float x, float y, float z) {
29 const float sum = x + y + z;
30 // The conversion matrices carry negative coefficients, so a spectrum unlike the one they were
31 // calibrated against can drive the sum to zero or below. Chromaticity is undefined there, and
32 // McCamy's formula would still return a plausible looking number from it.
33 if (sum <= MIN_TRISTIMULUS_SUM) {
34 return NAN;
35 }
36 const float chroma_x = x / sum;
37 const float chroma_y = y / sum;
38
39 // McCamy's approximation: cct = 437 n^3 + 3601 n^2 + 6861 n + 5517. The pole at
40 // chroma_y = 0.1858 sends the cubic off to either infinity, and it stays meaningless well
41 // either side of that, so the answer is only reported where the approximation holds.
42 const float denominator = 0.1858f - chroma_y;
43 if (std::abs(denominator) < 1e-4f) {
44 return NAN;
45 }
46 const float n = (chroma_x - 0.3320f) / denominator;
47 const float cct = ((437.0f * n + 3601.0f) * n + 6861.0f) * n + 5517.0f;
48 return (cct >= CCT_MIN_K && cct <= CCT_MAX_K) ? cct : NAN;
49}
50
51#ifdef USE_AS734X_RGB
52void tristimulus_to_rgb(float x, float y, float z, uint8_t &r, uint8_t &g, uint8_t &b) {
53 const float r_linear = 3.2406f * x - 1.5372f * y - 0.4986f * z;
54 const float g_linear = -0.9689f * x + 1.8758f * y + 0.0415f * z;
55 const float b_linear = 0.0557f * x - 0.2040f * y + 1.0570f * z;
56
57 r = to_byte(gamma_correct(r_linear));
58 g = to_byte(gamma_correct(g_linear));
59 b = to_byte(gamma_correct(b_linear));
60}
61#endif
62
63} // namespace esphome::as734x
bool z
Definition msa3xx.h:1
void tristimulus_to_rgb(float x, float y, float z, uint8_t &r, uint8_t &g, uint8_t &b)
float tristimulus_to_cct(float x, float y, float z)
constexpr float MIN_TRISTIMULUS_SUM
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6